You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ra...@apache.org on 2014/05/12 10:06:05 UTC
[4/5] CLOUDSTACK-6518 [Hyper-V] Efficient way of finding the empty
nic in VR/VpcVR to configure VPC entities fixed windows line ending issues
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4cb6c66f/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 0f084db..67c367d 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
@@ -1,112 +1,112 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-using Amazon;
-using Amazon.S3;
-using Amazon.S3.Model;
-using log4net;
-using Microsoft.CSharp.RuntimeBinder;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using System;
-using System.Collections;
-using System.Collections.Specialized;
-using System.Collections.Generic;
-using System.Configuration;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Text;
-using System.Security.Cryptography;
-using System.Security.Principal;
-using System.Web.Http;
-using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2;
-
-namespace HypervResource
-{
-
- public struct HypervResourceControllerConfig
- {
- private string privateIpAddress;
- private static ILog logger = LogManager.GetLogger(typeof(HypervResourceControllerConfig));
-
- public string PrivateIpAddress
- {
- get
- {
- return privateIpAddress;
- }
- set
- {
- ValidateIpAddress(value);
- privateIpAddress = value;
- System.Net.NetworkInformation.NetworkInterface nic = HypervResourceController.GetNicInfoFromIpAddress(privateIpAddress, out PrivateNetmask);
- PrivateMacAddress = nic.GetPhysicalAddress().ToString();
- }
- }
-
- private static void ValidateIpAddress(string value)
- {
- // Convert to IP address
- IPAddress ipAddress;
- if (!IPAddress.TryParse(value, out ipAddress))
- {
- String errMsg = "Invalid PrivateIpAddress: " + value;
- logger.Error(errMsg);
- throw new ArgumentException(errMsg);
- }
- }
- public string GatewayIpAddress;
- public string PrivateMacAddress;
- public string PrivateNetmask;
- public string StorageNetmask;
- public string StorageMacAddress;
- public string StorageIpAddress;
- public long RootDeviceReservedSpaceBytes;
- public string RootDeviceName;
- public ulong ParentPartitionMinMemoryMb;
- public string LocalSecondaryStoragePath;
- public string systemVmIso;
-
- private string getPrimaryKey(string id)
- {
- return "primary_storage_" + id;
- }
-
- public string getPrimaryStorage(string id)
- {
- NameValueCollection settings = ConfigurationManager.AppSettings;
- return settings.Get(getPrimaryKey(id));
- }
-
- public void setPrimaryStorage(string id, string path)
- {
- Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
- KeyValueConfigurationCollection settings = config.AppSettings.Settings;
- string key = getPrimaryKey(id);
- if (settings[key] != null)
- {
- settings.Remove(key);
- }
- settings.Add(key, path);
- config.Save(ConfigurationSaveMode.Modified);
- ConfigurationManager.RefreshSection("appSettings");
- }
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using Amazon;
+using Amazon.S3;
+using Amazon.S3.Model;
+using log4net;
+using Microsoft.CSharp.RuntimeBinder;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Collections.Generic;
+using System.Configuration;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using System.Security.Cryptography;
+using System.Security.Principal;
+using System.Web.Http;
+using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2;
+
+namespace HypervResource
+{
+
+ public struct HypervResourceControllerConfig
+ {
+ private string privateIpAddress;
+ private static ILog logger = LogManager.GetLogger(typeof(HypervResourceControllerConfig));
+
+ public string PrivateIpAddress
+ {
+ get
+ {
+ return privateIpAddress;
+ }
+ set
+ {
+ ValidateIpAddress(value);
+ privateIpAddress = value;
+ System.Net.NetworkInformation.NetworkInterface nic = HypervResourceController.GetNicInfoFromIpAddress(privateIpAddress, out PrivateNetmask);
+ PrivateMacAddress = nic.GetPhysicalAddress().ToString();
+ }
+ }
+
+ private static void ValidateIpAddress(string value)
+ {
+ // Convert to IP address
+ IPAddress ipAddress;
+ if (!IPAddress.TryParse(value, out ipAddress))
+ {
+ String errMsg = "Invalid PrivateIpAddress: " + value;
+ logger.Error(errMsg);
+ throw new ArgumentException(errMsg);
+ }
+ }
+ public string GatewayIpAddress;
+ public string PrivateMacAddress;
+ public string PrivateNetmask;
+ public string StorageNetmask;
+ public string StorageMacAddress;
+ public string StorageIpAddress;
+ public long RootDeviceReservedSpaceBytes;
+ public string RootDeviceName;
+ public ulong ParentPartitionMinMemoryMb;
+ public string LocalSecondaryStoragePath;
+ public string systemVmIso;
+
+ private string getPrimaryKey(string id)
+ {
+ return "primary_storage_" + id;
+ }
+
+ public string getPrimaryStorage(string id)
+ {
+ NameValueCollection settings = ConfigurationManager.AppSettings;
+ return settings.Get(getPrimaryKey(id));
+ }
+
+ public void setPrimaryStorage(string id, string path)
+ {
+ Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
+ KeyValueConfigurationCollection settings = config.AppSettings.Settings;
+ string key = getPrimaryKey(id);
+ if (settings[key] != null)
+ {
+ settings.Remove(key);
+ }
+ settings.Add(key, path);
+ config.Save(ConfigurationSaveMode.Modified);
+ ConfigurationManager.RefreshSection("appSettings");
+ }
public List<string> getAllPrimaryStorages()
{
@@ -122,2264 +122,2272 @@ namespace HypervResource
}
return poolPaths;
}
- }
-
- /// <summary>
- /// Supports one HTTP GET and multiple HTTP POST URIs
- /// </summary>
- /// <remarks>
- /// <para>
- /// POST takes dynamic to allow it to receive JSON without concern for what is the underlying object.
- /// E.g. http://stackoverflow.com/questions/14071715/passing-dynamic-json-object-to-web-api-newtonsoft-example
- /// and http://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object
- /// Use ActionName attribute to allow multiple POST URLs, one for each supported command
- /// E.g. http://stackoverflow.com/a/12703423/939250
- /// Strictly speaking, this goes against the purpose of an ApiController, which is to provide one GET/POST/PUT/DELETE, etc.
- /// However, it reduces the amount of code by removing the need for a switch according to the incoming command type.
- /// http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx
- /// </para>
- /// <para>
- /// Exceptions handled on command by command basis rather than globally to allow details of the command
- /// to be reflected in the response. Default error handling is in the catch for Exception, but
- /// other exception types may be caught where the feedback would be different.
- /// NB: global alternatives discussed at
- /// http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx
- /// </para>
- /// </remarks>
- public class HypervResourceController : ApiController
- {
- public static void Configure(HypervResourceControllerConfig config)
- {
- HypervResourceController.config = config;
- wmiCallsV2 = new WmiCallsV2();
- }
-
- public static HypervResourceControllerConfig config = new HypervResourceControllerConfig();
-
- private static ILog logger = LogManager.GetLogger(typeof(HypervResourceController));
- private string systemVmIso = "";
- Dictionary<String, String> contextMap = new Dictionary<String, String>();
-
- public static void Initialize()
- {
- }
-
- public static IWmiCallsV2 wmiCallsV2 { get; set;}
-
- // GET api/HypervResource
- public string Get()
- {
- using (log4net.NDC.Push(Guid.NewGuid().ToString()))
- {
- return "HypervResource controller running, use POST to send JSON encoded RPCs"; ;
- }
- }
-
- /// <summary>
- /// NOP - placeholder for future setup, e.g. delete existing VMs or Network ports
- /// POST api/HypervResource/SetupCommand
- /// </summary>
- /// <param name="cmd"></param>
- /// <returns></returns>
- /// TODO: produce test
- [HttpPost]
- [ActionName(CloudStackTypes.SetupCommand)]
- public JContainer SetupCommand([FromBody]dynamic cmd)
- {
- using (log4net.NDC.Push(Guid.NewGuid().ToString()))
- {
+ }
+
+ /// <summary>
+ /// Supports one HTTP GET and multiple HTTP POST URIs
+ /// </summary>
+ /// <remarks>
+ /// <para>
+ /// POST takes dynamic to allow it to receive JSON without concern for what is the underlying object.
+ /// E.g. http://stackoverflow.com/questions/14071715/passing-dynamic-json-object-to-web-api-newtonsoft-example
+ /// and http://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object
+ /// Use ActionName attribute to allow multiple POST URLs, one for each supported command
+ /// E.g. http://stackoverflow.com/a/12703423/939250
+ /// Strictly speaking, this goes against the purpose of an ApiController, which is to provide one GET/POST/PUT/DELETE, etc.
+ /// However, it reduces the amount of code by removing the need for a switch according to the incoming command type.
+ /// http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx
+ /// </para>
+ /// <para>
+ /// Exceptions handled on command by command basis rather than globally to allow details of the command
+ /// to be reflected in the response. Default error handling is in the catch for Exception, but
+ /// other exception types may be caught where the feedback would be different.
+ /// NB: global alternatives discussed at
+ /// http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx
+ /// </para>
+ /// </remarks>
+ public class HypervResourceController : ApiController
+ {
+ public static void Configure(HypervResourceControllerConfig config)
+ {
+ HypervResourceController.config = config;
+ wmiCallsV2 = new WmiCallsV2();
+ }
+
+ public static HypervResourceControllerConfig config = new HypervResourceControllerConfig();
+
+ private static ILog logger = LogManager.GetLogger(typeof(HypervResourceController));
+ private string systemVmIso = "";
+ Dictionary<String, String> contextMap = new Dictionary<String, String>();
+
+ public static void Initialize()
+ {
+ }
+
+ public static IWmiCallsV2 wmiCallsV2 { get; set;}
+
+ // GET api/HypervResource
+ public string Get()
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ return "HypervResource controller running, use POST to send JSON encoded RPCs"; ;
+ }
+ }
+
+ /// <summary>
+ /// NOP - placeholder for future setup, e.g. delete existing VMs or Network ports
+ /// POST api/HypervResource/SetupCommand
+ /// </summary>
+ /// <param name="cmd"></param>
+ /// <returns></returns>
+ /// TODO: produce test
+ [HttpPost]
+ [ActionName(CloudStackTypes.SetupCommand)]
+ public JContainer SetupCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
logger.Info(CloudStackTypes.SetupCommand + Utils.CleanString(cmd.ToString()));
-
- string details = null;
- bool result = false;
-
- try
- {
- result = true;
- }
- catch (Exception sysEx)
- {
- details = CloudStackTypes.SetupCommand + " failed due to " + sysEx.Message;
- logger.Error(details, sysEx);
- }
-
- object ansContent = new
- {
- result = result,
- details = "success - NOP",
- _reconnect = false,
- contextMap = contextMap
- };
-
- return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.SetupAnswer);
- }
- }
-
- // POST api/HypervResource/AttachCommand
- [HttpPost]
- [ActionName(CloudStackTypes.AttachCommand)]
- public JContainer AttachCommand([FromBody]dynamic cmd)
- {
- using (log4net.NDC.Push(Guid.NewGuid().ToString()))
- {
- logger.Info(CloudStackTypes.AttachCommand + Utils.CleanString(cmd.ToString()));
-
- string details = null;
- bool result = false;
-
- try
- {
- string vmName = (string)cmd.vmName;
- DiskTO disk = DiskTO.ParseJson(cmd.disk);
-
- if (disk.type.Equals("ISO"))
- {
- TemplateObjectTO dataStore = disk.templateObjectTO;
- NFSTO share = dataStore.nfsDataStoreTO;
- Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password);
- string diskPath = Utils.NormalizePath(Path.Combine(share.UncPath, dataStore.path));
- wmiCallsV2.AttachIso(vmName, diskPath);
- result = true;
- }
- else if (disk.type.Equals("DATADISK"))
- {
- VolumeObjectTO volume = disk.volumeObjectTO;
- PrimaryDataStoreTO primary = volume.primaryDataStore;
- if (!primary.isLocal)
- {
- Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password);
- }
- string diskPath = Utils.NormalizePath(volume.FullFileName);
- wmiCallsV2.AttachDisk(vmName, diskPath, disk.diskSequence);
- result = true;
- }
- else
- {
- details = "Invalid disk type to be attached to vm " + vmName;
- }
- }
- catch (Exception sysEx)
- {
- details = CloudStackTypes.AttachCommand + " failed due to " + sysEx.Message;
- logger.Error(details, sysEx);
- }
-
- object ansContent = new
- {
- result = result,
- details = details,
- disk = cmd.disk,
- contextMap = contextMap
- };
-
- return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.AttachAnswer);
- }
- }
-
- // POST api/HypervResource/DetachCommand
- [HttpPost]
- [ActionName(CloudStackTypes.DettachCommand)]
- public JContainer DetachCommand([FromBody]dynamic cmd)
- {
- using (log4net.NDC.Push(Guid.NewGuid().ToString()))
- {
- logger.Info(CloudStackTypes.DettachCommand + Utils.CleanString(cmd.ToString()));
-
- string details = null;
- bool result = false;
-
- try
- {
- string vmName = (string)cmd.vmName;
- DiskTO disk = DiskTO.ParseJson(cmd.disk);
-
- if (disk.type.Equals("ISO"))
- {
- TemplateObjectTO dataStore = disk.templateObjectTO;
- NFSTO share = dataStore.nfsDataStoreTO;
- string diskPath = Utils.NormalizePath(Path.Combine(share.UncPath, dataStore.path));
- wmiCallsV2.DetachDisk(vmName, diskPath);
- result = true;
- }
- else if (disk.type.Equals("DATADISK"))
- {
- VolumeObjectTO volume = disk.volumeObjectTO;
- PrimaryDataStoreTO primary = volume.primaryDataStore;
- string diskPath = Utils.NormalizePath(volume.FullFileName);
- wmiCallsV2.DetachDisk(vmName, diskPath);
- result = true;
- }
- else
- {
- details = "Invalid disk type to be dettached from vm " + vmName;
- }
- }
- catch (Exception sysEx)
- {
- details = CloudStackTypes.DettachCommand + " failed due to " + sysEx.Message;
- logger.Error(details, sysEx);
- }
-
- object ansContent = new
- {
- result = result,
- details = details,
- contextMap = contextMap
- };
-
- return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.DettachAnswer);
- }
- }
-
- // POST api/HypervResource/RebootCommand
- [HttpPost]
- [ActionName(CloudStackTypes.RebootCommand)]
- public JContainer RebootCommand([FromBody]dynamic cmd)
- {
- using (log4net.NDC.Push(Guid.NewGuid().ToString()))
- {
+
+ string details = null;
+ bool result = false;
+
+ try
+ {
+ result = true;
+ }
+ catch (Exception sysEx)
+ {
+ details = CloudStackTypes.SetupCommand + " failed due to " + sysEx.Message;
+ logger.Error(details, sysEx);
+ }
+
+ object ansContent = new
+ {
+ result = result,
+ details = "success - NOP",
+ _reconnect = false,
+ contextMap = contextMap
+ };
+
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.SetupAnswer);
+ }
+ }
+
+ // POST api/HypervResource/AttachCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.AttachCommand)]
+ public JContainer AttachCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.AttachCommand + Utils.CleanString(cmd.ToString()));
+
+ string details = null;
+ bool result = false;
+
+ try
+ {
+ string vmName = (string)cmd.vmName;
+ DiskTO disk = DiskTO.ParseJson(cmd.disk);
+
+ if (disk.type.Equals("ISO"))
+ {
+ TemplateObjectTO dataStore = disk.templateObjectTO;
+ NFSTO share = dataStore.nfsDataStoreTO;
+ Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password);
+ string diskPath = Utils.NormalizePath(Path.Combine(share.UncPath, dataStore.path));
+ wmiCallsV2.AttachIso(vmName, diskPath);
+ result = true;
+ }
+ else if (disk.type.Equals("DATADISK"))
+ {
+ VolumeObjectTO volume = disk.volumeObjectTO;
+ PrimaryDataStoreTO primary = volume.primaryDataStore;
+ if (!primary.isLocal)
+ {
+ Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password);
+ }
+ string diskPath = Utils.NormalizePath(volume.FullFileName);
+ wmiCallsV2.AttachDisk(vmName, diskPath, disk.diskSequence);
+ result = true;
+ }
+ else
+ {
+ details = "Invalid disk type to be attached to vm " + vmName;
+ }
+ }
+ catch (Exception sysEx)
+ {
+ details = CloudStackTypes.AttachCommand + " failed due to " + sysEx.Message;
+ logger.Error(details, sysEx);
+ }
+
+ object ansContent = new
+ {
+ result = result,
+ details = details,
+ disk = cmd.disk,
+ contextMap = contextMap
+ };
+
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.AttachAnswer);
+ }
+ }
+
+ // POST api/HypervResource/DetachCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.DettachCommand)]
+ public JContainer DetachCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.DettachCommand + Utils.CleanString(cmd.ToString()));
+
+ string details = null;
+ bool result = false;
+
+ try
+ {
+ string vmName = (string)cmd.vmName;
+ DiskTO disk = DiskTO.ParseJson(cmd.disk);
+
+ if (disk.type.Equals("ISO"))
+ {
+ TemplateObjectTO dataStore = disk.templateObjectTO;
+ NFSTO share = dataStore.nfsDataStoreTO;
+ string diskPath = Utils.NormalizePath(Path.Combine(share.UncPath, dataStore.path));
+ wmiCallsV2.DetachDisk(vmName, diskPath);
+ result = true;
+ }
+ else if (disk.type.Equals("DATADISK"))
+ {
+ VolumeObjectTO volume = disk.volumeObjectTO;
+ PrimaryDataStoreTO primary = volume.primaryDataStore;
+ string diskPath = Utils.NormalizePath(volume.FullFileName);
+ wmiCallsV2.DetachDisk(vmName, diskPath);
+ result = true;
+ }
+ else
+ {
+ details = "Invalid disk type to be dettached from vm " + vmName;
+ }
+ }
+ catch (Exception sysEx)
+ {
+ details = CloudStackTypes.DettachCommand + " failed due to " + sysEx.Message;
+ logger.Error(details, sysEx);
+ }
+
+ object ansContent = new
+ {
+ result = result,
+ details = details,
+ contextMap = contextMap
+ };
+
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.DettachAnswer);
+ }
+ }
+
+ // 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 + Utils.CleanString(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,
- contextMap = contextMap
- };
-
- return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.RebootAnswer);
- }
- }
-
- // POST api/HypervResource/DestroyCommand
- [HttpPost]
- [ActionName(CloudStackTypes.DestroyCommand)]
- public JContainer DestroyCommand([FromBody]dynamic cmd)
- {
- using (log4net.NDC.Push(Guid.NewGuid().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,
+ contextMap = contextMap
+ };
+
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.RebootAnswer);
+ }
+ }
+
+ // POST api/HypervResource/DestroyCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.DestroyCommand)]
+ public JContainer DestroyCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
logger.Info(CloudStackTypes.DestroyCommand + Utils.CleanString(cmd.ToString()));
-
- string details = null;
- bool result = false;
-
- try
- {
- // Assert
+
+ string details = null;
+ bool result = false;
+
+ try
+ {
+ // Assert
String errMsg = "No 'volume' details in " + CloudStackTypes.DestroyCommand + " " + Utils.CleanString(cmd.ToString());
- if (cmd.volume == null)
- {
- logger.Error(errMsg);
- throw new ArgumentException(errMsg);
- }
-
- // Assert
- errMsg = "No valide path in DestroyCommand in " + CloudStackTypes.DestroyCommand + " " + (String)cmd.ToString();
- if (cmd.volume.path == null)
- {
- logger.Error(errMsg);
- throw new ArgumentException(errMsg);
- }
-
- String path = (string)cmd.volume.path;
- if (!File.Exists(path))
- {
- logger.Info(CloudStackTypes.DestroyCommand + ", but volume at pass already deleted " + path);
- }
-
- string vmName = (string)cmd.vmName;
- if (!string.IsNullOrEmpty(vmName) && File.Exists(path))
- {
- // Make sure that this resource is removed from the VM
- wmiCallsV2.DetachDisk(vmName, path);
- }
-
- File.Delete(path);
- result = true;
- }
- catch (Exception sysEx)
- {
- details = CloudStackTypes.DestroyCommand + " failed due to " + sysEx.Message;
- logger.Error(details, sysEx);
- }
-
- object ansContent = new
- {
- result = result,
- details = details,
- contextMap = contextMap
- };
-
- return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
- }
- }
-
- // POST api/HypervResource/DeleteCommand
- [HttpPost]
- [ActionName(CloudStackTypes.DeleteCommand)]
- public JContainer DeleteCommand([FromBody]dynamic cmd)
- {
- using (log4net.NDC.Push(Guid.NewGuid().ToString()))
- {
+ if (cmd.volume == null)
+ {
+ logger.Error(errMsg);
+ throw new ArgumentException(errMsg);
+ }
+
+ // Assert
+ errMsg = "No valide path in DestroyCommand in " + CloudStackTypes.DestroyCommand + " " + (String)cmd.ToString();
+ if (cmd.volume.path == null)
+ {
+ logger.Error(errMsg);
+ throw new ArgumentException(errMsg);
+ }
+
+ String path = (string)cmd.volume.path;
+ if (!File.Exists(path))
+ {
+ logger.Info(CloudStackTypes.DestroyCommand + ", but volume at pass already deleted " + path);
+ }
+
+ string vmName = (string)cmd.vmName;
+ if (!string.IsNullOrEmpty(vmName) && File.Exists(path))
+ {
+ // Make sure that this resource is removed from the VM
+ wmiCallsV2.DetachDisk(vmName, path);
+ }
+
+ File.Delete(path);
+ result = true;
+ }
+ catch (Exception sysEx)
+ {
+ details = CloudStackTypes.DestroyCommand + " failed due to " + sysEx.Message;
+ logger.Error(details, sysEx);
+ }
+
+ object ansContent = new
+ {
+ result = result,
+ details = details,
+ contextMap = contextMap
+ };
+
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+ }
+ }
+
+ // POST api/HypervResource/DeleteCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.DeleteCommand)]
+ public JContainer DeleteCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
logger.Info(CloudStackTypes.DestroyCommand + Utils.CleanString(cmd.ToString()));
-
- string details = null;
- bool result = false;
-
- try
- {
- // Assert
+
+ string details = null;
+ bool result = false;
+
+ try
+ {
+ // Assert
String errMsg = "No 'volume' details in " + CloudStackTypes.DestroyCommand + " " + Utils.CleanString(cmd.ToString());
- VolumeObjectTO destVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.data);
-
- if (destVolumeObjectTO.name == null)
- {
- logger.Error(errMsg);
- throw new ArgumentException(errMsg);
- }
-
- String path = destVolumeObjectTO.FullFileName;
- if (!File.Exists(path))
- {
- logger.Info(CloudStackTypes.DestroyCommand + ", but volume at pass already deleted " + path);
- }
-
- string vmName = (string)cmd.vmName;
- if (!string.IsNullOrEmpty(vmName) && File.Exists(path))
- {
- // Make sure that this resource is removed from the VM
- wmiCallsV2.DetachDisk(vmName, path);
- }
-
- File.Delete(path);
- result = true;
- }
- catch (Exception sysEx)
- {
- details = CloudStackTypes.DestroyCommand + " failed due to " + sysEx.Message;
- logger.Error(details, sysEx);
- }
-
- object ansContent = new
- {
- result = result,
- details = details,
- contextMap = contextMap
- };
-
- return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
- }
- }
-
-
- private static JArray ReturnCloudStackTypedJArray(object ansContent, string ansType)
- {
- JObject ansObj = Utils.CreateCloudStackObject(ansType, ansContent);
- JArray answer = new JArray(ansObj);
- logger.Info(Utils.CleanString(ansObj.ToString()));
- return answer;
- }
-
- // POST api/HypervResource/CreateCommand
- [HttpPost]
- [ActionName(CloudStackTypes.CreateCommand)]
- public JContainer CreateCommand([FromBody]dynamic cmd)
- {
- using (log4net.NDC.Push(Guid.NewGuid().ToString()))
- {
- logger.Info(CloudStackTypes.CreateCommand + Utils.CleanString(cmd.ToString()));
-
- string details = null;
- bool result = false;
- VolumeInfo volume = new VolumeInfo();
-
- try
- {
- string diskType = cmd.diskCharacteristics.type;
- ulong disksize = cmd.diskCharacteristics.size;
- string templateUri = cmd.templateUrl;
-
- // assert: valid storagepool?
- string poolTypeStr = cmd.pool.type;
- string poolLocalPath = cmd.pool.path;
- string poolUuid = cmd.pool.uuid;
- string newVolPath = null;
- long volId = cmd.volId;
- string newVolName = null;
-
- if (ValidStoragePool(poolTypeStr, poolLocalPath, poolUuid, ref details))
- {
- // No template URI? Its a blank disk.
- if (string.IsNullOrEmpty(templateUri))
- {
- // assert
- VolumeType volType;
- if (!Enum.TryParse<VolumeType>(diskType, out volType) && volType != VolumeType.DATADISK)
- {
- details = "Cannot create volumes of type " + (string.IsNullOrEmpty(diskType) ? "NULL" : diskType);
- }
- else
- {
- newVolName = cmd.diskCharacteristics.name;
- newVolPath = Path.Combine(poolLocalPath, newVolName, diskType.ToLower());
- // TODO: make volume format and block size configurable
- wmiCallsV2.CreateDynamicVirtualHardDisk(disksize, newVolPath);
- if (File.Exists(newVolPath))
- {
- result = true;
- }
- else
- {
- details = "Failed to create DATADISK with name " + newVolName;
- }
- }
- }
- else
- {
- // TODO: Does this always work, or do I need to download template at times?
- if (templateUri.Contains("/") || templateUri.Contains("\\"))
- {
- details = "Problem with templateURL " + templateUri +
- " the URL should be volume UUID in primary storage created by previous PrimaryStorageDownloadCommand";
- logger.Error(details);
- }
- else
- {
- logger.Debug("Template's name in primary store should be " + templateUri);
- // HypervPhysicalDisk BaseVol = primaryPool.getPhysicalDisk(tmplturl);
- FileInfo srcFileInfo = new FileInfo(templateUri);
- newVolName = Guid.NewGuid() + srcFileInfo.Extension;
- newVolPath = Path.Combine(poolLocalPath, newVolName);
- logger.Debug("New volume will be at " + newVolPath);
- string oldVolPath = Path.Combine(poolLocalPath, templateUri);
- File.Copy(oldVolPath, newVolPath);
- if (File.Exists(newVolPath))
- {
- result = true;
- }
- else
- {
- details = "Failed to create DATADISK with name " + newVolName;
- }
- }
- volume = new VolumeInfo(
- volId, diskType,
- poolTypeStr, poolUuid, newVolName,
- newVolPath, newVolPath, (long)disksize, null);
- }
- }
- }
- catch (Exception sysEx)
- {
- // TODO: consider this as model for error processing in all commands
- details = CloudStackTypes.CreateCommand + " failed due to " + sysEx.Message;
- logger.Error(details, sysEx);
- }
-
- object ansContent = new
- {
- result = result,
- details = details,
- volume = volume,
- contextMap = contextMap
- };
- return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CreateAnswer);
- }
- }
-
- // POST api/HypervResource/PrimaryStorageDownloadCommand
- [HttpPost]
- [ActionName(CloudStackTypes.PrimaryStorageDownloadCommand)]
- public JContainer PrimaryStorageDownloadCommand([FromBody]dynamic cmd)
- {
- using (log4net.NDC.Push(Guid.NewGuid().ToString()))
- {
- logger.Info(CloudStackTypes.PrimaryStorageDownloadCommand + Utils.CleanString(cmd.ToString()));
- string details = null;
- bool result = false;
- long size = 0;
- string newCopyFileName = null;
-
- string poolLocalPath = cmd.localPath;
- string poolUuid = cmd.poolUuid;
- if (!Directory.Exists(poolLocalPath))
- {
- details = "None existent local path " + poolLocalPath;
- }
- else
- {
- // Compose name for downloaded file.
- string sourceUrl = cmd.url;
- if (sourceUrl.ToLower().EndsWith(".vhd"))
- {
- newCopyFileName = Guid.NewGuid() + ".vhd";
- }
- if (sourceUrl.ToLower().EndsWith(".vhdx"))
- {
- newCopyFileName = Guid.NewGuid() + ".vhdx";
- }
-
- // assert
- if (newCopyFileName == null)
- {
- details = CloudStackTypes.PrimaryStorageDownloadCommand + " Invalid file extension for hypervisor type in source URL " + sourceUrl;
- logger.Error(details);
- }
- else
- {
- try
- {
- FileInfo newFile;
- if (CopyURI(sourceUrl, newCopyFileName, poolLocalPath, out newFile, ref details))
- {
- size = newFile.Length;
- result = true;
- }
- }
- catch (System.Exception ex)
- {
- details = CloudStackTypes.PrimaryStorageDownloadCommand + " Cannot download source URL " + sourceUrl + " due to " + ex.Message;
- logger.Error(details, ex);
- }
- }
- }
-
- object ansContent = new
- {
- result = result,
- details = details,
- templateSize = size,
- installPath = newCopyFileName,
- contextMap = contextMap
- };
- return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PrimaryStorageDownloadAnswer);
- }
- }
-
- private static bool ValidStoragePool(string poolTypeStr, string poolLocalPath, string poolUuid, ref string details)
- {
- StoragePoolType poolType;
- if (!Enum.TryParse<StoragePoolType>(poolTypeStr, out poolType) || poolType != StoragePoolType.Filesystem)
- {
- details = "Primary storage pool " + poolUuid + " type " + poolType + " local path " + poolLocalPath + " has invalid StoragePoolType";
- logger.Error(details);
- return false;
- }
- else if (!Directory.Exists(poolLocalPath))
- {
- details = "Primary storage pool " + poolUuid + " type " + poolType + " local path " + poolLocalPath + " has invalid local path";
- logger.Error(details);
- return false;
- }
- return true;
- }
-
- /// <summary>
- /// Exceptions to watch out for:
- /// Exceptions related to URI creation
- /// System.SystemException
- /// +-System.ArgumentNullException
- /// +-System.FormatException
- /// +-System.UriFormatException
- ///
- /// Exceptions related to NFS URIs
- /// System.SystemException
- /// +-System.NotSupportedException
- /// +-System.ArgumentException
- /// +-System.ArgumentNullException
- /// +-System.Security.SecurityException;
- /// +-System.UnauthorizedAccessException
- /// +-System.IO.IOException
- /// +-System.IO.PathTooLongException
- ///
- /// Exceptions related to HTTP URIs
- /// System.SystemException
- /// +-System.InvalidOperationException
- /// +-System.Net.WebException
- /// +-System.NotSupportedException
- /// +-System.ArgumentNullException
- /// </summary>
- /// <param name="sourceUri"></param>
- /// <param name="newCopyFileName"></param>
- /// <param name="poolLocalPath"></param>
- /// <returns></returns>
- private bool CopyURI(string sourceUri, string newCopyFileName, string poolLocalPath, out FileInfo newFile, ref string details)
- {
- Uri source = new Uri(sourceUri);
- String destFilePath = Path.Combine(poolLocalPath, newCopyFileName);
- string[] pathSegments = source.Segments;
- String templateUUIDandExtension = pathSegments[pathSegments.Length - 1];
- newFile = new FileInfo(destFilePath);
-
- // NFS URI assumed to already be mounted locally. Mount location given by settings.
- if (source.Scheme.ToLower().Equals("nfs"))
- {
- String srcDiskPath = Path.Combine(HypervResourceController.config.LocalSecondaryStoragePath, templateUUIDandExtension);
- String taskMsg = "Copy NFS url in " + sourceUri + " at " + srcDiskPath + " to pool " + poolLocalPath;
- logger.Debug(taskMsg);
- File.Copy(srcDiskPath, destFilePath);
- }
- else if (source.Scheme.ToLower().Equals("http") || source.Scheme.ToLower().Equals("https"))
- {
- System.Net.WebClient webclient = new WebClient();
- webclient.DownloadFile(source, destFilePath);
- }
- else
- {
- details = "Unsupported URI scheme " + source.Scheme.ToLower() + " in source URI " + sourceUri;
- logger.Error(details);
- return false;
- }
-
- if (!File.Exists(destFilePath))
- {
- details = "Filed to copy " + sourceUri + " to primary pool destination " + destFilePath;
- logger.Error(details);
- return false;
- }
- return true;
- }
-
- // POST api/HypervResource/CheckHealthCommand
- [HttpPost]
- [ActionName(CloudStackTypes.CheckHealthCommand)]
- public JContainer CheckHealthCommand([FromBody]dynamic cmd)
- {
- using (log4net.NDC.Push(Guid.NewGuid().ToString()))
- {
- logger.Info(CloudStackTypes.CheckHealthCommand + Utils.CleanString(cmd.ToString()));
- object ansContent = new
- {
- result = true,
- details = "resource is alive",
- contextMap = contextMap
- };
- return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckHealthAnswer);
- }
- }
-
- // POST api/HypervResource/CheckOnHostCommand
- [HttpPost]
- [ActionName(CloudStackTypes.CheckOnHostCommand)]
- public JContainer CheckOnHostCommand([FromBody]dynamic cmd)
- {
- using (log4net.NDC.Push(Guid.NewGuid().ToString()))
- {
- logger.Info(CloudStackTypes.CheckOnHostCommand + Utils.CleanString(cmd.ToString()));
- string details = "host is not alive";
+ VolumeObjectTO destVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.data);
+
+ if (destVolumeObjectTO.name == null)
+ {
+ logger.Error(errMsg);
+ throw new ArgumentException(errMsg);
+ }
+
+ String path = destVolumeObjectTO.FullFileName;
+ if (!File.Exists(path))
+ {
+ logger.Info(CloudStackTypes.DestroyCommand + ", but volume at pass already deleted " + path);
+ }
+
+ string vmName = (string)cmd.vmName;
+ if (!string.IsNullOrEmpty(vmName) && File.Exists(path))
+ {
+ // Make sure that this resource is removed from the VM
+ wmiCallsV2.DetachDisk(vmName, path);
+ }
+
+ File.Delete(path);
+ result = true;
+ }
+ catch (Exception sysEx)
+ {
+ details = CloudStackTypes.DestroyCommand + " failed due to " + sysEx.Message;
+ logger.Error(details, sysEx);
+ }
+
+ object ansContent = new
+ {
+ result = result,
+ details = details,
+ contextMap = contextMap
+ };
+
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+ }
+ }
+
+
+ private static JArray ReturnCloudStackTypedJArray(object ansContent, string ansType)
+ {
+ JObject ansObj = Utils.CreateCloudStackObject(ansType, ansContent);
+ JArray answer = new JArray(ansObj);
+ logger.Info(Utils.CleanString(ansObj.ToString()));
+ return answer;
+ }
+
+ // POST api/HypervResource/CreateCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.CreateCommand)]
+ public JContainer CreateCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.CreateCommand + Utils.CleanString(cmd.ToString()));
+
+ string details = null;
+ bool result = false;
+ VolumeInfo volume = new VolumeInfo();
+
+ try
+ {
+ string diskType = cmd.diskCharacteristics.type;
+ ulong disksize = cmd.diskCharacteristics.size;
+ string templateUri = cmd.templateUrl;
+
+ // assert: valid storagepool?
+ string poolTypeStr = cmd.pool.type;
+ string poolLocalPath = cmd.pool.path;
+ string poolUuid = cmd.pool.uuid;
+ string newVolPath = null;
+ long volId = cmd.volId;
+ string newVolName = null;
+
+ if (ValidStoragePool(poolTypeStr, poolLocalPath, poolUuid, ref details))
+ {
+ // No template URI? Its a blank disk.
+ if (string.IsNullOrEmpty(templateUri))
+ {
+ // assert
+ VolumeType volType;
+ if (!Enum.TryParse<VolumeType>(diskType, out volType) && volType != VolumeType.DATADISK)
+ {
+ details = "Cannot create volumes of type " + (string.IsNullOrEmpty(diskType) ? "NULL" : diskType);
+ }
+ else
+ {
+ newVolName = cmd.diskCharacteristics.name;
+ newVolPath = Path.Combine(poolLocalPath, newVolName, diskType.ToLower());
+ // TODO: make volume format and block size configurable
+ wmiCallsV2.CreateDynamicVirtualHardDisk(disksize, newVolPath);
+ if (File.Exists(newVolPath))
+ {
+ result = true;
+ }
+ else
+ {
+ details = "Failed to create DATADISK with name " + newVolName;
+ }
+ }
+ }
+ else
+ {
+ // TODO: Does this always work, or do I need to download template at times?
+ if (templateUri.Contains("/") || templateUri.Contains("\\"))
+ {
+ details = "Problem with templateURL " + templateUri +
+ " the URL should be volume UUID in primary storage created by previous PrimaryStorageDownloadCommand";
+ logger.Error(details);
+ }
+ else
+ {
+ logger.Debug("Template's name in primary store should be " + templateUri);
+ // HypervPhysicalDisk BaseVol = primaryPool.getPhysicalDisk(tmplturl);
+ FileInfo srcFileInfo = new FileInfo(templateUri);
+ newVolName = Guid.NewGuid() + srcFileInfo.Extension;
+ newVolPath = Path.Combine(poolLocalPath, newVolName);
+ logger.Debug("New volume will be at " + newVolPath);
+ string oldVolPath = Path.Combine(poolLocalPath, templateUri);
+ File.Copy(oldVolPath, newVolPath);
+ if (File.Exists(newVolPath))
+ {
+ result = true;
+ }
+ else
+ {
+ details = "Failed to create DATADISK with name " + newVolName;
+ }
+ }
+ volume = new VolumeInfo(
+ volId, diskType,
+ poolTypeStr, poolUuid, newVolName,
+ newVolPath, newVolPath, (long)disksize, null);
+ }
+ }
+ }
+ catch (Exception sysEx)
+ {
+ // TODO: consider this as model for error processing in all commands
+ details = CloudStackTypes.CreateCommand + " failed due to " + sysEx.Message;
+ logger.Error(details, sysEx);
+ }
+
+ object ansContent = new
+ {
+ result = result,
+ details = details,
+ volume = volume,
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CreateAnswer);
+ }
+ }
+
+ // POST api/HypervResource/PrimaryStorageDownloadCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.PrimaryStorageDownloadCommand)]
+ public JContainer PrimaryStorageDownloadCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.PrimaryStorageDownloadCommand + Utils.CleanString(cmd.ToString()));
+ string details = null;
+ bool result = false;
+ long size = 0;
+ string newCopyFileName = null;
+
+ string poolLocalPath = cmd.localPath;
+ string poolUuid = cmd.poolUuid;
+ if (!Directory.Exists(poolLocalPath))
+ {
+ details = "None existent local path " + poolLocalPath;
+ }
+ else
+ {
+ // Compose name for downloaded file.
+ string sourceUrl = cmd.url;
+ if (sourceUrl.ToLower().EndsWith(".vhd"))
+ {
+ newCopyFileName = Guid.NewGuid() + ".vhd";
+ }
+ if (sourceUrl.ToLower().EndsWith(".vhdx"))
+ {
+ newCopyFileName = Guid.NewGuid() + ".vhdx";
+ }
+
+ // assert
+ if (newCopyFileName == null)
+ {
+ details = CloudStackTypes.PrimaryStorageDownloadCommand + " Invalid file extension for hypervisor type in source URL " + sourceUrl;
+ logger.Error(details);
+ }
+ else
+ {
+ try
+ {
+ FileInfo newFile;
+ if (CopyURI(sourceUrl, newCopyFileName, poolLocalPath, out newFile, ref details))
+ {
+ size = newFile.Length;
+ result = true;
+ }
+ }
+ catch (System.Exception ex)
+ {
+ details = CloudStackTypes.PrimaryStorageDownloadCommand + " Cannot download source URL " + sourceUrl + " due to " + ex.Message;
+ logger.Error(details, ex);
+ }
+ }
+ }
+
+ object ansContent = new
+ {
+ result = result,
+ details = details,
+ templateSize = size,
+ installPath = newCopyFileName,
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PrimaryStorageDownloadAnswer);
+ }
+ }
+
+ private static bool ValidStoragePool(string poolTypeStr, string poolLocalPath, string poolUuid, ref string details)
+ {
+ StoragePoolType poolType;
+ if (!Enum.TryParse<StoragePoolType>(poolTypeStr, out poolType) || poolType != StoragePoolType.Filesystem)
+ {
+ details = "Primary storage pool " + poolUuid + " type " + poolType + " local path " + poolLocalPath + " has invalid StoragePoolType";
+ logger.Error(details);
+ return false;
+ }
+ else if (!Directory.Exists(poolLocalPath))
+ {
+ details = "Primary storage pool " + poolUuid + " type " + poolType + " local path " + poolLocalPath + " has invalid local path";
+ logger.Error(details);
+ return false;
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Exceptions to watch out for:
+ /// Exceptions related to URI creation
+ /// System.SystemException
+ /// +-System.ArgumentNullException
+ /// +-System.FormatException
+ /// +-System.UriFormatException
+ ///
+ /// Exceptions related to NFS URIs
+ /// System.SystemException
+ /// +-System.NotSupportedException
+ /// +-System.ArgumentException
+ /// +-System.ArgumentNullException
+ /// +-System.Security.SecurityException;
+ /// +-System.UnauthorizedAccessException
+ /// +-System.IO.IOException
+ /// +-System.IO.PathTooLongException
+ ///
+ /// Exceptions related to HTTP URIs
+ /// System.SystemException
+ /// +-System.InvalidOperationException
+ /// +-System.Net.WebException
+ /// +-System.NotSupportedException
+ /// +-System.ArgumentNullException
+ /// </summary>
+ /// <param name="sourceUri"></param>
+ /// <param name="newCopyFileName"></param>
+ /// <param name="poolLocalPath"></param>
+ /// <returns></returns>
+ private bool CopyURI(string sourceUri, string newCopyFileName, string poolLocalPath, out FileInfo newFile, ref string details)
+ {
+ Uri source = new Uri(sourceUri);
+ String destFilePath = Path.Combine(poolLocalPath, newCopyFileName);
+ string[] pathSegments = source.Segments;
+ String templateUUIDandExtension = pathSegments[pathSegments.Length - 1];
+ newFile = new FileInfo(destFilePath);
+
+ // NFS URI assumed to already be mounted locally. Mount location given by settings.
+ if (source.Scheme.ToLower().Equals("nfs"))
+ {
+ String srcDiskPath = Path.Combine(HypervResourceController.config.LocalSecondaryStoragePath, templateUUIDandExtension);
+ String taskMsg = "Copy NFS url in " + sourceUri + " at " + srcDiskPath + " to pool " + poolLocalPath;
+ logger.Debug(taskMsg);
+ File.Copy(srcDiskPath, destFilePath);
+ }
+ else if (source.Scheme.ToLower().Equals("http") || source.Scheme.ToLower().Equals("https"))
+ {
+ System.Net.WebClient webclient = new WebClient();
+ webclient.DownloadFile(source, destFilePath);
+ }
+ else
+ {
+ details = "Unsupported URI scheme " + source.Scheme.ToLower() + " in source URI " + sourceUri;
+ logger.Error(details);
+ return false;
+ }
+
+ if (!File.Exists(destFilePath))
+ {
+ details = "Filed to copy " + sourceUri + " to primary pool destination " + destFilePath;
+ logger.Error(details);
+ return false;
+ }
+ return true;
+ }
+
+ // POST api/HypervResource/CheckHealthCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.CheckHealthCommand)]
+ public JContainer CheckHealthCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.CheckHealthCommand + Utils.CleanString(cmd.ToString()));
+ object ansContent = new
+ {
+ result = true,
+ details = "resource is alive",
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckHealthAnswer);
+ }
+ }
+
+ // POST api/HypervResource/CheckOnHostCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.CheckOnHostCommand)]
+ public JContainer CheckOnHostCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.CheckOnHostCommand + Utils.CleanString(cmd.ToString()));
+ string details = "host is not alive";
+ bool result = true;
+ try
+ {
+ foreach (string poolPath in config.getAllPrimaryStorages())
+ {
+ if (IsHostAlive(poolPath, (string)cmd.host.privateNetwork.ip))
+ {
+ result = false;
+ details = "host is alive";
+ break;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ logger.Error("Error Occurred in " + CloudStackTypes.CheckOnHostCommand + " : " + e.Message);
+ }
+
+ object ansContent = new
+ {
+ result = result,
+ details = details,
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckOnHostAnswer);
+ }
+ }
+
+ private bool IsHostAlive(string poolPath, string privateIp)
+ {
+ bool hostAlive = false;
+ try
+ {
+ string hbFile = Path.Combine(poolPath, "hb-" + privateIp);
+ FileInfo file = new FileInfo(hbFile);
+ using (StreamReader sr = file.OpenText())
+ {
+ string epoch = sr.ReadLine();
+ string[] dateTime = epoch.Split('@');
+ string[] date = dateTime[0].Split('-');
+ string[] time = dateTime[1].Split(':');
+ DateTime epochTime = new DateTime(Convert.ToInt32(date[0]), Convert.ToInt32(date[1]), Convert.ToInt32(date[2]), Convert.ToInt32(time[0]),
+ Convert.ToInt32(time[1]), Convert.ToInt32(time[2]), DateTimeKind.Utc);
+ DateTime currentTime = DateTime.UtcNow;
+ DateTime ThreeMinuteLaterEpoch = epochTime.AddMinutes(3);
+ if (currentTime.CompareTo(ThreeMinuteLaterEpoch) < 0)
+ {
+ hostAlive = true;
+ }
+ sr.Close();
+ }
+ }
+ catch (Exception e)
+ {
+ logger.Info("Exception occurred in verifying host " + e.Message);
+ }
+
+ return hostAlive;
+ }
+
+ // POST api/HypervResource/CheckSshCommand
+ // TODO: create test
+ [HttpPost]
+ [ActionName(CloudStackTypes.CheckSshCommand)]
+ public JContainer CheckSshCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.CheckSshCommand + Utils.CleanString(cmd.ToString()));
+ object ansContent = new
+ {
+ result = true,
+ details = "NOP, TODO: implement properly",
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckSshAnswer);
+ }
+ }
+
+ // POST api/HypervResource/CheckVirtualMachineCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.CheckVirtualMachineCommand)]
+ public JContainer CheckVirtualMachineCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.CheckVirtualMachineCommand + Utils.CleanString(cmd.ToString()));
+ string details = null;
+ bool result = false;
+ string vmName = cmd.vmName;
+ string state = null;
+
+ // TODO: Look up the VM, convert Hyper-V state to CloudStack version.
+ var sys = wmiCallsV2.GetComputerSystem(vmName);
+ if (sys == null)
+ {
+ details = CloudStackTypes.CheckVirtualMachineCommand + " requested unknown VM " + vmName;
+ logger.Error(details);
+ }
+ else
+ {
+ state = EnabledState.ToCloudStackState(sys.EnabledState); // TODO: V2 changes?
+ result = true;
+ }
+
+ object ansContent = new
+ {
+ result = result,
+ details = details,
+ state = state,
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckVirtualMachineAnswer);
+ }
+ }
+
+ // POST api/HypervResource/DeleteStoragePoolCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.DeleteStoragePoolCommand)]
+ public JContainer DeleteStoragePoolCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.DeleteStoragePoolCommand + Utils.CleanString(cmd.ToString()));
+ object ansContent = new
+ {
+ result = true,
+ details = "Current implementation does not delete local path corresponding to storage pool!",
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+ }
+ }
+
+ /// <summary>
+ /// NOP - legacy command -
+ /// POST api/HypervResource/CreateStoragePoolCommand
+ /// </summary>
+ /// <param name="cmd"></param>
+ /// <returns></returns>
+ [HttpPost]
+ [ActionName(CloudStackTypes.CreateStoragePoolCommand)]
+ public JContainer CreateStoragePoolCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.CreateStoragePoolCommand + Utils.CleanString(cmd.ToString()));
+ object ansContent = new
+ {
+ result = true,
+ details = "success - NOP",
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+ }
+ }
+
+ // POST api/HypervResource/ModifyStoragePoolCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.ModifyStoragePoolCommand)]
+ public JContainer ModifyStoragePoolCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.ModifyStoragePoolCommand + Utils.CleanString(cmd.ToString()));
+ string details = null;
+ string localPath;
+ StoragePoolType poolType;
+ object ansContent;
+
+ bool result = ValidateStoragePoolCommand(cmd, out localPath, out poolType, ref details);
+ if (!result)
+ {
+ ansContent = new
+ {
+ result = result,
+ details = details,
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+ }
+
+ var tInfo = new Dictionary<string, string>();
+ long capacityBytes = 0;
+ long availableBytes = 0;
+ string hostPath = null;
+ if (poolType == StoragePoolType.Filesystem)
+ {
+ GetCapacityForLocalPath(localPath, out capacityBytes, out availableBytes);
+ hostPath = localPath;
+ }
+ else if (poolType == StoragePoolType.NetworkFilesystem ||
+ poolType == StoragePoolType.SMB)
+ {
+ NFSTO share = new NFSTO();
+ String uriStr = "cifs://" + (string)cmd.pool.host + (string)cmd.pool.path;
+ share.uri = new Uri(uriStr);
+ hostPath = Utils.NormalizePath(share.UncPath);
+
+ // Check access to share.
+ Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password);
+ Utils.GetShareDetails(share.UncPath, out capacityBytes, out availableBytes);
+ config.setPrimaryStorage((string)cmd.pool.uuid, hostPath);
+ }
+ else
+ {
+ result = false;
+ }
+
+ String uuid = null;
+ var poolInfo = new
+ {
+ uuid = uuid,
+ host = cmd.pool.host,
+ hostPath = cmd.pool.path,
+ localPath = hostPath,
+ poolType = cmd.pool.type,
+ capacityBytes = capacityBytes,
+ availableBytes = availableBytes
+ };
+
+ ansContent = new
+ {
+ result = result,
+ details = details,
+ localPath = hostPath,
+ templateInfo = tInfo,
+ poolInfo = poolInfo,
+ contextMap = contextMap
+ };
+
+ if (result)
+ {
+ try
+ {
+ if ((bool)cmd.add)
+ {
+ logger.Info("Adding HeartBeat Task to task scheduler for pool " + (string)cmd.pool.uuid);
+ Utils.AddHeartBeatTask((string)cmd.pool.uuid, hostPath, config.PrivateIpAddress);
+ }
+ else
+ {
+ logger.Info("Deleting HeartBeat Task from task scheduler for pool " + (string)cmd.pool.uuid);
+ Utils.RemoveHeartBeatTask(cmd.pool.uuid);
+ }
+ }
+ catch (Exception e)
+ {
+ logger.Error("Error occurred in adding/delete HeartBeat Task to/from Task Scheduler : " + e.Message);
+ }
+ }
+
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ModifyStoragePoolAnswer);
+ }
+ }
+
+ private bool ValidateStoragePoolCommand(dynamic cmd, out string localPath, out StoragePoolType poolType, ref string details)
+ {
+ dynamic pool = cmd.pool;
+ string poolTypeStr = pool.type;
+ localPath = cmd.localPath;
+ if (!Enum.TryParse<StoragePoolType>(poolTypeStr, out poolType))
+ {
+ details = "Request to create / modify unsupported pool type: " + (poolTypeStr == null ? "NULL" : poolTypeStr) + "in cmd " + JsonConvert.SerializeObject(cmd);
+ logger.Error(details);
+ return false;
+ }
+
+ if (poolType != StoragePoolType.Filesystem &&
+ poolType != StoragePoolType.NetworkFilesystem &&
+ poolType != StoragePoolType.SMB)
+ {
+ details = "Request to create / modify unsupported pool type: " + (poolTypeStr == null ? "NULL" : poolTypeStr) + "in cmd " + JsonConvert.SerializeObject(cmd);
+ logger.Error(details);
+ return false;
+ }
+
+ return true;
+ }
+
+ // POST api/HypervResource/PlugNicCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.PlugNicCommand)]
+ public JContainer PlugNicCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.PlugNicCommand + Utils.CleanString(cmd.ToString()));
+ object ansContent = new
+ {
+ result = true,
+ details = "Hot Nic plug not supported, change any empty virtual network adapter network settings",
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PlugNicAnswer);
+ }
+ }
+
+
+ // POST api/HypervResource/CleanupNetworkRulesCmd
+ [HttpPost]
+ [ActionName(CloudStackTypes.CleanupNetworkRulesCmd)]
+ public JContainer CleanupNetworkRulesCmd([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.CleanupNetworkRulesCmd + Utils.CleanString(cmd.ToString()));
+ object ansContent = new
+ {
+ result = false,
+ details = "nothing to cleanup in our current implementation",
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+ }
+ }
+
+ // POST api/HypervResource/CheckNetworkCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.CheckNetworkCommand)]
+ public JContainer CheckNetworkCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.CheckNetworkCommand + Utils.CleanString(cmd.ToString()));
+ object ansContent = new
+ {
+ result = true,
+ details = (string)null,
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckNetworkAnswer);
+ }
+ }
+
+ // POST api/HypervResource/ReadyCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.ReadyCommand)]
+ public JContainer ReadyCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.ReadyCommand + Utils.CleanString(cmd.ToString()));
+ object ansContent = new
+ {
+ result = true,
+ details = (string)null,
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ReadyAnswer);
+ }
+
+ }
+
+ // POST api/HypervResource/StartCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.StartCommand)]
+ public JContainer StartCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.StartCommand + Utils.CleanString(cmd.ToString()));
+ string details = null;
+ bool result = false;
+
+ try
+ {
+ string systemVmIsoPath = systemVmIso;
+ lock (systemVmIso)
+ {
+ systemVmIsoPath = systemVmIso;
+ String uriStr = (String)cmd.secondaryStorage;
+ if (!String.IsNullOrEmpty(uriStr))
+ {
+ if (String.IsNullOrEmpty(systemVmIsoPath) || !File.Exists(systemVmIsoPath))
+ {
+ NFSTO share = new NFSTO();
+ share.uri = new Uri(uriStr);
+ string defaultDataPath = wmiCallsV2.GetDefaultDataRoot();
+
+ string secondaryPath = Utils.NormalizePath(Path.Combine(share.UncPath, "systemvm"));
+ string[] choices = choices = Directory.GetFiles(secondaryPath, "systemvm*.iso");
+ if (choices.Length != 1)
+ {
+ String errMsg = "Couldn't locate the systemvm iso on " + secondaryPath;
+ logger.Debug(errMsg);
+ }
+ else
+ {
+ systemVmIsoPath = Utils.NormalizePath(Path.Combine(defaultDataPath, Path.GetFileName(choices[0])));
+ if (!File.Exists(systemVmIsoPath))
+ {
+ Utils.DownloadCifsFileToLocalFile(choices[0], share, systemVmIsoPath);
+ }
+ systemVmIso = systemVmIsoPath;
+ }
+ }
+ }
+ }
+
+ wmiCallsV2.DeployVirtualMachine(cmd, systemVmIsoPath);
+ result = true;
+ }
+ catch (Exception wmiEx)
+ {
+ details = CloudStackTypes.StartCommand + " fail on exception" + wmiEx.Message;
+ logger.Error(details, wmiEx);
+ }
+
+ object ansContent = new
+ {
+ result = result,
+ details = details,
+ vm = cmd.vm,
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.StartAnswer);
+ }
+ }
+
+ // POST api/HypervResource/StopCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.StopCommand)]
+ public JContainer StopCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.StopCommand + Utils.CleanString(cmd.ToString()));
+ string details = null;
+ bool result = false;
+ bool checkBeforeCleanup = cmd.checkBeforeCleanup;
+ String vmName = cmd.vmName;
+
+ if (checkBeforeCleanup == true)
+ {
+ ComputerSystem vm = wmiCallsV2.GetComputerSystem(vmName);
+ if (vm == null || vm.EnabledState == 2)
+ {
+ // VM is not available or vm in running state
+ return ReturnCloudStackTypedJArray(new { result = false, details = "VM is running on host, bailing out", vm = vmName, contextMap = contextMap }, CloudStackTypes.StopAnswer);
+ }
+ }
+ try
+ {
+ wmiCallsV2.DestroyVm(cmd);
+ result = true;
+ }
+ catch (Exception wmiEx)
+ {
+ details = CloudStackTypes.StopCommand + " fail on exception" + wmiEx.Message;
+ logger.Error(details, wmiEx);
+ }
+
+ object ansContent = new
+ {
+ result = result,
+ details = details,
+ vm = cmd.vm,
+ contextMap = contextMap
+ };
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.StopAnswer);
+ }
+ }
+
+ // POST api/HypervResource/CreateObjectCommand
+ [HttpPost]
+ [ActionName(CloudStackTypes.CreateObjectCommand)]
+ public JContainer CreateObjectCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+ logger.Info(CloudStackTypes.CreateObjectCommand + Utils.CleanString(cmd.ToString()));
+
+ bool result = false;
+ string details = null;
+ object newData = null;
+ try
+ {
+ VolumeObjectTO volume = VolumeObjectTO.ParseJson(cmd.data);
+ PrimaryDataStoreTO primary = volume.primaryDataStore;
+ ulong volumeSize = volume.size;
+ string volumeName = volume.uuid + ".vhdx";
+ string volumePath = null;
+
+ if (primary.isLocal)
+ {
+ volumePath = Path.Combine(primary.Path, volumeName);
+ }
+ else
+ {
+ volumePath = @"\\" + primary.uri.Host + primary.uri.LocalPath + @"\" + volumeName;
+ volumePath = Utils.NormalizePath(volumePath);
+ Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password);
+ }
+ volume.path = volume.uuid;
+ wmiCallsV2.CreateDynamicVirtualHardDisk(volumeSize, volumePath);
+ if (File.Exists(volumePath))
+ {
+ result = true;
+ JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, volume);
+ newData = ansObj;
+ }
+ else
+ {
+ details = "Failed to create disk with name " + volumePath;
+ }
+ }
+ catch (Exception ex)
+ {
+ // Test by providing wrong key
+ details = CloudStackTypes.CreateObjectCommand + " failed on exception, " + ex.Message;
+ logger.Error(details, ex);
+ }
+
+ object ansContent = new
+ {
+ result = result,
+ details = details,
+ data = newData,
+ contextMap = contextMap
+ };
+
+ return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CreateObjectAnswer);
+ }
+ }
+
+ // POST api/HypervResource/MaintainCommand
+ // TODO: should this be a NOP?
+ [HttpPost]
+ [ActionName(CloudStackTypes.MaintainCommand)]
+ public JContainer MaintainCommand([FromBody]dynamic cmd)
+ {
+ using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+ {
+
<TRUNCATED>