diff --git a/README.md b/README.md index 23f5004cd94..009df8313c3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Apache CloudStack Version 4.4.0 +Apache CloudStack Version 4.4.1 # About Apache CloudStack diff --git a/agent-simulator/tomcatconf/commands-simulator.properties.in b/agent-simulator/tomcatconf/commands-simulator.properties.in index ba19e33dc5f..4350bb788b4 100644 --- a/agent-simulator/tomcatconf/commands-simulator.properties.in +++ b/agent-simulator/tomcatconf/commands-simulator.properties.in @@ -17,3 +17,5 @@ configureSimulator=com.cloud.api.commands.ConfigureSimulatorCmd;1 +querySimulatorMock=com.cloud.api.commands.QuerySimulatorMockCmd;1 +cleanupSimulatorMock=com.cloud.api.commands.CleanupSimulatorMockCmd;1 diff --git a/api/src/com/cloud/network/IpAddress.java b/api/src/com/cloud/network/IpAddress.java index fc14387e7ee..301edce5e03 100644 --- a/api/src/com/cloud/network/IpAddress.java +++ b/api/src/com/cloud/network/IpAddress.java @@ -19,6 +19,7 @@ package com.cloud.network; import java.util.Date; import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Displayable; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; @@ -35,7 +36,7 @@ import com.cloud.utils.net.Ip; * - DomainId = domain of the account owner. * - Allocated = time it was allocated. */ -public interface IpAddress extends ControlledEntity, Identity, InternalIdentity { +public interface IpAddress extends ControlledEntity, Identity, InternalIdentity, Displayable { enum State { Allocating, // The IP Address is being propagated to other network elements and is not ready for use yet. Allocated, // The IP address is in used. @@ -85,6 +86,7 @@ public interface IpAddress extends ControlledEntity, Identity, InternalIdentity Long getNetworkId(); + @Override boolean isDisplay(); public Date getRemoved(); diff --git a/api/src/com/cloud/network/NetworkModel.java b/api/src/com/cloud/network/NetworkModel.java index f6555db565e..574160d2c64 100644 --- a/api/src/com/cloud/network/NetworkModel.java +++ b/api/src/com/cloud/network/NetworkModel.java @@ -90,6 +90,8 @@ public interface NetworkModel { boolean areServicesSupportedByNetworkOffering(long networkOfferingId, Service... services); + Network getNetworkWithSGWithFreeIPs(Long zoneId); + Network getNetworkWithSecurityGroupEnabled(Long zoneId); String getIpOfNetworkElementInVirtualNetwork(long accountId, long dataCenterId); @@ -273,4 +275,4 @@ public interface NetworkModel { boolean isNetworkReadyForGc(long networkId); boolean getNetworkEgressDefaultPolicy(Long networkId); -} \ No newline at end of file +} diff --git a/api/src/com/cloud/network/RemoteAccessVpn.java b/api/src/com/cloud/network/RemoteAccessVpn.java index 4d7e4d49b12..25b4fbbcdeb 100644 --- a/api/src/com/cloud/network/RemoteAccessVpn.java +++ b/api/src/com/cloud/network/RemoteAccessVpn.java @@ -17,10 +17,11 @@ package com.cloud.network; import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Displayable; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; -public interface RemoteAccessVpn extends ControlledEntity, InternalIdentity, Identity { +public interface RemoteAccessVpn extends ControlledEntity, InternalIdentity, Identity, Displayable { enum State { Added, Running, Removed } @@ -39,5 +40,6 @@ public interface RemoteAccessVpn extends ControlledEntity, InternalIdentity, Ide State getState(); + @Override boolean isDisplay(); } diff --git a/api/src/com/cloud/network/Site2SiteVpnConnection.java b/api/src/com/cloud/network/Site2SiteVpnConnection.java index 81e81801195..cfc439abcd8 100644 --- a/api/src/com/cloud/network/Site2SiteVpnConnection.java +++ b/api/src/com/cloud/network/Site2SiteVpnConnection.java @@ -19,9 +19,10 @@ package com.cloud.network; import java.util.Date; import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Displayable; import org.apache.cloudstack.api.InternalIdentity; -public interface Site2SiteVpnConnection extends ControlledEntity, InternalIdentity { +public interface Site2SiteVpnConnection extends ControlledEntity, InternalIdentity, Displayable { enum State { Pending, Connected, Disconnected, Error, } @@ -43,5 +44,6 @@ public interface Site2SiteVpnConnection extends ControlledEntity, InternalIdenti public boolean isPassive(); + @Override boolean isDisplay(); } diff --git a/api/src/com/cloud/network/Site2SiteVpnGateway.java b/api/src/com/cloud/network/Site2SiteVpnGateway.java index bae12597f27..57037d6b640 100644 --- a/api/src/com/cloud/network/Site2SiteVpnGateway.java +++ b/api/src/com/cloud/network/Site2SiteVpnGateway.java @@ -19,16 +19,18 @@ package com.cloud.network; import java.util.Date; import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Displayable; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; -public interface Site2SiteVpnGateway extends ControlledEntity, Identity, InternalIdentity { +public interface Site2SiteVpnGateway extends ControlledEntity, Identity, InternalIdentity, Displayable { public long getAddrId(); public long getVpcId(); public Date getRemoved(); + @Override boolean isDisplay(); } diff --git a/api/src/com/cloud/network/as/AutoScaleVmGroup.java b/api/src/com/cloud/network/as/AutoScaleVmGroup.java index 14c761593b1..cf2c15c4216 100644 --- a/api/src/com/cloud/network/as/AutoScaleVmGroup.java +++ b/api/src/com/cloud/network/as/AutoScaleVmGroup.java @@ -20,9 +20,10 @@ package com.cloud.network.as; import java.util.Date; import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Displayable; import org.apache.cloudstack.api.InternalIdentity; -public interface AutoScaleVmGroup extends ControlledEntity, InternalIdentity { +public interface AutoScaleVmGroup extends ControlledEntity, InternalIdentity, Displayable { String State_New = "new"; String State_Revoke = "revoke"; @@ -53,6 +54,7 @@ public interface AutoScaleVmGroup extends ControlledEntity, InternalIdentity { String getUuid(); + @Override boolean isDisplay(); } diff --git a/api/src/com/cloud/network/as/AutoScaleVmProfile.java b/api/src/com/cloud/network/as/AutoScaleVmProfile.java index 6e0b5ffb91b..495446a6e83 100644 --- a/api/src/com/cloud/network/as/AutoScaleVmProfile.java +++ b/api/src/com/cloud/network/as/AutoScaleVmProfile.java @@ -20,6 +20,7 @@ package com.cloud.network.as; import java.util.List; import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Displayable; import org.apache.cloudstack.api.InternalIdentity; import com.cloud.utils.Pair; @@ -27,7 +28,7 @@ import com.cloud.utils.Pair; /** * AutoScaleVmProfile */ -public interface AutoScaleVmProfile extends ControlledEntity, InternalIdentity { +public interface AutoScaleVmProfile extends ControlledEntity, InternalIdentity, Displayable { @Override public long getId(); @@ -48,6 +49,7 @@ public interface AutoScaleVmProfile extends ControlledEntity, InternalIdentity { public long getAutoScaleUserId(); + @Override boolean isDisplay(); } diff --git a/api/src/com/cloud/network/rules/HealthCheckPolicy.java b/api/src/com/cloud/network/rules/HealthCheckPolicy.java index 2b1b68bbc88..f7562e8e892 100644 --- a/api/src/com/cloud/network/rules/HealthCheckPolicy.java +++ b/api/src/com/cloud/network/rules/HealthCheckPolicy.java @@ -16,12 +16,13 @@ // under the License. package com.cloud.network.rules; +import org.apache.cloudstack.api.Displayable; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; /** */ -public interface HealthCheckPolicy extends InternalIdentity, Identity { +public interface HealthCheckPolicy extends InternalIdentity, Identity, Displayable { public long getLoadBalancerId(); @@ -39,9 +40,7 @@ public interface HealthCheckPolicy extends InternalIdentity, Identity { public boolean isRevoke(); - /** - * @return - */ + @Override boolean isDisplay(); } diff --git a/api/src/com/cloud/network/rules/StickinessPolicy.java b/api/src/com/cloud/network/rules/StickinessPolicy.java index c7700718ba8..7f956f98d44 100644 --- a/api/src/com/cloud/network/rules/StickinessPolicy.java +++ b/api/src/com/cloud/network/rules/StickinessPolicy.java @@ -18,6 +18,7 @@ package com.cloud.network.rules; import java.util.List; +import org.apache.cloudstack.api.Displayable; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; @@ -25,7 +26,7 @@ import com.cloud.utils.Pair; /** */ -public interface StickinessPolicy extends InternalIdentity, Identity { +public interface StickinessPolicy extends InternalIdentity, Identity, Displayable { public long getLoadBalancerId(); @@ -39,9 +40,7 @@ public interface StickinessPolicy extends InternalIdentity, Identity { public List> getParams(); /* get params in Map format */ - /** - * @return - */ + @Override boolean isDisplay(); } diff --git a/api/src/com/cloud/network/vpc/NetworkACL.java b/api/src/com/cloud/network/vpc/NetworkACL.java index 3ebee146ed8..193a48c60f3 100644 --- a/api/src/com/cloud/network/vpc/NetworkACL.java +++ b/api/src/com/cloud/network/vpc/NetworkACL.java @@ -17,9 +17,10 @@ package com.cloud.network.vpc; +import org.apache.cloudstack.api.Displayable; import org.apache.cloudstack.api.InternalIdentity; -public interface NetworkACL extends InternalIdentity { +public interface NetworkACL extends InternalIdentity, Displayable { public static final long DEFAULT_DENY = 1; public static final long DEFAULT_ALLOW = 2; @@ -34,5 +35,6 @@ public interface NetworkACL extends InternalIdentity { String getName(); + @Override boolean isDisplay(); } diff --git a/api/src/com/cloud/network/vpc/NetworkACLItem.java b/api/src/com/cloud/network/vpc/NetworkACLItem.java index faa4d273c9c..8e288a2b967 100644 --- a/api/src/com/cloud/network/vpc/NetworkACLItem.java +++ b/api/src/com/cloud/network/vpc/NetworkACLItem.java @@ -18,9 +18,10 @@ package com.cloud.network.vpc; import java.util.List; +import org.apache.cloudstack.api.Displayable; import org.apache.cloudstack.api.InternalIdentity; -public interface NetworkACLItem extends InternalIdentity { +public interface NetworkACLItem extends InternalIdentity, Displayable { String getUuid(); @@ -73,6 +74,7 @@ public interface NetworkACLItem extends InternalIdentity { */ TrafficType getTrafficType(); + @Override boolean isDisplay(); } diff --git a/api/src/com/cloud/server/ResourceMetaDataService.java b/api/src/com/cloud/server/ResourceMetaDataService.java index 56fe1045ab3..113dc0703b3 100644 --- a/api/src/com/cloud/server/ResourceMetaDataService.java +++ b/api/src/com/cloud/server/ResourceMetaDataService.java @@ -46,6 +46,16 @@ public interface ResourceMetaDataService { ResourceDetail getDetail(long resourceId, ResourceObjectType resourceType, String key); + /** + * List by key, value pair + * @param resourceType + * @param key + * @param value + * @param forDisplay + * @return + */ + List getDetails(ResourceObjectType resourceType, String key, String value, Boolean forDisplay); + Map getDetailsMap(long resourceId, ResourceObjectType resourceType, Boolean forDisplay); List getDetailsList(long resourceId, ResourceObjectType resourceType, Boolean forDisplay); diff --git a/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java b/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java index 3f0d2467bf3..96174e12377 100644 --- a/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java @@ -201,10 +201,19 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd { } } + @Deprecated public Boolean getDisplayIp() { return display; } + @Override + public boolean isDisplay() { + if(display == null) + return true; + else + return display; + } + @Override public long getEntityOwnerId() { Account caller = CallContext.current().getCallingAccount(); diff --git a/api/src/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmGroupCmd.java b/api/src/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmGroupCmd.java index 1fd0029e342..0308c1710c3 100644 --- a/api/src/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmGroupCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmGroupCmd.java @@ -184,10 +184,19 @@ public class CreateAutoScaleVmGroupCmd extends BaseAsyncCreateCmd { return ApiCommandJobType.AutoScaleVmGroup; } + @Deprecated public Boolean getDisplay() { return display; } + @Override + public boolean isDisplay() { + if(display == null) + return true; + else + return display; + } + @Override public void create() throws ResourceAllocationException { AutoScaleVmGroup result = _autoScaleService.createAutoScaleVmGroup(this); diff --git a/api/src/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmProfileCmd.java b/api/src/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmProfileCmd.java index 189217a2022..447085e79b5 100644 --- a/api/src/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmProfileCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmProfileCmd.java @@ -131,10 +131,19 @@ public class CreateAutoScaleVmProfileCmd extends BaseAsyncCreateCmd { return templateId; } + @Deprecated public Boolean getDisplay() { return display; } + @Override + public boolean isDisplay() { + if(display == null) + return true; + else + return display; + } + public Map getCounterParamList() { return counterParamList; } diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLBHealthCheckPolicyCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLBHealthCheckPolicyCmd.java index b48722661ec..f6eb48e800f 100644 --- a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLBHealthCheckPolicyCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLBHealthCheckPolicyCmd.java @@ -97,10 +97,19 @@ public class CreateLBHealthCheckPolicyCmd extends BaseAsyncCreateCmd { // ///////////////// Accessors /////////////////////// // /////////////////////////////////////////////////// + @Deprecated public Boolean getDisplay() { return display; } + @Override + public boolean isDisplay() { + if(display == null) + return true; + else + return display; + } + public Long getLbRuleId() { return lbRuleId; } diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLBStickinessPolicyCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLBStickinessPolicyCmd.java index 5ea571722bb..152f6612f0c 100644 --- a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLBStickinessPolicyCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLBStickinessPolicyCmd.java @@ -82,10 +82,19 @@ public class CreateLBStickinessPolicyCmd extends BaseAsyncCreateCmd { // ///////////////// Accessors /////////////////////// // /////////////////////////////////////////////////// + @Deprecated public Boolean getDisplay() { return display; } + @Override + public boolean isDisplay() { + if(display == null) + return true; + else + return display; + } + public Long getLbRuleId() { return lbRuleId; } diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java index a405913f78e..7c371928d99 100644 --- a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java @@ -124,8 +124,13 @@ public class CreateLoadBalancerRuleCmd extends BaseAsyncCreateCmd /*implements L /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// - public Boolean getDisplay() { - return display; + @Override + public boolean isDisplay() { + if (display != null) { + return display; + } else { + return true; + } } public String getAlgorithm() { @@ -309,7 +314,7 @@ public class CreateLoadBalancerRuleCmd extends BaseAsyncCreateCmd /*implements L try { LoadBalancer result = _lbService.createPublicLoadBalancerRule(getXid(), getName(), getDescription(), getSourcePortStart(), getSourcePortEnd(), getDefaultPortStart(), - getDefaultPortEnd(), getSourceIpAddressId(), getProtocol(), getAlgorithm(), getNetworkId(), getEntityOwnerId(), getOpenFirewall(), getLbProtocol(), getDisplay()); + getDefaultPortEnd(), getSourceIpAddressId(), getProtocol(), getAlgorithm(), getNetworkId(), getEntityOwnerId(), getOpenFirewall(), getLbProtocol(), isDisplay()); this.setEntityId(result.getId()); this.setEntityUuid(result.getUuid()); } catch (NetworkRuleConflictException e) { diff --git a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkACLCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkACLCmd.java index e47fa8b2cf7..b4d54896d9b 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkACLCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkACLCmd.java @@ -103,10 +103,20 @@ public class CreateNetworkACLCmd extends BaseAsyncCreateCmd { // /////////////////////////////////////////////////// // ///////////////// Accessors /////////////////////// // /////////////////////////////////////////////////// + @Deprecated public Boolean getDisplay() { return display; } + @Override + public boolean isDisplay() { + if (display != null) { + return display; + } else { + return true; + } + } + public String getProtocol() { String p = protocol.trim(); // Deal with ICMP(protocol number 1) specially because it need to be paired with icmp type and code diff --git a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java index 07156cf944f..9aa0bab5ae9 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java @@ -77,8 +77,13 @@ public class CreateNetworkACLListCmd extends BaseAsyncCreateCmd { return vpcId; } - public Boolean getDisplay() { - return display; + @Override + public boolean isDisplay() { + if (display != null) { + return display; + } else { + return true; + } } // /////////////////////////////////////////////////// @@ -92,7 +97,7 @@ public class CreateNetworkACLListCmd extends BaseAsyncCreateCmd { @Override public void create() { - NetworkACL result = _networkACLService.createNetworkACL(getName(), getDescription(), getVpcId(), getDisplay()); + NetworkACL result = _networkACLService.createNetworkACL(getName(), getDescription(), getVpcId(), isDisplay()); setEntityId(result.getId()); setEntityUuid(result.getUuid()); } diff --git a/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkACLItemCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkACLItemCmd.java index eb095df2091..59ae05df400 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkACLItemCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkACLItemCmd.java @@ -88,8 +88,14 @@ public class UpdateNetworkACLItemCmd extends BaseAsyncCustomIdCmd { // /////////////////////////////////////////////////// // ///////////////// Accessors /////////////////////// // /////////////////////////////////////////////////// - public Boolean getDisplay() { - return display; + + @Override + public boolean isDisplay() { + if (display != null) { + return display; + } else { + return true; + } } public Long getId() { @@ -172,7 +178,7 @@ public class UpdateNetworkACLItemCmd extends BaseAsyncCustomIdCmd { CallContext.current().setEventDetails("Rule Id: " + getId()); NetworkACLItem aclItem = _networkACLService.updateNetworkACLItem(getId(), getProtocol(), getSourceCidrList(), getTrafficType(), getAction(), getNumber(), getSourcePortStart(), - getSourcePortEnd(), getIcmpCode(), getIcmpType(), this.getCustomId(), this.getDisplay()); + getSourcePortEnd(), getIcmpCode(), getIcmpType(), this.getCustomId(), this.isDisplay()); if (aclItem == null) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update network ACL Item"); } diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ListResourceDetailsCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ListResourceDetailsCmd.java index 93dc29db790..47f80a034f3 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/ListResourceDetailsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/ListResourceDetailsCmd.java @@ -44,6 +44,10 @@ public class ListResourceDetailsCmd extends BaseListProjectAndAccountResourcesCm @Parameter(name = ApiConstants.KEY, type = CommandType.STRING, description = "list by key") private String key; + @Parameter(name = ApiConstants.VALUE, type = CommandType.STRING, description = "list by key, value. Needs to be passed only along with key" , + since = "4.4", authorized = { RoleType.Admin }) + private String value; + @Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "if set to true, only details marked with display=true, are returned." + " False by default", since = "4.3", authorized = { RoleType.Admin }) private Boolean forDisplay; @@ -56,6 +60,10 @@ public class ListResourceDetailsCmd extends BaseListProjectAndAccountResourcesCm return key; } + public String getValue() { + return value; + } + @Override public String getCommandName() { return s_name; diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java index 7a08abf2766..c360c146d60 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java @@ -25,6 +25,7 @@ import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ResponseObject.ResponseView; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ProjectResponse; import org.apache.cloudstack.api.response.VolumeResponse; @@ -89,6 +90,9 @@ public class UploadVolumeCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Upload volume for the project") private Long projectId; + @Parameter(name = ApiConstants.DISK_OFFERING_ID, required = false, type = CommandType.UUID, entityType = DiskOfferingResponse.class, description = "the ID of the disk offering. This must be a custom sized offering since during uploadVolume volume size is unknown.") + private Long diskOfferingId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -125,6 +129,10 @@ public class UploadVolumeCmd extends BaseAsyncCmd { return imageStoreUuid; } + public Long getDiskOfferingId() { + return diskOfferingId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateRemoteAccessVpnCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateRemoteAccessVpnCmd.java index 2883b1999d6..14b781d2361 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateRemoteAccessVpnCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateRemoteAccessVpnCmd.java @@ -145,7 +145,7 @@ public class CreateRemoteAccessVpnCmd extends BaseAsyncCreateCmd { @Override public void create() { try { - RemoteAccessVpn vpn = _ravService.createRemoteAccessVpn(publicIpId, ipRange, getOpenFirewall(), getDisplay()); + RemoteAccessVpn vpn = _ravService.createRemoteAccessVpn(publicIpId, ipRange, getOpenFirewall(), isDisplay()); if (vpn != null) { setEntityId(vpn.getServerAddressId()); // find uuid for server ip address @@ -198,7 +198,11 @@ public class CreateRemoteAccessVpnCmd extends BaseAsyncCreateCmd { return ip; } - public Boolean getDisplay() { - return display; + @Override + public boolean isDisplay() { + if(display == null) + return true; + else + return display; } } diff --git a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnConnectionCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnConnectionCmd.java index 71245c340a3..6c08a423259 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnConnectionCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnConnectionCmd.java @@ -87,10 +87,20 @@ public class CreateVpnConnectionCmd extends BaseAsyncCreateCmd { return passive; } + @Deprecated public Boolean getDisplay() { return display; } + @Override + public boolean isDisplay() { + if (display != null) { + return display; + } else { + return true; + } + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnGatewayCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnGatewayCmd.java index d5b5edbeeea..3043edcb048 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnGatewayCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnGatewayCmd.java @@ -16,25 +16,26 @@ // under the License. package org.apache.cloudstack.api.command.user.vpn; -import org.apache.log4j.Logger; - +import com.cloud.event.EventTypes; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.network.Site2SiteVpnGateway; +import com.cloud.network.vpc.Vpc; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.Site2SiteVpnGatewayResponse; import org.apache.cloudstack.api.response.VpcResponse; - -import com.cloud.event.EventTypes; -import com.cloud.network.Site2SiteVpnGateway; -import com.cloud.network.vpc.Vpc; +import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; @APICommand(name = "createVpnGateway", description = "Creates site to site vpn local gateway", responseObject = Site2SiteVpnGatewayResponse.class, entityType = {Site2SiteVpnGateway.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) -public class CreateVpnGatewayCmd extends BaseAsyncCmd { +public class CreateVpnGatewayCmd extends BaseAsyncCreateCmd { public static final Logger s_logger = Logger.getLogger(CreateVpnGatewayCmd.class.getName()); private static final String s_name = "createvpngatewayresponse"; @@ -60,10 +61,20 @@ public class CreateVpnGatewayCmd extends BaseAsyncCmd { return vpcId; } + @Deprecated public Boolean getDisplay() { return display; } + @Override + public boolean isDisplay() { + if (display != null) { + return display; + } else { + return true; + } + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -91,8 +102,8 @@ public class CreateVpnGatewayCmd extends BaseAsyncCmd { @Override public void execute() { - Site2SiteVpnGateway result; - result = _s2sVpnService.createVpnGateway(this); + CallContext.current().setEventDetails("VPN gateway Id: " + getEntityId()); + Site2SiteVpnGateway result = _s2sVpnService.getVpnGateway(getEntityId()); if (result != null) { Site2SiteVpnGatewayResponse response = _responseGenerator.createSite2SiteVpnGatewayResponse(result); response.setResponseName(getCommandName()); @@ -111,4 +122,15 @@ public class CreateVpnGatewayCmd extends BaseAsyncCmd { public Long getSyncObjId() { return getVpcId(); } + + @Override + public void create() throws ResourceAllocationException { + Site2SiteVpnGateway result = _s2sVpnService.createVpnGateway(this); + if (result != null) { + setEntityId(result.getId()); + setEntityUuid(result.getUuid()); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create VPN gateway"); + } + } } diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 13e08be65b5..d247aa03475 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -620,6 +620,8 @@ deleteStratoshereSsp=1 #### host simulator commands configureSimulator=1 +querySimulatorMock=1 +cleanupSimulatorMock=1 #### api discovery commands diff --git a/core/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml b/core/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml index d54823a33ef..819fb830d5d 100644 --- a/core/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml +++ b/core/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml @@ -75,6 +75,7 @@ + + + diff --git a/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java b/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java index fd1531e25a6..24a6fe71f85 100755 --- a/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java +++ b/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java @@ -30,7 +30,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.log4j.Logger; @@ -107,7 +106,6 @@ public abstract class AgentAttache { protected Status _status = Status.Connecting; protected boolean _maintenance; protected long _nextSequence; - protected AtomicInteger _outstandingTaskCount; protected AgentManagerImpl _agentMgr; @@ -130,7 +128,6 @@ public abstract class AgentAttache { _requests = new LinkedList(); _agentMgr = agentMgr; _nextSequence = new Long(s_rand.nextInt(Short.MAX_VALUE)) << 48; - _outstandingTaskCount = new AtomicInteger(0); } public synchronized long getNextSequence() { diff --git a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java index f43086fab9f..2d0be24fcf8 100755 --- a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -162,6 +162,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl protected ExecutorService _executor; protected ThreadPoolExecutor _connectExecutor; protected ScheduledExecutorService _directAgentExecutor; + protected ScheduledExecutorService _cronJobExecutor; protected ScheduledExecutorService _monitorExecutor; private int _directAgentThreadCap; @@ -219,7 +220,10 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl _connection = new NioServer("AgentManager", Port.value(), Workers.value() + 10, this); s_logger.info("Listening on " + Port.value() + " with " + Workers.value() + " workers"); + // executes all agent commands other than cron and ping _directAgentExecutor = new ScheduledThreadPoolExecutor(DirectAgentPoolSize.value(), new NamedThreadFactory("DirectAgent")); + // executes cron and ping agent commands + _cronJobExecutor = new ScheduledThreadPoolExecutor(DirectAgentPoolSize.value(), new NamedThreadFactory("DirectAgentCronJob")); s_logger.debug("Created DirectAgentAttache pool with size: " + DirectAgentPoolSize.value()); _directAgentThreadCap = Math.round(DirectAgentPoolSize.value() * DirectAgentThreadCap.value()) + 1; // add 1 to always make the value > 0 @@ -1451,6 +1455,10 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl return _directAgentExecutor; } + public ScheduledExecutorService getCronJobPool() { + return _cronJobExecutor; + } + public int getDirectAgentThreadCap() { return _directAgentThreadCap; } diff --git a/engine/orchestration/src/com/cloud/agent/manager/DirectAgentAttache.java b/engine/orchestration/src/com/cloud/agent/manager/DirectAgentAttache.java index 9874ee41932..7ca6929686a 100755 --- a/engine/orchestration/src/com/cloud/agent/manager/DirectAgentAttache.java +++ b/engine/orchestration/src/com/cloud/agent/manager/DirectAgentAttache.java @@ -17,12 +17,13 @@ package com.cloud.agent.manager; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.log4j.Logger; - import org.apache.cloudstack.managed.context.ManagedContextRunnable; import com.cloud.agent.api.Answer; @@ -43,11 +44,16 @@ public class DirectAgentAttache extends AgentAttache { List> _futures = new ArrayList>(); AgentManagerImpl _mgr; long _seq = 0; + LinkedList tasks = new LinkedList(); + AtomicInteger _outstandingTaskCount; + AtomicInteger _outstandingCronTaskCount; public DirectAgentAttache(AgentManagerImpl agentMgr, long id, String name, ServerResource resource, boolean maintenance, AgentManagerImpl mgr) { super(agentMgr, id, name, maintenance); _resource = resource; _mgr = mgr; + _outstandingTaskCount = new AtomicInteger(0); + _outstandingCronTaskCount = new AtomicInteger(0); } @Override @@ -90,15 +96,16 @@ public class DirectAgentAttache extends AgentAttache { if (answers != null && answers[0] instanceof StartupAnswer) { StartupAnswer startup = (StartupAnswer)answers[0]; int interval = startup.getPingInterval(); - _futures.add(_agentMgr.getDirectAgentPool().scheduleAtFixedRate(new PingTask(), interval, interval, TimeUnit.SECONDS)); + _futures.add(_agentMgr.getCronJobPool().scheduleAtFixedRate(new PingTask(), interval, interval, TimeUnit.SECONDS)); } } else { Command[] cmds = req.getCommands(); if (cmds.length > 0 && !(cmds[0] instanceof CronCommand)) { - _agentMgr.getDirectAgentPool().execute(new Task(req)); + queueTask(new Task(req)); + scheduleFromQueue(); } else { CronCommand cmd = (CronCommand)cmds[0]; - _futures.add(_agentMgr.getDirectAgentPool().scheduleAtFixedRate(new Task(req), cmd.getInterval(), cmd.getInterval(), TimeUnit.SECONDS)); + _futures.add(_agentMgr.getCronJobPool().scheduleAtFixedRate(new CronTask(req), cmd.getInterval(), cmd.getInterval(), TimeUnit.SECONDS)); } } } @@ -109,7 +116,7 @@ public class DirectAgentAttache extends AgentAttache { StartupAnswer startup = (StartupAnswer)answers[0]; int interval = startup.getPingInterval(); s_logger.info("StartupAnswer received " + startup.getHostId() + " Interval = " + interval); - _futures.add(_agentMgr.getDirectAgentPool().scheduleAtFixedRate(new PingTask(), interval, interval, TimeUnit.SECONDS)); + _futures.add(_agentMgr.getCronJobPool().scheduleAtFixedRate(new PingTask(), interval, interval, TimeUnit.SECONDS)); } } @@ -128,13 +135,26 @@ public class DirectAgentAttache extends AgentAttache { } } + private synchronized void queueTask(Task task) { + tasks.add(task); + } + + private synchronized void scheduleFromQueue() { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Agent attache=" + _id + ", task queue size=" + tasks.size() + ", outstanding tasks=" + _outstandingTaskCount.get()); + } + while (!tasks.isEmpty() && _outstandingTaskCount.get() < _agentMgr.getDirectAgentThreadCap()) { + _outstandingTaskCount.incrementAndGet(); + _agentMgr.getDirectAgentPool().execute(tasks.remove()); + } + } + protected class PingTask extends ManagedContextRunnable { @Override protected synchronized void runInContext() { try { - if (_outstandingTaskCount.incrementAndGet() > _agentMgr.getDirectAgentThreadCap()) { - s_logger.warn("Task execution for direct attache(" + _id + ") has reached maximum outstanding limit(" + _agentMgr.getDirectAgentThreadCap() + - "), bailing out"); + if (_outstandingCronTaskCount.incrementAndGet() >= _agentMgr.getDirectAgentThreadCap()) { + s_logger.warn("PingTask execution for direct attache(" + _id + ") has reached maximum outstanding limit(" + _agentMgr.getDirectAgentThreadCap() + "), bailing out"); return; } @@ -162,15 +182,15 @@ public class DirectAgentAttache extends AgentAttache { } catch (Exception e) { s_logger.warn("Unable to complete the ping task", e); } finally { - _outstandingTaskCount.decrementAndGet(); + _outstandingCronTaskCount.decrementAndGet(); } } } - protected class Task extends ManagedContextRunnable { + protected class CronTask extends ManagedContextRunnable { Request _req; - public Task(Request req) { + public CronTask(Request req) { _req = req; } @@ -194,9 +214,8 @@ public class DirectAgentAttache extends AgentAttache { protected void runInContext() { long seq = _req.getSequence(); try { - if (_outstandingTaskCount.incrementAndGet() > _agentMgr.getDirectAgentThreadCap()) { - s_logger.warn("Task execution for direct attache(" + _id + ") has reached maximum outstanding limit(" + _agentMgr.getDirectAgentThreadCap() + - "), bailing out"); + if (_outstandingCronTaskCount.incrementAndGet() >= _agentMgr.getDirectAgentThreadCap()) { + s_logger.warn("CronTask execution for direct attache(" + _id + ") has reached maximum outstanding limit(" + _agentMgr.getDirectAgentThreadCap() + "), bailing out"); bailout(); return; } @@ -243,9 +262,67 @@ public class DirectAgentAttache extends AgentAttache { } catch (Exception e) { s_logger.warn(log(seq, "Exception caught "), e); } finally { - _outstandingTaskCount.decrementAndGet(); + _outstandingCronTaskCount.decrementAndGet(); } } } + protected class Task extends ManagedContextRunnable { + Request _req; + + public Task(Request req) { + _req = req; + } + + @Override + protected void runInContext() { + long seq = _req.getSequence(); + try { + ServerResource resource = _resource; + Command[] cmds = _req.getCommands(); + boolean stopOnError = _req.stopOnError(); + + if (s_logger.isDebugEnabled()) { + s_logger.debug(log(seq, "Executing request")); + } + ArrayList answers = new ArrayList(cmds.length); + for (int i = 0; i < cmds.length; i++) { + Answer answer = null; + try { + if (resource != null) { + answer = resource.executeRequest(cmds[i]); + if (answer == null) { + s_logger.warn("Resource returned null answer!"); + answer = new Answer(cmds[i], false, "Resource returned null answer"); + } + } else { + answer = new Answer(cmds[i], false, "Agent is disconnected"); + } + } catch (Exception e) { + s_logger.warn(log(seq, "Exception Caught while executing command"), e); + answer = new Answer(cmds[i], false, e.toString()); + } + answers.add(answer); + if (!answer.getResult() && stopOnError) { + if (i < cmds.length - 1 && s_logger.isDebugEnabled()) { + s_logger.debug(log(seq, "Cancelling because one of the answers is false and it is stop on error.")); + } + break; + } + } + + Response resp = new Response(_req, answers.toArray(new Answer[answers.size()])); + if (s_logger.isDebugEnabled()) { + s_logger.debug(log(seq, "Response Received: ")); + } + + processAnswers(seq, resp); + } catch (Exception e) { + s_logger.warn(log(seq, "Exception caught "), e); + } finally { + _outstandingTaskCount.decrementAndGet(); + scheduleFromQueue(); + } + } + } } diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index 358b3bd35bd..76281c6ba15 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -866,9 +866,11 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati if (volumesForVm != null) { for (VolumeVO volumeForVm : volumesForVm) { VolumeInfo volumeInfo = volFactory.getVolume(volumeForVm.getId()); - DataStore dataStore = dataStoreMgr.getDataStore(volumeForVm.getPoolId(), DataStoreRole.Primary); - - volService.disconnectVolumeFromHost(volumeInfo, host, dataStore); + // pool id can be null for the VM's volumes in Allocated state + if (volumeForVm.getPoolId() != null) { + DataStore dataStore = dataStoreMgr.getDataStore(volumeForVm.getPoolId(), DataStoreRole.Primary); + volService.disconnectVolumeFromHost(volumeInfo, host, dataStore); + } } } } diff --git a/engine/schema/src/com/cloud/upgrade/dao/DatabaseAccessObject.java b/engine/schema/src/com/cloud/upgrade/dao/DatabaseAccessObject.java index 836a5376865..1e620a5a584 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/DatabaseAccessObject.java +++ b/engine/schema/src/com/cloud/upgrade/dao/DatabaseAccessObject.java @@ -26,63 +26,50 @@ public class DatabaseAccessObject { private static Logger s_logger = Logger.getLogger(DatabaseAccessObject.class); - public void dropKey(Connection conn, String tableName, String key, boolean isForeignKey) { - PreparedStatement pstmt = null; - try { - if (isForeignKey) { - pstmt = conn.prepareStatement("ALTER TABLE " + tableName + " DROP FOREIGN KEY " + key); - } else { - pstmt = conn.prepareStatement("ALTER TABLE " + tableName + " DROP KEY " + key); - } + public void dropKey(Connection conn, String tableName, String key, boolean isForeignKey) + { + String alter_sql_str; + if (isForeignKey) { + alter_sql_str = "ALTER TABLE " + tableName + " DROP FOREIGN KEY " + key; + } else { + alter_sql_str = "ALTER TABLE " + tableName + " DROP KEY " + key; + } + try(PreparedStatement pstmt = conn.prepareStatement(alter_sql_str);) + { pstmt.executeUpdate(); s_logger.debug("Key " + key + " is dropped successfully from the table " + tableName); } catch (SQLException e) { - s_logger.warn("Ignored SQL Exception when trying to drop " + (isForeignKey ? "foreign " : "") + "key " + key + " on table " + tableName, e); - } finally { - closePreparedStatement(pstmt, "Ignored SQL Exception when trying to close PreparedStatement atfer dropping " + (isForeignKey ? "foreign " : "") + "key " + key - + " on table " + tableName); + s_logger.warn("Ignored SQL Exception when trying to drop " + (isForeignKey ? "foreign " : "") + "key " + key + " on table " + tableName, e); + } } public void dropPrimaryKey(Connection conn, String tableName) { - PreparedStatement pstmt = null; - try { - pstmt = conn.prepareStatement("ALTER TABLE " + tableName + " DROP PRIMARY KEY "); + try(PreparedStatement pstmt = conn.prepareStatement("ALTER TABLE " + tableName + " DROP PRIMARY KEY ");) { pstmt.executeUpdate(); s_logger.debug("Primary key is dropped successfully from the table " + tableName); } catch (SQLException e) { s_logger.warn("Ignored SQL Exception when trying to drop primary key on table " + tableName, e); - } finally { - closePreparedStatement(pstmt, "Ignored SQL Exception when trying to close PreparedStatement atfer dropping primary key on table " + tableName); } } public void dropColumn(Connection conn, String tableName, String columnName) { - PreparedStatement pstmt = null; - try { - pstmt = conn.prepareStatement("ALTER TABLE " + tableName + " DROP COLUMN " + columnName); + try (PreparedStatement pstmt = conn.prepareStatement("ALTER TABLE " + tableName + " DROP COLUMN " + columnName);){ pstmt.executeUpdate(); s_logger.debug("Column " + columnName + " is dropped successfully from the table " + tableName); } catch (SQLException e) { - s_logger.warn("Unable to drop columns using query " + pstmt + " due to exception", e); - } finally { - closePreparedStatement(pstmt, "Ignored SQL Exception when trying to close PreparedStatement after dropping column " + columnName + " on table " + tableName); + s_logger.warn("Unable to drop column " + columnName + " due to exception", e); } } public boolean columnExists(Connection conn, String tableName, String columnName) { boolean columnExists = false; - PreparedStatement pstmt = null; - try { - pstmt = conn.prepareStatement("SELECT " + columnName + " FROM " + tableName); + try (PreparedStatement pstmt = conn.prepareStatement("SELECT " + columnName + " FROM " + tableName);){ pstmt.executeQuery(); columnExists = true; } catch (SQLException e) { s_logger.warn("Field " + columnName + " doesn't exist in " + tableName, e); - } finally { - closePreparedStatement(pstmt, "Ignored SQL Exception when trying to close PreparedStatement atfer checking if column " + columnName + " existed on table " + tableName); } - return columnExists; } diff --git a/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java index bcd6fa78a75..df023bfcf79 100644 --- a/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java +++ b/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java @@ -659,12 +659,12 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem finalQuery.append(COUNT_VMS_BASED_ON_VGPU_TYPES1); if (podId != null) { - finalQuery.append(" AND host.pod_id = ?"); + finalQuery.append("AND host.pod_id = ? "); resourceIdList.add(podId); } if (clusterId != null) { - finalQuery.append(" AND host.cluster_id = ?"); + finalQuery.append("AND host.cluster_id = ? "); resourceIdList.add(clusterId); } finalQuery.append(COUNT_VMS_BASED_ON_VGPU_TYPES2); diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDao.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDao.java index 50026837915..5d2d919a685 100644 --- a/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDao.java +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDao.java @@ -32,6 +32,15 @@ public interface ResourceDetailsDao extends GenericDao */ public R findDetail(long resourceId, String name); + /** + * Find details by key,value pair + * @param key + * @param value + * @param display + * @return + */ + public List findDetails(String key, String value, Boolean display); + /** * Removes all details for the resource specified * @param resourceId diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java index 60d7f162f2f..b3e7ea27587 100644 --- a/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java @@ -34,6 +34,7 @@ public abstract class ResourceDetailsDaoBase extends G AllFieldsSearch = createSearchBuilder(); AllFieldsSearch.and("resourceId", AllFieldsSearch.entity().getResourceId(), SearchCriteria.Op.EQ); AllFieldsSearch.and("name", AllFieldsSearch.entity().getName(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("value", AllFieldsSearch.entity().getValue(), SearchCriteria.Op.EQ); // FIXME SnapshotDetailsVO doesn't have a display field if (_allAttributes.containsKey("display")) { AllFieldsSearch.and("display", AllFieldsSearch.entity().isDisplay(), SearchCriteria.Op.EQ); @@ -49,6 +50,25 @@ public abstract class ResourceDetailsDaoBase extends G return findOneBy(sc); } + public List findDetails(String name, String value, Boolean display) { + SearchCriteria sc = AllFieldsSearch.create(); + + if(display != null){ + sc.setParameters("display", display); + } + + if(name != null){ + sc.setParameters("name", name); + } + + if(value != null){ + sc.setParameters("value", value); + } + + List results = search(sc, null); + return results; + } + public Map listDetailsKeyPairs(long resourceId) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("resourceId", resourceId); diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java index fffd1e815c4..e77d5489cb6 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java @@ -81,7 +81,7 @@ public class DefaultHostListener implements HypervisorHostListener { } StoragePoolVO poolVO = this.primaryStoreDao.findById(poolId); - poolVO.setUsedBytes(mspAnswer.getPoolInfo().getAvailableBytes()); + poolVO.setUsedBytes(mspAnswer.getPoolInfo().getCapacityBytes() - mspAnswer.getPoolInfo().getAvailableBytes()); poolVO.setCapacityBytes(mspAnswer.getPoolInfo().getCapacityBytes()); primaryStoreDao.update(pool.getId(), poolVO); diff --git a/framework/db/src/com/cloud/utils/crypt/EncryptionSecretKeyChanger.java b/framework/db/src/com/cloud/utils/crypt/EncryptionSecretKeyChanger.java index 4cee081724c..ae103ff34f6 100755 --- a/framework/db/src/com/cloud/utils/crypt/EncryptionSecretKeyChanger.java +++ b/framework/db/src/com/cloud/utils/crypt/EncryptionSecretKeyChanger.java @@ -105,8 +105,8 @@ public class EncryptionSecretKeyChanger { PropertiesConfiguration backupDBProps = null; System.out.println("Parsing db.properties file"); - try { - dbProps.load(new FileInputStream(dbPropsFile)); + try(FileInputStream db_prop_fstream = new FileInputStream(dbPropsFile);) { + dbProps.load(db_prop_fstream); backupDBProps = new PropertiesConfiguration(dbPropsFile); } catch (FileNotFoundException e) { System.out.println("db.properties file not found while reading DB secret key" + e.getMessage()); @@ -142,11 +142,10 @@ public class EncryptionSecretKeyChanger { //db.properties updated successfully if (encryptionType.equals("file")) { //update key file with new MS key - try { - FileWriter fwriter = new FileWriter(keyFile); - BufferedWriter bwriter = new BufferedWriter(fwriter); + try (FileWriter fwriter = new FileWriter(keyFile); + BufferedWriter bwriter = new BufferedWriter(fwriter);) + { bwriter.write(newMSKey); - bwriter.close(); } catch (IOException e) { System.out.println("Failed to write new secret to file. Please update the file manually"); } @@ -180,11 +179,10 @@ public class EncryptionSecretKeyChanger { } if (encryptionType.equals("file")) { //revert secret key in file - try { - FileWriter fwriter = new FileWriter(keyFile); - BufferedWriter bwriter = new BufferedWriter(fwriter); + try (FileWriter fwriter = new FileWriter(keyFile); + BufferedWriter bwriter = new BufferedWriter(fwriter);) + { bwriter.write(oldMSKey); - bwriter.close(); } catch (IOException e) { System.out.println("Failed to revert to old secret to file. Please update the file manually"); } diff --git a/framework/db/src/com/cloud/utils/db/ScriptRunner.java b/framework/db/src/com/cloud/utils/db/ScriptRunner.java index 932b37baf45..45494b93915 100644 --- a/framework/db/src/com/cloud/utils/db/ScriptRunner.java +++ b/framework/db/src/com/cloud/utils/db/ScriptRunner.java @@ -131,52 +131,44 @@ public class ScriptRunner { } else if (!fullLineDelimiter && trimmedLine.endsWith(getDelimiter()) || fullLineDelimiter && trimmedLine.equals(getDelimiter())) { command.append(line.substring(0, line.lastIndexOf(getDelimiter()))); command.append(" "); - Statement statement = conn.createStatement(); - - println(command); - - boolean hasResults = false; - if (stopOnError) { - hasResults = statement.execute(command.toString()); - } else { - try { - statement.execute(command.toString()); - } catch (SQLException e) { - e.fillInStackTrace(); - printlnError("Error executing: " + command); - printlnError(e); - } - } - - if (autoCommit && !conn.getAutoCommit()) { - conn.commit(); - } - - ResultSet rs = statement.getResultSet(); - if (hasResults && rs != null) { - ResultSetMetaData md = rs.getMetaData(); - int cols = md.getColumnCount(); - for (int i = 0; i < cols; i++) { - String name = md.getColumnLabel(i); - print(name + "\t"); - } - println(""); - while (rs.next()) { - for (int i = 1; i <= cols; i++) { - String value = rs.getString(i); - print(value + "\t"); + try (Statement statement = conn.createStatement();) { + println(command); + boolean hasResults = false; + if (stopOnError) { + hasResults = statement.execute(command.toString()); + } else { + try { + statement.execute(command.toString()); + } catch (SQLException e) { + e.fillInStackTrace(); + printlnError("Error executing: " + command); + printlnError(e); } - println(""); + } + if (autoCommit && !conn.getAutoCommit()) { + conn.commit(); + } + try(ResultSet rs = statement.getResultSet();) { + if (hasResults && rs != null) { + ResultSetMetaData md = rs.getMetaData(); + int cols = md.getColumnCount(); + for (int i = 0; i < cols; i++) { + String name = md.getColumnLabel(i); + print(name + "\t"); + } + println(""); + while (rs.next()) { + for (int i = 1; i <= cols; i++) { + String value = rs.getString(i); + print(value + "\t"); + } + println(""); + } + } + command = null; + Thread.yield(); } } - - command = null; - try { - statement.close(); - } catch (Exception e) { - // Ignore to workaround a bug in Jakarta DBCP - } - Thread.yield(); } else { int idx = line.indexOf("--"); if (idx != -1) diff --git a/framework/db/src/com/cloud/utils/db/TransactionLegacy.java b/framework/db/src/com/cloud/utils/db/TransactionLegacy.java index aedf93982b7..3e14a043bb1 100755 --- a/framework/db/src/com/cloud/utils/db/TransactionLegacy.java +++ b/framework/db/src/com/cloud/utils/db/TransactionLegacy.java @@ -112,9 +112,6 @@ public class TransactionLegacy { TransactionLegacy txn = tls.get(); if (check) { assert txn != null : "No Transaction on stack. Did you mark the method with @DB?"; - - assert checkAnnotation(4, txn) : "Did you even read the guide to use Transaction...IOW...other people's code? Try method can't be private. What about @DB? hmmm... could that be it? " + - txn; } return txn; } diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/AsyncJobJoinMapDaoImpl.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/AsyncJobJoinMapDaoImpl.java index 7bc29db8cbe..fcdea76a250 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/AsyncJobJoinMapDaoImpl.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/AsyncJobJoinMapDaoImpl.java @@ -214,12 +214,14 @@ public class AsyncJobJoinMapDaoImpl extends GenericDaoBase standaloneList = new ArrayList(); TransactionLegacy txn = TransactionLegacy.currentTxn(); String sql = "SELECT job_id FROM async_job_join_map WHERE join_job_id = ? AND job_id NOT IN (SELECT content_id FROM sync_queue_item)"; - try { - PreparedStatement pstmt = txn.prepareStatement(sql); + try (PreparedStatement pstmt = txn.prepareStatement(sql);){ pstmt.setLong(1, joinedJobId); - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) { - standaloneList.add(rs.getLong(1)); + try(ResultSet rs = pstmt.executeQuery();) { + while (rs.next()) { + standaloneList.add(rs.getLong(1)); + } + }catch (SQLException e) { + throw new CloudRuntimeException("Unable to execute " + sql, e); } } catch (SQLException e) { throw new CloudRuntimeException("Unable to execute " + sql, e); @@ -231,23 +233,26 @@ public class AsyncJobJoinMapDaoImpl extends GenericDaoBase findJobsToWakeBetween(Date cutDate) { List standaloneList = new ArrayList(); TransactionLegacy txn = TransactionLegacy.currentTxn(); - try { - String sql = "SELECT job_id FROM async_job_join_map WHERE next_wakeup < ? AND expiration > ? AND job_id NOT IN (SELECT content_id FROM sync_queue_item)"; - PreparedStatement pstmt = txn.prepareStatement(sql); + String sql = "SELECT job_id FROM async_job_join_map WHERE next_wakeup < ? AND expiration > ? AND job_id NOT IN (SELECT content_id FROM sync_queue_item)"; + try (PreparedStatement pstmt = txn.prepareStatement(sql);){ pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate)); pstmt.setString(2, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate)); - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) { - standaloneList.add(rs.getLong(1)); + try(ResultSet rs = pstmt.executeQuery();) { + while (rs.next()) { + standaloneList.add(rs.getLong(1)); + } + }catch (SQLException e) { + throw new CloudRuntimeException("Unable to handle SQL exception", e); } - // update for next wake-up sql = "UPDATE async_job_join_map SET next_wakeup=DATE_ADD(next_wakeup, INTERVAL wakeup_interval SECOND) WHERE next_wakeup < ? AND expiration > ?"; - pstmt = txn.prepareStatement(sql); - pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate)); - pstmt.setString(2, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate)); - pstmt.executeUpdate(); - + try(PreparedStatement update_pstmt = txn.prepareStatement(sql);) { + update_pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate)); + update_pstmt.setString(2, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate)); + update_pstmt.executeUpdate(); + }catch (SQLException e) { + throw new CloudRuntimeException("Unable to handle SQL exception", e); + } return standaloneList; } catch (SQLException e) { throw new CloudRuntimeException("Unable to handle SQL exception", e); diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs index ef24c79bf80..4516191c014 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs @@ -302,7 +302,7 @@ namespace HypervResource path = Utils.NormalizePath(path); if (Directory.Exists(path)) { - string[] choices = choices = Directory.GetFiles(path, volInfo.uuid + ".vhd*"); + string[] choices = Directory.GetFiles(path, volInfo.uuid + ".vhd*"); if (choices.Length != 1) { String errMsg = "Tried to guess file extension, but cannot find file corresponding to " + @@ -609,6 +609,7 @@ namespace HypervResource public struct VolumeInfo { +#pragma warning disable 0414 public long id; public string type; public string storagePoolType; @@ -618,6 +619,7 @@ namespace HypervResource public string path; long size; string chainInfo; +#pragma warning restore 0414 public VolumeInfo(long id, string type, string poolType, String poolUuid, String name, String mountPoint, String path, long size, String chainInfo) { @@ -635,10 +637,12 @@ namespace HypervResource public class VmState { +#pragma warning disable 0414 [JsonProperty("state")] public String state; [JsonProperty("host")] String host; +#pragma warning restore 0414 public VmState() { } public VmState(String vmState, String host) { @@ -649,6 +653,7 @@ namespace HypervResource public struct StoragePoolInfo { +#pragma warning disable 0414 [JsonProperty("uuid")] public String uuid; [JsonProperty("host")] @@ -667,6 +672,7 @@ namespace HypervResource long availableBytes; [JsonProperty("details")] Dictionary details; +#pragma warning restore 0414 public StoragePoolInfo(String uuid, String host, String hostPath, String localPath, string poolType, long capacityBytes, diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs index 1a46b501f97..41a3a8aa71e 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs @@ -189,149 +189,154 @@ namespace HypervResource 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; - 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; - 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; + 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; @@ -448,1609 +453,344 @@ namespace HypervResource { // 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(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(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; - } - - /// - /// 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 - /// - /// - /// - /// - /// - 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())) - { + 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(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; + 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(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; + } + + /// + /// 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 + /// + /// + /// + /// + /// + 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())) - { + 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); - } - } - - /// - /// NOP - legacy command - - /// POST api/HypervResource/CreateStoragePoolCommand - /// - /// - /// - [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(); - 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.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(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 = 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); - } - 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())) - { - logger.Info(CloudStackTypes.MaintainCommand + Utils.CleanString(cmd.ToString())); - - object ansContent = new - { - result = true, - willMigrate = true, - details = "success - NOP for MaintainCommand", - _reconnect = false, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MaintainAnswer); - } - } - - // POST api/HypervResource/PingRoutingCommand - // TODO: should this be a NOP? - [HttpPost] - [ActionName(CloudStackTypes.PingRoutingCommand)] - public JContainer PingRoutingCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.PingRoutingCommand + Utils.CleanString(cmd.ToString())); - - object ansContent = new - { - result = true, - details = "success - NOP for PingRoutingCommand", - _reconnect = false, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); - } - } - - // POST api/HypervResource/PingCommand - // TODO: should this be a NOP? - [HttpPost] - [ActionName(CloudStackTypes.PingCommand)] - public JContainer PingCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.PingCommand + Utils.CleanString(cmd.ToString())); - - object ansContent = new - { - result = true, - details = "success - NOP for PingCommand", - _reconnect = false, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); - } - } - - // POST api/HypervResource/ModifyVmVnicVlanCommand - [HttpPost] - [ActionName(CloudStackTypes.ModifyVmNicConfigCommand)] - public JContainer ModifyVmNicConfigCommand([FromBody]dynamic cmd) - { - - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.ModifyVmNicConfigCommand + Utils.CleanString(cmd.ToString())); - bool result = false; - String vmName = cmd.vmName; - String vlan = cmd.vlan; - string macAddress = cmd.macAddress; - uint pos = cmd.index; - bool enable = cmd.enable; - string switchLableName = cmd.switchLableName; - if (macAddress != null) - { - wmiCallsV2.ModifyVmVLan(vmName, vlan, macAddress); - result = true; - } - else if (pos >= 1) - { - wmiCallsV2.ModifyVmVLan(vmName, vlan, pos, enable, switchLableName); - result = true; - } - - object ansContent = new - { - vmName = vmName, - result = result, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ModifyVmNicConfigAnswer); - } - - } - - // POST api/HypervResource/GetVmConfigCommand - [HttpPost] - [ActionName(CloudStackTypes.GetVmConfigCommand)] - public JContainer GetVmConfigCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.GetVmConfigCommand + Utils.CleanString(cmd.ToString())); - bool result = false; - String vmName = cmd.vmName; - ComputerSystem vm = wmiCallsV2.GetComputerSystem(vmName); - List nicDetails = new List(); - var nicSettingsViaVm = wmiCallsV2.GetEthernetPortSettings(vm); - NicDetails nic = null; - int index = 0; - int[] nicStates = new int[8]; - int[] nicVlan = new int[8]; - int vlanid = 1; - - var ethernetConnections = wmiCallsV2.GetEthernetConnections(vm); - foreach (EthernetPortAllocationSettingData item in ethernetConnections) - { - EthernetSwitchPortVlanSettingData vlanSettings = wmiCallsV2.GetVlanSettings(item); - if (vlanSettings == null) - { - vlanid = -1; - } - else - { - vlanid = vlanSettings.AccessVlanId; - } - nicStates[index] = (Int32)(item.EnabledState); - nicVlan[index] = vlanid; - index++; - } - - index = 0; - foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm) - { - nic = new NicDetails(item.Address, nicVlan[index], nicStates[index]); - index++; - nicDetails.Add(nic); - } - - - result = true; - - object ansContent = new - { - vmName = vmName, - nics = nicDetails, - result = result, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVmConfigAnswer); - } - } - - - - // POST api/HypervResource/GetVmStatsCommand - [HttpPost] - [ActionName(CloudStackTypes.GetVmStatsCommand)] - public JContainer GetVmStatsCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.GetVmStatsCommand + Utils.CleanString(cmd.ToString())); - bool result = false; - JArray vmNamesJson = cmd.vmNames; - string[] vmNames = vmNamesJson.ToObject(); - Dictionary vmProcessorInfo = new Dictionary(vmNames.Length); - - var vmsToInspect = new List(); - foreach (var vmName in vmNames) - { - var sys = wmiCallsV2.GetComputerSystem(vmName); - if (sys == null) - { - logger.InfoFormat("GetVmStatsCommand requested unknown VM {0}", vmNames); - continue; - } - var sysInfo = wmiCallsV2.GetVmSettings(sys); - vmsToInspect.Add(sysInfo.Path); - } - - wmiCallsV2.GetSummaryInfo(vmProcessorInfo, vmsToInspect); - - // TODO: Network usage comes from Performance Counter API; however it is only available in kb/s, and not in total terms. - // Curious about these? Use perfmon to inspect them, e.g. http://msdn.microsoft.com/en-us/library/xhcx5a20%28v=vs.100%29.aspx - // Recent post on these counter at http://blogs.technet.com/b/cedward/archive/2011/07/19/hyper-v-networking-optimizations-part-6-of-6-monitoring-hyper-v-network-consumption.aspx - result = true; - - object ansContent = new - { - vmStatsMap = vmProcessorInfo, - result = result, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVmStatsAnswer); - } - } - - // POST api/HypervResource/CopyCommand - [HttpPost] - [ActionName(CloudStackTypes.CopyCommand)] - public JContainer CopyCommand(dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - // Log command *after* we've removed security details from the command. - logger.Info(CloudStackTypes.CopyCommand + Utils.CleanString(cmd.ToString())); - - bool result = false; - string details = null; - object newData = null; - TemplateObjectTO destTemplateObjectTO = null; - VolumeObjectTO destVolumeObjectTO = null; - VolumeObjectTO srcVolumeObjectTO = null; - TemplateObjectTO srcTemplateObjectTO = null; - - try - { - dynamic timeout = cmd.wait; // TODO: Useful? - - srcTemplateObjectTO = TemplateObjectTO.ParseJson(cmd.srcTO); - destTemplateObjectTO = TemplateObjectTO.ParseJson(cmd.destTO); - srcVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.srcTO); - destVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.destTO); - - string destFile = null; - if (destTemplateObjectTO != null) - { - if (destTemplateObjectTO.primaryDataStore != null) - { - destFile = destTemplateObjectTO.FullFileName; - } - else if (destTemplateObjectTO.nfsDataStoreTO != null) - { - destFile = destTemplateObjectTO.FullFileName; - } - } - - // Template already downloaded? - if (destFile != null && File.Exists(destFile) && - !String.IsNullOrEmpty(destTemplateObjectTO.checksum)) - { - // TODO: checksum fails us, because it is of the compressed image. - // ASK: should we store the compressed or uncompressed version or is the checksum not calculated correctly? - logger.Debug(CloudStackTypes.CopyCommand + " calling VerifyChecksum to see if we already have the file at " + destFile); - result = VerifyChecksum(destFile, destTemplateObjectTO.checksum); - if (!result) - { - result = true; - logger.Debug(CloudStackTypes.CopyCommand + " existing file has different checksum " + destFile); - } - } - - // Do we have to create a new one? - if (!result) - { - // Create local copy of a template? - if (srcTemplateObjectTO != null && destTemplateObjectTO != null) - { - // S3 download to primary storage? - // NFS provider download to primary storage? - if ((srcTemplateObjectTO.s3DataStoreTO != null || srcTemplateObjectTO.nfsDataStoreTO != null) && destTemplateObjectTO.primaryDataStore != null) - { - if (File.Exists(destFile)) - { - logger.Info("Deleting existing file " + destFile); - File.Delete(destFile); - } - - if (srcTemplateObjectTO.s3DataStoreTO != null) - { - // Download from S3 to destination data storage - DownloadS3ObjectToFile(srcTemplateObjectTO.path, srcTemplateObjectTO.s3DataStoreTO, destFile); - } - else if (srcTemplateObjectTO.nfsDataStoreTO != null) - { - // Download from S3 to destination data storage - Utils.DownloadCifsFileToLocalFile(srcTemplateObjectTO.path, srcTemplateObjectTO.nfsDataStoreTO, destFile); - } - - // Uncompress, as required - if (srcTemplateObjectTO.path.EndsWith(".bz2")) - { - String uncompressedFile = destFile + ".tmp"; - String compressedFile = destFile; - using (var uncompressedOutStrm = new FileStream(uncompressedFile, FileMode.CreateNew, FileAccess.Write)) - { - using (var compressedInStrm = new FileStream(destFile, FileMode.Open, FileAccess.Read)) - { - using (var bz2UncompressorStrm = new Ionic.BZip2.BZip2InputStream(compressedInStrm, true) /* outer 'using' statement will close FileStream*/ ) - { - int count = 0; - int bufsize = 1024 * 1024; - byte[] buf = new byte[bufsize]; - - // EOF returns -1, see http://dotnetzip.codeplex.com/workitem/16069 - while (0 < (count = bz2UncompressorStrm.Read(buf, 0, bufsize))) - { - uncompressedOutStrm.Write(buf, 0, count); - } - } - } - } - File.Delete(compressedFile); - File.Move(uncompressedFile, compressedFile); - if (File.Exists(uncompressedFile)) - { - String errMsg = "Extra file left around called " + uncompressedFile + " when creating " + destFile; - logger.Error(errMsg); - throw new IOException(errMsg); - } - } - - // assert - if (!File.Exists(destFile)) - { - String errMsg = "Failed to create " + destFile + " , because the file is missing"; - logger.Error(errMsg); - throw new IOException(errMsg); - } - - newData = cmd.destTO; - result = true; - } - else - { - details = "Data store combination not supported"; - } - } - // Create volume from a template? - else if (srcTemplateObjectTO != null && destVolumeObjectTO != null) - { - // VolumeObjectTO guesses file extension based on existing files - // this can be wrong if the previous file had a different file type - var guessedDestFile = destVolumeObjectTO.FullFileName; - if (File.Exists(guessedDestFile)) - { - logger.Info("Deleting existing file " + guessedDestFile); - File.Delete(guessedDestFile); - } - - destVolumeObjectTO.format = srcTemplateObjectTO.format; - destFile = destVolumeObjectTO.FullFileName; - if (File.Exists(destFile)) - { - logger.Info("Deleting existing file " + destFile); - File.Delete(destFile); - } - - string srcFile = srcTemplateObjectTO.FullFileName; - if (!File.Exists(srcFile)) - { - details = "Local template file missing from " + srcFile; - } - else - { - // TODO: thin provision instead of copying the full file. - File.Copy(srcFile, destFile); - destVolumeObjectTO.path = destVolumeObjectTO.uuid; - JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, destVolumeObjectTO); - newData = ansObj; - result = true; - } - } - else if (srcVolumeObjectTO != null && destVolumeObjectTO != null) - { - var guessedDestFile = destVolumeObjectTO.FullFileName; - if (File.Exists(guessedDestFile)) - { - logger.Info("Deleting existing file " + guessedDestFile); - File.Delete(guessedDestFile); - } - - destVolumeObjectTO.format = srcVolumeObjectTO.format; - destFile = destVolumeObjectTO.FullFileName; - if (File.Exists(destFile)) - { - logger.Info("Deleting existing file " + destFile); - File.Delete(destFile); - } - - string srcFile = srcVolumeObjectTO.FullFileName; - if (!File.Exists(srcFile)) - { - details = "Local template file missing from " + srcFile; - } - else - { - // Create the directory before copying the files. CreateDirectory - // doesn't do anything if the directory is already present. - Directory.CreateDirectory(Path.GetDirectoryName(destFile)); - File.Copy(srcFile, destFile); - - if (srcVolumeObjectTO.nfsDataStore != null && srcVolumeObjectTO.primaryDataStore == null) - { - logger.Info("Copied volume from secondary data store to primary. Path: " + destVolumeObjectTO.path); - } - else if (srcVolumeObjectTO.primaryDataStore != null && srcVolumeObjectTO.nfsDataStore == null) - { - destVolumeObjectTO.path = destVolumeObjectTO.path + "/" + destVolumeObjectTO.uuid; - if (destVolumeObjectTO.format != null) - { - destVolumeObjectTO.path += "." + destVolumeObjectTO.format.ToLower(); - } - } - else - { - logger.Error("Destination volume path wasn't set. Unsupported source volume data store."); - } - - // Create volumeto object deserialize and send it - JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, destVolumeObjectTO); - newData = ansObj; - result = true; - } - } - else if (srcVolumeObjectTO != null && destTemplateObjectTO != null) - { - var guessedDestFile = destTemplateObjectTO.FullFileName; - if (File.Exists(guessedDestFile)) - { - logger.Info("Deleting existing file " + guessedDestFile); - File.Delete(guessedDestFile); - } - - destTemplateObjectTO.format = srcVolumeObjectTO.format; - destFile = destTemplateObjectTO.FullFileName; - if (File.Exists(destFile)) - { - logger.Info("Deleting existing file " + destFile); - File.Delete(destFile); - } - - string srcFile = srcVolumeObjectTO.FullFileName; - if (!File.Exists(srcFile)) - { - details = "Local template file missing from " + srcFile; - } - else - { - // Create the directory before copying the files. CreateDirectory - // doesn't do anything if the directory is already present. - Directory.CreateDirectory(Path.GetDirectoryName(destFile)); - File.Copy(srcFile, destFile); - - FileInfo destFileInfo = new FileInfo(destFile); - // Write the template.properties file - PostCreateTemplate(Path.GetDirectoryName(destFile), destTemplateObjectTO.id, destTemplateObjectTO.name, - destFileInfo.Length.ToString(), srcVolumeObjectTO.size.ToString(), destTemplateObjectTO.format); - - TemplateObjectTO destTemplateObject = new TemplateObjectTO(); - destTemplateObject.size = srcVolumeObjectTO.size.ToString(); - destTemplateObject.format = srcVolumeObjectTO.format; - destTemplateObject.path = destTemplateObjectTO.path + "/" + destTemplateObjectTO.uuid; - if (destTemplateObject.format != null) - { - destTemplateObject.path += "." + destTemplateObject.format.ToLower(); - } - destTemplateObject.nfsDataStoreTO = destTemplateObjectTO.nfsDataStoreTO; - destTemplateObject.checksum = destTemplateObjectTO.checksum; - newData = destTemplateObject; - JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.TemplateObjectTO, destTemplateObject); - newData = ansObj; - result = true; - } - } - else - { - details = "Data store combination not supported"; - } - } - } - catch (Exception ex) - { - // Test by providing wrong key - details = CloudStackTypes.CopyCommand + " failed on exception, " + ex.Message; - logger.Error(details, ex); - } - - object ansContent = new - { - result = result, - details = details, - newData = newData, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CopyCmdAnswer); - } - } - - private static void PostCreateTemplate(string path, string templateId, string templateUuid, string physicalSize, string virtualSize, string format) - { - string templatePropFile = Path.Combine(path, "template.properties"); - using (StreamWriter sw = new StreamWriter(File.Open(templatePropFile, FileMode.Create), Encoding.GetEncoding("iso-8859-1"))) - { - if (format != null) - { - format = format.ToLower(); - } - - sw.NewLine = "\n"; - sw.WriteLine("id=" + templateId); - sw.WriteLine("filename=" + templateUuid + "." + format); - sw.WriteLine(format + ".filename=" + templateUuid + "." + format); - sw.WriteLine("uniquename=" + templateUuid); - sw.WriteLine(format + "=true"); - sw.WriteLine("virtualsize=" + virtualSize); - sw.WriteLine(format + ".virtualsize=" + virtualSize); - sw.WriteLine("size=" + physicalSize); - sw.WriteLine(format + ".size=" + physicalSize); - sw.WriteLine("public=false"); - } - } - - private static bool VerifyChecksum(string destFile, string checksum) - { - string localChecksum = BitConverter.ToString(CalcFileChecksum(destFile)).Replace("-", "").ToLower(); - logger.Debug("Checksum of " + destFile + " is " + checksum); - if (checksum.Equals(localChecksum)) - { - return true; - } - return false; - } - - /// - /// Match implmentation of DownloadManagerImpl.computeCheckSum - /// - /// - /// - private static byte[] CalcFileChecksum(string destFile) - { - // TODO: Add unit test to verify that checksum algorithm has not changed. - using (MD5 md5 = MD5.Create()) - { - using (FileStream stream = File.OpenRead(destFile)) - { - return md5.ComputeHash(stream); - } - } - } - - private static void DownloadS3ObjectToFile(string srcObjectKey, S3TO srcS3TO, string destFile) - { - AmazonS3Config S3Config = new AmazonS3Config - { - ServiceURL = srcS3TO.endpoint, - CommunicationProtocol = Amazon.S3.Model.Protocol.HTTP - }; - - if (srcS3TO.httpsFlag) - { - S3Config.CommunicationProtocol = Protocol.HTTPS; - } - - try - { - using (AmazonS3 client = Amazon.AWSClientFactory.CreateAmazonS3Client(srcS3TO.accessKey, srcS3TO.secretKey, S3Config)) - { - GetObjectRequest getObjectRequest = new GetObjectRequest().WithBucketName(srcS3TO.bucketName).WithKey(srcObjectKey); - - using (S3Response getObjectResponse = client.GetObject(getObjectRequest)) - { - using (Stream s = getObjectResponse.ResponseStream) - { - using (FileStream fs = new FileStream(destFile, FileMode.Create, FileAccess.Write)) - { - byte[] data = new byte[524288]; - int bytesRead = 0; - do - { - bytesRead = s.Read(data, 0, data.Length); - fs.Write(data, 0, bytesRead); - } - while (bytesRead > 0); - fs.Flush(); - } - } - } - } - } - catch (Exception ex) - { - string errMsg = "Download from S3 url" + srcS3TO.endpoint + " said: " + ex.Message; - logger.Error(errMsg, ex); - throw new Exception(errMsg, ex); - } - } - - // POST api/HypervResource/GetStorageStatsCommand - [HttpPost] - [ActionName(CloudStackTypes.GetStorageStatsCommand)] - public JContainer GetStorageStatsCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.GetStorageStatsCommand + Utils.CleanString(cmd.ToString())); - bool result = false; - string details = null; - long capacity = 0; - long available = 0; - long used = 0; - try - { - StoragePoolType poolType; - string poolId = (string)cmd.id; - string hostPath = null; - if (!Enum.TryParse((string)cmd.pooltype, out poolType)) - { - details = "Request to get unsupported pool type: " + ((string)cmd.pooltype == null ? "NULL" : (string)cmd.pooltype) + "in cmd " + - JsonConvert.SerializeObject(cmd); - logger.Error(details); - } - else if (poolType == StoragePoolType.Filesystem) - { - hostPath = (string)cmd.localPath;; - GetCapacityForLocalPath(hostPath, out capacity, out available); - used = capacity - available; - result = true; - } - else if (poolType == StoragePoolType.NetworkFilesystem || poolType == StoragePoolType.SMB) - { - string sharePath = config.getPrimaryStorage((string)cmd.id); - if (sharePath != null) - { - hostPath = sharePath; - Utils.GetShareDetails(sharePath, out capacity, out available); - used = capacity - available; - result = true; - } - } - else - { - result = false; - } - - if (result) - { - logger.Debug(CloudStackTypes.GetStorageStatsCommand + " set used bytes for " + hostPath + " to " + used); - } - } - catch (Exception ex) - { - details = CloudStackTypes.GetStorageStatsCommand + " failed on exception" + ex.Message; - logger.Error(details, ex); - } - - object ansContent = new - { - result = result, - details = details, - capacity = capacity, - used = used, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetStorageStatsAnswer); - } - } - - // POST api/HypervResource/GetHostStatsCommand - [HttpPost] - [ActionName(CloudStackTypes.GetHostStatsCommand)] - public JContainer GetHostStatsCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.GetHostStatsCommand + Utils.CleanString(cmd.ToString())); - bool result = false; - string details = null; - object hostStats = null; - - var entityType = "host"; - ulong totalMemoryKBs; - ulong freeMemoryKBs; - double networkReadKBs; - double networkWriteKBs; - double cpuUtilization; - - try - { - long hostId = (long)cmd.hostId; - wmiCallsV2.GetMemoryResources(out totalMemoryKBs, out freeMemoryKBs); - wmiCallsV2.GetProcessorUsageInfo(out cpuUtilization); - - // TODO: can we assume that the host has only one adaptor? - string tmp; - var privateNic = GetNicInfoFromIpAddress(config.PrivateIpAddress, out tmp); - var nicStats = privateNic.GetIPv4Statistics(); //TODO: add IPV6 support, currentl - networkReadKBs = nicStats.BytesReceived; - networkWriteKBs = nicStats.BytesSent; - - // Generate GetHostStatsAnswer - hostStats = new - { - hostId = hostId, - entityType = entityType, - cpuUtilization = cpuUtilization, - networkReadKBs = networkReadKBs, - networkWriteKBs = networkWriteKBs, - totalMemoryKBs = (double)totalMemoryKBs, - freeMemoryKBs = (double)freeMemoryKBs - }; - result = true; - } - catch (Exception ex) - { - details = CloudStackTypes.GetHostStatsCommand + " failed on exception" + ex.Message; - logger.Error(details, ex); - } - - object ansContent = new - { - result = result, - hostStats = hostStats, - details = details, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetHostStatsAnswer); - } - } - - // POST api/HypervResource/PrepareForMigrationCommand - [HttpPost] - [ActionName(CloudStackTypes.PrepareForMigrationCommand)] - public JContainer PrepareForMigrationCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.PrepareForMigrationCommand + Utils.CleanString(cmd.ToString())); - - string details = null; - bool result = true; try { @@ -2147,7 +887,302 @@ namespace HypervResource } } - // POST api/HypervResource/MigrateWithStorageCommand + + // 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 = 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())) + { + logger.Info(CloudStackTypes.MaintainCommand + Utils.CleanString(cmd.ToString())); + + object ansContent = new + { + result = true, + willMigrate = true, + details = "success - NOP for MaintainCommand", + _reconnect = false, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MaintainAnswer); + } + } + + // POST api/HypervResource/PingRoutingCommand + // TODO: should this be a NOP? + [HttpPost] + [ActionName(CloudStackTypes.PingRoutingCommand)] + public JContainer PingRoutingCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.PingRoutingCommand + Utils.CleanString(cmd.ToString())); + + object ansContent = new + { + result = true, + details = "success - NOP for PingRoutingCommand", + _reconnect = false, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); + } + } + + // POST api/HypervResource/PingCommand + // TODO: should this be a NOP? + [HttpPost] + [ActionName(CloudStackTypes.PingCommand)] + public JContainer PingCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.PingCommand + Utils.CleanString(cmd.ToString())); + + object ansContent = new + { + result = true, + details = "success - NOP for PingCommand", + _reconnect = false, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); + } + } + + // POST api/HypervResource/ModifyVmVnicVlanCommand [HttpPost] [ActionName(CloudStackTypes.MigrateWithStorageCommand)] public JContainer MigrateWithStorageCommand([FromBody]dynamic cmd) @@ -2373,6 +1408,911 @@ namespace HypervResource } } + + + // POST api/HypervResource/GetVmStatsCommand + [HttpPost] + [ActionName(CloudStackTypes.GetVmStatsCommand)] + public JContainer GetVmStatsCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.GetVmStatsCommand + Utils.CleanString(cmd.ToString())); + bool result = false; + JArray vmNamesJson = cmd.vmNames; + string[] vmNames = vmNamesJson.ToObject(); + Dictionary vmProcessorInfo = new Dictionary(vmNames.Length); + + var vmsToInspect = new List(); + foreach (var vmName in vmNames) + { + var sys = wmiCallsV2.GetComputerSystem(vmName); + if (sys == null) + { + logger.InfoFormat("GetVmStatsCommand requested unknown VM {0}", vmNames); + continue; + } + var sysInfo = wmiCallsV2.GetVmSettings(sys); + vmsToInspect.Add(sysInfo.Path); + } + + wmiCallsV2.GetSummaryInfo(vmProcessorInfo, vmsToInspect); + + // TODO: Network usage comes from Performance Counter API; however it is only available in kb/s, and not in total terms. + // Curious about these? Use perfmon to inspect them, e.g. http://msdn.microsoft.com/en-us/library/xhcx5a20%28v=vs.100%29.aspx + // Recent post on these counter at http://blogs.technet.com/b/cedward/archive/2011/07/19/hyper-v-networking-optimizations-part-6-of-6-monitoring-hyper-v-network-consumption.aspx + result = true; + + object ansContent = new + { + vmStatsMap = vmProcessorInfo, + result = result, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVmStatsAnswer); + } + } + + // POST api/HypervResource/CopyCommand + [HttpPost] + [ActionName(CloudStackTypes.CopyCommand)] + public JContainer CopyCommand(dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + // Log command *after* we've removed security details from the command. + logger.Info(CloudStackTypes.CopyCommand + Utils.CleanString(cmd.ToString())); + + bool result = false; + string details = null; + object newData = null; + TemplateObjectTO destTemplateObjectTO = null; + VolumeObjectTO destVolumeObjectTO = null; + VolumeObjectTO srcVolumeObjectTO = null; + TemplateObjectTO srcTemplateObjectTO = null; + + try + { + srcTemplateObjectTO = TemplateObjectTO.ParseJson(cmd.srcTO); + destTemplateObjectTO = TemplateObjectTO.ParseJson(cmd.destTO); + srcVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.srcTO); + destVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.destTO); + + string destFile = null; + if (destTemplateObjectTO != null) + { + if (destTemplateObjectTO.primaryDataStore != null) + { + destFile = destTemplateObjectTO.FullFileName; + if (!destTemplateObjectTO.primaryDataStore.isLocal) + { + PrimaryDataStoreTO primary = destTemplateObjectTO.primaryDataStore; + Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password); + } + } + else if (destTemplateObjectTO.nfsDataStoreTO != null) + { + destFile = destTemplateObjectTO.FullFileName; + NFSTO store = destTemplateObjectTO.nfsDataStoreTO; + Utils.ConnectToRemote(store.UncPath, store.Domain, store.User, store.Password); + } + } + + // Template already downloaded? + if (destFile != null && File.Exists(destFile) && + !String.IsNullOrEmpty(destTemplateObjectTO.checksum)) + { + // TODO: checksum fails us, because it is of the compressed image. + // ASK: should we store the compressed or uncompressed version or is the checksum not calculated correctly? + logger.Debug(CloudStackTypes.CopyCommand + " calling VerifyChecksum to see if we already have the file at " + destFile); + result = VerifyChecksum(destFile, destTemplateObjectTO.checksum); + if (!result) + { + result = true; + logger.Debug(CloudStackTypes.CopyCommand + " existing file has different checksum " + destFile); + } + } + + // Do we have to create a new one? + if (!result) + { + // Create local copy of a template? + if (srcTemplateObjectTO != null && destTemplateObjectTO != null) + { + // S3 download to primary storage? + // NFS provider download to primary storage? + if ((srcTemplateObjectTO.s3DataStoreTO != null || srcTemplateObjectTO.nfsDataStoreTO != null) && destTemplateObjectTO.primaryDataStore != null) + { + if (File.Exists(destFile)) + { + logger.Info("Deleting existing file " + destFile); + File.Delete(destFile); + } + + if (srcTemplateObjectTO.s3DataStoreTO != null) + { + // Download from S3 to destination data storage + DownloadS3ObjectToFile(srcTemplateObjectTO.path, srcTemplateObjectTO.s3DataStoreTO, destFile); + } + else if (srcTemplateObjectTO.nfsDataStoreTO != null) + { + // Download from S3 to destination data storage + Utils.DownloadCifsFileToLocalFile(srcTemplateObjectTO.path, srcTemplateObjectTO.nfsDataStoreTO, destFile); + } + + // Uncompress, as required + if (srcTemplateObjectTO.path.EndsWith(".bz2")) + { + String uncompressedFile = destFile + ".tmp"; + String compressedFile = destFile; + using (var uncompressedOutStrm = new FileStream(uncompressedFile, FileMode.CreateNew, FileAccess.Write)) + { + using (var compressedInStrm = new FileStream(destFile, FileMode.Open, FileAccess.Read)) + { + using (var bz2UncompressorStrm = new Ionic.BZip2.BZip2InputStream(compressedInStrm, true) /* outer 'using' statement will close FileStream*/ ) + { + int count = 0; + int bufsize = 1024 * 1024; + byte[] buf = new byte[bufsize]; + + // EOF returns -1, see http://dotnetzip.codeplex.com/workitem/16069 + while (0 < (count = bz2UncompressorStrm.Read(buf, 0, bufsize))) + { + uncompressedOutStrm.Write(buf, 0, count); + } + } + } + } + File.Delete(compressedFile); + File.Move(uncompressedFile, compressedFile); + if (File.Exists(uncompressedFile)) + { + String errMsg = "Extra file left around called " + uncompressedFile + " when creating " + destFile; + logger.Error(errMsg); + throw new IOException(errMsg); + } + } + + // assert + if (!File.Exists(destFile)) + { + String errMsg = "Failed to create " + destFile + " , because the file is missing"; + logger.Error(errMsg); + throw new IOException(errMsg); + } + + newData = cmd.destTO; + result = true; + } + else + { + details = "Data store combination not supported"; + } + } + // Create volume from a template? + else if (srcTemplateObjectTO != null && destVolumeObjectTO != null) + { + // VolumeObjectTO guesses file extension based on existing files + // this can be wrong if the previous file had a different file type + var guessedDestFile = destVolumeObjectTO.FullFileName; + if (File.Exists(guessedDestFile)) + { + logger.Info("Deleting existing file " + guessedDestFile); + File.Delete(guessedDestFile); + } + + destVolumeObjectTO.format = srcTemplateObjectTO.format; + destFile = destVolumeObjectTO.FullFileName; + if (File.Exists(destFile)) + { + logger.Info("Deleting existing file " + destFile); + File.Delete(destFile); + } + + string srcFile = srcTemplateObjectTO.FullFileName; + if (!File.Exists(srcFile)) + { + details = "Local template file missing from " + srcFile; + } + else + { + // TODO: thin provision instead of copying the full file. + File.Copy(srcFile, destFile); + destVolumeObjectTO.path = destVolumeObjectTO.uuid; + JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, destVolumeObjectTO); + newData = ansObj; + result = true; + } + } + else if (srcVolumeObjectTO != null && destVolumeObjectTO != null) + { + var guessedDestFile = destVolumeObjectTO.FullFileName; + if (File.Exists(guessedDestFile)) + { + logger.Info("Deleting existing file " + guessedDestFile); + File.Delete(guessedDestFile); + } + + destVolumeObjectTO.format = srcVolumeObjectTO.format; + destFile = destVolumeObjectTO.FullFileName; + if (File.Exists(destFile)) + { + logger.Info("Deleting existing file " + destFile); + File.Delete(destFile); + } + + string srcFile = srcVolumeObjectTO.FullFileName; + if (!File.Exists(srcFile)) + { + details = "Local template file missing from " + srcFile; + } + else + { + // Create the directory before copying the files. CreateDirectory + // doesn't do anything if the directory is already present. + Directory.CreateDirectory(Path.GetDirectoryName(destFile)); + File.Copy(srcFile, destFile); + + if (srcVolumeObjectTO.nfsDataStore != null && srcVolumeObjectTO.primaryDataStore == null) + { + logger.Info("Copied volume from secondary data store to primary. Path: " + destVolumeObjectTO.path); + } + else if (srcVolumeObjectTO.primaryDataStore != null && srcVolumeObjectTO.nfsDataStore == null) + { + destVolumeObjectTO.path = destVolumeObjectTO.path + "/" + destVolumeObjectTO.uuid; + if (destVolumeObjectTO.format != null) + { + destVolumeObjectTO.path += "." + destVolumeObjectTO.format.ToLower(); + } + } + else + { + logger.Error("Destination volume path wasn't set. Unsupported source volume data store."); + } + + // Create volumeto object deserialize and send it + JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, destVolumeObjectTO); + newData = ansObj; + result = true; + } + } + else if (srcVolumeObjectTO != null && destTemplateObjectTO != null) + { + var guessedDestFile = destTemplateObjectTO.FullFileName; + if (File.Exists(guessedDestFile)) + { + logger.Info("Deleting existing file " + guessedDestFile); + File.Delete(guessedDestFile); + } + + destTemplateObjectTO.format = srcVolumeObjectTO.format; + destFile = destTemplateObjectTO.FullFileName; + if (File.Exists(destFile)) + { + logger.Info("Deleting existing file " + destFile); + File.Delete(destFile); + } + + string srcFile = srcVolumeObjectTO.FullFileName; + if (!File.Exists(srcFile)) + { + details = "Local template file missing from " + srcFile; + } + else + { + // Create the directory before copying the files. CreateDirectory + // doesn't do anything if the directory is already present. + Directory.CreateDirectory(Path.GetDirectoryName(destFile)); + File.Copy(srcFile, destFile); + + FileInfo destFileInfo = new FileInfo(destFile); + // Write the template.properties file + PostCreateTemplate(Path.GetDirectoryName(destFile), destTemplateObjectTO.id, destTemplateObjectTO.name, + destFileInfo.Length.ToString(), srcVolumeObjectTO.size.ToString(), destTemplateObjectTO.format); + + TemplateObjectTO destTemplateObject = new TemplateObjectTO(); + destTemplateObject.size = srcVolumeObjectTO.size.ToString(); + destTemplateObject.format = srcVolumeObjectTO.format; + destTemplateObject.path = destTemplateObjectTO.path + "/" + destTemplateObjectTO.uuid; + if (destTemplateObject.format != null) + { + destTemplateObject.path += "." + destTemplateObject.format.ToLower(); + } + destTemplateObject.nfsDataStoreTO = destTemplateObjectTO.nfsDataStoreTO; + destTemplateObject.checksum = destTemplateObjectTO.checksum; + newData = destTemplateObject; + JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.TemplateObjectTO, destTemplateObject); + newData = ansObj; + result = true; + } + } + else + { + details = "Data store combination not supported"; + } + } + } + catch (Exception ex) + { + // Test by providing wrong key + details = CloudStackTypes.CopyCommand + " failed on exception, " + ex.Message; + logger.Error(details, ex); + } + + object ansContent = new + { + result = result, + details = details, + newData = newData, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CopyCmdAnswer); + } + } + + private static void PostCreateTemplate(string path, string templateId, string templateUuid, string physicalSize, string virtualSize, string format) + { + string templatePropFile = Path.Combine(path, "template.properties"); + using (StreamWriter sw = new StreamWriter(File.Open(templatePropFile, FileMode.Create), Encoding.GetEncoding("iso-8859-1"))) + { + if (format != null) + { + format = format.ToLower(); + } + + sw.NewLine = "\n"; + sw.WriteLine("id=" + templateId); + sw.WriteLine("filename=" + templateUuid + "." + format); + sw.WriteLine(format + ".filename=" + templateUuid + "." + format); + sw.WriteLine("uniquename=" + templateUuid); + sw.WriteLine(format + "=true"); + sw.WriteLine("virtualsize=" + virtualSize); + sw.WriteLine(format + ".virtualsize=" + virtualSize); + sw.WriteLine("size=" + physicalSize); + sw.WriteLine(format + ".size=" + physicalSize); + sw.WriteLine("public=false"); + } + } + + private static bool VerifyChecksum(string destFile, string checksum) + { + string localChecksum = BitConverter.ToString(CalcFileChecksum(destFile)).Replace("-", "").ToLower(); + logger.Debug("Checksum of " + destFile + " is " + checksum); + if (checksum.Equals(localChecksum)) + { + return true; + } + return false; + } + + /// + /// Match implmentation of DownloadManagerImpl.computeCheckSum + /// + /// + /// + private static byte[] CalcFileChecksum(string destFile) + { + // TODO: Add unit test to verify that checksum algorithm has not changed. + using (MD5 md5 = MD5.Create()) + { + using (FileStream stream = File.OpenRead(destFile)) + { + return md5.ComputeHash(stream); + } + } + } + + private static void DownloadS3ObjectToFile(string srcObjectKey, S3TO srcS3TO, string destFile) + { + AmazonS3Config S3Config = new AmazonS3Config + { + ServiceURL = srcS3TO.endpoint, + CommunicationProtocol = Amazon.S3.Model.Protocol.HTTP + }; + + if (srcS3TO.httpsFlag) + { + S3Config.CommunicationProtocol = Protocol.HTTPS; + } + + try + { + using (AmazonS3 client = Amazon.AWSClientFactory.CreateAmazonS3Client(srcS3TO.accessKey, srcS3TO.secretKey, S3Config)) + { + GetObjectRequest getObjectRequest = new GetObjectRequest().WithBucketName(srcS3TO.bucketName).WithKey(srcObjectKey); + + using (S3Response getObjectResponse = client.GetObject(getObjectRequest)) + { + using (Stream s = getObjectResponse.ResponseStream) + { + using (FileStream fs = new FileStream(destFile, FileMode.Create, FileAccess.Write)) + { + byte[] data = new byte[524288]; + int bytesRead = 0; + do + { + bytesRead = s.Read(data, 0, data.Length); + fs.Write(data, 0, bytesRead); + } + while (bytesRead > 0); + fs.Flush(); + } + } + } + } + } + catch (Exception ex) + { + string errMsg = "Download from S3 url" + srcS3TO.endpoint + " said: " + ex.Message; + logger.Error(errMsg, ex); + throw new Exception(errMsg, ex); + } + } + + // POST api/HypervResource/GetStorageStatsCommand + [HttpPost] + [ActionName(CloudStackTypes.GetStorageStatsCommand)] + public JContainer GetStorageStatsCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.GetStorageStatsCommand + Utils.CleanString(cmd.ToString())); + bool result = false; + string details = null; + long capacity = 0; + long available = 0; + long used = 0; + try + { + StoragePoolType poolType; + string hostPath = null; + if (!Enum.TryParse((string)cmd.pooltype, out poolType)) + { + details = "Request to get unsupported pool type: " + ((string)cmd.pooltype == null ? "NULL" : (string)cmd.pooltype) + "in cmd " + + JsonConvert.SerializeObject(cmd); + logger.Error(details); + } + else if (poolType == StoragePoolType.Filesystem) + { + hostPath = (string)cmd.localPath;; + GetCapacityForLocalPath(hostPath, out capacity, out available); + used = capacity - available; + result = true; + } + else if (poolType == StoragePoolType.NetworkFilesystem || poolType == StoragePoolType.SMB) + { + string sharePath = config.getPrimaryStorage((string)cmd.id); + if (sharePath != null) + { + hostPath = sharePath; + Utils.GetShareDetails(sharePath, out capacity, out available); + used = capacity - available; + result = true; + } + } + else + { + result = false; + } + + if (result) + { + logger.Debug(CloudStackTypes.GetStorageStatsCommand + " set used bytes for " + hostPath + " to " + used); + } + } + catch (Exception ex) + { + details = CloudStackTypes.GetStorageStatsCommand + " failed on exception" + ex.Message; + logger.Error(details, ex); + } + + object ansContent = new + { + result = result, + details = details, + capacity = capacity, + used = used, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetStorageStatsAnswer); + } + } + + // POST api/HypervResource/GetHostStatsCommand + [HttpPost] + [ActionName(CloudStackTypes.GetHostStatsCommand)] + public JContainer GetHostStatsCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.GetHostStatsCommand + Utils.CleanString(cmd.ToString())); + bool result = false; + string details = null; + object hostStats = null; + + var entityType = "host"; + ulong totalMemoryKBs; + ulong freeMemoryKBs; + double networkReadKBs; + double networkWriteKBs; + double cpuUtilization; + + try + { + long hostId = (long)cmd.hostId; + wmiCallsV2.GetMemoryResources(out totalMemoryKBs, out freeMemoryKBs); + wmiCallsV2.GetProcessorUsageInfo(out cpuUtilization); + + // TODO: can we assume that the host has only one adaptor? + string tmp; + var privateNic = GetNicInfoFromIpAddress(config.PrivateIpAddress, out tmp); + var nicStats = privateNic.GetIPv4Statistics(); //TODO: add IPV6 support, currentl + networkReadKBs = nicStats.BytesReceived; + networkWriteKBs = nicStats.BytesSent; + + // Generate GetHostStatsAnswer + hostStats = new + { + hostId = hostId, + entityType = entityType, + cpuUtilization = cpuUtilization, + networkReadKBs = networkReadKBs, + networkWriteKBs = networkWriteKBs, + totalMemoryKBs = (double)totalMemoryKBs, + freeMemoryKBs = (double)freeMemoryKBs + }; + result = true; + } + catch (Exception ex) + { + details = CloudStackTypes.GetHostStatsCommand + " failed on exception" + ex.Message; + logger.Error(details, ex); + } + + object ansContent = new + { + result = result, + hostStats = hostStats, + details = details, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetHostStatsAnswer); + } + } + + // POST api/HypervResource/PrepareForMigrationCommand + [HttpPost] + [ActionName(CloudStackTypes.PrepareForMigrationCommand)] + public JContainer PrepareForMigrationCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.PrepareForMigrationCommand + Utils.CleanString(cmd.ToString())); + + string details = null; + bool result = true; + + try + { + details = "NOP - success"; + } + catch (Exception sysEx) + { + result = false; + details = CloudStackTypes.PrepareForMigrationCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PrepareForMigrationAnswer); + } + } + + // POST api/HypervResource/MigrateCommand + [HttpPost] + [ActionName(CloudStackTypes.MigrateCommand)] + public JContainer MigrateCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.MigrateCommand + Utils.CleanString(cmd.ToString())); + + string details = null; + bool result = false; + + try + { + string vm = (string)cmd.vmName; + string destination = (string)cmd.destIp; + wmiCallsV2.MigrateVm(vm, destination); + result = true; + } + catch (Exception sysEx) + { + details = CloudStackTypes.MigrateCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateAnswer); + } + } + + // POST api/HypervResource/MigrateVolumeCommand + [HttpPost] + [ActionName(CloudStackTypes.MigrateVolumeCommand)] + public JContainer MigrateVolumeCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.MigrateVolumeCommand + Utils.CleanString(cmd.ToString())); + + string details = null; + bool result = false; + + try + { + string vm = (string)cmd.attachedVmName; + string volume = (string)cmd.volumePath; + wmiCallsV2.MigrateVolume(vm, volume, GetStoragePoolPath(cmd.pool)); + result = true; + } + catch (Exception sysEx) + { + details = CloudStackTypes.MigrateVolumeCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + volumePath = (string)cmd.volumePath, + details = details, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateVolumeAnswer); + } + } + + // POST api/HypervResource/MigrateWithStorageCommand + [HttpPost] + [ActionName(CloudStackTypes.MigrateWithStorageCommand)] + public JContainer MigrateWithStorageCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.MigrateWithStorageCommand + Utils.CleanString(cmd.ToString())); + + string details = null; + bool result = false; + List volumeTos = new List(); + + try + { + string vm = (string)cmd.vm.name; + string destination = (string)cmd.tgtHost; + var volumeToPoolList = cmd.volumeToFilerAsList; + var volumeToPool = new Dictionary(); + foreach (var item in volumeToPoolList) + { + volumeTos.Add(item.t); + string poolPath = GetStoragePoolPath(item.u); + volumeToPool.Add((string)item.t.path, poolPath); + } + + wmiCallsV2.MigrateVmWithVolume(vm, destination, volumeToPool); + result = true; + } + catch (Exception sysEx) + { + details = CloudStackTypes.MigrateWithStorageCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + volumeTos = JArray.FromObject(volumeTos), + details = details, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateWithStorageAnswer); + } + } + + private string GetStoragePoolPath(dynamic pool) + { + string poolTypeStr = pool.type; + StoragePoolType poolType; + if (!Enum.TryParse(poolTypeStr, out poolType)) + { + throw new ArgumentException("Invalid pool type " + poolTypeStr); + } + else if (poolType == StoragePoolType.SMB) + { + NFSTO share = new NFSTO(); + String uriStr = "cifs://" + (string)pool.host + (string)pool.path; + share.uri = new Uri(uriStr); + return Utils.NormalizePath(share.UncPath); + } + else if (poolType == StoragePoolType.Filesystem) + { + return pool.path; + } + + throw new ArgumentException("Couldn't parse path for pool type " + poolTypeStr); + } + + // POST api/HypervResource/StartupCommand + [HttpPost] + [ActionName(CloudStackTypes.StartupCommand)] + public JContainer StartupCommand([FromBody]dynamic cmdArray) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(cmdArray.ToString()); + // Log agent configuration + logger.Info("Agent StartupRoutingCommand received " + cmdArray.ToString()); + dynamic strtRouteCmd = cmdArray[0][CloudStackTypes.StartupRoutingCommand]; + + // Insert networking details + string privateIpAddress = strtRouteCmd.privateIpAddress; + config.PrivateIpAddress = privateIpAddress; + string subnet; + System.Net.NetworkInformation.NetworkInterface privateNic = GetNicInfoFromIpAddress(privateIpAddress, out subnet); + strtRouteCmd.privateIpAddress = privateIpAddress; + strtRouteCmd.privateNetmask = subnet; + strtRouteCmd.privateMacAddress = privateNic.GetPhysicalAddress().ToString(); + string storageip = strtRouteCmd.storageIpAddress; + System.Net.NetworkInformation.NetworkInterface storageNic = GetNicInfoFromIpAddress(storageip, out subnet); + + strtRouteCmd.storageIpAddress = storageip; + strtRouteCmd.storageNetmask = subnet; + strtRouteCmd.storageMacAddress = storageNic.GetPhysicalAddress().ToString(); + strtRouteCmd.gatewayIpAddress = storageNic.GetPhysicalAddress().ToString(); + strtRouteCmd.hypervisorVersion = System.Environment.OSVersion.Version.Major.ToString() + "." + + System.Environment.OSVersion.Version.Minor.ToString(); + strtRouteCmd.caps = "hvm"; + + dynamic details = strtRouteCmd.hostDetails; + if (details != null) + { + string productVersion = System.Environment.OSVersion.Version.Major.ToString() + "." + + System.Environment.OSVersion.Version.Minor.ToString(); + details.Add("product_version", productVersion); + details.Add("rdp.server.port", 2179); + } + + // Detect CPUs, speed, memory + uint cores; + uint mhz; + uint sockets; + wmiCallsV2.GetProcessorResources(out sockets, out cores, out mhz); + strtRouteCmd.cpus = cores; + strtRouteCmd.speed = mhz; + strtRouteCmd.cpuSockets = sockets; + ulong memoryKBs; + ulong freeMemoryKBs; + wmiCallsV2.GetMemoryResources(out memoryKBs, out freeMemoryKBs); + strtRouteCmd.memory = memoryKBs * 1024; // Convert to bytes + + // Need 2 Gig for DOM0, see http://technet.microsoft.com/en-us/magazine/hh750394.aspx + strtRouteCmd.dom0MinMemory = config.ParentPartitionMinMemoryMb * 1024 * 1024; // Convert to bytes + + // Insert storage pool details. + // + // Read the localStoragePath for virtual disks from the Hyper-V configuration + // See http://blogs.msdn.com/b/virtual_pc_guy/archive/2010/05/06/managing-the-default-virtual-machine-location-with-hyper-v.aspx + // for discussion of Hyper-V file locations paths. + string localStoragePath = wmiCallsV2.GetDefaultVirtualDiskFolder(); + if (localStoragePath != null) + { + // GUID arbitrary. Host agents deals with storage pool in terms of localStoragePath. + // We use HOST guid. + string poolGuid = strtRouteCmd.guid; + + if (poolGuid == null) + { + poolGuid = Guid.NewGuid().ToString(); + logger.InfoFormat("Setting Startup StoragePool GUID to " + poolGuid); + } + else + { + logger.InfoFormat("Setting Startup StoragePool GUID same as HOST, i.e. " + poolGuid); + } + + long capacity; + long available; + GetCapacityForLocalPath(localStoragePath, out capacity, out available); + + logger.Debug(CloudStackTypes.StartupStorageCommand + " set available bytes to " + available); + + string ipAddr = strtRouteCmd.privateIpAddress; + var vmStates = wmiCallsV2.GetVmSync(config.PrivateIpAddress); + strtRouteCmd.vms = Utils.CreateCloudStackMapObject(vmStates); + + StoragePoolInfo pi = new StoragePoolInfo( + poolGuid.ToString(), + ipAddr, + localStoragePath, + localStoragePath, + StoragePoolType.Filesystem.ToString(), + capacity, + available); + + // Build StartupStorageCommand using an anonymous type + // See http://stackoverflow.com/a/6029228/939250 + object ansContent = new + { + poolInfo = pi, + guid = pi.uuid, + dataCenter = strtRouteCmd.dataCenter, + resourceType = StorageResourceType.STORAGE_POOL.ToString(), // TODO: check encoding + contextMap = contextMap + }; + JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.StartupStorageCommand, ansContent); + cmdArray.Add(ansObj); + } + + // Convert result to array for type correctness? + logger.Info(CloudStackTypes.StartupCommand + " result is " + cmdArray.ToString()); + return cmdArray; + } + } + + // POST api/HypervResource/GetVncPortCommand + [HttpPost] + [ActionName(CloudStackTypes.GetVncPortCommand)] + public JContainer GetVncPortCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.GetVncPortCommand + Utils.CleanString(cmd.ToString())); + + string details = null; + bool result = false; + string address = null; + int port = -9; + + try + { + string vmName = (string)cmd.name; + var sys = wmiCallsV2.GetComputerSystem(vmName); + address = "instanceId=" + sys.Name ; + result = true; + } + catch (Exception sysEx) + { + details = CloudStackTypes.GetVncPortAnswer + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details, + address = address, + port = port + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVncPortAnswer); + } + } + // POST api/HypervResource/HostVmStateReportCommand [HttpPost] [ActionName(CloudStackTypes.HostVmStateReportCommand)] diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs index 07dd78b84b3..b40cb8f783b 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs @@ -1,4 +1,4 @@ -// Licensed to the Apache Software Foundation (ASF) under one +// 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 @@ -88,7 +88,7 @@ namespace HypervResource { IntPtr token = IntPtr.Zero; - bool isSuccess = LogonUser(cifsShareDetails.User, cifsShareDetails.Domain, cifsShareDetails.Password, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref token); + 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 = ""; diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs index c1f6bcf7be5..104ee2d5e0d 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs @@ -267,186 +267,180 @@ namespace HypervResource else { errMsg = string.Format("Create VM failing, because there exists a VM with name {0}, state {1}", - vmName, - EnabledState.ToString(vmWmiObj.EnabledState)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - - // Create vm carcase - logger.DebugFormat("Going ahead with create VM {0}, {1} vcpus, {2}MB RAM", vmName, vcpus, memSize); - var newVm = CreateVM(vmName, memSize, vcpus); - - // Add a SCSI controller for attaching/detaching data volumes. - AddScsiController(newVm); - - foreach (var diskDrive in diskDrives) - { - string vhdFile = null; - string diskName = null; - string isoPath = null; - VolumeObjectTO volInfo = VolumeObjectTO.ParseJson(diskDrive.data); - TemplateObjectTO templateInfo = TemplateObjectTO.ParseJson(diskDrive.data); - - if (volInfo != null) - { - // assert - errMsg = vmName + ": volume missing primaryDataStore for disk " + diskDrive.ToString(); - if (volInfo.primaryDataStore == null) - { - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - diskName = volInfo.name; - - // assert - errMsg = vmName + ": can't deal with DataStore type for disk " + diskDrive.ToString(); - if (volInfo.primaryDataStore == null) - { - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - errMsg = vmName + ": Malformed PrimaryDataStore for disk " + diskDrive.ToString(); - if (String.IsNullOrEmpty(volInfo.primaryDataStore.Path)) - { - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - errMsg = vmName + ": Missing folder PrimaryDataStore for disk " + diskDrive.ToString() + ", missing path: " + volInfo.primaryDataStore.Path; - if (!Directory.Exists(volInfo.primaryDataStore.Path)) - { - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - - vhdFile = volInfo.FullFileName; - if (!System.IO.File.Exists(vhdFile)) - { - errMsg = vmName + ": non-existent volume, missing " + vhdFile + " for drive " + diskDrive.ToString(); - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - logger.Debug("Going to create " + vmName + " with attached voluem " + diskName + " at " + vhdFile); - } - else if (templateInfo != null && templateInfo.nfsDataStoreTO != null) - { - NFSTO share = templateInfo.nfsDataStoreTO; - // The share is mapped, now attach the iso - isoPath = Utils.NormalizePath(Path.Combine(share.UncPath, templateInfo.path)); - } - - string driveType = diskDrive.type; - string ideCtrllr = "0"; - string driveResourceType = null; - switch (driveType) { - case "ROOT": - ideCtrllr = "0"; - driveResourceType = HARDDISK_DRIVE; - break; - case "ISO": - ideCtrllr = "1"; - driveResourceType = ISO_DRIVE; - break; - case "DATADISK": - break; - default: - // TODO: double check exception type - errMsg = string.Format("Unknown disk type {0} for disk {1}, vm named {2}", - string.IsNullOrEmpty(driveType) ? "NULL" : driveType, - string.IsNullOrEmpty(diskName) ? "NULL" : diskName, vmName); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - logger.DebugFormat("Create disk type {1} (Named: {0}), on vm {2} {3}", diskName, driveResourceType, vmName, - string.IsNullOrEmpty(vhdFile) ? " no disk to insert" : ", inserting disk" + vhdFile); - if (driveType.Equals("DATADISK")) - { - AttachDisk(vmName, vhdFile, (string)diskDrive.diskSeq); - } - else - { - AddDiskDriveToIdeController(newVm, vhdFile, ideCtrllr, driveResourceType); - if (isoPath != null) - { - AttachIso(vmName, isoPath); - } - } - } - - String publicIpAddress = ""; - int nicCount = 0; - int enableState = 2; - - // Add the Nics to the VM in the deviceId order. - foreach (var nc in nicInfo) - { - foreach (var nic in nicInfo) - { - - int nicid = nic.deviceId; + vmName, + EnabledState.ToString(vmWmiObj.EnabledState)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + // Create vm carcase + logger.DebugFormat("Going ahead with create VM {0}, {1} vcpus, {2}MB RAM", vmName, vcpus, memSize); + var newVm = CreateVM(vmName, memSize, vcpus); + + // Add a SCSI controller for attaching/detaching data volumes. + AddScsiController(newVm); + + foreach (var diskDrive in diskDrives) + { + string vhdFile = null; + string diskName = null; + string isoPath = null; + VolumeObjectTO volInfo = VolumeObjectTO.ParseJson(diskDrive.data); + TemplateObjectTO templateInfo = TemplateObjectTO.ParseJson(diskDrive.data); + + if (volInfo != null) + { + // assert + errMsg = vmName + ": volume missing primaryDataStore for disk " + diskDrive.ToString(); + if (volInfo.primaryDataStore == null) + { + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + diskName = volInfo.name; + + // assert + errMsg = vmName + ": can't deal with DataStore type for disk " + diskDrive.ToString(); + if (volInfo.primaryDataStore == null) + { + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + errMsg = vmName + ": Malformed PrimaryDataStore for disk " + diskDrive.ToString(); + if (String.IsNullOrEmpty(volInfo.primaryDataStore.Path)) + { + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + errMsg = vmName + ": Missing folder PrimaryDataStore for disk " + diskDrive.ToString() + ", missing path: " + volInfo.primaryDataStore.Path; + if (!Directory.Exists(volInfo.primaryDataStore.Path)) + { + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + + vhdFile = volInfo.FullFileName; + if (!System.IO.File.Exists(vhdFile)) + { + errMsg = vmName + ": non-existent volume, missing " + vhdFile + " for drive " + diskDrive.ToString(); + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + logger.Debug("Going to create " + vmName + " with attached voluem " + diskName + " at " + vhdFile); + } + else if (templateInfo != null && templateInfo.nfsDataStoreTO != null) + { + NFSTO share = templateInfo.nfsDataStoreTO; + Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password); + // The share is mapped, now attach the iso + isoPath = Utils.NormalizePath(Path.Combine(share.UncPath, templateInfo.path)); + } + + string driveType = diskDrive.type; + string ideCtrllr = "0"; + string driveResourceType = null; + switch (driveType) { + case "ROOT": + ideCtrllr = "0"; + driveResourceType = HARDDISK_DRIVE; + break; + case "ISO": + ideCtrllr = "1"; + driveResourceType = ISO_DRIVE; + break; + case "DATADISK": + break; + default: + // TODO: double check exception type + errMsg = string.Format("Unknown disk type {0} for disk {1}, vm named {2}", + string.IsNullOrEmpty(driveType) ? "NULL" : driveType, + string.IsNullOrEmpty(diskName) ? "NULL" : diskName, vmName); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + logger.DebugFormat("Create disk type {1} (Named: {0}), on vm {2} {3}", diskName, driveResourceType, vmName, + string.IsNullOrEmpty(vhdFile) ? " no disk to insert" : ", inserting disk" + vhdFile); + if (driveType.Equals("DATADISK")) + { + AttachDisk(vmName, vhdFile, (string)diskDrive.diskSeq); + } + else + { + AddDiskDriveToIdeController(newVm, vhdFile, ideCtrllr, driveResourceType); + if (isoPath != null) + { + AttachIso(vmName, isoPath); + } + } + } + + int nicCount = 0; + // Add the Nics to the VM in the deviceId order. + foreach (var nc in nicInfo) + { + foreach (var nic in nicInfo) + { + + int nicid = nic.deviceId; Int32 networkRateMbps = nic.networkRateMbps; - string mac = nic.mac; - string vlan = null; - string isolationUri = nic.isolationUri; - string broadcastUri = nic.broadcastUri; + string mac = nic.mac; + string vlan = null; + string isolationUri = nic.isolationUri; + string broadcastUri = nic.broadcastUri; string nicIp = nic.ip; string nicNetmask = nic.netmask; - if ( (broadcastUri != null ) || (isolationUri != null && isolationUri.StartsWith("vlan://"))) - { - if (broadcastUri != null && broadcastUri.StartsWith("storage")) - { - vlan = broadcastUri.Substring("storage://".Length); - } - else - { - vlan = isolationUri.Substring("vlan://".Length); - } - int tmp; + if ( (broadcastUri != null ) || (isolationUri != null && isolationUri.StartsWith("vlan://"))) + { + if (broadcastUri != null && broadcastUri.StartsWith("storage")) + { + vlan = broadcastUri.Substring("storage://".Length); + } + else + { + vlan = isolationUri.Substring("vlan://".Length); + } + int tmp; if (vlan.Equals("untagged", StringComparison.CurrentCultureIgnoreCase) ) { // recevied vlan is untagged, don't parse for the vlan in the isolation uri vlan = null; } - else if (!int.TryParse(vlan, out tmp)) - { - // TODO: double check exception type - errMsg = string.Format("Invalid VLAN value {0} for on vm {1} for nic uuid {2}", isolationUri, vmName, nic.uuid); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } + else if (!int.TryParse(vlan, out tmp)) + { + // TODO: double check exception type + errMsg = string.Format("Invalid VLAN value {0} for on vm {1} for nic uuid {2}", isolationUri, vmName, nic.uuid); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + if(nicIp.Equals("0.0.0.0") && nicNetmask.Equals("255.255.255.255") ) { + // this is the extra nic added to VR. + vlan = defaultvlan; } - - if (nicid == nicCount) - { - if (nicIp.Equals("0.0.0.0") && nicNetmask.Equals("255.255.255.255")) - { - // this is the extra nic added to VR. - vlan = null; - enableState = 3; - } - - // Create network adapter - var newAdapter = CreateNICforVm(newVm, mac); - String switchName =""; - if (nic.name != null) - { - switchName = nic.name; - } - EthernetPortAllocationSettingData portSettings = null; - // connection to vswitch - portSettings = AttachNicToPort(newVm, newAdapter, switchName, enableState); - //reset the flag for other nics - enableState = 2; - // set vlan - if (vlan != null) - { - SetPortVlan(vlan, portSettings); - } - + + if (nicid == nicCount) + { + // Create network adapter + var newAdapter = CreateNICforVm(newVm, mac); + String switchName =""; + if (nic.name != null) + { + switchName = nic.name; + } + + // connection to vswitch + var portSettings = AttachNicToPort(newVm, newAdapter, switchName); + + // set vlan + if (vlan != null) + { + SetPortVlan(vlan, portSettings); + } + if (networkRateMbps > 0) { SetBandWidthLimit((ulong)networkRateMbps, portSettings); @@ -486,6 +480,433 @@ namespace HypervResource SetState(newVm, RequiredState.Enabled); // Mark the VM as created by cloudstack tag TagVm(newVm); + + // we need to reboot to get the hv kvp daemon get started vr gets configured. + if (vmName.StartsWith("r-") || vmName.StartsWith("s-") || vmName.StartsWith("v-")) + { + System.Threading.Thread.Sleep(90000); + } + logger.InfoFormat("Started VM {0}", vmName); + return newVm; + } + + public static Boolean pingResource(String ip) + { + PingOptions pingOptions = null; + PingReply pingReply = null; + IPAddress ipAddress = null; + Ping pingSender = new Ping(); + int numberOfPings = 6; + int pingTimeout = 1000; + int byteSize = 32; + byte[] buffer = new byte[byteSize]; + ipAddress = IPAddress.Parse(ip); + pingOptions = new PingOptions(); + for (int i = 0; i < numberOfPings; i++) + { + pingReply = pingSender.Send(ipAddress, pingTimeout, buffer, pingOptions); + if (pingReply.Status == IPStatus.Success) + { + System.Threading.Thread.Sleep(30000); + return true; + } + else + { + // wait for the second boot and then return with suces + System.Threading.Thread.Sleep(30000); + } + } + return false; + } + + private EthernetPortAllocationSettingData AttachNicToPort(ComputerSystem newVm, SyntheticEthernetPortSettingData newAdapter, String vSwitchName) + { + // Get the virtual switch + VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch(vSwitchName); + //check the the recevied vSwitch is the same as vSwitchName. + if (!vSwitchName.Equals("") && !vSwitch.ElementName.Equals(vSwitchName)) + { + var errMsg = string.Format("Internal error, coudl not find Virtual Switch with the name : " +vSwitchName); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + // Create port for adapter + var defaultEthernetPortSettings = EthernetPortAllocationSettingData.GetInstances(vSwitch.Scope, "InstanceID LIKE \"%Default\""); + + // assert + if (defaultEthernetPortSettings.Count != 1) + { + var errMsg = string.Format("Internal error, coudl not find default EthernetPortAllocationSettingData instance"); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + var defaultEthernetPortSettingsObj = defaultEthernetPortSettings.OfType().First(); + var newEthernetPortSettings = new EthernetPortAllocationSettingData((ManagementBaseObject)defaultEthernetPortSettingsObj.LateBoundObject.Clone()); + newEthernetPortSettings.LateBoundObject["Parent"] = newAdapter.Path.Path; + newEthernetPortSettings.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path }; + + // Insert NIC into vm + string[] newResources = new string[] { newEthernetPortSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; + ManagementPath[] newResourcePaths = AddVirtualResource(newResources, newVm); + + // assert + if (newResourcePaths.Length != 1) + { + var errMsg = string.Format( + "Failed to properly insert a single NIC on VM {0} (GUID {1}): number of resource created {2}", + newVm.ElementName, + newVm.Name, + newResourcePaths.Length); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + return new EthernetPortAllocationSettingData(newResourcePaths[0]); + } + + /// this method is to add a dvd drive and attach the systemvm iso. + /// + public void patchSystemVmIso(String vmName, String systemVmIso) + { + ComputerSystem vmObject = GetComputerSystem(vmName); + AddDiskDriveToIdeController(vmObject, "", "1", ISO_DRIVE); + AttachIso(vmName, systemVmIso); + } + + public void AttachDisk(string vmName, string diskPath, string addressOnController) + { + logger.DebugFormat("Got request to attach disk {0} to vm {1}", diskPath, vmName); + + ComputerSystem vm = GetComputerSystem(vmName); + if (vm == null) + { + logger.DebugFormat("VM {0} not found", vmName); + return; + } + else + { + ManagementPath newDrivePath = GetDiskDriveOnScsiController(vm, addressOnController); + if (newDrivePath == null) + { + newDrivePath = AttachDiskDriveToScsiController(vm, addressOnController); + } + InsertDiskImage(vm, diskPath, HARDDISK_DISK, newDrivePath); + } + } + + /// + /// + /// + /// IDE_HARDDISK_DRIVE or IDE_ISO_DRIVE + public ManagementPath AddDiskDriveToIdeController(ComputerSystem vm, string vhdfile, string cntrllerAddr, string driveResourceType) + { + logger.DebugFormat("Creating DISK for VM {0} (GUID {1}) by attaching {2}", + vm.ElementName, + vm.Name, + vhdfile); + + // Determine disk type for drive and assert drive type valid + string diskResourceSubType = null; + switch(driveResourceType) { + case HARDDISK_DRIVE: + diskResourceSubType = HARDDISK_DISK; + break; + case ISO_DRIVE: + diskResourceSubType = ISO_DISK; + break; + default: + var errMsg = string.Format( + "Unrecognised disk drive type {0} for VM {1} (GUID {2})", + string.IsNullOrEmpty(driveResourceType) ? "NULL": driveResourceType, + vm.ElementName, + vm.Name); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + ManagementPath newDrivePath = AttachNewDrive(vm, cntrllerAddr, driveResourceType); + + // If there's not disk to insert, we are done. + if (String.IsNullOrEmpty(vhdfile)) + { + logger.DebugFormat("No disk to be added to drive, disk drive {0} is complete", newDrivePath.Path); + } + else + { + InsertDiskImage(vm, vhdfile, diskResourceSubType, newDrivePath); + } + return newDrivePath; + } + + + public void DetachDisk(string displayName, string diskFileName) + { + logger.DebugFormat("Got request to detach virtual disk {0} from vm {1}", diskFileName, displayName); + + ComputerSystem vm = GetComputerSystem(displayName); + if (vm == null) + { + logger.DebugFormat("VM {0} not found", displayName); + return; + } + else + { + RemoveStorageImage(vm, diskFileName); + } + } + + /// + /// Removes a disk image from a drive, but does not remove the drive itself. + /// + /// + /// + private void RemoveStorageImage(ComputerSystem vm, string diskFileName) + { + // Obtain StorageAllocationSettingData for disk + StorageAllocationSettingData.StorageAllocationSettingDataCollection storageSettingsObjs = StorageAllocationSettingData.GetInstances(); + + StorageAllocationSettingData imageToRemove = null; + foreach (StorageAllocationSettingData item in storageSettingsObjs) + { + if (item.HostResource == null || item.HostResource.Length != 1) + { + continue; + } + + string hostResource = item.HostResource[0]; + if (Path.Equals(hostResource, diskFileName)) + { + imageToRemove = item; + break; + } + } + + // assert + if (imageToRemove == null) + { + var errMsg = string.Format( + "Failed to remove disk image {0} from VM {1} (GUID {2}): the disk image is not attached.", + diskFileName, + vm.ElementName, + vm.Name); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + RemoveStorageResource(imageToRemove.Path, vm); + + logger.InfoFormat("Removed disk image {0} from VM {1} (GUID {2}): the disk image is not attached.", + diskFileName, + vm.ElementName, + vm.Name); + } + + private ManagementPath AttachNewDrive(ComputerSystem vm, string cntrllerAddr, string driveType) + { + // 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 ctrller = GetIDEControllerSettings(vmSettings, cntrllerAddr); + + // A description of the drive is created by modifying a clone of the default ResourceAllocationSettingData for that drive type + string defaultDriveQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", driveType); + var newDiskDriveSettings = CloneResourceAllocationSetting(defaultDriveQuery); + + // Set IDE controller and address on the controller for the new drive + newDiskDriveSettings.LateBoundObject["Parent"] = ctrller.Path.ToString(); + newDiskDriveSettings.LateBoundObject["AddressOnParent"] = "0"; + newDiskDriveSettings.CommitObject(); + + // Add this new disk drive to the VM + logger.DebugFormat("Creating disk drive type {0}, parent IDE controller is {1} and address on controller is {2}", + newDiskDriveSettings.ResourceSubType, + newDiskDriveSettings.Parent, + newDiskDriveSettings.AddressOnParent); + string[] newDriveResource = new string[] { newDiskDriveSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; + ManagementPath[] newDrivePaths = AddVirtualResource(newDriveResource, vm); + + // assert + if (newDrivePaths.Length != 1) + { + var errMsg = string.Format( + "Failed to add disk drive type {3} to VM {0} (GUID {1}): number of resource created {2}", + vm.ElementName, + vm.Name, + newDrivePaths.Length, + driveType); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + logger.DebugFormat("New disk drive type {0} WMI path is {1}s", + newDiskDriveSettings.ResourceSubType, + newDrivePaths[0].Path); + return newDrivePaths[0]; + } + + private ManagementPath AddScsiController(ComputerSystem vm) + { + // A description of the controller is created by modifying a clone of the default ResourceAllocationSettingData for scsi controller + string scsiQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", SCSI_CONTROLLER); + var scsiSettings = CloneResourceAllocationSetting(scsiQuery); + + scsiSettings.LateBoundObject["ElementName"] = "SCSI Controller"; + scsiSettings.CommitObject(); + + // Insert SCSI controller into vm + string[] newResources = new string[] { scsiSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; + ManagementPath[] newResourcePaths = AddVirtualResource(newResources, vm); + + // assert + if (newResourcePaths.Length != 1) + { + var errMsg = string.Format( + "Failed to add scsi controller to VM {0} (GUID {1}): number of resource created {2}", + vm.ElementName, + vm.Name, + newResourcePaths.Length); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + logger.DebugFormat("New controller type {0} WMI path is {1}s", + scsiSettings.ResourceSubType, + newResourcePaths[0].Path); + return newResourcePaths[0]; + } + + private ManagementPath GetDiskDriveOnScsiController(ComputerSystem vm, string addrOnController) + { + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + var wmiObjCollection = GetResourceAllocationSettings(vmSettings); + foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection) + { + if (wmiObj.ResourceSubType == HARDDISK_DRIVE) + { + ResourceAllocationSettingData parent = new ResourceAllocationSettingData(new ManagementObject(wmiObj.Parent)); + if (parent.ResourceSubType == SCSI_CONTROLLER && wmiObj.AddressOnParent == addrOnController) + { + return wmiObj.Path; + } + } + } + return null; + } + + private ManagementPath AttachDiskDriveToScsiController(ComputerSystem vm, string addrOnController) + { + // Disk drives are attached to a 'Parent' Scsi controller. + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + var ctrller = GetScsiControllerSettings(vmSettings); + + // A description of the drive is created by modifying a clone of the default ResourceAllocationSettingData for that drive type + string defaultDriveQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", HARDDISK_DRIVE); + var newDiskDriveSettings = CloneResourceAllocationSetting(defaultDriveQuery); + + // Set IDE controller and address on the controller for the new drive + newDiskDriveSettings.LateBoundObject["Parent"] = ctrller.Path.ToString(); + newDiskDriveSettings.LateBoundObject["AddressOnParent"] = addrOnController; + newDiskDriveSettings.CommitObject(); + + // Add this new disk drive to the VM + logger.DebugFormat("Creating disk drive type {0}, parent IDE controller is {1} and address on controller is {2}", + newDiskDriveSettings.ResourceSubType, + newDiskDriveSettings.Parent, + newDiskDriveSettings.AddressOnParent); + string[] newDriveResource = new string[] { newDiskDriveSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; + ManagementPath[] newDrivePaths = AddVirtualResource(newDriveResource, vm); + + // assert + if (newDrivePaths.Length != 1) + { + var errMsg = string.Format( + "Failed to add disk drive type {3} to VM {0} (GUID {1}): number of resource created {2}", + vm.ElementName, + vm.Name, + newDrivePaths.Length, + HARDDISK_DRIVE); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + logger.DebugFormat("New disk drive type {0} WMI path is {1}s", + newDiskDriveSettings.ResourceSubType, + newDrivePaths[0].Path); + return newDrivePaths[0]; + } + + + private void InsertDiskImage(ComputerSystem vm, string diskImagePath, string diskResourceSubType, ManagementPath drivePath) + { + // A description of the disk is created by modifying a clone of the default ResourceAllocationSettingData for that disk type + string defaultDiskQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", diskResourceSubType); + var newDiskSettings = CloneStorageAllocationSetting(defaultDiskQuery); + + // Set file containing the disk image + newDiskSettings.LateBoundObject["Parent"] = drivePath.Path; + + // V2 API uses HostResource to specify image, see http://msdn.microsoft.com/en-us/library/hh859775(v=vs.85).aspx + newDiskSettings.LateBoundObject["HostResource"] = new string[] { diskImagePath }; + newDiskSettings.CommitObject(); + + // Add the new Msvm_StorageAllocationSettingData object as a virtual hard disk to the vm. + string[] newDiskResource = new string[] { newDiskSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; + ManagementPath[] newDiskPaths = AddStorageResource(newDiskResource, vm); + // assert + if (newDiskPaths.Length != 1) + { + var errMsg = string.Format( + "Failed to add disk image type {3} to VM {0} (GUID {1}): number of resource created {2}", + vm.ElementName, + vm.Name, + newDiskPaths.Length, + diskResourceSubType); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + logger.InfoFormat("Created disk {2} for VM {0} (GUID {1}), image {3} ", + vm.ElementName, + vm.Name, + newDiskPaths[0].Path, + diskImagePath); + } + + /// + /// Create Msvm_StorageAllocationSettingData corresponding to the ISO image, and + /// associate this with the VM's DVD drive. + /// + private void AttachIso(ComputerSystem vm, string isoPath) + { + // 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, ISO_DISK, driveWmiObj.Path); + } + + private static ResourceAllocationSettingData CloneResourceAllocationSetting(string wmiQuery) + { + var defaultDiskDriveSettingsObjs = ResourceAllocationSettingData.GetInstances(wmiQuery); + + // assert + if (defaultDiskDriveSettingsObjs.Count != 1) + { + var errMsg = string.Format("Failed to find Msvm_ResourceAllocationSettingData for the query {0}", wmiQuery); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + ResourceAllocationSettingData defaultDiskDriveSettings = defaultDiskDriveSettingsObjs.OfType().First(); + return new ResourceAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone()); + } // we need to reboot to get the hv kvp daemon get started vr gets configured. if (vmName.StartsWith("r-") || vmName.StartsWith("s-") || vmName.StartsWith("v-")) @@ -2024,13 +2445,9 @@ namespace HypervResource public VirtualEthernetSwitchManagementService GetVirtualSwitchManagementService() { - // VirtualSwitchManagementService is a singleton, most anonymous way of lookup is by asking for the set - // of local instances, which should be size 1. - var virtSwtichSvcCollection = VirtualEthernetSwitchManagementService.GetInstances(); - foreach (VirtualEthernetSwitchManagementService item in virtSwtichSvcCollection) - { - return item; - } + ComputerSystem vm = GetComputerSystem(vmName); + // Obtain controller for Hyper-V virtualisation subsystem + VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); var errMsg = string.Format("No Hyper-V subsystem on server"); var ex = new WmiException(errMsg); @@ -2221,164 +2638,789 @@ namespace HypervResource } } - public void GetProcessorResources(out uint sockets, out uint cores, out uint mhz) - { - // Processor processors - cores = 0; - mhz = 0; - sockets = 0; - Processor.ProcessorCollection procCol = Processor.GetInstances(); - foreach (Processor procInfo in procCol) - { - cores += procInfo.NumberOfCores; - mhz = procInfo.MaxClockSpeed; - sockets++; - } - } - - public void GetProcessorUsageInfo(out double cpuUtilization) - { - PerfFormattedData_Counters_ProcessorInformation.PerfFormattedData_Counters_ProcessorInformationCollection coll = - PerfFormattedData_Counters_ProcessorInformation.GetInstances("Name=\"_Total\""); - cpuUtilization = 100; - // Use the first one - foreach (PerfFormattedData_Counters_ProcessorInformation procInfo in coll) - { - // Idle during a given internal - // See http://library.wmifun.net/cimv2/win32_perfformatteddata_counters_processorinformation.html - cpuUtilization = 100.0 - (double)procInfo.PercentIdleTime; - } - } + /// + /// Migrates a vm to the given destination host + /// + /// + /// + public void MigrateVm(string vmName, string destination) + { + ComputerSystem vm = GetComputerSystem(vmName); + VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance(); + VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService(); + + IPAddress addr = IPAddress.Parse(destination); + IPHostEntry entry = Dns.GetHostEntry(addr); + string[] destinationHost = new string[] { destination }; + + migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.VirtualSystem; + migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP; + migrationSettingData.LateBoundObject["DestinationIPAddressList"] = destinationHost; + string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + + ManagementPath jobPath; + var ret_val = service.MigrateVirtualSystemToHost(vm.Path, entry.HostName, migrationSettings, null, null, out jobPath); + if (ret_val == ReturnCode.Started) + { + MigrationJobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed migrating VM {0} (GUID {1}) due to {2}", + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + /// + /// Migrates the volume of a vm to a given destination storage + /// + /// + /// + /// + public void MigrateVolume(string vmName, string volume, string destination) + { + ComputerSystem vm = GetComputerSystem(vmName); + VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance(); + VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService(); + StorageAllocationSettingData[] sasd = GetStorageSettings(vm); + + string[] rasds = null; + if (sasd != null) + { + rasds = new string[1]; + foreach (StorageAllocationSettingData item in sasd) + { + string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]); + if (!String.IsNullOrEmpty(vhdFileName) && vhdFileName.Equals(volume)) + { + string newVhdPath = Path.Combine(destination, Path.GetFileName(item.HostResource[0])); + item.LateBoundObject["HostResource"] = new string[] { newVhdPath }; + item.LateBoundObject["PoolId"] = ""; + rasds[0] = item.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + break; + } + } + } + + migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.Storage; + migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP; + string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + + ManagementPath jobPath; + var ret_val = service.MigrateVirtualSystemToHost(vm.Path, null, migrationSettings, rasds, null, out jobPath); + if (ret_val == ReturnCode.Started) + { + MigrationJobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed migrating volume {0} of VM {1} (GUID {2}) due to {3}", + volume, + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + /// + /// Migrates the volume of a vm to a given destination storage + /// + /// + /// + /// volume to me migrated to which pool + public void MigrateVmWithVolume(string vmName, string destination, Dictionary volumeToPool) + { + ComputerSystem vm = GetComputerSystem(vmName); + VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance(); + VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService(); + StorageAllocationSettingData[] sasd = GetStorageSettings(vm); + + string[] rasds = null; + if (sasd != null) + { + rasds = new string[sasd.Length]; + uint index = 0; + foreach (StorageAllocationSettingData item in sasd) + { + string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]); + if (!String.IsNullOrEmpty(vhdFileName) && volumeToPool.ContainsKey(vhdFileName)) + { + string newVhdPath = Path.Combine(volumeToPool[vhdFileName], Path.GetFileName(item.HostResource[0])); + item.LateBoundObject["HostResource"] = new string[] { newVhdPath }; + item.LateBoundObject["PoolId"] = ""; + } + + rasds[index++] = item.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + } + } + + IPAddress addr = IPAddress.Parse(destination); + IPHostEntry entry = Dns.GetHostEntry(addr); + string[] destinationHost = new string[] { destination }; + + migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.VirtualSystemAndStorage; + migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP; + migrationSettingData.LateBoundObject["DestinationIPAddressList"] = destinationHost; + string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + + ManagementPath jobPath; + var ret_val = service.MigrateVirtualSystemToHost(vm.Path, entry.HostName, migrationSettings, rasds, null, out jobPath); + if (ret_val == ReturnCode.Started) + { + MigrationJobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed migrating VM {0} and its volumes to destination {1} (GUID {2}) due to {3}", + vm.ElementName, + destination, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + /// + /// Create new storage media resources, e.g. hard disk images and ISO disk images + /// see http://msdn.microsoft.com/en-us/library/hh859775(v=vs.85).aspx + /// + /// + /// + private static StorageAllocationSettingData CloneStorageAllocationSetting(string wmiQuery) + { + var defaultDiskImageSettingsObjs = StorageAllocationSettingData.GetInstances(wmiQuery); + + // assert + if (defaultDiskImageSettingsObjs.Count != 1) + { + var errMsg = string.Format("Failed to find Msvm_StorageAllocationSettingData for the query {0}", wmiQuery); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + StorageAllocationSettingData defaultDiskDriveSettings = defaultDiskImageSettingsObjs.OfType().First(); + return new StorageAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone()); + } + + /// < summary> + /// Removes a storage resource from a computer system. + /// + /// Path that uniquely identifies the resource. + /// VM to which the disk image will be attached. + // Add new + private void RemoveNetworkResource(ManagementPath resourcePath) + { + var virtSwitchMgmtSvc = GetVirtualSwitchManagementService(); + ManagementPath jobPath; + var ret_val = virtSwitchMgmtSvc.RemoveResourceSettings( + new ManagementPath[] { resourcePath }, + out jobPath); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to remove network resources {0} from switch due to {1}", + resourcePath.Path, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + /// < summary> + /// Removes a storage resource from a computer system. + /// + /// Path that uniquely identifies the resource. + /// VM to which the disk image will be attached. + private void RemoveStorageResource(ManagementPath resourcePath, ComputerSystem vm) + { + logger.DebugFormat("Got request to attach iso {0} to vm {1}", iso, displayName); + + ComputerSystem vm = GetComputerSystem(displayName); + if (vm == null) + { + logger.DebugFormat("VM {0} not found", displayName); + return; + } + else + { + AttachIso(vm, iso); + } + } + + public void DestroyVm(dynamic jsonObj) + { + string vmToDestroy = jsonObj.vmName; + DestroyVm(vmToDestroy); + } + + /// + /// Remove all VMs and all SwitchPorts with the displayName. VHD gets deleted elsewhere. + /// + /// + public void DestroyVm(string displayName) + { + logger.DebugFormat("Got request to destroy vm {0}", displayName); + + var vm = GetComputerSystem(displayName); + if ( vm == null ) + { + logger.DebugFormat("VM {0} already destroyed (or never existed)", displayName); + return; + } + + //try to shutdown vm first + ShutdownVm(vm); - - public void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs) - { - OperatingSystem0 os = new OperatingSystem0(); - physicalRamKBs = os.TotalVisibleMemorySize; - freeMemoryKBs = os.FreePhysicalMemory; - } - - public string GetDefaultVirtualDiskFolder() - { - VirtualSystemManagementServiceSettingData.VirtualSystemManagementServiceSettingDataCollection coll = VirtualSystemManagementServiceSettingData.GetInstances(); - string defaultVirtualHardDiskPath = null; - foreach (VirtualSystemManagementServiceSettingData settings in coll) + if(GetComputerSystem(vm.ElementName).EnabledState != EnabledState.Disabled) { - defaultVirtualHardDiskPath = settings.DefaultVirtualHardDiskPath; + logger.Info("Could not shutdown system cleanly, will forcefully delete the system"); } - // assert - if (!System.IO.Directory.Exists(defaultVirtualHardDiskPath) ){ - var errMsg = string.Format( - "Hyper-V DefaultVirtualHardDiskPath is invalid!"); - logger.Error(errMsg); - return null; - } - - return defaultVirtualHardDiskPath; - } - - public ComputerSystem GetComputerSystem(string displayName) + // Remove VM + logger.DebugFormat("Remove VM {0} (GUID {1})", vm.ElementName, vm.Name); + SetState(vm, RequiredState.Disabled); + + // Delete SwitchPort + logger.DebugFormat("Remove associated switch ports for VM {0} (GUID {1})", vm.ElementName, vm.Name); + DeleteSwitchPort(vm.ElementName); + + // Delete VM + var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); + ManagementPath jobPath; + + do + { + logger.DebugFormat("Delete VM {0} (GUID {1})", vm.ElementName, vm.Name); + var ret_val = virtSysMgmtSvc.DestroySystem(vm.Path, out jobPath); + + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed Delete VM {0} (GUID {1}) due to {2}", + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + vm = GetComputerSystem(displayName); + } + while (vm != null); + } + + public void ShutdownVm(ComputerSystem vm) { - var wmiQuery = String.Format("ElementName=\"{0}\"", displayName); - ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(wmiQuery); - - // Return the first one - foreach (ComputerSystem vm in vmCollection) + ShutdownComponent sc = GetShutdownComponent(vm); + if (sc != null) { - return vm; - } - return null; - } - - public ComputerSystem.ComputerSystemCollection GetComputerSystemCollection() - { - var wmiQuery = String.Format("Caption=\"Virtual Machine\""); - return ComputerSystem.GetInstances(wmiQuery); - } - - public Dictionary GetVmSync(String privateIpAddress) - { - List vms = GetVmElementNames(); - Dictionary vmSyncStates = new Dictionary(); - String vmState; - foreach (String vm in vms) - { - vmState = EnabledState.ToCloudStackState(GetComputerSystem(vm).EnabledState); - vmSyncStates.Add(vm, new VmState(vmState, privateIpAddress)); - } - return vmSyncStates; - } - - public List GetVmElementNames() - { - List result = new List(); - ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(); - - // Return the first one - foreach (ComputerSystem vm in vmCollection) - { - if (vm.Caption.StartsWith("Hosting Computer System") ) + var ret_val = sc.InitiateShutdown(true, "need to shutdown"); + if (ret_val != ReturnCode.Completed) { - continue; + logger.Info("Shutting down of system failed, may be shutdown integration services are missing"); + } + else + { + // shutdown job is not returned so checking for shutdown completion by checking the current state of system. + // poll every one second and timeout after 10 minutes + for (int period = 0 ; period < 600 && (GetComputerSystem(vm.ElementName).EnabledState != EnabledState.Disabled); period++) + { + System.Threading.Thread.Sleep(1000); + } } - result.Add(vm.ElementName); } - return result; - } - - public ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings) - { - // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the - // ProcessorSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. - // Instead, we use the System.Management to code the equivalant of - // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); - // - var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ProcessorSettingData.CreatedClassName); - - // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain - // the virtualisation objects. - var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); - var wmiObjCollection = new ProcessorSettingData.ProcessorSettingDataCollection(wmiObjectSearch.Get()); - - foreach (ProcessorSettingData wmiObj in wmiObjCollection) + else { - return wmiObj; + logger.Info("Shutting down of system failed; may be shutdown integration services are missing"); } - - var errMsg = string.Format("No ProcessorSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; } - public MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings) - { - // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the - // MemorySettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. - // Instead, we use the System.Management to code the equivalant of - // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); - // - var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, MemorySettingData.CreatedClassName); - - // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain - // the virtualisation objects. - var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); - var wmiObjCollection = new MemorySettingData.MemorySettingDataCollection(wmiObjectSearch.Get()); - - foreach (MemorySettingData wmiObj in wmiObjCollection) - { - return wmiObj; - } - - var errMsg = string.Format("No MemorySettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - - public ResourceAllocationSettingData GetDvdDriveSettings(VirtualSystemSettingData vmSettings) + /// + /// Migrates a vm to the given destination host + /// + /// + /// + public void MigrateVm(string vmName, string destination) + { + ComputerSystem vm = GetComputerSystem(vmName); + VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance(); + VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService(); + + IPAddress addr = IPAddress.Parse(destination); + IPHostEntry entry = Dns.GetHostEntry(addr); + string[] destinationHost = new string[] { destination }; + + migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.VirtualSystem; + migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP; + migrationSettingData.LateBoundObject["DestinationIPAddressList"] = destinationHost; + string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + + ManagementPath jobPath; + var ret_val = service.MigrateVirtualSystemToHost(vm.Path, entry.HostName, migrationSettings, null, null, out jobPath); + if (ret_val == ReturnCode.Started) + { + MigrationJobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed migrating VM {0} (GUID {1}) due to {2}", + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + /// + /// Migrates the volume of a vm to a given destination storage + /// + /// + /// + /// + public void MigrateVolume(string vmName, string volume, string destination) + { + ComputerSystem vm = GetComputerSystem(vmName); + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance(); + VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService(); + StorageAllocationSettingData[] sasd = GetStorageSettings(vm); + + string[] rasds = null; + if (sasd != null) + { + rasds = new string[1]; + foreach (StorageAllocationSettingData item in sasd) + { + string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]); + if (!String.IsNullOrEmpty(vhdFileName) && vhdFileName.Equals(volume)) + { + string newVhdPath = Path.Combine(destination, Path.GetFileName(item.HostResource[0])); + item.LateBoundObject["HostResource"] = new string[] { newVhdPath }; + item.LateBoundObject["PoolId"] = ""; + rasds[0] = item.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + break; + } + } + } + + migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.Storage; + migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP; + string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + + ManagementPath jobPath; + var ret_val = service.MigrateVirtualSystemToHost(vm.Path, null, migrationSettings, rasds, null, out jobPath); + if (ret_val == ReturnCode.Started) + { + MigrationJobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed migrating volume {0} of VM {1} (GUID {2}) due to {3}", + volume, + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + /// + /// Migrates the volume of a vm to a given destination storage + /// + /// + /// + /// volume to me migrated to which pool + public void MigrateVmWithVolume(string vmName, string destination, Dictionary volumeToPool) + { + ComputerSystem vm = GetComputerSystem(vmName); + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance(); + VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService(); + StorageAllocationSettingData[] sasd = GetStorageSettings(vm); + + string[] rasds = null; + if (sasd != null) + { + rasds = new string[sasd.Length]; + uint index = 0; + foreach (StorageAllocationSettingData item in sasd) + { + string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]); + if (!String.IsNullOrEmpty(vhdFileName) && volumeToPool.ContainsKey(vhdFileName)) + { + string newVhdPath = Path.Combine(volumeToPool[vhdFileName], Path.GetFileName(item.HostResource[0])); + item.LateBoundObject["HostResource"] = new string[] { newVhdPath }; + item.LateBoundObject["PoolId"] = ""; + } + + rasds[index++] = item.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + } + } + + IPAddress addr = IPAddress.Parse(destination); + IPHostEntry entry = Dns.GetHostEntry(addr); + string[] destinationHost = new string[] { destination }; + + migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.VirtualSystemAndStorage; + migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP; + migrationSettingData.LateBoundObject["DestinationIPAddressList"] = destinationHost; + string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + + ManagementPath jobPath; + var ret_val = service.MigrateVirtualSystemToHost(vm.Path, entry.HostName, migrationSettings, rasds, null, out jobPath); + if (ret_val == ReturnCode.Started) + { + MigrationJobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed migrating VM {0} and its volumes to destination {1} (GUID {2}) due to {3}", + vm.ElementName, + destination, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + /// + /// Create new storage media resources, e.g. hard disk images and ISO disk images + /// see http://msdn.microsoft.com/en-us/library/hh859775(v=vs.85).aspx + /// + /// + /// + private static StorageAllocationSettingData CloneStorageAllocationSetting(string wmiQuery) + { + var defaultDiskImageSettingsObjs = StorageAllocationSettingData.GetInstances(wmiQuery); + + // assert + if (defaultDiskImageSettingsObjs.Count != 1) + { + var errMsg = string.Format("Failed to find Msvm_StorageAllocationSettingData for the query {0}", wmiQuery); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + StorageAllocationSettingData defaultDiskDriveSettings = defaultDiskImageSettingsObjs.OfType().First(); + return new StorageAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone()); + } + + /// < summary> + /// Removes a storage resource from a computer system. + /// + /// Path that uniquely identifies the resource. + /// VM to which the disk image will be attached. + // Add new + private void RemoveNetworkResource(ManagementPath resourcePath) + { + var virtSwitchMgmtSvc = GetVirtualSwitchManagementService(); + ManagementPath jobPath; + var ret_val = virtSwitchMgmtSvc.RemoveResourceSettings( + new ManagementPath[] { resourcePath }, + out jobPath); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to remove network resources {0} from switch due to {1}", + resourcePath.Path, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + /// < summary> + /// Removes a storage resource from a computer system. + /// + /// Path that uniquely identifies the resource. + /// VM to which the disk image will be attached. + private void RemoveStorageResource(ManagementPath resourcePath, ComputerSystem vm) + { + var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); + + ManagementPath jobPath; + var ret_val = virtSysMgmtSvc.RemoveResourceSettings( + new ManagementPath[] { resourcePath }, + out jobPath); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to remove resource {0} from VM {1} (GUID {2}) due to {3}", + resourcePath.Path, + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + public void SetState(ComputerSystem vm, ushort requiredState) + { + logger.InfoFormat( + "Changing state of {0} (GUID {1}) to {2}", + vm.ElementName, + vm.Name, + RequiredState.ToString(requiredState)); + + ManagementPath jobPath; + // DateTime is unused + var ret_val = vm.RequestStateChange(requiredState, new DateTime(), out jobPath); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val == 32775) + { // TODO: check + logger.InfoFormat("RequestStateChange returned 32775, which means vm in wrong state for requested state change. Treating as if requested state was reached"); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to change state of VM {0} (GUID {1}) to {2} due to {3}", + vm.ElementName, + vm.Name, + RequiredState.ToString(requiredState), + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + logger.InfoFormat( + "Successfully changed vm state of {0} (GUID {1} to requested state {2}", + vm.ElementName, + vm.Name, + requiredState); + } + + + //TODO: Write method to delete SwitchPort based on Name + /// + /// Delete switch port by removing settings from the switch + /// + /// + /// + public void DeleteSwitchPort(string elementName) + { + // Get NIC path + var condition = string.Format("ElementName=\"{0}\"", elementName); + var virtSwitchMgmtSvc = GetVirtualSwitchManagementService(); + + var switchPortCollection = EthernetSwitchPort.GetInstances(virtSwitchMgmtSvc.Scope, condition); + if (switchPortCollection.Count == 0) + { + return; + } + + foreach (EthernetSwitchPort port in switchPortCollection) + { + var settings = GetSyntheticEthernetPortSettings(port); + RemoveNetworkResource(settings.Path); + } + } + + public SyntheticEthernetPortSettingData GetSyntheticEthernetPortSettings(EthernetSwitchPort port) + { + // An ASSOCIATOR object provides the cross reference from the EthernetSwitchPort and the + // SyntheticEthernetPortSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(port.Path.Path, SyntheticEthernetPortSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(port.Scope, wmiObjQuery); + var wmiObjCollection = new SyntheticEthernetPortSettingData.SyntheticEthernetPortSettingDataCollection(wmiObjectSearch.Get()); + + // When snapshots are taken into account, there can be multiple settings objects + // take the first one that isn't a snapshot + foreach (SyntheticEthernetPortSettingData wmiObj in wmiObjCollection) + { + return wmiObj; + } + + var errMsg = string.Format("No SyntheticEthernetPortSettingData for port {0}, path {1}", port.ElementName, port.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + /// + /// Adds storage images to coputer system (disk image, iso image). + /// + /// Msvm_StorageAllocationSettings with HostResource configured with image + /// file and Parent set to a controller associated with the ComputerSystem + /// VM to which the disk image will be attached. + // Add new + private ManagementPath[] AddStorageResource(string[] storageSettings, ComputerSystem vm) + { + return AddVirtualResource(storageSettings, vm); + } + + private ManagementPath[] AddVirtualResource(string[] resourceSettings, ComputerSystem vm ) + { + var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); + + ManagementPath jobPath; + ManagementPath[] resourcePaths; + var ret_val = virtSysMgmtSvc.AddResourceSettings( + vm.Path, + resourceSettings, + out jobPath, + out resourcePaths); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to add resources to VM {0} (GUID {1}) due to {2}", + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + return resourcePaths; + } + + private ManagementPath[] AddFeatureSettings(string[] featureSettings, ManagementPath affectedConfiguration) + { + var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); + + ManagementPath jobPath; + ManagementPath[] resultSettings; + var ret_val = virtSysMgmtSvc.AddFeatureSettings( + affectedConfiguration, + featureSettings, + out jobPath, + out resultSettings); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to add features settings {0} to resource {1} due to {2}", + featureSettings, + affectedConfiguration, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + return resultSettings; + } + + private ManagementPath SetPortVlan(string vlan, EthernetPortAllocationSettingData portPath) + { + logger.DebugFormat("Setting VLAN to {0}", vlan); + + var vmVirtMgmtSvc = GetVirtualisationSystemManagementService(); + EthernetSwitchPortVlanSettingData.GetInstances(); + + // Create NIC resource by cloning the default NIC + var vlanSettings = EthernetSwitchPortVlanSettingData.GetInstances(vmVirtMgmtSvc.Scope, "InstanceID LIKE \"%Default\""); + + // Assert + if (vlanSettings.Count != 1) + { + var errMsg = string.Format("Internal error, could not find default EthernetSwitchPortVlanSettingData instance"); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + var defaultVlanSettings = vlanSettings.OfType().First(); + + var newVlanSettings = new EthernetSwitchPortVlanSettingData((ManagementBaseObject)defaultVlanSettings.LateBoundObject.Clone()); + + // Assign configuration to new NIC + newVlanSettings.LateBoundObject["AccessVlanId"] = vlan; + newVlanSettings.LateBoundObject["OperationMode"] = 1; // Access=1, trunk=2, private=3 ; + newVlanSettings.CommitObject(); + + // Insert NIC into vm + string[] newResources = new string[] { newVlanSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; + ManagementPath[] newResourcePaths = AddFeatureSettings(newResources, portPath.Path); + + // assert + if (newResourcePaths.Length != 1) + { + var errMsg = string.Format( + "Failed to properly set VLAN to {0} for NIC on port {1}", + vlan, + portPath.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + return newResourcePaths[0]; + } + + private void SetBandWidthLimit(ulong limit, EthernetPortAllocationSettingData portPath) { var wmiObjCollection = GetResourceAllocationSettings(vmSettings); @@ -2647,41 +3689,404 @@ namespace HypervResource throw ex; } - public void GetSummaryInfo(Dictionary vmProcessorInfo, List vmsToInspect) + public ShutdownComponent GetShutdownComponent(ComputerSystem vm) { - // Process info available from WMI, - // See http://msdn.microsoft.com/en-us/library/hh850062(v=vs.85).aspx - uint[] requestedInfo = new uint[] { // TODO: correct? - 0, // Name - 1, // ElementName - 4, // Number of processes - 101 // ProcessorLoad - }; + var wmiQuery = String.Format("SystemName=\"{0}\"", vm.Name); + ShutdownComponent.ShutdownComponentCollection vmCollection = ShutdownComponent.GetInstances(wmiQuery); - System.Management.ManagementBaseObject[] sysSummary; - var vmsvc = GetVirtualisationSystemManagementService(); - System.Management.ManagementPath[] vmPaths = vmsToInspect.ToArray(); - vmsvc.GetSummaryInformation(requestedInfo, vmPaths, out sysSummary); - - foreach (var summary in sysSummary) + // Return the first one + foreach (ShutdownComponent sc in vmCollection) { - - var summaryInfo = new SummaryInformation(summary); - - logger.Debug("VM " + summaryInfo.Name + "(elementName " + summaryInfo.ElementName + ") has " + - summaryInfo.NumberOfProcessors + " CPUs, and load of " + summaryInfo.ProcessorLoad); - var vmInfo = new VmStatsEntry - { - cpuUtilization = summaryInfo.ProcessorLoad, - numCPUs = summaryInfo.NumberOfProcessors, - networkReadKBs = 1, - networkWriteKBs = 1, - entityType = "vm" - }; - vmProcessorInfo.Add(summaryInfo.ElementName, vmInfo); + return sc; } + return null; } + public Dictionary GetVmSync(String privateIpAddress) + { + List vms = GetVmElementNames(); + Dictionary vmSyncStates = new Dictionary(); + String vmState; + foreach (String vm in vms) + { + vmState = EnabledState.ToCloudStackState(GetComputerSystem(vm).EnabledState); + vmSyncStates.Add(vm, new VmState(vmState, privateIpAddress)); + } + return vmSyncStates; + } + + public List GetVmElementNames() + { + List result = new List(); + ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(); + + // Return the first one + foreach (ComputerSystem vm in vmCollection) + { + if (vm.Caption.StartsWith("Hosting Computer System") ) + { + continue; + } + result.Add(vm.ElementName); + } + return result; + } + + public ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings) + { + // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the + // ProcessorSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ProcessorSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); + var wmiObjCollection = new ProcessorSettingData.ProcessorSettingDataCollection(wmiObjectSearch.Get()); + + foreach (ProcessorSettingData wmiObj in wmiObjCollection) + { + return wmiObj; + } + + var errMsg = string.Format("No ProcessorSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + public MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings) + { + // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the + // MemorySettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, MemorySettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); + var wmiObjCollection = new MemorySettingData.MemorySettingDataCollection(wmiObjectSearch.Get()); + + foreach (MemorySettingData wmiObj in wmiObjCollection) + { + return wmiObj; + } + + var errMsg = string.Format("No MemorySettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + + public ResourceAllocationSettingData GetDvdDriveSettings(VirtualSystemSettingData vmSettings) + { + var wmiObjCollection = GetResourceAllocationSettings(vmSettings); + + foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection) + { + // DVD drive is '16', see http://msdn.microsoft.com/en-us/library/hh850200(v=vs.85).aspx + if (wmiObj.ResourceType == 16) + { + return wmiObj; + } + } + + var errMsg = string.Format( + "Cannot find the Dvd drive in VirtualSystemSettingData {0}", + vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + public ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr) + { + var wmiObjCollection = GetResourceAllocationSettings(vmSettings); + + foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection) + { + if (wmiObj.ResourceSubType == IDE_CONTROLLER && wmiObj.Address == cntrllerAddr) + { + return wmiObj; + } + } + + var errMsg = string.Format( + "Cannot find the Microsoft Emulated IDE Controlle at address {0} in VirtualSystemSettingData {1}", + cntrllerAddr, + vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + public ResourceAllocationSettingData GetScsiControllerSettings(VirtualSystemSettingData vmSettings) + { + var wmiObjCollection = GetResourceAllocationSettings(vmSettings); + + foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection) + { + if (wmiObj.ResourceSubType == SCSI_CONTROLLER) + { + return wmiObj; + } + } + + var errMsg = string.Format( + "Cannot find the Microsoft Synthetic SCSI Controller in VirtualSystemSettingData {1}", + vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + /// + /// VM resources, typically hardware a described by a generic MSVM_ResourceAllocationSettingData object. The hardware type being + /// described is identified in two ways: in general terms using an enum in the ResourceType field, and in terms of the implementation + /// using text in the ResourceSubType field. + /// See http://msdn.microsoft.com/en-us/library/cc136877%28v=vs.85%29.aspx + /// + /// + /// + public ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings) + { + // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the + // ResourceAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ResourceAllocationSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); + var wmiObjCollection = new ResourceAllocationSettingData.ResourceAllocationSettingDataCollection(wmiObjectSearch.Get()); + + if (wmiObjCollection != null) + { + return wmiObjCollection; + } + + var errMsg = string.Format("No ResourceAllocationSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + public EthernetPortAllocationSettingData[] GetEthernetConnections(ComputerSystem vm) + { + // ComputerSystem -> VirtualSystemSettingData -> EthernetPortAllocationSettingData + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + + // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the + // EthernetPortAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, EthernetPortAllocationSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); + var wmiObjCollection = new EthernetPortAllocationSettingData.EthernetPortAllocationSettingDataCollection(wmiObjectSearch.Get()); + + var result = new List(wmiObjCollection.Count); + foreach (EthernetPortAllocationSettingData item in wmiObjCollection) + { + result.Add(item); + } + return result.ToArray(); + } + + public StorageAllocationSettingData[] GetStorageSettings(ComputerSystem vm) + { + // ComputerSystem -> VirtualSystemSettingData -> EthernetPortAllocationSettingData + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, StorageAllocationSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); + var wmiObjCollection = new StorageAllocationSettingData.StorageAllocationSettingDataCollection(wmiObjectSearch.Get()); + + var result = new List(wmiObjCollection.Count); + foreach (StorageAllocationSettingData item in wmiObjCollection) + { + result.Add(item); + } + return result.ToArray(); + } + + + public EthernetSwitchPortVlanSettingData GetVlanSettings(EthernetPortAllocationSettingData ethernetConnection) + { + // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the + // EthernetPortAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(ethernetConnection.Path.Path, EthernetSwitchPortVlanSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(ethernetConnection.Scope, wmiObjQuery); + var wmiObjCollection = new EthernetSwitchPortVlanSettingData.EthernetSwitchPortVlanSettingDataCollection(wmiObjectSearch.Get()); + + if (wmiObjCollection.Count == 0) + { + return null; + } + + // Assert + if (wmiObjCollection.Count > 1) + { + var errMsg = string.Format("Internal error, morn one VLAN settings for a single ethernetConnection"); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + return wmiObjCollection.OfType().First(); + } + + + public SyntheticEthernetPortSettingData[] GetEthernetPortSettings(ComputerSystem vm) + { + // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the + // SyntheticEthernetPortSettingData, via the VirtualSystemSettingData. + // However, generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName); + // + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, SyntheticEthernetPortSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery); + var wmiObjCollection = new SyntheticEthernetPortSettingData.SyntheticEthernetPortSettingDataCollection(wmiObjectSearch.Get()); + + List results = new List(wmiObjCollection.Count); + foreach (SyntheticEthernetPortSettingData item in wmiObjCollection) + { + results.Add(item); + } + + return results.ToArray(); + } + + public string GetDefaultDataRoot() + { + string defaultRootPath = null; + VirtualSystemManagementServiceSettingData vs_mgmt_data = VirtualSystemManagementServiceSettingData.CreateInstance(); + defaultRootPath = vs_mgmt_data.DefaultVirtualHardDiskPath; + if (defaultRootPath == null) { + defaultRootPath = Path.GetPathRoot(Environment.SystemDirectory) + + "\\Users\\Public\\Documents\\Hyper-V\\Virtual hard disks"; + } + + return defaultRootPath; + } + + public VirtualSystemSettingData GetVmSettings(ComputerSystem vm) + { + // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the + // VirtualSystemSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(vm.Path.Path, VirtualSystemSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery); + var wmiObjCollection = new VirtualSystemSettingData.VirtualSystemSettingDataCollection(wmiObjectSearch.Get()); + + // When snapshots are taken into account, there can be multiple settings objects + // take the first one that isn't a snapshot + foreach (VirtualSystemSettingData wmiObj in wmiObjCollection) + { + if (wmiObj.VirtualSystemType == "Microsoft:Hyper-V:System:Realized" || + wmiObj.VirtualSystemType == "Microsoft:Hyper-V:System:Planned") + { + return wmiObj; + } + } + + var errMsg = string.Format("No VirtualSystemSettingData for VM {0}, path {1}", vm.ElementName, vm.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + public KvpExchangeComponentSettingData GetKvpSettings(VirtualSystemSettingData vmSettings) + { + // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the + // KvpExchangeComponentSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, KvpExchangeComponentSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); + var wmiObjCollection = new KvpExchangeComponentSettingData.KvpExchangeComponentSettingDataCollection(wmiObjectSearch.Get()); + + foreach (KvpExchangeComponentSettingData wmiObj in wmiObjCollection) + { + return wmiObj; + } + + var errMsg = string.Format("No KvpExchangeComponentSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + public void GetSummaryInfo(Dictionary vmProcessorInfo, List vmsToInspect) + { + // Process info available from WMI, + // See http://msdn.microsoft.com/en-us/library/hh850062(v=vs.85).aspx + uint[] requestedInfo = new uint[] { // TODO: correct? + 0, // Name + 1, // ElementName + 4, // Number of processes + 101 // ProcessorLoad + }; + + System.Management.ManagementBaseObject[] sysSummary; + var vmsvc = GetVirtualisationSystemManagementService(); + System.Management.ManagementPath[] vmPaths = vmsToInspect.ToArray(); + vmsvc.GetSummaryInformation(requestedInfo, vmPaths, out sysSummary); + + foreach (var summary in sysSummary) + { + + var summaryInfo = new SummaryInformation(summary); + + logger.Debug("VM " + summaryInfo.Name + "(elementName " + summaryInfo.ElementName + ") has " + + summaryInfo.NumberOfProcessors + " CPUs, and load of " + summaryInfo.ProcessorLoad); + var vmInfo = new VmStatsEntry + { + cpuUtilization = summaryInfo.ProcessorLoad, + numCPUs = summaryInfo.NumberOfProcessors, + networkReadKBs = 1, + networkWriteKBs = 1, + entityType = "vm" + }; + vmProcessorInfo.Add(summaryInfo.ElementName, vmInfo); + } + } + public string GetVmNote(System.Management.ManagementPath sysPath) { uint[] requestedInfo = new uint[] { 3 }; diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/ROOT.virtualization.v2.Msvm_ShutdownComponent.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/ROOT.virtualization.v2.Msvm_ShutdownComponent.cs new file mode 100644 index 00000000000..81613ea88f4 --- /dev/null +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/ROOT.virtualization.v2.Msvm_ShutdownComponent.cs @@ -0,0 +1,1609 @@ +// 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. + +namespace CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2 { + using System; + using System.ComponentModel; + using System.Management; + using System.Collections; + using System.Globalization; + using System.ComponentModel.Design.Serialization; + using System.Reflection; + + + // Functions ShouldSerialize are functions used by VS property browser to check if a particular property has to be serialized. These functions are added for all ValueType properties ( properties of type Int32, BOOL etc.. which cannot be set to null). These functions use IsNull function. These functions are also used in the TypeConverter implementation for the properties to check for NULL value of property so that an empty value can be shown in Property browser in case of Drag and Drop in Visual studio. + // Functions IsNull() are used to check if a property is NULL. + // Functions Reset are added for Nullable Read/Write properties. These functions are used by VS designer in property browser to set a property to NULL. + // Every property added to the class for WMI property has attributes set to define its behavior in Visual Studio designer and also to define a TypeConverter to be used. + // Datetime conversion functions ToDateTime and ToDmtfDateTime are added to the class to convert DMTF datetime to System.DateTime and vice-versa. + // An Early Bound class generated for the WMI class.Msvm_ShutdownComponent + public class ShutdownComponent : System.ComponentModel.Component { + + // Private property to hold the WMI namespace in which the class resides. + private static string CreatedWmiNamespace = "ROOT\\virtualization\\v2"; + + // Private property to hold the name of WMI class which created this class. + private static string CreatedClassName = "Msvm_ShutdownComponent"; + + // Private member variable to hold the ManagementScope which is used by the various methods. + private static System.Management.ManagementScope statMgmtScope = null; + + private ManagementSystemProperties PrivateSystemProperties; + + // Underlying lateBound WMI object. + private System.Management.ManagementObject PrivateLateBoundObject; + + // Member variable to store the 'automatic commit' behavior for the class. + private bool AutoCommitProp; + + // Private variable to hold the embedded property representing the instance. + private System.Management.ManagementBaseObject embeddedObj; + + // The current WMI object used + private System.Management.ManagementBaseObject curObj; + + // Flag to indicate if the instance is an embedded object. + private bool isEmbedded; + + // Below are different overloads of constructors to initialize an instance of the class with a WMI object. + public ShutdownComponent() { + this.InitializeObject(null, null, null); + } + + public ShutdownComponent(string keyCreationClassName, string keyDeviceID, string keySystemCreationClassName, string keySystemName) { + this.InitializeObject(null, new System.Management.ManagementPath(ShutdownComponent.ConstructPath(keyCreationClassName, keyDeviceID, keySystemCreationClassName, keySystemName)), null); + } + + public ShutdownComponent(System.Management.ManagementScope mgmtScope, string keyCreationClassName, string keyDeviceID, string keySystemCreationClassName, string keySystemName) { + this.InitializeObject(((System.Management.ManagementScope)(mgmtScope)), new System.Management.ManagementPath(ShutdownComponent.ConstructPath(keyCreationClassName, keyDeviceID, keySystemCreationClassName, keySystemName)), null); + } + + public ShutdownComponent(System.Management.ManagementPath path, System.Management.ObjectGetOptions getOptions) { + this.InitializeObject(null, path, getOptions); + } + + public ShutdownComponent(System.Management.ManagementScope mgmtScope, System.Management.ManagementPath path) { + this.InitializeObject(mgmtScope, path, null); + } + + public ShutdownComponent(System.Management.ManagementPath path) { + this.InitializeObject(null, path, null); + } + + public ShutdownComponent(System.Management.ManagementScope mgmtScope, System.Management.ManagementPath path, System.Management.ObjectGetOptions getOptions) { + this.InitializeObject(mgmtScope, path, getOptions); + } + + public ShutdownComponent(System.Management.ManagementObject theObject) { + Initialize(); + if ((CheckIfProperClass(theObject) == true)) { + PrivateLateBoundObject = theObject; + PrivateSystemProperties = new ManagementSystemProperties(PrivateLateBoundObject); + curObj = PrivateLateBoundObject; + } + else { + throw new System.ArgumentException("Class name does not match."); + } + } + + public ShutdownComponent(System.Management.ManagementBaseObject theObject) { + Initialize(); + if ((CheckIfProperClass(theObject) == true)) { + embeddedObj = theObject; + PrivateSystemProperties = new ManagementSystemProperties(theObject); + curObj = embeddedObj; + isEmbedded = true; + } + else { + throw new System.ArgumentException("Class name does not match."); + } + } + + // Property returns the namespace of the WMI class. + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string OriginatingNamespace { + get { + return "ROOT\\virtualization\\v2"; + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string ManagementClassName { + get { + string strRet = CreatedClassName; + if ((curObj != null)) { + if ((curObj.ClassPath != null)) { + strRet = ((string)(curObj["__CLASS"])); + if (((strRet == null) + || (strRet == string.Empty))) { + strRet = CreatedClassName; + } + } + } + return strRet; + } + } + + // Property pointing to an embedded object to get System properties of the WMI object. + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ManagementSystemProperties SystemProperties { + get { + return PrivateSystemProperties; + } + } + + // Property returning the underlying lateBound object. + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public System.Management.ManagementBaseObject LateBoundObject { + get { + return curObj; + } + } + + // ManagementScope of the object. + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public System.Management.ManagementScope Scope { + get { + if ((isEmbedded == false)) { + return PrivateLateBoundObject.Scope; + } + else { + return null; + } + } + set { + if ((isEmbedded == false)) { + PrivateLateBoundObject.Scope = value; + } + } + } + + // Property to show the commit behavior for the WMI object. If true, WMI object will be automatically saved after each property modification.(ie. Put() is called after modification of a property). + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool AutoCommit { + get { + return AutoCommitProp; + } + set { + AutoCommitProp = value; + } + } + + // The ManagementPath of the underlying WMI object. + [Browsable(true)] + public System.Management.ManagementPath Path { + get { + if ((isEmbedded == false)) { + return PrivateLateBoundObject.Path; + } + else { + return null; + } + } + set { + if ((isEmbedded == false)) { + if ((CheckIfProperClass(null, value, null) != true)) { + throw new System.ArgumentException("Class name does not match."); + } + PrivateLateBoundObject.Path = value; + } + } + } + + // Public static scope property which is used by the various methods. + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public static System.Management.ManagementScope StaticScope { + get { + return statMgmtScope; + } + set { + statMgmtScope = value; + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ushort[] AdditionalAvailability { + get { + return ((ushort[])(curObj["AdditionalAvailability"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsAvailabilityNull { + get { + if ((curObj["Availability"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ushort Availability { + get { + if ((curObj["Availability"] == null)) { + return System.Convert.ToUInt16(0); + } + return ((ushort)(curObj["Availability"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ushort[] AvailableRequestedStates { + get { + return ((ushort[])(curObj["AvailableRequestedStates"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Caption { + get { + return ((string)(curObj["Caption"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsCommunicationStatusNull { + get { + if ((curObj["CommunicationStatus"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ushort CommunicationStatus { + get { + if ((curObj["CommunicationStatus"] == null)) { + return System.Convert.ToUInt16(0); + } + return ((ushort)(curObj["CommunicationStatus"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string CreationClassName { + get { + return ((string)(curObj["CreationClassName"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Description { + get { + return ((string)(curObj["Description"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsDetailedStatusNull { + get { + if ((curObj["DetailedStatus"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ushort DetailedStatus { + get { + if ((curObj["DetailedStatus"] == null)) { + return System.Convert.ToUInt16(0); + } + return ((ushort)(curObj["DetailedStatus"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string DeviceID { + get { + return ((string)(curObj["DeviceID"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string ElementName { + get { + return ((string)(curObj["ElementName"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsEnabledDefaultNull { + get { + if ((curObj["EnabledDefault"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ushort EnabledDefault { + get { + if ((curObj["EnabledDefault"] == null)) { + return System.Convert.ToUInt16(0); + } + return ((ushort)(curObj["EnabledDefault"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsEnabledStateNull { + get { + if ((curObj["EnabledState"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ushort EnabledState { + get { + if ((curObj["EnabledState"] == null)) { + return System.Convert.ToUInt16(0); + } + return ((ushort)(curObj["EnabledState"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsErrorClearedNull { + get { + if ((curObj["ErrorCleared"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public bool ErrorCleared { + get { + if ((curObj["ErrorCleared"] == null)) { + return System.Convert.ToBoolean(0); + } + return ((bool)(curObj["ErrorCleared"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string ErrorDescription { + get { + return ((string)(curObj["ErrorDescription"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsHealthStateNull { + get { + if ((curObj["HealthState"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ushort HealthState { + get { + if ((curObj["HealthState"] == null)) { + return System.Convert.ToUInt16(0); + } + return ((ushort)(curObj["HealthState"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string[] IdentifyingDescriptions { + get { + return ((string[])(curObj["IdentifyingDescriptions"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsInstallDateNull { + get { + if ((curObj["InstallDate"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public System.DateTime InstallDate { + get { + if ((curObj["InstallDate"] != null)) { + return ToDateTime(((string)(curObj["InstallDate"]))); + } + else { + return System.DateTime.MinValue; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string InstanceID { + get { + return ((string)(curObj["InstanceID"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsLastErrorCodeNull { + get { + if ((curObj["LastErrorCode"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public uint LastErrorCode { + get { + if ((curObj["LastErrorCode"] == null)) { + return System.Convert.ToUInt32(0); + } + return ((uint)(curObj["LastErrorCode"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsMaxQuiesceTimeNull { + get { + if ((curObj["MaxQuiesceTime"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ulong MaxQuiesceTime { + get { + if ((curObj["MaxQuiesceTime"] == null)) { + return System.Convert.ToUInt64(0); + } + return ((ulong)(curObj["MaxQuiesceTime"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Name { + get { + return ((string)(curObj["Name"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsOperatingStatusNull { + get { + if ((curObj["OperatingStatus"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ushort OperatingStatus { + get { + if ((curObj["OperatingStatus"] == null)) { + return System.Convert.ToUInt16(0); + } + return ((ushort)(curObj["OperatingStatus"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ushort[] OperationalStatus { + get { + return ((ushort[])(curObj["OperationalStatus"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string OtherEnabledState { + get { + return ((string)(curObj["OtherEnabledState"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string[] OtherIdentifyingInfo { + get { + return ((string[])(curObj["OtherIdentifyingInfo"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ushort[] PowerManagementCapabilities { + get { + return ((ushort[])(curObj["PowerManagementCapabilities"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsPowerManagementSupportedNull { + get { + if ((curObj["PowerManagementSupported"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public bool PowerManagementSupported { + get { + if ((curObj["PowerManagementSupported"] == null)) { + return System.Convert.ToBoolean(0); + } + return ((bool)(curObj["PowerManagementSupported"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsPowerOnHoursNull { + get { + if ((curObj["PowerOnHours"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ulong PowerOnHours { + get { + if ((curObj["PowerOnHours"] == null)) { + return System.Convert.ToUInt64(0); + } + return ((ulong)(curObj["PowerOnHours"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsPrimaryStatusNull { + get { + if ((curObj["PrimaryStatus"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ushort PrimaryStatus { + get { + if ((curObj["PrimaryStatus"] == null)) { + return System.Convert.ToUInt16(0); + } + return ((ushort)(curObj["PrimaryStatus"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsRequestedStateNull { + get { + if ((curObj["RequestedState"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ushort RequestedState { + get { + if ((curObj["RequestedState"] == null)) { + return System.Convert.ToUInt16(0); + } + return ((ushort)(curObj["RequestedState"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Status { + get { + return ((string)(curObj["Status"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string[] StatusDescriptions { + get { + return ((string[])(curObj["StatusDescriptions"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsStatusInfoNull { + get { + if ((curObj["StatusInfo"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ushort StatusInfo { + get { + if ((curObj["StatusInfo"] == null)) { + return System.Convert.ToUInt16(0); + } + return ((ushort)(curObj["StatusInfo"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string SystemCreationClassName { + get { + return ((string)(curObj["SystemCreationClassName"])); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string SystemName { + get { + return ((string)(curObj["SystemName"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsTimeOfLastStateChangeNull { + get { + if ((curObj["TimeOfLastStateChange"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public System.DateTime TimeOfLastStateChange { + get { + if ((curObj["TimeOfLastStateChange"] != null)) { + return ToDateTime(((string)(curObj["TimeOfLastStateChange"]))); + } + else { + return System.DateTime.MinValue; + } + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsTotalPowerOnHoursNull { + get { + if ((curObj["TotalPowerOnHours"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ulong TotalPowerOnHours { + get { + if ((curObj["TotalPowerOnHours"] == null)) { + return System.Convert.ToUInt64(0); + } + return ((ulong)(curObj["TotalPowerOnHours"])); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsTransitioningToStateNull { + get { + if ((curObj["TransitioningToState"] == null)) { + return true; + } + else { + return false; + } + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [TypeConverter(typeof(WMIValueTypeConverter))] + public ushort TransitioningToState { + get { + if ((curObj["TransitioningToState"] == null)) { + return System.Convert.ToUInt16(0); + } + return ((ushort)(curObj["TransitioningToState"])); + } + } + + private bool CheckIfProperClass(System.Management.ManagementScope mgmtScope, System.Management.ManagementPath path, System.Management.ObjectGetOptions OptionsParam) { + if (((path != null) + && (string.Compare(path.ClassName, this.ManagementClassName, true, System.Globalization.CultureInfo.InvariantCulture) == 0))) { + return true; + } + else { + return CheckIfProperClass(new System.Management.ManagementObject(mgmtScope, path, OptionsParam)); + } + } + + private bool CheckIfProperClass(System.Management.ManagementBaseObject theObj) { + if (((theObj != null) + && (string.Compare(((string)(theObj["__CLASS"])), this.ManagementClassName, true, System.Globalization.CultureInfo.InvariantCulture) == 0))) { + return true; + } + else { + System.Array parentClasses = ((System.Array)(theObj["__DERIVATION"])); + if ((parentClasses != null)) { + int count = 0; + for (count = 0; (count < parentClasses.Length); count = (count + 1)) { + if ((string.Compare(((string)(parentClasses.GetValue(count))), this.ManagementClassName, true, System.Globalization.CultureInfo.InvariantCulture) == 0)) { + return true; + } + } + } + } + return false; + } + + private bool ShouldSerializeAvailability() { + if ((this.IsAvailabilityNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeCommunicationStatus() { + if ((this.IsCommunicationStatusNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeDetailedStatus() { + if ((this.IsDetailedStatusNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeEnabledDefault() { + if ((this.IsEnabledDefaultNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeEnabledState() { + if ((this.IsEnabledStateNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeErrorCleared() { + if ((this.IsErrorClearedNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeHealthState() { + if ((this.IsHealthStateNull == false)) { + return true; + } + return false; + } + + // Converts a given datetime in DMTF format to System.DateTime object. + static System.DateTime ToDateTime(string dmtfDate) { + System.DateTime initializer = System.DateTime.MinValue; + int year = initializer.Year; + int month = initializer.Month; + int day = initializer.Day; + int hour = initializer.Hour; + int minute = initializer.Minute; + int second = initializer.Second; + long ticks = 0; + string dmtf = dmtfDate; + System.DateTime datetime = System.DateTime.MinValue; + string tempString = string.Empty; + if ((dmtf == null)) { + throw new System.ArgumentOutOfRangeException(); + } + if ((dmtf.Length == 0)) { + throw new System.ArgumentOutOfRangeException(); + } + if ((dmtf.Length != 25)) { + throw new System.ArgumentOutOfRangeException(); + } + try { + tempString = dmtf.Substring(0, 4); + if (("****" != tempString)) { + year = int.Parse(tempString); + } + tempString = dmtf.Substring(4, 2); + if (("**" != tempString)) { + month = int.Parse(tempString); + } + tempString = dmtf.Substring(6, 2); + if (("**" != tempString)) { + day = int.Parse(tempString); + } + tempString = dmtf.Substring(8, 2); + if (("**" != tempString)) { + hour = int.Parse(tempString); + } + tempString = dmtf.Substring(10, 2); + if (("**" != tempString)) { + minute = int.Parse(tempString); + } + tempString = dmtf.Substring(12, 2); + if (("**" != tempString)) { + second = int.Parse(tempString); + } + tempString = dmtf.Substring(15, 6); + if (("******" != tempString)) { + ticks = (long.Parse(tempString) * ((long)((System.TimeSpan.TicksPerMillisecond / 1000)))); + } + if (((((((((year < 0) + || (month < 0)) + || (day < 0)) + || (hour < 0)) + || (minute < 0)) + || (minute < 0)) + || (second < 0)) + || (ticks < 0))) { + throw new System.ArgumentOutOfRangeException(); + } + } + catch (System.Exception e) { + throw new System.ArgumentOutOfRangeException(null, e.Message); + } + datetime = new System.DateTime(year, month, day, hour, minute, second, 0); + datetime = datetime.AddTicks(ticks); + System.TimeSpan tickOffset = System.TimeZone.CurrentTimeZone.GetUtcOffset(datetime); + int UTCOffset = 0; + int OffsetToBeAdjusted = 0; + long OffsetMins = ((long)((tickOffset.Ticks / System.TimeSpan.TicksPerMinute))); + tempString = dmtf.Substring(22, 3); + if ((tempString != "******")) { + tempString = dmtf.Substring(21, 4); + try { + UTCOffset = int.Parse(tempString); + } + catch (System.Exception e) { + throw new System.ArgumentOutOfRangeException(null, e.Message); + } + OffsetToBeAdjusted = ((int)((OffsetMins - UTCOffset))); + datetime = datetime.AddMinutes(((double)(OffsetToBeAdjusted))); + } + return datetime; + } + + // Converts a given System.DateTime object to DMTF datetime format. + static string ToDmtfDateTime(System.DateTime date) { + string utcString = string.Empty; + System.TimeSpan tickOffset = System.TimeZone.CurrentTimeZone.GetUtcOffset(date); + long OffsetMins = ((long)((tickOffset.Ticks / System.TimeSpan.TicksPerMinute))); + if ((System.Math.Abs(OffsetMins) > 999)) { + date = date.ToUniversalTime(); + utcString = "+000"; + } + else { + if ((tickOffset.Ticks >= 0)) { + utcString = string.Concat("+", ((long)((tickOffset.Ticks / System.TimeSpan.TicksPerMinute))).ToString().PadLeft(3, '0')); + } + else { + string strTemp = ((long)(OffsetMins)).ToString(); + utcString = string.Concat("-", strTemp.Substring(1, (strTemp.Length - 1)).PadLeft(3, '0')); + } + } + string dmtfDateTime = ((int)(date.Year)).ToString().PadLeft(4, '0'); + dmtfDateTime = string.Concat(dmtfDateTime, ((int)(date.Month)).ToString().PadLeft(2, '0')); + dmtfDateTime = string.Concat(dmtfDateTime, ((int)(date.Day)).ToString().PadLeft(2, '0')); + dmtfDateTime = string.Concat(dmtfDateTime, ((int)(date.Hour)).ToString().PadLeft(2, '0')); + dmtfDateTime = string.Concat(dmtfDateTime, ((int)(date.Minute)).ToString().PadLeft(2, '0')); + dmtfDateTime = string.Concat(dmtfDateTime, ((int)(date.Second)).ToString().PadLeft(2, '0')); + dmtfDateTime = string.Concat(dmtfDateTime, "."); + System.DateTime dtTemp = new System.DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, 0); + long microsec = ((long)((((date.Ticks - dtTemp.Ticks) + * 1000) + / System.TimeSpan.TicksPerMillisecond))); + string strMicrosec = ((long)(microsec)).ToString(); + if ((strMicrosec.Length > 6)) { + strMicrosec = strMicrosec.Substring(0, 6); + } + dmtfDateTime = string.Concat(dmtfDateTime, strMicrosec.PadLeft(6, '0')); + dmtfDateTime = string.Concat(dmtfDateTime, utcString); + return dmtfDateTime; + } + + private bool ShouldSerializeInstallDate() { + if ((this.IsInstallDateNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeLastErrorCode() { + if ((this.IsLastErrorCodeNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeMaxQuiesceTime() { + if ((this.IsMaxQuiesceTimeNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeOperatingStatus() { + if ((this.IsOperatingStatusNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializePowerManagementSupported() { + if ((this.IsPowerManagementSupportedNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializePowerOnHours() { + if ((this.IsPowerOnHoursNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializePrimaryStatus() { + if ((this.IsPrimaryStatusNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeRequestedState() { + if ((this.IsRequestedStateNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeStatusInfo() { + if ((this.IsStatusInfoNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeTimeOfLastStateChange() { + if ((this.IsTimeOfLastStateChangeNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeTotalPowerOnHours() { + if ((this.IsTotalPowerOnHoursNull == false)) { + return true; + } + return false; + } + + private bool ShouldSerializeTransitioningToState() { + if ((this.IsTransitioningToStateNull == false)) { + return true; + } + return false; + } + + [Browsable(true)] + public void CommitObject() { + if ((isEmbedded == false)) { + PrivateLateBoundObject.Put(); + } + } + + [Browsable(true)] + public void CommitObject(System.Management.PutOptions putOptions) { + if ((isEmbedded == false)) { + PrivateLateBoundObject.Put(putOptions); + } + } + + private void Initialize() { + AutoCommitProp = true; + isEmbedded = false; + } + + private static string ConstructPath(string keyCreationClassName, string keyDeviceID, string keySystemCreationClassName, string keySystemName) { + string strPath = "ROOT\\virtualization\\v2:Msvm_ShutdownComponent"; + strPath = string.Concat(strPath, string.Concat(".CreationClassName=", string.Concat("\"", string.Concat(keyCreationClassName, "\"")))); + strPath = string.Concat(strPath, string.Concat(",DeviceID=", string.Concat("\"", string.Concat(keyDeviceID, "\"")))); + strPath = string.Concat(strPath, string.Concat(",SystemCreationClassName=", string.Concat("\"", string.Concat(keySystemCreationClassName, "\"")))); + strPath = string.Concat(strPath, string.Concat(",SystemName=", string.Concat("\"", string.Concat(keySystemName, "\"")))); + return strPath; + } + + private void InitializeObject(System.Management.ManagementScope mgmtScope, System.Management.ManagementPath path, System.Management.ObjectGetOptions getOptions) { + Initialize(); + if ((path != null)) { + if ((CheckIfProperClass(mgmtScope, path, getOptions) != true)) { + throw new System.ArgumentException("Class name does not match."); + } + } + PrivateLateBoundObject = new System.Management.ManagementObject(mgmtScope, path, getOptions); + PrivateSystemProperties = new ManagementSystemProperties(PrivateLateBoundObject); + curObj = PrivateLateBoundObject; + } + + // Different overloads of GetInstances() help in enumerating instances of the WMI class. + public static ShutdownComponentCollection GetInstances() { + return GetInstances(null, null, null); + } + + public static ShutdownComponentCollection GetInstances(string condition) { + return GetInstances(null, condition, null); + } + + public static ShutdownComponentCollection GetInstances(string[] selectedProperties) { + return GetInstances(null, null, selectedProperties); + } + + public static ShutdownComponentCollection GetInstances(string condition, string[] selectedProperties) { + return GetInstances(null, condition, selectedProperties); + } + + public static ShutdownComponentCollection GetInstances(System.Management.ManagementScope mgmtScope, System.Management.EnumerationOptions enumOptions) { + if ((mgmtScope == null)) { + if ((statMgmtScope == null)) { + mgmtScope = new System.Management.ManagementScope(); + mgmtScope.Path.NamespacePath = "root\\virtualization\\v2"; + } + else { + mgmtScope = statMgmtScope; + } + } + System.Management.ManagementPath pathObj = new System.Management.ManagementPath(); + pathObj.ClassName = "Msvm_ShutdownComponent"; + pathObj.NamespacePath = "root\\virtualization\\v2"; + System.Management.ManagementClass clsObject = new System.Management.ManagementClass(mgmtScope, pathObj, null); + if ((enumOptions == null)) { + enumOptions = new System.Management.EnumerationOptions(); + enumOptions.EnsureLocatable = true; + } + return new ShutdownComponentCollection(clsObject.GetInstances(enumOptions)); + } + + public static ShutdownComponentCollection GetInstances(System.Management.ManagementScope mgmtScope, string condition) { + return GetInstances(mgmtScope, condition, null); + } + + public static ShutdownComponentCollection GetInstances(System.Management.ManagementScope mgmtScope, string[] selectedProperties) { + return GetInstances(mgmtScope, null, selectedProperties); + } + + public static ShutdownComponentCollection GetInstances(System.Management.ManagementScope mgmtScope, string condition, string[] selectedProperties) { + if ((mgmtScope == null)) { + if ((statMgmtScope == null)) { + mgmtScope = new System.Management.ManagementScope(); + mgmtScope.Path.NamespacePath = "root\\virtualization\\v2"; + } + else { + mgmtScope = statMgmtScope; + } + } + System.Management.ManagementObjectSearcher ObjectSearcher = new System.Management.ManagementObjectSearcher(mgmtScope, new SelectQuery("Msvm_ShutdownComponent", condition, selectedProperties)); + System.Management.EnumerationOptions enumOptions = new System.Management.EnumerationOptions(); + enumOptions.EnsureLocatable = true; + ObjectSearcher.Options = enumOptions; + return new ShutdownComponentCollection(ObjectSearcher.Get()); + } + + [Browsable(true)] + public static ShutdownComponent CreateInstance() { + System.Management.ManagementScope mgmtScope = null; + if ((statMgmtScope == null)) { + mgmtScope = new System.Management.ManagementScope(); + mgmtScope.Path.NamespacePath = CreatedWmiNamespace; + } + else { + mgmtScope = statMgmtScope; + } + System.Management.ManagementPath mgmtPath = new System.Management.ManagementPath(CreatedClassName); + System.Management.ManagementClass tmpMgmtClass = new System.Management.ManagementClass(mgmtScope, mgmtPath, null); + return new ShutdownComponent(tmpMgmtClass.CreateInstance()); + } + + [Browsable(true)] + public void Delete() { + PrivateLateBoundObject.Delete(); + } + + public uint EnableDevice(bool Enabled) { + if ((isEmbedded == false)) { + System.Management.ManagementBaseObject inParams = null; + inParams = PrivateLateBoundObject.GetMethodParameters("EnableDevice"); + inParams["Enabled"] = ((bool)(Enabled)); + System.Management.ManagementBaseObject outParams = PrivateLateBoundObject.InvokeMethod("EnableDevice", inParams, null); + return System.Convert.ToUInt32(outParams.Properties["ReturnValue"].Value); + } + else { + return System.Convert.ToUInt32(0); + } + } + + public uint InitiateShutdown(bool Force, string Reason) { + if ((isEmbedded == false)) { + System.Management.ManagementBaseObject inParams = null; + inParams = PrivateLateBoundObject.GetMethodParameters("InitiateShutdown"); + inParams["Force"] = ((bool)(Force)); + inParams["Reason"] = ((string)(Reason)); + System.Management.ManagementBaseObject outParams = PrivateLateBoundObject.InvokeMethod("InitiateShutdown", inParams, null); + return System.Convert.ToUInt32(outParams.Properties["ReturnValue"].Value); + } + else { + return System.Convert.ToUInt32(0); + } + } + + public uint OnlineDevice(bool Online) { + if ((isEmbedded == false)) { + System.Management.ManagementBaseObject inParams = null; + inParams = PrivateLateBoundObject.GetMethodParameters("OnlineDevice"); + inParams["Online"] = ((bool)(Online)); + System.Management.ManagementBaseObject outParams = PrivateLateBoundObject.InvokeMethod("OnlineDevice", inParams, null); + return System.Convert.ToUInt32(outParams.Properties["ReturnValue"].Value); + } + else { + return System.Convert.ToUInt32(0); + } + } + + public uint QuiesceDevice(bool Quiesce) { + if ((isEmbedded == false)) { + System.Management.ManagementBaseObject inParams = null; + inParams = PrivateLateBoundObject.GetMethodParameters("QuiesceDevice"); + inParams["Quiesce"] = ((bool)(Quiesce)); + System.Management.ManagementBaseObject outParams = PrivateLateBoundObject.InvokeMethod("QuiesceDevice", inParams, null); + return System.Convert.ToUInt32(outParams.Properties["ReturnValue"].Value); + } + else { + return System.Convert.ToUInt32(0); + } + } + + public uint RequestStateChange(ushort RequestedState, System.DateTime TimeoutPeriod, out System.Management.ManagementPath Job) { + if ((isEmbedded == false)) { + System.Management.ManagementBaseObject inParams = null; + inParams = PrivateLateBoundObject.GetMethodParameters("RequestStateChange"); + inParams["RequestedState"] = ((ushort)(RequestedState)); + inParams["TimeoutPeriod"] = ToDmtfDateTime(((System.DateTime)(TimeoutPeriod))); + System.Management.ManagementBaseObject outParams = PrivateLateBoundObject.InvokeMethod("RequestStateChange", inParams, null); + Job = null; + if ((outParams.Properties["Job"] != null)) { + Job = new System.Management.ManagementPath(outParams.Properties["Job"].ToString()); + } + return System.Convert.ToUInt32(outParams.Properties["ReturnValue"].Value); + } + else { + Job = null; + return System.Convert.ToUInt32(0); + } + } + + public uint Reset() { + if ((isEmbedded == false)) { + System.Management.ManagementBaseObject inParams = null; + System.Management.ManagementBaseObject outParams = PrivateLateBoundObject.InvokeMethod("Reset", inParams, null); + return System.Convert.ToUInt32(outParams.Properties["ReturnValue"].Value); + } + else { + return System.Convert.ToUInt32(0); + } + } + + public uint RestoreProperties() { + if ((isEmbedded == false)) { + System.Management.ManagementBaseObject inParams = null; + System.Management.ManagementBaseObject outParams = PrivateLateBoundObject.InvokeMethod("RestoreProperties", inParams, null); + return System.Convert.ToUInt32(outParams.Properties["ReturnValue"].Value); + } + else { + return System.Convert.ToUInt32(0); + } + } + + public uint SaveProperties() { + if ((isEmbedded == false)) { + System.Management.ManagementBaseObject inParams = null; + System.Management.ManagementBaseObject outParams = PrivateLateBoundObject.InvokeMethod("SaveProperties", inParams, null); + return System.Convert.ToUInt32(outParams.Properties["ReturnValue"].Value); + } + else { + return System.Convert.ToUInt32(0); + } + } + + public uint SetPowerState(ushort PowerState, System.DateTime Time) { + if ((isEmbedded == false)) { + System.Management.ManagementBaseObject inParams = null; + inParams = PrivateLateBoundObject.GetMethodParameters("SetPowerState"); + inParams["PowerState"] = ((ushort)(PowerState)); + inParams["Time"] = ToDmtfDateTime(((System.DateTime)(Time))); + System.Management.ManagementBaseObject outParams = PrivateLateBoundObject.InvokeMethod("SetPowerState", inParams, null); + return System.Convert.ToUInt32(outParams.Properties["ReturnValue"].Value); + } + else { + return System.Convert.ToUInt32(0); + } + } + + // Enumerator implementation for enumerating instances of the class. + public class ShutdownComponentCollection : object, ICollection { + + private ManagementObjectCollection privColObj; + + public ShutdownComponentCollection(ManagementObjectCollection objCollection) { + privColObj = objCollection; + } + + public virtual int Count { + get { + return privColObj.Count; + } + } + + public virtual bool IsSynchronized { + get { + return privColObj.IsSynchronized; + } + } + + public virtual object SyncRoot { + get { + return this; + } + } + + public virtual void CopyTo(System.Array array, int index) { + privColObj.CopyTo(array, index); + int nCtr; + for (nCtr = 0; (nCtr < array.Length); nCtr = (nCtr + 1)) { + array.SetValue(new ShutdownComponent(((System.Management.ManagementObject)(array.GetValue(nCtr)))), nCtr); + } + } + + public virtual System.Collections.IEnumerator GetEnumerator() { + return new ShutdownComponentEnumerator(privColObj.GetEnumerator()); + } + + public class ShutdownComponentEnumerator : object, System.Collections.IEnumerator { + + private ManagementObjectCollection.ManagementObjectEnumerator privObjEnum; + + public ShutdownComponentEnumerator(ManagementObjectCollection.ManagementObjectEnumerator objEnum) { + privObjEnum = objEnum; + } + + public virtual object Current { + get { + return new ShutdownComponent(((System.Management.ManagementObject)(privObjEnum.Current))); + } + } + + public virtual bool MoveNext() { + return privObjEnum.MoveNext(); + } + + public virtual void Reset() { + privObjEnum.Reset(); + } + } + } + + // TypeConverter to handle null values for ValueType properties + public class WMIValueTypeConverter : TypeConverter { + + private TypeConverter baseConverter; + + private System.Type baseType; + + public WMIValueTypeConverter(System.Type inBaseType) { + baseConverter = TypeDescriptor.GetConverter(inBaseType); + baseType = inBaseType; + } + + public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type srcType) { + return baseConverter.CanConvertFrom(context, srcType); + } + + public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type destinationType) { + return baseConverter.CanConvertTo(context, destinationType); + } + + public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) { + return baseConverter.ConvertFrom(context, culture, value); + } + + public override object CreateInstance(System.ComponentModel.ITypeDescriptorContext context, System.Collections.IDictionary dictionary) { + return baseConverter.CreateInstance(context, dictionary); + } + + public override bool GetCreateInstanceSupported(System.ComponentModel.ITypeDescriptorContext context) { + return baseConverter.GetCreateInstanceSupported(context); + } + + public override PropertyDescriptorCollection GetProperties(System.ComponentModel.ITypeDescriptorContext context, object value, System.Attribute[] attributeVar) { + return baseConverter.GetProperties(context, value, attributeVar); + } + + public override bool GetPropertiesSupported(System.ComponentModel.ITypeDescriptorContext context) { + return baseConverter.GetPropertiesSupported(context); + } + + public override System.ComponentModel.TypeConverter.StandardValuesCollection GetStandardValues(System.ComponentModel.ITypeDescriptorContext context) { + return baseConverter.GetStandardValues(context); + } + + public override bool GetStandardValuesExclusive(System.ComponentModel.ITypeDescriptorContext context) { + return baseConverter.GetStandardValuesExclusive(context); + } + + public override bool GetStandardValuesSupported(System.ComponentModel.ITypeDescriptorContext context) { + return baseConverter.GetStandardValuesSupported(context); + } + + public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType) { + if ((baseType.BaseType == typeof(System.Enum))) { + if ((value.GetType() == destinationType)) { + return value; + } + if ((((value == null) + && (context != null)) + && (context.PropertyDescriptor.ShouldSerializeValue(context.Instance) == false))) { + return "NULL_ENUM_VALUE" ; + } + return baseConverter.ConvertTo(context, culture, value, destinationType); + } + if (((baseType == typeof(bool)) + && (baseType.BaseType == typeof(System.ValueType)))) { + if ((((value == null) + && (context != null)) + && (context.PropertyDescriptor.ShouldSerializeValue(context.Instance) == false))) { + return ""; + } + return baseConverter.ConvertTo(context, culture, value, destinationType); + } + if (((context != null) + && (context.PropertyDescriptor.ShouldSerializeValue(context.Instance) == false))) { + return ""; + } + return baseConverter.ConvertTo(context, culture, value, destinationType); + } + } + + // Embedded class to represent WMI system Properties. + [TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))] + public class ManagementSystemProperties { + + private System.Management.ManagementBaseObject PrivateLateBoundObject; + + public ManagementSystemProperties(System.Management.ManagementBaseObject ManagedObject) { + PrivateLateBoundObject = ManagedObject; + } + + [Browsable(true)] + public int GENUS { + get { + return ((int)(PrivateLateBoundObject["__GENUS"])); + } + } + + [Browsable(true)] + public string CLASS { + get { + return ((string)(PrivateLateBoundObject["__CLASS"])); + } + } + + [Browsable(true)] + public string SUPERCLASS { + get { + return ((string)(PrivateLateBoundObject["__SUPERCLASS"])); + } + } + + [Browsable(true)] + public string DYNASTY { + get { + return ((string)(PrivateLateBoundObject["__DYNASTY"])); + } + } + + [Browsable(true)] + public string RELPATH { + get { + return ((string)(PrivateLateBoundObject["__RELPATH"])); + } + } + + [Browsable(true)] + public int PROPERTY_COUNT { + get { + return ((int)(PrivateLateBoundObject["__PROPERTY_COUNT"])); + } + } + + [Browsable(true)] + public string[] DERIVATION { + get { + return ((string[])(PrivateLateBoundObject["__DERIVATION"])); + } + } + + [Browsable(true)] + public string SERVER { + get { + return ((string)(PrivateLateBoundObject["__SERVER"])); + } + } + + [Browsable(true)] + public string NAMESPACE { + get { + return ((string)(PrivateLateBoundObject["__NAMESPACE"])); + } + } + + [Browsable(true)] + public string PATH { + get { + return ((string)(PrivateLateBoundObject["__PATH"])); + } + } + } + } +} diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/WmiWrappers.csproj b/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/WmiWrappers.csproj index 70ae8e86390..5404736ae6d 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/WmiWrappers.csproj +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/WmiWrappers.csproj @@ -135,6 +135,9 @@ Component + + Component + Component @@ -181,8 +184,8 @@ - - + +