You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by de...@apache.org on 2013/11/07 08:44:51 UTC

git commit: updated refs/heads/master to e77ab38

Updated Branches:
  refs/heads/master 7095ea2b5 -> e77ab3854


Fixing the implementation for AttachCommand and DetachCommand in hyperv agent.
Also implemented RebootCommand for rebooting an instance on hyperv host.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/e77ab385
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/e77ab385
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/e77ab385

Branch: refs/heads/master
Commit: e77ab385439272dabbd424ff63efb0637def9e0a
Parents: 7095ea2
Author: Devdeep Singh <de...@gmail.com>
Authored: Thu Nov 7 13:13:39 2013 +0530
Committer: Devdeep Singh <de...@gmail.com>
Committed: Thu Nov 7 13:13:39 2013 +0530

----------------------------------------------------------------------
 .../HypervResource/CloudStackTypes.cs           |  22 +++
 .../HypervResource/HypervResourceController.cs  |  70 ++++++-
 .../ServerResource/HypervResource/Utils.cs      | 190 ++++++++++++++++---
 .../ServerResource/HypervResource/WmiCallsV2.cs |   8 +-
 4 files changed, 260 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e77ab385/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
index ae595fc..41b2bac 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
@@ -279,6 +279,27 @@ namespace HypervResource
         }
     }
 
+    public class DiskTO
+    {
+        public string type;
+        public TemplateObjectTO templateObjectTO = null;
+
+        public static DiskTO ParseJson(dynamic json)
+        {
+            DiskTO result = null;
+            if (json != null)
+            {
+                result = new DiskTO()
+                {
+                    templateObjectTO = TemplateObjectTO.ParseJson(json.data),
+                    type = (string)json.type,
+                };
+            }
+
+            return result;
+        }
+    }
+
     enum VolumeType
     {
         UNKNOWN,
@@ -589,6 +610,7 @@ namespace HypervResource
         public const string SwiftTO = "com.cloud.agent.api.to.SwiftTO";
         public const string VirtualMachineTO = "com.cloud.agent.api.to.VirtualMachineTO";
         public const string VolumeTO = "com.cloud.agent.api.to.VolumeTO";
+        public const string DiskTO = "com.cloud.agent.api.to.DiskTO";
         public const string InternalErrorException = "com.cloud.exception.InternalErrorException";
         public const string HostType = "com.cloud.host.Host.Type";
         public const string HypervisorType = "com.cloud.hypervisor.Hypervisor.HypervisorType";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e77ab385/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
index ed3736b..43b44df 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
@@ -196,7 +196,19 @@ namespace HypervResource
                 try
                 {
                     string vmName = (string)cmd.vmName;
-                    result = true;
+                    DiskTO disk = DiskTO.ParseJson(cmd.disk);
+                    TemplateObjectTO dataStore = disk.templateObjectTO;
+
+                    if (dataStore.nfsDataStoreTO != null)
+                    {
+                        NFSTO share = dataStore.nfsDataStoreTO;
+                        Utils.connectToRemote(share.UncPath, share.Domain, share.User, share.Password);
+
+                        // The share is mapped, now attach the iso
+                        string isoPath = Path.Combine(share.UncPath.Replace('/', Path.DirectorySeparatorChar), dataStore.path);
+                        wmiCallsV2.AttachIso(vmName, isoPath);
+                        result = true;
+                    }
                 }
                 catch (Exception sysEx)
                 {
@@ -229,7 +241,18 @@ namespace HypervResource
                 try
                 {
                     string vmName = (string)cmd.vmName;
-                    result = true;
+                    DiskTO disk = DiskTO.ParseJson(cmd.disk);
+                    TemplateObjectTO dataStore = disk.templateObjectTO;
+
+                    if (dataStore.nfsDataStoreTO != null)
+                    {
+                        NFSTO share = dataStore.nfsDataStoreTO;
+                        // The share is mapped, now attach the iso
+                        string isoPath = Path.Combine(share.UncPath.Replace('/', Path.DirectorySeparatorChar),
+                            dataStore.path.Replace('/', Path.DirectorySeparatorChar));
+                        wmiCallsV2.DetachDisk(vmName, isoPath);
+                        result = true;
+                    }
                 }
                 catch (Exception sysEx)
                 {
@@ -247,6 +270,49 @@ namespace HypervResource
             }
         }
 
+        // POST api/HypervResource/RebootCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.RebootCommand)]
+        public JContainer RebootCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.RebootCommand + cmd.ToString());
+
+                string details = null;
+                bool result = false;
+
+                try
+                {
+                    string vmName = (string)cmd.vmName;
+                    var sys = wmiCallsV2.GetComputerSystem(vmName);
+                    if (sys == null)
+                    {
+                        details = CloudStackTypes.RebootCommand + " requested unknown VM " + vmName;
+                        logger.Error(details);
+                    }
+                    else
+                    {
+                        wmiCallsV2.SetState(sys, RequiredState.Reset);
+                        result = true;
+                    }
+                }
+                catch (Exception sysEx)
+                {
+                    details = CloudStackTypes.RebootCommand + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.RebootAnswer);
+            }
+        }
+
         // POST api/HypervResource/DestroyCommand
         [HttpPost]
         [ActionName(CloudStackTypes.DestroyCommand)]

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e77ab385/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs
index e55f2ad..631a7bd 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs
@@ -66,30 +66,30 @@ namespace HypervResource
                 bool isSuccess = LogonUser(cifsShareDetails.User, cifsShareDetails.Domain, cifsShareDetails.Password, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref token);
                 using (WindowsImpersonationContext remoteIdentity = new WindowsIdentity(token).Impersonate())
                 {
-                 String dest = "";
-                 if (filePathRelativeToShare.EndsWith(".iso") || filePathRelativeToShare.EndsWith(".vhd") || filePathRelativeToShare.EndsWith(".vhdx"))
-                 {
-                     dest = Path.Combine(cifsShareDetails.UncPath, filePathRelativeToShare);
-                     dest = dest.Replace('/', Path.DirectorySeparatorChar);
-                 }
-                 // if the filePathRelativeToShare string don't have filename and only a dir point then find the vhd files in that folder and use
-                 // In the clean setup, first copy command wont be having the filename it contains onlyu dir path.
-                 // we need to scan the folder point and then copy the file to destination.
-                 else if (!filePathRelativeToShare.EndsWith(".vhd") || !filePathRelativeToShare.EndsWith(".vhdx"))
-                 {
-                     // scan the folder and get the vhd filename.
-                     String uncPath = Path.Combine(cifsShareDetails.UncPath, Path.Combine(filePathRelativeToShare.Split('/')));
-                     //uncPath = uncPath.Replace("/", "\\");
-                     DirectoryInfo dir = new DirectoryInfo(uncPath);
-                     FileInfo[] vhdFiles = dir.GetFiles("*.vhd*");
-                     if (vhdFiles.Length > 0)
-                     {
-                         FileInfo file = vhdFiles[0];
-                         dest = file.FullName;
-                     }
-                 }
-                    s_logger.Info(CloudStackTypes.CopyCommand + ": copy " + Path.Combine(cifsShareDetails.UncPath, filePathRelativeToShare) + " to " + destFile);
+                    String dest = "";
+                    if (filePathRelativeToShare.EndsWith(".iso") || filePathRelativeToShare.EndsWith(".vhd") || filePathRelativeToShare.EndsWith(".vhdx"))
+                    {
+                        dest = Path.Combine(cifsShareDetails.UncPath, filePathRelativeToShare);
+                        dest = dest.Replace('/', Path.DirectorySeparatorChar);
+                    }
+                    // if the filePathRelativeToShare string don't have filename and only a dir point then find the vhd files in that folder and use
+                    // In the clean setup, first copy command wont be having the filename it contains onlyu dir path.
+                    // we need to scan the folder point and then copy the file to destination.
+                    else if (!filePathRelativeToShare.EndsWith(".vhd") || !filePathRelativeToShare.EndsWith(".vhdx"))
+                    {
+                        // scan the folder and get the vhd filename.
+                        String uncPath = Path.Combine(cifsShareDetails.UncPath, Path.Combine(filePathRelativeToShare.Split('/')));
+                        //uncPath = uncPath.Replace("/", "\\");
+                        DirectoryInfo dir = new DirectoryInfo(uncPath);
+                        FileInfo[] vhdFiles = dir.GetFiles("*.vhd*");
+                        if (vhdFiles.Length > 0)
+                        {
+                            FileInfo file = vhdFiles[0];
+                            dest = file.FullName;
+                        }
+                    }
 
+                    s_logger.Info(CloudStackTypes.CopyCommand + ": copy " + Path.Combine(cifsShareDetails.UncPath, filePathRelativeToShare) + " to " + destFile);
                     File.Copy(dest, destFile, true);
                     remoteIdentity.Undo();
                 }
@@ -103,6 +103,32 @@ namespace HypervResource
             }
         }
 
+        public static void connectToRemote(string remoteUNC, string domain, string username, string password)
+        {
+            NETRESOURCE nr = new NETRESOURCE();
+            nr.dwType = RESOURCETYPE_DISK;
+            nr.lpRemoteName = remoteUNC.Replace('/', Path.DirectorySeparatorChar);
+            if (domain != null)
+            {
+                username = domain + @"\" + username;
+            }
+
+            int ret = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null);
+            if (ret != NO_ERROR)
+            {
+                throw new ArgumentException("net use of share " + remoteUNC + "failed with "+ getErrorForNumber(ret));
+            }
+        }
+
+        public static void disconnectRemote(string remoteUNC)
+        {
+            int ret = WNetCancelConnection2(remoteUNC, CONNECT_UPDATE_PROFILE, false);
+            if (ret != NO_ERROR)
+            {
+                throw new ArgumentException("net disconnect of share " + remoteUNC + "failed with " + getErrorForNumber(ret));
+            }
+        }
+
         // from http://stackoverflow.com/a/2541569/939250
         #region imports
         [DllImport("advapi32.dll", SetLastError = true)]
@@ -113,9 +139,16 @@ namespace HypervResource
 
         [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
         public extern static bool DuplicateToken(IntPtr existingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr duplicateTokenHandle);
+
+        [DllImport("Mpr.dll")]
+        private static extern int WNetUseConnection(IntPtr hwndOwner, NETRESOURCE lpNetResource, string lpPassword, string lpUserID, int dwFlags,
+            string lpAccessName, string lpBufferSize, string lpResult);
+
+        [DllImport("Mpr.dll")]
+        private static extern int WNetCancelConnection2(string lpName, int dwFlags, bool fForce);
         #endregion
 
-        #region logon consts
+        #region consts
         // logon types 
         const int LOGON32_LOGON_INTERACTIVE = 2;
         const int LOGON32_LOGON_NETWORK = 3;
@@ -126,6 +159,115 @@ namespace HypervResource
         const int LOGON32_PROVIDER_WINNT50 = 3;
         const int LOGON32_PROVIDER_WINNT40 = 2;
         const int LOGON32_PROVIDER_WINNT35 = 1;
+
+        const int RESOURCE_CONNECTED = 0x00000001;
+        const int RESOURCE_GLOBALNET = 0x00000002;
+        const int RESOURCE_REMEMBERED = 0x00000003;
+
+        const int RESOURCETYPE_ANY = 0x00000000;
+        const int RESOURCETYPE_DISK = 0x00000001;
+        const int RESOURCETYPE_PRINT = 0x00000002;
+
+        const int RESOURCEDISPLAYTYPE_GENERIC = 0x00000000;
+        const int RESOURCEDISPLAYTYPE_DOMAIN = 0x00000001;
+        const int RESOURCEDISPLAYTYPE_SERVER = 0x00000002;
+        const int RESOURCEDISPLAYTYPE_SHARE = 0x00000003;
+        const int RESOURCEDISPLAYTYPE_FILE = 0x00000004;
+        const int RESOURCEDISPLAYTYPE_GROUP = 0x00000005;
+
+        const int RESOURCEUSAGE_CONNECTABLE = 0x00000001;
+        const int RESOURCEUSAGE_CONTAINER = 0x00000002;
+
+
+        const int CONNECT_INTERACTIVE = 0x00000008;
+        const int CONNECT_PROMPT = 0x00000010;
+        const int CONNECT_REDIRECT = 0x00000080;
+        const int CONNECT_UPDATE_PROFILE = 0x00000001;
+        const int CONNECT_COMMANDLINE = 0x00000800;
+        const int CONNECT_CMD_SAVECRED = 0x00001000;
+
+        const int CONNECT_LOCALDRIVE = 0x00000100;
         #endregion
+
+        #region Errors
+        const int NO_ERROR = 0;
+
+        const int ERROR_ACCESS_DENIED = 5;
+        const int ERROR_ALREADY_ASSIGNED = 85;
+        const int ERROR_BAD_DEVICE = 1200;
+        const int ERROR_BAD_NET_NAME = 67;
+        const int ERROR_BAD_PROVIDER = 1204;
+        const int ERROR_CANCELLED = 1223;
+        const int ERROR_EXTENDED_ERROR = 1208;
+        const int ERROR_INVALID_ADDRESS = 487;
+        const int ERROR_INVALID_PARAMETER = 87;
+        const int ERROR_INVALID_PASSWORD = 1216;
+        const int ERROR_MORE_DATA = 234;
+        const int ERROR_NO_MORE_ITEMS = 259;
+        const int ERROR_NO_NET_OR_BAD_PATH = 1203;
+        const int ERROR_NO_NETWORK = 1222;
+
+        const int ERROR_BAD_PROFILE = 1206;
+        const int ERROR_CANNOT_OPEN_PROFILE = 1205;
+        const int ERROR_DEVICE_IN_USE = 2404;
+        const int ERROR_NOT_CONNECTED = 2250;
+        const int ERROR_OPEN_FILES = 2401;
+
+        private struct ErrorClass
+        {
+            public int num;
+            public string message;
+            public ErrorClass(int num, string message)
+            {
+                this.num = num;
+                this.message = message;
+            }
+        }
+
+        private static ErrorClass[] ERROR_LIST = new ErrorClass[] {
+            new ErrorClass(ERROR_ACCESS_DENIED, "Error: Access Denied"),
+            new ErrorClass(ERROR_ALREADY_ASSIGNED, "Error: Already Assigned"),
+            new ErrorClass(ERROR_BAD_DEVICE, "Error: Bad Device"),
+            new ErrorClass(ERROR_BAD_NET_NAME, "Error: Bad Net Name"),
+            new ErrorClass(ERROR_BAD_PROVIDER, "Error: Bad Provider"),
+            new ErrorClass(ERROR_CANCELLED, "Error: Cancelled"),
+            new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"),
+            new ErrorClass(ERROR_INVALID_ADDRESS, "Error: Invalid Address"),
+            new ErrorClass(ERROR_INVALID_PARAMETER, "Error: Invalid Parameter"),
+            new ErrorClass(ERROR_INVALID_PASSWORD, "Error: Invalid Password"),
+            new ErrorClass(ERROR_MORE_DATA, "Error: More Data"),
+            new ErrorClass(ERROR_NO_MORE_ITEMS, "Error: No More Items"),
+            new ErrorClass(ERROR_NO_NET_OR_BAD_PATH, "Error: No Net Or Bad Path"),
+            new ErrorClass(ERROR_NO_NETWORK, "Error: No Network"),
+            new ErrorClass(ERROR_BAD_PROFILE, "Error: Bad Profile"),
+            new ErrorClass(ERROR_CANNOT_OPEN_PROFILE, "Error: Cannot Open Profile"),
+            new ErrorClass(ERROR_DEVICE_IN_USE, "Error: Device In Use"),
+            new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"),
+            new ErrorClass(ERROR_NOT_CONNECTED, "Error: Not Connected"),
+            new ErrorClass(ERROR_OPEN_FILES, "Error: Open Files"),
+        };
+
+        private static string getErrorForNumber(int errNum)
+        {
+            foreach (ErrorClass er in ERROR_LIST)
+            {
+                if (er.num == errNum) return er.message;
+            }
+            return "Error: Unknown, " + errNum;
+        }
+        #endregion
+
+        [StructLayout(LayoutKind.Sequential)]
+        private class NETRESOURCE
+        {
+            public int dwScope = 0;
+            public int dwType = 0;
+            public int dwDisplayType = 0;
+            public int dwUsage = 0;
+            public string lpLocalName = "";
+            public string lpRemoteName = "";
+            public string lpComment = "";
+            public string lpProvider = "";
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e77ab385/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
index 18b96cc..547a6b7 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
@@ -447,6 +447,7 @@ namespace HypervResource
                 pingReply = pingSender.Send(ipAddress, pingTimeout, buffer, pingOptions);
                 if (pingReply.Status == IPStatus.Success)
                 {
+                    System.Threading.Thread.Sleep(30000);
                     return true;
                 }
                 else
@@ -591,11 +592,11 @@ namespace HypervResource
                 }
 
                 string hostResource = item.HostResource[0];
-                if (!hostResource.Equals(diskFileName))
+                if (Path.Equals(hostResource, diskFileName))
                 {
-                    continue;
+                    imageToRemove = item;
+                    break;
                 }
-                imageToRemove = item;
             }
 
             // assert
@@ -739,7 +740,6 @@ namespace HypervResource
             // Disk drives are attached to a 'Parent' IDE controller.  We IDE Controller's settings for the 'Path', which our new Disk drive will use to reference it.
             VirtualSystemSettingData vmSettings = GetVmSettings(vm);
             var driveWmiObj = GetDvdDriveSettings(vmSettings);
-
             InsertDiskImage(vm, isoPath, IDE_ISO_DISK, driveWmiObj.Path);
         }