diff --git a/.gitignore b/.gitignore index 5efa7bbb5ca..8e3b0525daa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# Licensed to the Apache Software Foundation (ASF) under one +G# 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 @@ -83,3 +83,5 @@ build-indep-stamp configure-stamp *_flymake.js engine/storage/integration-test/test-output +tools/apidoc/log/ +log/ diff --git a/agent/src/com/cloud/agent/resource/DummyResource.java b/agent/src/com/cloud/agent/resource/DummyResource.java index 37a8b3d67e7..4918207546c 100755 --- a/agent/src/com/cloud/agent/resource/DummyResource.java +++ b/agent/src/com/cloud/agent/resource/DummyResource.java @@ -169,7 +169,7 @@ public class DummyResource implements ServerResource { final StartupRoutingCommand cmd = new StartupRoutingCommand( (Integer) info.get(0), (Long) info.get(1), (Long) info.get(2), (Long) info.get(4), (String) info.get(3), HypervisorType.KVM, - RouterPrivateIpStrategy.HostLocal, changes); + RouterPrivateIpStrategy.HostLocal, changes, null); fillNetworkInformation(cmd); cmd.getHostDetails().putAll(getVersionStrings()); cmd.setCluster(getConfiguredProperty("cluster", "1")); diff --git a/api/src/com/cloud/agent/api/HostVmStateReportEntry.java b/api/src/com/cloud/agent/api/HostVmStateReportEntry.java index 7bcb50f361a..0b1a01e97e7 100644 --- a/api/src/com/cloud/agent/api/HostVmStateReportEntry.java +++ b/api/src/com/cloud/agent/api/HostVmStateReportEntry.java @@ -19,16 +19,29 @@ package com.cloud.agent.api; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.PowerState; +// +// TODO vmsync +// We should also have a HostVmStateReport class instead of using raw Map<> data structure, +// for now, we store host-specific info at each VM entry and host fields are fixed +// +// This needs to be refactor-ed afterwards +// public class HostVmStateReportEntry { VirtualMachine.PowerState state; + + // host name or host uuid String host; + + // XS needs Xen Tools version info + String hostToolsVersion; public HostVmStateReportEntry() { } - public HostVmStateReportEntry(PowerState state, String host) { + public HostVmStateReportEntry(PowerState state, String host, String hostToolsVersion) { this.state = state; this.host = host; + this.hostToolsVersion = hostToolsVersion; } public PowerState getState() { @@ -38,4 +51,8 @@ public class HostVmStateReportEntry { public String getHost() { return host; } + + public String getHostToolsVersion() { + return hostToolsVersion; + } } diff --git a/api/src/com/cloud/deploy/DeploymentClusterPlanner.java b/api/src/com/cloud/deploy/DeploymentClusterPlanner.java index ca73267e732..b4782239a35 100644 --- a/api/src/com/cloud/deploy/DeploymentClusterPlanner.java +++ b/api/src/com/cloud/deploy/DeploymentClusterPlanner.java @@ -20,10 +20,20 @@ import java.util.List; import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.vm.VirtualMachineProfile; +import org.apache.cloudstack.framework.config.ConfigKey; /** */ public interface DeploymentClusterPlanner extends DeploymentPlanner { + + static final String ClusterCPUCapacityDisableThresholdCK = "cluster.cpu.allocated.capacity.disablethreshold"; + static final String ClusterMemoryCapacityDisableThresholdCK = "cluster.memory.allocated.capacity.disablethreshold"; + + static final ConfigKey ClusterCPUCapacityDisableThreshold = new ConfigKey(Float.class, ClusterCPUCapacityDisableThresholdCK, "Alert", "0.85", + "Percentage (as a value between 0 and 1) of cpu utilization above which allocators will disable using the cluster for low cpu available. Keep the corresponding notification threshold lower than this to be notified beforehand.", true, ConfigKey.Scope.Cluster, null); + static final ConfigKey ClusterMemoryCapacityDisableThreshold = new ConfigKey(Float.class, ClusterMemoryCapacityDisableThresholdCK, "Alert", "0.85", + "Percentage (as a value between 0 and 1) of memory utilization above which allocators will disable using the cluster for low memory available. Keep the corresponding notification threshold lower than this to be notified beforehand.", true, ConfigKey.Scope.Cluster, null); + /** * This is called to determine list of possible clusters where a virtual * machine can be deployed. diff --git a/api/src/com/cloud/network/lb/SslCert.java b/api/src/com/cloud/network/lb/SslCert.java index f7a7c4b790e..56555b64dae 100644 --- a/api/src/com/cloud/network/lb/SslCert.java +++ b/api/src/com/cloud/network/lb/SslCert.java @@ -1,3 +1,19 @@ +// 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. package com.cloud.network.lb; diff --git a/api/src/com/cloud/server/ResourceTag.java b/api/src/com/cloud/server/ResourceTag.java index ab74d260dc3..ba1aeb8ee9a 100644 --- a/api/src/com/cloud/server/ResourceTag.java +++ b/api/src/com/cloud/server/ResourceTag.java @@ -31,17 +31,17 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit Snapshot (true, false), Network (true, true), Nic (false, true), - LoadBalancer (true, false), - PortForwardingRule (true, false), + LoadBalancer (true, true), + PortForwardingRule (true, true), FirewallRule (true, true), SecurityGroup (true, false), - PublicIpAddress (true, false), + PublicIpAddress (true, true), Project (true, false), Vpc (true, false), NetworkACL (true, false), StaticRoute (true, false), VMSnapshot (true, false), - RemoteAccessVpn (true, false), + RemoteAccessVpn (true, true), Zone (false, true), ServiceOffering (false, true), Storage(false, true); diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 82b2af69759..ea3137d107d 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -223,6 +223,7 @@ public class ApiConstants { public static final String STATUS = "status"; public static final String STORAGE_TYPE = "storagetype"; public static final String STORAGE_MOTION_ENABLED = "storagemotionenabled"; + public static final String STORAGE_CAPABILITIES = "storagecapabilities"; public static final String SYSTEM_VM_TYPE = "systemvmtype"; public static final String TAGS = "tags"; public static final String TARGET_IQN = "targetiqn"; diff --git a/api/src/org/apache/cloudstack/api/command/user/firewall/ListFirewallRulesCmd.java b/api/src/org/apache/cloudstack/api/command/user/firewall/ListFirewallRulesCmd.java index c2aee55f51e..ae1a2dd69a2 100644 --- a/api/src/org/apache/cloudstack/api/command/user/firewall/ListFirewallRulesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/firewall/ListFirewallRulesCmd.java @@ -27,6 +27,7 @@ import org.apache.cloudstack.api.response.FirewallResponse; import org.apache.cloudstack.api.response.FirewallRuleResponse; import org.apache.cloudstack.api.response.IPAddressResponse; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.log4j.Logger; import com.cloud.network.rules.FirewallRule; @@ -47,6 +48,10 @@ public class ListFirewallRulesCmd extends BaseListTaggedResourcesCmd { @Parameter(name=ApiConstants.IP_ADDRESS_ID, type=CommandType.UUID, entityType = IPAddressResponse.class, description="the id of IP address of the firwall services") private Long ipAddressId; + + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class, + description="list firewall rules for ceratin network", since="4.3") + private Long networkId; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -63,6 +68,10 @@ public class ListFirewallRulesCmd extends BaseListTaggedResourcesCmd { public Long getId() { return id; } + + public Long getNetworkId() { + return networkId; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/firewall/ListPortForwardingRulesCmd.java b/api/src/org/apache/cloudstack/api/command/user/firewall/ListPortForwardingRulesCmd.java index 9fd4e450ea6..7e96e0b2fab 100644 --- a/api/src/org/apache/cloudstack/api/command/user/firewall/ListPortForwardingRulesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/firewall/ListPortForwardingRulesCmd.java @@ -26,6 +26,7 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.response.FirewallRuleResponse; import org.apache.cloudstack.api.response.IPAddressResponse; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.log4j.Logger; import com.cloud.network.rules.PortForwardingRule; @@ -48,6 +49,10 @@ public class ListPortForwardingRulesCmd extends BaseListTaggedResourcesCmd { @Parameter(name=ApiConstants.IP_ADDRESS_ID, type=CommandType.UUID, entityType = IPAddressResponse.class, description="the id of IP address of the port forwarding services") private Long ipAddressId; + + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class, + description="list port forwarding rules for ceratin network", since="4.3") + private Long networkId; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -60,6 +65,10 @@ public class ListPortForwardingRulesCmd extends BaseListTaggedResourcesCmd { public Long getId() { return id; } + + public Long getNetworkId() { + return networkId; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/vpn/ListRemoteAccessVpnsCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpn/ListRemoteAccessVpnsCmd.java index 12ee95ba5f4..3b4d6cdb2a0 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpn/ListRemoteAccessVpnsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpn/ListRemoteAccessVpnsCmd.java @@ -25,6 +25,7 @@ import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.response.IPAddressResponse; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.cloudstack.api.response.RemoteAccessVpnResponse; import org.apache.log4j.Logger; @@ -41,8 +42,16 @@ public class ListRemoteAccessVpnsCmd extends BaseListProjectAndAccountResourcesC //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// @Parameter(name=ApiConstants.PUBLIC_IP_ID, type=CommandType.UUID, entityType=IPAddressResponse.class, - required=true, description="public ip address id of the vpn server") + description="public ip address id of the vpn server") private Long publicIpId; + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = RemoteAccessVpnResponse.class, + description="Lists remote access vpn rule with the specified ID", since="4.3") + private Long id; + + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class, + description="list remote access VPNs for ceratin network", since="4.3") + private Long networkId; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -52,6 +61,14 @@ public class ListRemoteAccessVpnsCmd extends BaseListProjectAndAccountResourcesC public Long getPublicIpId() { return publicIpId; } + + public Long getId() { + return id; + } + + public Long getNetworkId() { + return networkId; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/api/response/FirewallRuleResponse.java b/api/src/org/apache/cloudstack/api/response/FirewallRuleResponse.java index 787410a24c5..20ea407e2b7 100644 --- a/api/src/org/apache/cloudstack/api/response/FirewallRuleResponse.java +++ b/api/src/org/apache/cloudstack/api/response/FirewallRuleResponse.java @@ -73,6 +73,9 @@ public class FirewallRuleResponse extends BaseResponse { @SerializedName(ApiConstants.VM_GUEST_IP) @Param(description="the vm ip address for the port forwarding rule") private String destNatVmIp; + + @SerializedName(ApiConstants.NETWORK_ID) @Param(description="the id of the guest network the port forwarding rule belongs to") + private String networkId; public String getDestNatVmIp() { @@ -196,4 +199,8 @@ public class FirewallRuleResponse extends BaseResponse { public void setTags(List tags) { this.tags = tags; } + + public void setNetworkId(String networkId) { + this.networkId = networkId; + } } diff --git a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java index 7321d98b476..1c943774e41 100644 --- a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java +++ b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java @@ -25,6 +25,7 @@ import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; import java.util.Date; +import java.util.Map; @EntityReference(value=StoragePool.class) public class StoragePoolResponse extends BaseResponse { @@ -93,6 +94,16 @@ public class StoragePoolResponse extends BaseResponse { " false otherwise") private Boolean suitableForMigration; + @SerializedName(ApiConstants.STORAGE_CAPABILITIES) @Param(description="the storage pool capabilities") + private Map caps; + + public Map getCaps() { + return caps; + } + + public void setCaps(Map cap) { + this.caps = cap; + } /** * @return the scope */ diff --git a/client/tomcatconf/db.properties.in b/client/tomcatconf/db.properties.in index 31e08033370..b224cec9700 100644 --- a/client/tomcatconf/db.properties.in +++ b/client/tomcatconf/db.properties.in @@ -85,6 +85,7 @@ db.simulator.autoReconnect=true # High Availability And Cluster Properties db.ha.enabled=false +db.ha.loadBalanceStrategy=com.cloud.utils.db.StaticStrategy # cloud stack Database db.cloud.slaves=localhost,localhost db.cloud.autoReconnect=true 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 a8b2e2954af..be11a1f711f 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 @@ -213,6 +213,16 @@ + + + + + + + + + diff --git a/core/resources/META-INF/cloudstack/network/spring-core-lifecycle-network-context-inheritable.xml b/core/resources/META-INF/cloudstack/network/spring-core-lifecycle-network-context-inheritable.xml index 3388ca41284..a54d58818bc 100644 --- a/core/resources/META-INF/cloudstack/network/spring-core-lifecycle-network-context-inheritable.xml +++ b/core/resources/META-INF/cloudstack/network/spring-core-lifecycle-network-context-inheritable.xml @@ -90,5 +90,11 @@ + + + + + \ No newline at end of file diff --git a/core/src/com/cloud/agent/api/PingRoutingCommand.java b/core/src/com/cloud/agent/api/PingRoutingCommand.java index e25ac62786f..cffa7ecab21 100755 --- a/core/src/com/cloud/agent/api/PingRoutingCommand.java +++ b/core/src/com/cloud/agent/api/PingRoutingCommand.java @@ -22,21 +22,33 @@ import com.cloud.host.Host; import com.cloud.vm.VirtualMachine.State; public class PingRoutingCommand extends PingCommand { - Map newStates; + + // TODO vmsync { + Map newStates; + // TODO vmsync } + + Map _hostVmStateReport; + boolean _gatewayAccessible = true; boolean _vnetAccessible = true; protected PingRoutingCommand() { } - public PingRoutingCommand(Host.Type type, long id, Map states) { + public PingRoutingCommand(Host.Type type, long id, Map states, + Map hostVmStateReport) { super(type, id); this.newStates = states; + this._hostVmStateReport = hostVmStateReport; } public Map getNewStates() { return newStates; } + + public Map getHostVmStateReport() { + return this._hostVmStateReport; + } public boolean isGatewayAccessible() { return _gatewayAccessible; diff --git a/core/src/com/cloud/agent/api/PingRoutingWithNwGroupsCommand.java b/core/src/com/cloud/agent/api/PingRoutingWithNwGroupsCommand.java index 51226bc36c1..5a25a7583ce 100644 --- a/core/src/com/cloud/agent/api/PingRoutingWithNwGroupsCommand.java +++ b/core/src/com/cloud/agent/api/PingRoutingWithNwGroupsCommand.java @@ -31,8 +31,10 @@ public class PingRoutingWithNwGroupsCommand extends PingRoutingCommand { super(); } - public PingRoutingWithNwGroupsCommand(Host.Type type, long id, Map states, HashMap> nwGrpStates) { - super(type, id, states); + public PingRoutingWithNwGroupsCommand(Host.Type type, long id, + Map states, Map hostVmStateReport, + HashMap> nwGrpStates) { + super(type, id, states, hostVmStateReport); newGroupStates = nwGrpStates; } diff --git a/core/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java b/core/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java index d44987b20fd..b87dd0a7e96 100644 --- a/core/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java +++ b/core/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java @@ -31,8 +31,10 @@ public class PingRoutingWithOvsCommand extends PingRoutingCommand { } public PingRoutingWithOvsCommand(Host.Type type, long id, - Map states, List> ovsStates) { - super(type, id, states); + Map states, Map hostVmStateReport, + List> ovsStates) { + super(type, id, states, hostVmStateReport); + this.states = ovsStates; } diff --git a/core/src/com/cloud/agent/api/StartupRoutingCommand.java b/core/src/com/cloud/agent/api/StartupRoutingCommand.java index f312e0fc72d..c75b6d1e73f 100755 --- a/core/src/com/cloud/agent/api/StartupRoutingCommand.java +++ b/core/src/com/cloud/agent/api/StartupRoutingCommand.java @@ -48,8 +48,18 @@ public class StartupRoutingCommand extends StartupCommand { long memory; long dom0MinMemory; boolean poolSync; + + // VM power state report is added in a side-by-side way as old VM state report + // this is to allow a graceful migration from the old VM state sync model to the new model + // + // side-by-side addition of power state sync + Map _hostVmStateReport; + + // TODO vmsync + // deprecated, will delete after full replacement Map vms; HashMap> _clusterVMStates; + String caps; String pool; HypervisorType hypervisorType; @@ -70,8 +80,10 @@ public class StartupRoutingCommand extends StartupCommand { String caps, HypervisorType hypervisorType, RouterPrivateIpStrategy privIpStrategy, - Map vms) { - this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, vms); + Map vms, + Map hostVmStateReport + ) { + this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, vms, hostVmStateReport); getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStrategy.toString()); } @@ -82,9 +94,11 @@ public class StartupRoutingCommand extends StartupCommand { String caps, HypervisorType hypervisorType, RouterPrivateIpStrategy privIpStrategy) { -this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, new HashMap(), new HashMap()); -getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStrategy.toString()); -} + this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, new HashMap(), + new HashMap(), new HashMap()); + + getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStrategy.toString()); + } public StartupRoutingCommand(int cpus, long speed, @@ -93,13 +107,15 @@ getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStr final String caps, final HypervisorType hypervisorType, final Map hostDetails, - Map vms) { + Map vms, + Map hostVmStateReport) { super(Host.Type.Routing); this.cpus = cpus; this.speed = speed; this.memory = memory; this.dom0MinMemory = dom0MinMemory; this.vms = vms; + this._hostVmStateReport = hostVmStateReport; this.hypervisorType = hypervisorType; this.hostDetails = hostDetails; this.caps = caps; @@ -108,12 +124,14 @@ getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStr public StartupRoutingCommand(int cpus2, long speed2, long memory2, long dom0MinMemory2, String caps2, HypervisorType hypervisorType2, - Map vms2) { - this(cpus2, speed2, memory2, dom0MinMemory2, caps2, hypervisorType2, new HashMap(), vms2); + Map vms2, Map hostVmStateReport + ) { + this(cpus2, speed2, memory2, dom0MinMemory2, caps2, hypervisorType2, new HashMap(), vms2, hostVmStateReport); } - public StartupRoutingCommand(int cpus, long speed, long memory, long dom0MinMemory, final String caps, final HypervisorType hypervisorType, final Map hostDetails, Map vms, String hypervisorVersion) { - this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, hostDetails, vms); + public StartupRoutingCommand(int cpus, long speed, long memory, long dom0MinMemory, final String caps, final HypervisorType hypervisorType, final Map hostDetails, + Map vms, Map vmPowerStates, String hypervisorVersion) { + this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, hostDetails, vms, vmPowerStates); this.hypervisorVersion = hypervisorVersion; } @@ -229,5 +247,13 @@ getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStr public void setHypervisorVersion(String hypervisorVersion) { this.hypervisorVersion = hypervisorVersion; } + + public Map getHostVmStateReport() { + return this._hostVmStateReport; + } + + public void setHostVmStateReport(Map hostVmStateReport) { + this._hostVmStateReport = hostVmStateReport; + } } diff --git a/core/src/com/cloud/agent/api/VMSnapshotTO.java b/core/src/com/cloud/agent/api/VMSnapshotTO.java index 473c39a595d..9bc8712f3aa 100644 --- a/core/src/com/cloud/agent/api/VMSnapshotTO.java +++ b/core/src/com/cloud/agent/api/VMSnapshotTO.java @@ -31,6 +31,7 @@ public class VMSnapshotTO { private String description; private VMSnapshotTO parent; private List volumes; + private boolean quiescevm; public Long getId() { return id; @@ -40,7 +41,8 @@ public class VMSnapshotTO { } public VMSnapshotTO(Long id, String snapshotName, VMSnapshot.Type type, Long createTime, - String description, Boolean current, VMSnapshotTO parent) { + String description, Boolean current, VMSnapshotTO parent, + boolean quiescevm) { super(); this.id = id; this.snapshotName = snapshotName; @@ -49,9 +51,10 @@ public class VMSnapshotTO { this.current = current; this.description = description; this.parent = parent; + this.quiescevm = quiescevm; } public VMSnapshotTO() { - + this.quiescevm = true; } public String getDescription() { return description; @@ -99,4 +102,12 @@ public class VMSnapshotTO { public void setVolumes(List volumes) { this.volumes = volumes; } + + public boolean getQuiescevm() { + return this.quiescevm; + } + + public void setQuiescevm(boolean quiescevm) { + this.quiescevm = quiescevm; + } } diff --git a/debian/cloudstack-management.install b/debian/cloudstack-management.install index f06ab86dda1..ea3f93ba0cb 100644 --- a/debian/cloudstack-management.install +++ b/debian/cloudstack-management.install @@ -17,7 +17,6 @@ /etc/cloudstack/management/catalina.policy /etc/cloudstack/management/catalina.properties -/etc/cloudstack/management/cloudmanagementserver.keystore /etc/cloudstack/management/logging.properties /etc/cloudstack/management/commands.properties /etc/cloudstack/management/ehcache.xml diff --git a/developer/pom.xml b/developer/pom.xml index 0eb18bf2d3f..8ea0492e597 100644 --- a/developer/pom.xml +++ b/developer/pom.xml @@ -201,6 +201,7 @@ ${basedir}/target/db/create-schema-simulator.sql ${basedir}/target/db/templates.simulator.sql + ${basedir}/target/db/hypervisor_capabilities.simulator.sql com.cloud.upgrade.DatabaseUpgradeChecker --database=simulator diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreCapabilities.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreCapabilities.java new file mode 100644 index 00000000000..79ce92e0865 --- /dev/null +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreCapabilities.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +package org.apache.cloudstack.engine.subsystem.api.storage; + +public enum DataStoreCapabilities { + VOLUME_SNAPSHOT_QUIESCEVM +} diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java index 127b8589987..9e7329f118e 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java @@ -23,7 +23,10 @@ import com.cloud.agent.api.to.DataTO; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.command.CommandResult; +import java.util.Map; + public interface DataStoreDriver { + Map getCapabilities(); DataTO getTO(DataObject data); DataStoreTO getStoreTO(DataStore store); void createAsync(DataStore store, DataObject data, AsyncCompletionCallback callback); diff --git a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java index 39d470213a9..488caf572b5 100755 --- a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -258,7 +258,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl _creationMonitors.add(0, new Pair( _monitorId, creator)); } else { - _creationMonitors.add(0, new Pair( + _creationMonitors.add(new Pair( _monitorId, creator)); } } 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 f839d6cf343..991e052f5ef 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -738,6 +738,16 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati } catch (NoTransitionException e) { s_logger.debug("Unable to destroy existing volume: " + e.toString()); } + // In case of VMware VM will continue to use the old root disk until expunged, so force expunge old root disk + if (vm.getHypervisorType() == HypervisorType.VMware) { + s_logger.info("Expunging volume " + existingVolume.getId() + " from primary data store"); + AsyncCallFuture future = volService.expungeVolumeAsync(volFactory.getVolume(existingVolume.getId())); + try { + future.get(); + } catch (Exception e) { + s_logger.debug("Failed to expunge volume:" + existingVolume.getId(), e); + } + } return newVolume; } diff --git a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index c71190b5cf5..a8a1bffdb01 100644 --- a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -321,6 +321,8 @@ + + diff --git a/engine/schema/src/com/cloud/network/dao/NetworkVO.java b/engine/schema/src/com/cloud/network/dao/NetworkVO.java index 6580ea054f9..8f13e9d9524 100644 --- a/engine/schema/src/com/cloud/network/dao/NetworkVO.java +++ b/engine/schema/src/com/cloud/network/dao/NetworkVO.java @@ -189,7 +189,7 @@ public class NetworkVO implements Network { this.dataCenterId = dataCenterId; this.physicalNetworkId = physicalNetworkId; if (state == null) { - state = State.Allocated; + this.state = State.Allocated; } else { this.state = state; } diff --git a/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java b/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java index 483c28d295b..af0d9705d3f 100644 --- a/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java +++ b/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java @@ -1,3 +1,19 @@ +// 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. package com.cloud.network.dao; import com.cloud.utils.db.GenericDaoBase; diff --git a/engine/schema/src/com/cloud/storage/dao/SnapshotDetailsDao.java b/engine/schema/src/com/cloud/storage/dao/SnapshotDetailsDao.java new file mode 100644 index 00000000000..b216de6ed6a --- /dev/null +++ b/engine/schema/src/com/cloud/storage/dao/SnapshotDetailsDao.java @@ -0,0 +1,25 @@ +/* + * 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. + */ +package com.cloud.storage.dao; + +import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; + +public interface SnapshotDetailsDao extends GenericDao, ResourceDetailsDao { +} diff --git a/engine/schema/src/com/cloud/storage/dao/SnapshotDetailsDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/SnapshotDetailsDaoImpl.java new file mode 100644 index 00000000000..f8d3813d64d --- /dev/null +++ b/engine/schema/src/com/cloud/storage/dao/SnapshotDetailsDaoImpl.java @@ -0,0 +1,28 @@ +/* + * 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. + */ +package com.cloud.storage.dao; + +import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; + +public class SnapshotDetailsDaoImpl extends ResourceDetailsDaoBase implements SnapshotDetailsDao { + @Override + public void addDetail(long resourceId, String key, String value) { + super.addDetail(new SnapshotDetailsVO(resourceId, key, value)); + } +} diff --git a/engine/schema/src/com/cloud/storage/dao/SnapshotDetailsVO.java b/engine/schema/src/com/cloud/storage/dao/SnapshotDetailsVO.java new file mode 100644 index 00000000000..5406749563b --- /dev/null +++ b/engine/schema/src/com/cloud/storage/dao/SnapshotDetailsVO.java @@ -0,0 +1,72 @@ +/* + * 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. + */ +package com.cloud.storage.dao; + +import org.apache.cloudstack.api.ResourceDetail; + +import javax.persistence.*; + +@Entity +@Table(name = "snapshot_details") +public class SnapshotDetailsVO implements ResourceDetail { + @Id + @GeneratedValue(strategy= GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "snapshot_id") + private long resourceId; + + @Column(name = "name") + String name; + + @Column(name = "value") + String value; + + public SnapshotDetailsVO(Long resourceId, String name, String value) { + this.resourceId = resourceId; + this.name = name; + this.value = value; + } + + @Override + public long getResourceId() { + return resourceId; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getValue() { + return value; + } + + @Override + public boolean isDisplay() { + return false; + } + + @Override + public long getId() { + return id; + } +} diff --git a/engine/schema/src/com/cloud/storage/dao/VolumeDao.java b/engine/schema/src/com/cloud/storage/dao/VolumeDao.java index 1f5083a8e14..24ade51c3b4 100755 --- a/engine/schema/src/com/cloud/storage/dao/VolumeDao.java +++ b/engine/schema/src/com/cloud/storage/dao/VolumeDao.java @@ -37,6 +37,8 @@ public interface VolumeDao extends GenericDao, StateDao getNonDestroyedCountAndTotalByPool(long poolId); + long getVMSnapshotSizeByPool(long poolId); + List findByInstance(long id); List findByInstanceAndType(long id, Volume.Type vType); diff --git a/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java index 54b6465642e..2fb9dbae07d 100755 --- a/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java +++ b/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java @@ -59,6 +59,7 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol protected final SearchBuilder DetachedAccountIdSearch; protected final SearchBuilder TemplateZoneSearch; protected final GenericSearchBuilder TotalSizeByPoolSearch; + protected final GenericSearchBuilder TotalVMSnapshotSizeByPoolSearch; protected final GenericSearchBuilder ActiveTemplateSearch; protected final SearchBuilder InstanceStatesSearch; protected final SearchBuilder AllFieldsSearch; @@ -316,6 +317,15 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol TotalSizeByPoolSearch.and("state", TotalSizeByPoolSearch.entity().getState(), Op.NEQ); TotalSizeByPoolSearch.done(); + TotalVMSnapshotSizeByPoolSearch = createSearchBuilder(SumCount.class); + TotalVMSnapshotSizeByPoolSearch.select("sum", Func.SUM, TotalVMSnapshotSizeByPoolSearch.entity().getVmSnapshotChainSize()); + TotalVMSnapshotSizeByPoolSearch.and("poolId", TotalVMSnapshotSizeByPoolSearch.entity().getPoolId(), Op.EQ); + TotalVMSnapshotSizeByPoolSearch.and("removed", TotalVMSnapshotSizeByPoolSearch.entity().getRemoved(), Op.NULL); + TotalVMSnapshotSizeByPoolSearch.and("state", TotalVMSnapshotSizeByPoolSearch.entity().getState(), Op.NEQ); + TotalVMSnapshotSizeByPoolSearch.and("vType", TotalVMSnapshotSizeByPoolSearch.entity().getVolumeType(), Op.EQ); + TotalVMSnapshotSizeByPoolSearch.and("instanceId", TotalVMSnapshotSizeByPoolSearch.entity().getInstanceId(), Op.NNULL); + TotalVMSnapshotSizeByPoolSearch.done(); + ActiveTemplateSearch = createSearchBuilder(Long.class); ActiveTemplateSearch.and("pool", ActiveTemplateSearch.entity().getPoolId(), Op.EQ); ActiveTemplateSearch.and("template", ActiveTemplateSearch.entity().getTemplateId(), Op.EQ); @@ -516,6 +526,20 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol return new Pair(sumCount.count, sumCount.sum); } + @Override + public long getVMSnapshotSizeByPool(long poolId) { + SearchCriteria sc = TotalVMSnapshotSizeByPoolSearch.create(); + sc.setParameters("poolId", poolId); + sc.setParameters("state", State.Destroy); + sc.setParameters("vType", Volume.Type.ROOT.toString()); + List results = customSearch(sc, null); + if (results != null) { + return results.get(0).sum; + } else { + return 0; + } + } + @Override @DB public boolean remove(Long id) { diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/FirewallRuleDetailVO.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/FirewallRuleDetailVO.java index 88d2b0096bb..9b431f2f1b8 100644 --- a/engine/schema/src/org/apache/cloudstack/resourcedetail/FirewallRuleDetailVO.java +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/FirewallRuleDetailVO.java @@ -28,53 +28,53 @@ import org.apache.cloudstack.api.ResourceDetail; @Entity @Table(name="firewall_rule_details") public class FirewallRuleDetailVO implements ResourceDetail{ - @Id - @GeneratedValue(strategy= GenerationType.IDENTITY) - @Column(name="id") - private long id; + @Id + @GeneratedValue(strategy= GenerationType.IDENTITY) + @Column(name="id") + private long id; - @Column(name="firewall_rule_id") - private long resourceId; + @Column(name="firewall_rule_id") + private long resourceId; - @Column(name="name") - private String name; + @Column(name="name") + private String name; - @Column(name="value", length=1024) - private String value; - - @Column(name="display") - private boolean display; + @Column(name="value", length=1024) + private String value; + + @Column(name="display") + private boolean display; - public FirewallRuleDetailVO() {} + public FirewallRuleDetailVO() {} - public FirewallRuleDetailVO(long networkId, String name, String value) { - this.resourceId = networkId; - this.name = name; - this.value = value; - } + public FirewallRuleDetailVO(long id, String name, String value) { + this.resourceId = id; + this.name = name; + this.value = value; + } - @Override - public long getId() { - return id; - } + @Override + public long getId() { + return id; + } - @Override - public String getName() { - return name; - } + @Override + public String getName() { + return name; + } - @Override - public String getValue() { - return value; - } + @Override + public String getValue() { + return value; + } - @Override - public long getResourceId() { - return resourceId; - } + @Override + public long getResourceId() { + return resourceId; + } - @Override - public boolean isDisplay() { - return display; - } + @Override + public boolean isDisplay() { + return display; + } } diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/RemoteAccessVpnDetailVO.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/RemoteAccessVpnDetailVO.java new file mode 100644 index 00000000000..625feb5d580 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/RemoteAccessVpnDetailVO.java @@ -0,0 +1,80 @@ +// 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. +package org.apache.cloudstack.resourcedetail; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.apache.cloudstack.api.ResourceDetail; + +@Entity +@Table(name="remote_access_vpn_details") +public class RemoteAccessVpnDetailVO implements ResourceDetail{ + @Id + @GeneratedValue(strategy= GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="remote_access_vpn_id") + private long resourceId; + + @Column(name="name") + private String name; + + @Column(name="value", length=1024) + private String value; + + @Column(name="display") + private boolean display; + + public RemoteAccessVpnDetailVO() {} + + public RemoteAccessVpnDetailVO(long id, String name, String value) { + this.resourceId = id; + this.name = name; + this.value = value; + } + + @Override + public long getId() { + return id; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getValue() { + return value; + } + + @Override + public long getResourceId() { + return resourceId; + } + + @Override + public boolean isDisplay() { + return display; + } +} diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/UserIpAddressDetailVO.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/UserIpAddressDetailVO.java new file mode 100644 index 00000000000..2b2f5e172b8 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/UserIpAddressDetailVO.java @@ -0,0 +1,80 @@ +// 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. +package org.apache.cloudstack.resourcedetail; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.apache.cloudstack.api.ResourceDetail; + +@Entity +@Table(name="user_ip_address_details") +public class UserIpAddressDetailVO implements ResourceDetail{ + @Id + @GeneratedValue(strategy= GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="user_ip_address_id") + private long resourceId; + + @Column(name="name") + private String name; + + @Column(name="value", length=1024) + private String value; + + @Column(name="display") + private boolean display; + + public UserIpAddressDetailVO() {} + + public UserIpAddressDetailVO(long id, String name, String value) { + this.resourceId = id; + this.name = name; + this.value = value; + } + + @Override + public long getId() { + return id; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getValue() { + return value; + } + + @Override + public long getResourceId() { + return resourceId; + } + + @Override + public boolean isDisplay() { + return display; + } +} diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/RemoteAccessVpnDetailsDao.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/RemoteAccessVpnDetailsDao.java new file mode 100644 index 00000000000..697c91b8789 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/RemoteAccessVpnDetailsDao.java @@ -0,0 +1,26 @@ +// 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. +package org.apache.cloudstack.resourcedetail.dao; + +import org.apache.cloudstack.resourcedetail.RemoteAccessVpnDetailVO; +import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; + +import com.cloud.utils.db.GenericDao; + +public interface RemoteAccessVpnDetailsDao extends GenericDao, ResourceDetailsDao{ + +} diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/RemoteAccessVpnDetailsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/RemoteAccessVpnDetailsDaoImpl.java new file mode 100644 index 00000000000..46e6be994a7 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/RemoteAccessVpnDetailsDaoImpl.java @@ -0,0 +1,35 @@ +// 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. +package org.apache.cloudstack.resourcedetail.dao; + +import javax.ejb.Local; + +import org.apache.cloudstack.resourcedetail.RemoteAccessVpnDetailVO; +import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; +import org.springframework.stereotype.Component; + + +@Component +@Local (value={RemoteAccessVpnDetailsDao.class}) +public class RemoteAccessVpnDetailsDaoImpl extends ResourceDetailsDaoBase implements RemoteAccessVpnDetailsDao { + + @Override + public void addDetail(long resourceId, String key, String value) { + super.addDetail(new RemoteAccessVpnDetailVO(resourceId, key, value)); + } +} + diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/UserIpAddressDetailsDao.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/UserIpAddressDetailsDao.java new file mode 100644 index 00000000000..856f5089578 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/UserIpAddressDetailsDao.java @@ -0,0 +1,26 @@ +// 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. +package org.apache.cloudstack.resourcedetail.dao; + +import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; +import org.apache.cloudstack.resourcedetail.UserIpAddressDetailVO; + +import com.cloud.utils.db.GenericDao; + +public interface UserIpAddressDetailsDao extends GenericDao, ResourceDetailsDao{ + +} diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/UserIpAddressDetailsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/UserIpAddressDetailsDaoImpl.java new file mode 100644 index 00000000000..c1cb137ec03 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/UserIpAddressDetailsDaoImpl.java @@ -0,0 +1,35 @@ +// 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. +package org.apache.cloudstack.resourcedetail.dao; + +import javax.ejb.Local; + +import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; +import org.apache.cloudstack.resourcedetail.UserIpAddressDetailVO; +import org.springframework.stereotype.Component; + + +@Component +@Local (value={UserIpAddressDetailsDao.class}) +public class UserIpAddressDetailsDaoImpl extends ResourceDetailsDaoBase implements UserIpAddressDetailsDao { + + @Override + public void addDetail(long resourceId, String key, String value) { + super.addDetail(new UserIpAddressDetailVO(resourceId, key, value)); + } +} + diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java index 7eec5ffbb23..69900afa29f 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java @@ -21,6 +21,7 @@ import java.util.List; import javax.inject.Inject; +import com.cloud.storage.*; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -41,10 +42,6 @@ import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import com.cloud.exception.InvalidParameterValueException; -import com.cloud.storage.DataStoreRole; -import com.cloud.storage.Snapshot; -import com.cloud.storage.SnapshotVO; -import com.cloud.storage.Volume; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.utils.NumbersUtil; @@ -260,6 +257,14 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase { @Override @DB public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) { + Object payload = snapshot.getPayload(); + if (payload != null) { + CreateSnapshotPayload createSnapshotPayload = (CreateSnapshotPayload)payload; + if (createSnapshotPayload.getQuiescevm()) { + throw new InvalidParameterValueException("can't handle quiescevm equal true for volume snapshot"); + } + } + SnapshotVO snapshotVO = snapshotDao.acquireInLockTable(snapshot.getId()); if (snapshotVO == null) { throw new CloudRuntimeException("Failed to get lock on snapshot:" + snapshot.getId()); diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java index be3cce94da9..3f5e4f78d64 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java @@ -25,6 +25,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; +import org.apache.cloudstack.engine.subsystem.api.storage.VMSnapshotOptions; import org.apache.cloudstack.engine.subsystem.api.storage.VMSnapshotStrategy; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.to.VolumeObjectTO; @@ -111,8 +112,12 @@ public class DefaultVMSnapshotStrategy extends ManagerBase implements VMSnapshot VMSnapshotVO currentSnapshot = vmSnapshotDao.findCurrentSnapshotByVmId(userVm.getId()); if (currentSnapshot != null) current = vmSnapshotHelper.getSnapshotWithParents(currentSnapshot); + VMSnapshotOptions options = ((VMSnapshotVO) vmSnapshot).getOptions(); + boolean quiescevm = true; + if (options != null) + quiescevm = options.needQuiesceVM(); VMSnapshotTO target = new VMSnapshotTO(vmSnapshot.getId(), vmSnapshot.getName(), vmSnapshot.getType(), null, vmSnapshot.getDescription(), false, - current); + current, quiescevm); if (current == null) vmSnapshotVO.setParent(null); else @@ -174,7 +179,7 @@ public class DefaultVMSnapshotStrategy extends ManagerBase implements VMSnapshot String vmInstanceName = userVm.getInstanceName(); VMSnapshotTO parent = vmSnapshotHelper.getSnapshotWithParents(vmSnapshotVO).getParent(); VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(vmSnapshot.getId(), vmSnapshot.getName(), vmSnapshot.getType(), - vmSnapshot.getCreated().getTime(), vmSnapshot.getDescription(), vmSnapshot.getCurrent(), parent); + vmSnapshot.getCreated().getTime(), vmSnapshot.getDescription(), vmSnapshot.getCurrent(), parent, true); GuestOSVO guestOS = guestOSDao.findById(userVm.getGuestOSId()); DeleteVMSnapshotCommand deleteSnapshotCommand = new DeleteVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs,guestOS.getDisplayName()); @@ -330,7 +335,7 @@ public class DefaultVMSnapshotStrategy extends ManagerBase implements VMSnapshot VMSnapshotTO parent = vmSnapshotHelper.getSnapshotWithParents(snapshot).getParent(); VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(snapshot.getId(), snapshot.getName(), snapshot.getType(), - snapshot.getCreated().getTime(), snapshot.getDescription(), snapshot.getCurrent(), parent); + snapshot.getCreated().getTime(), snapshot.getDescription(), snapshot.getCurrent(), parent, true); Long hostId = vmSnapshotHelper.pickRunningHost(vmSnapshot.getVmId()); GuestOSVO guestOS = guestOSDao.findById(userVm.getGuestOSId()); RevertToVMSnapshotCommand revertToSnapshotCommand = new RevertToVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs, guestOS.getDisplayName()); diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java index 652df43c785..d9a5164b317 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java @@ -86,6 +86,7 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager { public ObjectInDataStoreManagerImpl() { stateMachines = new StateMachine2(); stateMachines.addTransition(State.Allocated, Event.CreateOnlyRequested, State.Creating); + stateMachines.addTransition(State.Allocated, Event.DestroyRequested, State.Destroying); stateMachines.addTransition(State.Creating, Event.OperationFailed, State.Allocated); stateMachines.addTransition(State.Creating, Event.OperationSuccessed, State.Ready); stateMachines.addTransition(State.Ready, Event.CopyingRequested, State.Copying); @@ -256,13 +257,7 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager { // Image store switch (dataObj.getType()) { case TEMPLATE: - TemplateDataStoreVO destTmpltStore = templateDataStoreDao.findByStoreTemplate(dataStore.getId(), objId); - if (destTmpltStore != null && destTmpltStore.getState() != ObjectInDataStoreStateMachine.State.Ready) { - return templateDataStoreDao.remove(destTmpltStore.getId()); - } else { - s_logger.warn("Template " + objId + " is not found on image store " + dataStore.getId() + ", so no need to delete"); - return true; - } + return true; case SNAPSHOT: SnapshotDataStoreVO destSnapshotStore = snapshotDataStoreDao.findByStoreSnapshot(dataStore.getRole(), dataStore.getId(), objId); if (destSnapshotStore != null && destSnapshotStore.getState() != ObjectInDataStoreStateMachine.State.Ready) { diff --git a/engine/storage/src/org/apache/cloudstack/storage/helper/HypervisorHelperImpl.java b/engine/storage/src/org/apache/cloudstack/storage/helper/HypervisorHelperImpl.java index 7dbd35cf254..eb29aa4d85b 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/helper/HypervisorHelperImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/helper/HypervisorHelperImpl.java @@ -111,7 +111,7 @@ public class HypervisorHelperImpl implements HypervisorHelper { int wait = NumbersUtil.parseInt(value, 1800); Long hostId = vmSnapshotHelper.pickRunningHost(virtualMachine.getId()); VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(1L, UUID.randomUUID().toString(), VMSnapshot.Type.DiskAndMemory, null, null, false, - null); + null, true); GuestOSVO guestOS = guestOSDao.findById(virtualMachine.getGuestOSId()); List volumeTOs = vmSnapshotHelper.getVolumeTOList(virtualMachine.getId()); CreateVMSnapshotCommand ccmd = new CreateVMSnapshotCommand(virtualMachine.getInstanceName(),vmSnapshotTO ,volumeTOs, guestOS.getDisplayName(),virtualMachine.getState()); diff --git a/engine/storage/src/org/apache/cloudstack/storage/helper/VMSnapshotHelperImpl.java b/engine/storage/src/org/apache/cloudstack/storage/helper/VMSnapshotHelperImpl.java index 1200be89629..9693e914cd4 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/helper/VMSnapshotHelperImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/helper/VMSnapshotHelperImpl.java @@ -122,7 +122,7 @@ public class VMSnapshotHelperImpl implements VMSnapshotHelper { private VMSnapshotTO convert2VMSnapshotTO(VMSnapshotVO vo) { return new VMSnapshotTO(vo.getId(), vo.getName(), vo.getType(), vo.getCreated().getTime(), vo.getDescription(), - vo.getCurrent(), null); + vo.getCurrent(), null, true); } @Override diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java index bd93e73e0ef..6a74c4540a5 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java @@ -21,17 +21,14 @@ package org.apache.cloudstack.storage.image; import java.net.URI; import java.net.URISyntaxException; import java.util.Date; +import java.util.HashMap; +import java.util.Map; import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.*; import org.apache.log4j.Logger; -import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; -import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; -import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.async.AsyncRpcContext; @@ -86,6 +83,11 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { } } + @Override + public Map getCapabilities() { + return null; + } + @Override public DataTO getTO(DataObject data) { return null; diff --git a/framework/config/src/org/apache/cloudstack/framework/config/ConfigDepot.java b/framework/config/src/org/apache/cloudstack/framework/config/ConfigDepot.java index 2fd6efbb5da..22452b90417 100644 --- a/framework/config/src/org/apache/cloudstack/framework/config/ConfigDepot.java +++ b/framework/config/src/org/apache/cloudstack/framework/config/ConfigDepot.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.framework.config; +import java.util.List; + /** * ConfigDepot is a repository of configurations. * @@ -23,4 +25,6 @@ package org.apache.cloudstack.framework.config; public interface ConfigDepot { ConfigKey get(String paramName); + + List> getConfigListByScope(String scope); } diff --git a/framework/config/src/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java b/framework/config/src/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java index 254e6d20b06..305d286b580 100644 --- a/framework/config/src/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java +++ b/framework/config/src/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java @@ -76,8 +76,14 @@ public class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin { HashMap>> _allKeys = new HashMap>>(1007); + HashMap>> _scopeLevelConfigsMap = new HashMap>>(); + public ConfigDepotImpl() { ConfigKey.init(this); + _scopeLevelConfigsMap.put(ConfigKey.Scope.Zone, new ArrayList>()); + _scopeLevelConfigsMap.put(ConfigKey.Scope.Cluster, new ArrayList>()); + _scopeLevelConfigsMap.put(ConfigKey.Scope.StoragePool, new ArrayList>()); + _scopeLevelConfigsMap.put(ConfigKey.Scope.Account, new ArrayList>()); } @Override @@ -108,7 +114,7 @@ public class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin { ": " + key.toString()); } _allKeys.put(key.key(), new Pair>(configurable.getConfigComponentName(), key)); - + ConfigurationVO vo = _configDao.findById(key.key()); if (vo == null) { vo = new ConfigurationVO(configurable.getConfigComponentName(), key); @@ -125,6 +131,10 @@ public class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin { _configDao.persist(vo); } } + if (key.scope() != ConfigKey.Scope.Global) { + List> currentConfigs = _scopeLevelConfigsMap.get(key.scope()); + currentConfigs.add(key); + } } _configured.add(configurable); @@ -172,4 +182,9 @@ public class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin { this._configurables = configurables; } + @Override + public List> getConfigListByScope(String scope) { + return _scopeLevelConfigsMap.get(ConfigKey.Scope.valueOf(scope)); + } + } diff --git a/framework/db/pom.xml b/framework/db/pom.xml index 5af00a00747..e28628e5e9f 100644 --- a/framework/db/pom.xml +++ b/framework/db/pom.xml @@ -44,6 +44,11 @@ cloud-utils ${project.version} + + mysql + mysql-connector-java + compile + diff --git a/framework/db/src/com/cloud/utils/db/StaticStrategy.java b/framework/db/src/com/cloud/utils/db/StaticStrategy.java new file mode 100644 index 00000000000..29e96dfc18e --- /dev/null +++ b/framework/db/src/com/cloud/utils/db/StaticStrategy.java @@ -0,0 +1,130 @@ +// 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 +// 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. +package com.cloud.utils.db; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import com.mysql.jdbc.BalanceStrategy; +import com.mysql.jdbc.Connection; +import com.mysql.jdbc.ConnectionImpl; +import com.mysql.jdbc.LoadBalancingConnectionProxy; +import com.mysql.jdbc.SQLError; + +public class StaticStrategy implements BalanceStrategy { + + public StaticStrategy() { + } + + public void destroy() { + // we don't have anything to clean up + } + + public void init(Connection conn, Properties props) throws SQLException { + // we don't have anything to initialize + } + + public ConnectionImpl pickConnection(LoadBalancingConnectionProxy proxy, + List configuredHosts, Map liveConnections, long[] responseTimes, + int numRetries) throws SQLException { + int numHosts = configuredHosts.size(); + + SQLException ex = null; + + List whiteList = new ArrayList(numHosts); + whiteList.addAll(configuredHosts); + + Map blackList = proxy.getGlobalBlacklist(); + + whiteList.removeAll(blackList.keySet()); + + Map whiteListMap = this.getArrayIndexMap(whiteList); + + + for (int attempts = 0; attempts < numRetries;) { + if(whiteList.size() == 0){ + throw SQLError.createSQLException("No hosts configured", null); + } + + String hostPortSpec = whiteList.get(0); //Always take the first host + + ConnectionImpl conn = liveConnections.get(hostPortSpec); + + if (conn == null) { + try { + conn = proxy.createConnectionForHost(hostPortSpec); + } catch (SQLException sqlEx) { + ex = sqlEx; + + if (proxy.shouldExceptionTriggerFailover(sqlEx)) { + + Integer whiteListIndex = whiteListMap.get(hostPortSpec); + + // exclude this host from being picked again + if (whiteListIndex != null) { + whiteList.remove(whiteListIndex.intValue()); + whiteListMap = this.getArrayIndexMap(whiteList); + } + proxy.addToGlobalBlacklist( hostPortSpec ); + + if (whiteList.size() == 0) { + attempts++; + try { + Thread.sleep(250); + } catch (InterruptedException e) { + } + + // start fresh + whiteListMap = new HashMap(numHosts); + whiteList.addAll(configuredHosts); + blackList = proxy.getGlobalBlacklist(); + + whiteList.removeAll(blackList.keySet()); + whiteListMap = this.getArrayIndexMap(whiteList); + } + + continue; + } + + throw sqlEx; + } + } + + return conn; + } + + if (ex != null) { + throw ex; + } + + return null; // we won't get here, compiler can't tell + } + + private Map getArrayIndexMap(List l) { + Map m = new HashMap(l.size()); + for (int i = 0; i < l.size(); i++) { + m.put(l.get(i), Integer.valueOf(i)); + } + return m; + + } + +} \ No newline at end of file diff --git a/framework/db/src/com/cloud/utils/db/TransactionLegacy.java b/framework/db/src/com/cloud/utils/db/TransactionLegacy.java index 39893bd4eab..d50118bdc8f 100755 --- a/framework/db/src/com/cloud/utils/db/TransactionLegacy.java +++ b/framework/db/src/com/cloud/utils/db/TransactionLegacy.java @@ -1034,7 +1034,7 @@ public class TransactionLegacy { s_dbHAEnabled = Boolean.valueOf(dbProps.getProperty("db.ha.enabled")); s_logger.info("Is Data Base High Availiability enabled? Ans : " + s_dbHAEnabled); - + String loadBalanceStrategy = dbProps.getProperty("db.ha.loadBalanceStrategy"); // FIXME: If params are missing...default them???? final int cloudMaxActive = Integer.parseInt(dbProps.getProperty("db.cloud.maxActive")); final int cloudMaxIdle = Integer.parseInt(dbProps.getProperty("db.cloud.maxIdle")); @@ -1090,7 +1090,7 @@ public class TransactionLegacy { cloudMaxWait, cloudMaxIdle, cloudTestOnBorrow, false, cloudTimeBtwEvictionRunsMillis, 1, cloudMinEvcitableIdleTimeMillis, cloudTestWhileIdle); final ConnectionFactory cloudConnectionFactory = new DriverManagerConnectionFactory("jdbc:mysql://" + cloudHost + (s_dbHAEnabled ? "," + cloudSlaves : "") + ":" + cloudPort + "/" + cloudDbName + - "?autoReconnect=" + cloudAutoReconnect + (url != null ? "&" + url : "") + (useSSL ? "&useSSL=true" : "") + (s_dbHAEnabled ? "&" + cloudDbHAParams : ""), cloudUsername, cloudPassword); + "?autoReconnect=" + cloudAutoReconnect + (url != null ? "&" + url : "") + (useSSL ? "&useSSL=true" : "") + (s_dbHAEnabled ? "&" + cloudDbHAParams : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : ""), cloudUsername, cloudPassword); final KeyedObjectPoolFactory poolableObjFactory = (cloudPoolPreparedStatements ? new StackKeyedObjectPoolFactory() : null); @@ -1116,7 +1116,7 @@ public class TransactionLegacy { usageMaxWait, usageMaxIdle); final ConnectionFactory usageConnectionFactory = new DriverManagerConnectionFactory("jdbc:mysql://" + usageHost + (s_dbHAEnabled ? "," + dbProps.getProperty("db.cloud.slaves") : "") + ":" + usagePort + "/" + usageDbName + - "?autoReconnect=" + usageAutoReconnect + (usageUrl != null ? "&" + usageUrl : "") + (s_dbHAEnabled ? "&" + getDBHAParams("usage", dbProps) : ""), usageUsername, usagePassword); + "?autoReconnect=" + usageAutoReconnect + (usageUrl != null ? "&" + usageUrl : "") + (s_dbHAEnabled ? "&" + getDBHAParams("usage", dbProps) : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : ""), usageUsername, usagePassword); final PoolableConnectionFactory usagePoolableConnectionFactory = new PoolableConnectionFactory(usageConnectionFactory, usageConnectionPool, new StackKeyedObjectPoolFactory(), null, false, false); @@ -1129,7 +1129,7 @@ public class TransactionLegacy { final GenericObjectPool awsapiConnectionPool = new GenericObjectPool(null, usageMaxActive, GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION, usageMaxWait, usageMaxIdle); final ConnectionFactory awsapiConnectionFactory = new DriverManagerConnectionFactory("jdbc:mysql://" + cloudHost + (s_dbHAEnabled ? "," + cloudSlaves : "") + ":" + cloudPort + "/" + awsapiDbName + - "?autoReconnect=" + cloudAutoReconnect + (s_dbHAEnabled ? "&" + cloudDbHAParams : ""), cloudUsername, cloudPassword); + "?autoReconnect=" + cloudAutoReconnect + (s_dbHAEnabled ? "&" + cloudDbHAParams : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : ""), cloudUsername, cloudPassword); final PoolableConnectionFactory awsapiPoolableConnectionFactory = new PoolableConnectionFactory(awsapiConnectionFactory, awsapiConnectionPool, new StackKeyedObjectPoolFactory(), null, false, false); diff --git a/framework/db/test/com/cloud/utils/DbUtilTest.java b/framework/db/test/com/cloud/utils/DbUtilTest.java new file mode 100644 index 00000000000..e9a72870f5f --- /dev/null +++ b/framework/db/test/com/cloud/utils/DbUtilTest.java @@ -0,0 +1,81 @@ +// 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 +// 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. +package com.cloud.utils; + +import javax.persistence.Column; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import com.cloud.utils.db.DbUtil; + +public class DbUtilTest { + + static class Testbean { + String noAnnotation; + @Column() + String withAnnotation; + @Column(name = "surprise") + String withAnnotationAndName; + } + + @Test + public void getColumnName() throws SecurityException, NoSuchFieldException { + // if no annotation, then the field name + Assert.assertEquals("noAnnotation", DbUtil.getColumnName(Testbean.class + .getDeclaredField("noAnnotation"))); + // there is annotation with name, take the name + Assert.assertEquals("surprise", DbUtil.getColumnName(Testbean.class + .getDeclaredField("withAnnotationAndName"))); + } + + @Test + @Ignore + public void getColumnNameWithAnnotationButWithoutNameAttribute() + throws SecurityException, NoSuchFieldException { + // there is annotation, but no name defined, fallback to field name + // this does not work this way, it probably should + Assert.assertEquals("withAnnotation", DbUtil + .getColumnName(Testbean.class + .getDeclaredField("withAnnotation"))); + + } + + static class IsPersistableTestBean { + static final String staticFinal = "no"; + final String justFinal = "no"; + transient String transientField; + transient static String strange = ""; + String instanceField; + } + + @Test + public void isPersistable() throws SecurityException, NoSuchFieldException { + Assert.assertFalse(DbUtil.isPersistable(IsPersistableTestBean.class + .getDeclaredField("staticFinal"))); + Assert.assertFalse(DbUtil.isPersistable(IsPersistableTestBean.class + .getDeclaredField("justFinal"))); + Assert.assertFalse(DbUtil.isPersistable(IsPersistableTestBean.class + .getDeclaredField("transientField"))); + Assert.assertFalse(DbUtil.isPersistable(IsPersistableTestBean.class + .getDeclaredField("strange"))); + Assert.assertTrue(DbUtil.isPersistable(IsPersistableTestBean.class + .getDeclaredField("instanceField"))); + } + +} diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index cd6ff4bfbe2..893628d55d2 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -252,7 +252,7 @@ rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapps/client/WEB-INF/cl rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/vms for name in db.properties log4j-cloud.xml tomcat6-nonssl.conf tomcat6-ssl.conf server-ssl.xml server-nonssl.xml \ - catalina.policy catalina.properties classpath.conf tomcat-users.xml web.xml environment.properties cloudmanagementserver.keystore ; do + catalina.policy catalina.properties classpath.conf tomcat-users.xml web.xml environment.properties ; do mv ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/$name \ ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management/$name done @@ -451,7 +451,6 @@ else fi if [ -f "%{_sysconfdir}/cloud.rpmsave/management/cloud.keystore" ]; then - mv %{_sysconfdir}/%{name}/management/cloudmanagementserver.keystore %{_sysconfdir}/%{name}/management/cloudmanagementserver.keystore.rpmnew cp -p %{_sysconfdir}/cloud.rpmsave/management/cloud.keystore %{_sysconfdir}/%{name}/management/cloudmanagementserver.keystore # make sure we only do this on the first install of this RPM, don't want to overwrite on a reinstall mv %{_sysconfdir}/cloud.rpmsave/management/cloud.keystore %{_sysconfdir}/cloud.rpmsave/management/cloud.keystore.rpmsave @@ -546,7 +545,6 @@ fi %config(noreplace) %{_sysconfdir}/%{name}/management/cloud-bridge.properties %config(noreplace) %{_sysconfdir}/%{name}/management/commons-logging.properties %config(noreplace) %{_sysconfdir}/%{name}/management/ec2-service.properties -%config(noreplace) %{_sysconfdir}/%{name}/management/cloudmanagementserver.keystore %attr(0755,root,root) %{_initrddir}/%{name}-management %attr(0755,root,root) %{_bindir}/%{name}-setup-management %attr(0755,root,root) %{_bindir}/%{name}-update-xenserver-licenses diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java index fa7abd58331..2418a194685 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java @@ -31,7 +31,6 @@ import javax.ejb.Local; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; - import org.apache.cloudstack.api.ApiConstants; import com.cloud.agent.IAgentControl; @@ -41,6 +40,7 @@ import com.cloud.agent.api.CheckNetworkCommand; import com.cloud.agent.api.CheckVirtualMachineAnswer; import com.cloud.agent.api.CheckVirtualMachineCommand; import com.cloud.agent.api.Command; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.MaintainAnswer; import com.cloud.agent.api.MaintainCommand; import com.cloud.agent.api.MigrateAnswer; @@ -77,6 +77,7 @@ import com.cloud.utils.script.Script2; import com.cloud.utils.script.Script2.ParamType; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.VMInstanceDao; @@ -332,10 +333,36 @@ public class BareMetalResourceBase extends ManagerBase implements ServerResource return states; } + + protected Map getHostVmStateReport() { + Map states = new HashMap(); + if (hostId != null) { + vmDao = ComponentContext.getComponent(VMInstanceDao.class); + final List vms = vmDao.listByHostId(hostId); + for (VMInstanceVO vm : vms) { + states.put( + vm.getInstanceName(), + new HostVmStateReportEntry( + vm.getState() == State.Running ? PowerState.PowerOn : PowerState.PowerOff, "host-" + hostId, null + ) + ); + } + } + /* + * Map changes = new HashMap(); + * + * if (_vmName != null) { State state = getVmState(); if (state != null) + * { changes.put(_vmName, state); } } + */ + + return states; + } @Override public StartupCommand[] initialize() { - StartupRoutingCommand cmd = new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.BareMetal, new HashMap(), null); + StartupRoutingCommand cmd = new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.BareMetal, + new HashMap(), null, null); + cmd.setDataCenter(_zone); cmd.setPod(_pod); cmd.setCluster(_cluster); @@ -372,7 +399,7 @@ public class BareMetalResourceBase extends ManagerBase implements ServerResource return null; } - return new PingRoutingCommand(getType(), id, deltaSync()); + return new PingRoutingCommand(getType(), id, deltaSync(), getHostVmStateReport()); } protected Answer execute(IpmISetBootDevCommand cmd) { diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResourceBase.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResourceBase.java index 2a17a436842..f992fe9af3b 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResourceBase.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResourceBase.java @@ -32,6 +32,7 @@ import org.apache.log4j.Logger; import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingRoutingCommand; import com.cloud.agent.api.ReadyAnswer; @@ -129,7 +130,8 @@ public class BaremetalDhcpResourceBase extends ManagerBase implements ServerReso @Override public PingCommand getCurrentStatus(long id) { //TODO: check server - return new PingRoutingCommand(getType(), id, new HashMap()); + return new PingRoutingCommand(getType(), id, new HashMap(), + new HashMap()); } protected ReadyAnswer execute(ReadyCommand cmd) { diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpdResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpdResource.java index a27a6f26896..dc778125777 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpdResource.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpdResource.java @@ -31,6 +31,7 @@ import org.apache.log4j.Logger; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingRoutingCommand; import com.cloud.agent.api.routing.DhcpEntryCommand; @@ -105,7 +106,8 @@ public class BaremetalDhcpdResource extends BaremetalDhcpResourceBase { return null; } else { SSHCmdHelper.releaseSshConnection(sshConnection); - return new PingRoutingCommand(getType(), id, new HashMap()); + return new PingRoutingCommand(getType(), id, new HashMap(), + new HashMap()); } } diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java index d0fb2b4c098..19a4d903609 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java @@ -32,6 +32,7 @@ import org.apache.log4j.Logger; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingRoutingCommand; import com.cloud.agent.api.routing.DhcpEntryCommand; @@ -98,7 +99,8 @@ public class BaremetalDnsmasqResource extends BaremetalDhcpResourceBase { return null; } else { SSHCmdHelper.releaseSshConnection(sshConnection); - return new PingRoutingCommand(getType(), id, new HashMap()); + return new PingRoutingCommand(getType(), id, new HashMap(), + new HashMap()); } } diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java index 7a7a5153e5c..e4f0cee6fab 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java @@ -29,6 +29,7 @@ import org.apache.log4j.Logger; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingRoutingCommand; import com.cloud.agent.api.routing.VmDataCommand; @@ -106,7 +107,8 @@ public class BaremetalKickStartPxeResource extends BaremetalPxeResourceBase { return null; } else { SSHCmdHelper.releaseSshConnection(sshConnection); - return new PingRoutingCommand(getType(), id, new HashMap()); + return new PingRoutingCommand(getType(), id, new HashMap(), + new HashMap()); } } diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java index 2fb54154489..59efe245224 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java @@ -32,6 +32,7 @@ import org.apache.log4j.Logger; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingRoutingCommand; import com.cloud.agent.api.baremetal.PreparePxeServerAnswer; @@ -142,7 +143,8 @@ public class BaremetalPingPxeResource extends BaremetalPxeResourceBase { return null; } else { SSHCmdHelper.releaseSshConnection(sshConnection); - return new PingRoutingCommand(getType(), id, new HashMap()); + return new PingRoutingCommand(getType(), id, new HashMap(), + new HashMap()); } } diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java index 194ad77b05d..165d706d006 100644 --- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java +++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java @@ -42,7 +42,6 @@ import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; import com.google.gson.Gson; - import com.cloud.agent.api.Answer; import com.cloud.agent.api.CheckRouterAnswer; import com.cloud.agent.api.CheckRouterCommand; @@ -51,6 +50,7 @@ import com.cloud.agent.api.CheckS2SVpnConnectionsCommand; import com.cloud.agent.api.Command; import com.cloud.agent.api.GetDomRVersionAnswer; import com.cloud.agent.api.GetDomRVersionCmd; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.NetworkUsageAnswer; import com.cloud.agent.api.NetworkUsageCommand; import com.cloud.agent.api.PingCommand; @@ -158,7 +158,8 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.Hyperv, RouterPrivateIpStrategy.HostLocal, - new HashMap()); + new HashMap(), + new HashMap()); // Identity within the data centre is decided by CloudStack kernel, // and passed via ServerResource.configure() @@ -293,7 +294,8 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S @Override public final PingCommand getCurrentStatus(final long id) { - PingCommand pingCmd = new PingRoutingCommand(getType(), id, null); + // TODO, need to report VM states on host + PingCommand pingCmd = new PingRoutingCommand(getType(), id, null, null); if (s_logger.isDebugEnabled()) { s_logger.debug("Ping host " + _name + " (IP " + _agentIp + ")"); diff --git a/plugins/hypervisors/hyperv/test/com/cloud/hypervisor/hyperv/test/HypervDirectConnectResourceTest.java b/plugins/hypervisors/hyperv/test/com/cloud/hypervisor/hyperv/test/HypervDirectConnectResourceTest.java index 1f90da9aded..33694603f74 100644 --- a/plugins/hypervisors/hyperv/test/com/cloud/hypervisor/hyperv/test/HypervDirectConnectResourceTest.java +++ b/plugins/hypervisors/hyperv/test/com/cloud/hypervisor/hyperv/test/HypervDirectConnectResourceTest.java @@ -57,6 +57,7 @@ import com.cloud.agent.api.GetStorageStatsAnswer; import com.cloud.agent.api.GetStorageStatsCommand; import com.cloud.agent.api.GetVmStatsAnswer; import com.cloud.agent.api.GetVmStatsCommand; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.ModifyStoragePoolCommand; import com.cloud.agent.api.StartAnswer; import com.cloud.agent.api.StartCommand; @@ -298,7 +299,8 @@ public class HypervDirectConnectResourceTest { StartupRoutingCommand defaultStartRoutCmd = new StartupRoutingCommand( 0, 0, 0, 0, null, Hypervisor.HypervisorType.Hyperv, RouterPrivateIpStrategy.HostLocal, - new HashMap()); + new HashMap(), + new HashMap()); // Identity within the data centre is decided by CloudStack kernel, // and passed via ServerResource.configure() diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 63bd5dc051a..50561a92099 100755 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -59,6 +59,7 @@ import javax.naming.ConfigurationException; import com.cloud.agent.api.CheckOnHostCommand; import com.cloud.agent.api.routing.*; + import org.apache.commons.io.FileUtils; import org.apache.log4j.Logger; import org.libvirt.Connect; @@ -69,7 +70,6 @@ import org.libvirt.DomainInterfaceStats; import org.libvirt.DomainSnapshot; import org.libvirt.LibvirtException; import org.libvirt.NodeInfo; - import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; @@ -112,6 +112,7 @@ import com.cloud.agent.api.GetVmStatsCommand; import com.cloud.agent.api.GetVncPortAnswer; import com.cloud.agent.api.GetVncPortCommand; import com.cloud.agent.api.HostStatsEntry; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.MaintainAnswer; import com.cloud.agent.api.MaintainCommand; import com.cloud.agent.api.ManageSnapshotAnswer; @@ -236,8 +237,8 @@ import com.cloud.utils.script.OutputInterpreter; import com.cloud.utils.script.Script; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VirtualMachine.State; - import com.ceph.rados.Rados; import com.ceph.rados.RadosException; import com.ceph.rados.IoCTX; @@ -373,6 +374,8 @@ ServerResource { protected int _timeout; protected int _cmdsTimeout; protected int _stopTimeout; + + // TODO vmsync { protected static HashMap s_statesTable; static { s_statesTable = new HashMap(); @@ -389,6 +392,24 @@ ServerResource { s_statesTable.put(DomainInfo.DomainState.VIR_DOMAIN_SHUTDOWN, State.Stopping); } + // TODO vmsync } + + protected static HashMap s_powerStatesTable; + static { + s_powerStatesTable = new HashMap(); + s_powerStatesTable.put(DomainInfo.DomainState.VIR_DOMAIN_SHUTOFF, + PowerState.PowerOff); + s_powerStatesTable.put(DomainInfo.DomainState.VIR_DOMAIN_PAUSED, + PowerState.PowerOn); + s_powerStatesTable.put(DomainInfo.DomainState.VIR_DOMAIN_RUNNING, + PowerState.PowerOn); + s_powerStatesTable.put(DomainInfo.DomainState.VIR_DOMAIN_BLOCKED, + PowerState.PowerOn); + s_powerStatesTable.put(DomainInfo.DomainState.VIR_DOMAIN_NOSTATE, + PowerState.PowerUnknown); + s_powerStatesTable.put(DomainInfo.DomainState.VIR_DOMAIN_SHUTDOWN, + PowerState.PowerOff); + } protected HashMap _vms = new HashMap(20); protected List _vmsKilled = new ArrayList(); @@ -2812,6 +2833,11 @@ ServerResource { final State state = s_statesTable.get(ps); return state == null ? State.Unknown : state; } + + protected PowerState convertToPowerState(DomainInfo.DomainState ps) { + final PowerState state = s_powerStatesTable.get(ps); + return state == null ? PowerState.PowerUnknown : state; + } protected State getVmState(Connect conn, final String vmName) { int retry = 3; @@ -3960,10 +3986,10 @@ ServerResource { if (!_can_bridge_firewall) { return new PingRoutingCommand(com.cloud.host.Host.Type.Routing, id, - newStates); + newStates, this.getHostVmStateReport()); } else { HashMap> nwGrpStates = syncNetworkGroups(id); - return new PingRoutingWithNwGroupsCommand(getType(), id, newStates, + return new PingRoutingWithNwGroupsCommand(getType(), id, newStates, this.getHostVmStateReport(), nwGrpStates); } } @@ -4008,6 +4034,7 @@ ServerResource { cmd.setPool(_pool); cmd.setCluster(_clusterId); cmd.setGatewayIpAddress(_localGateway); + cmd.setHostVmStateReport(getHostVmStateReport()); StartupStorageCommand sscmd = null; try { @@ -4321,6 +4348,104 @@ ServerResource { return vmStates; } + + private HashMap getHostVmStateReport() { + final HashMap vmStates = new HashMap(); + Connect conn = null; + + if (_hypervisorType == HypervisorType.LXC) { + try { + conn = LibvirtConnection.getConnectionByType(HypervisorType.LXC.toString()); + vmStates.putAll(getHostVmStateReport(conn)); + } catch (LibvirtException e) { + s_logger.debug("Failed to get connection: " + e.getMessage()); + } + } + + if (_hypervisorType == HypervisorType.KVM) { + try { + conn = LibvirtConnection.getConnectionByType(HypervisorType.KVM.toString()); + vmStates.putAll(getHostVmStateReport(conn)); + } catch (LibvirtException e) { + s_logger.debug("Failed to get connection: " + e.getMessage()); + } + } + + return vmStates; + } + + private HashMap getHostVmStateReport(Connect conn) { + final HashMap vmStates = new HashMap(); + + String[] vms = null; + int[] ids = null; + + try { + ids = conn.listDomains(); + } catch (final LibvirtException e) { + s_logger.warn("Unable to listDomains", e); + return null; + } + try { + vms = conn.listDefinedDomains(); + } catch (final LibvirtException e) { + s_logger.warn("Unable to listDomains", e); + return null; + } + + Domain dm = null; + for (int i = 0; i < ids.length; i++) { + try { + dm = conn.domainLookupByID(ids[i]); + + DomainInfo.DomainState ps = dm.getInfo().state; + + final PowerState state = convertToPowerState(ps); + + s_logger.trace("VM " + dm.getName() + ": powerstate = " + ps + + "; vm state=" + state.toString()); + String vmName = dm.getName(); + vmStates.put(vmName, new HostVmStateReportEntry(state, conn.getHostName(), null)); + } catch (final LibvirtException e) { + s_logger.warn("Unable to get vms", e); + } finally { + try { + if (dm != null) { + dm.free(); + } + } catch (LibvirtException e) { + s_logger.trace("Ignoring libvirt error.", e); + } + } + } + + for (int i = 0; i < vms.length; i++) { + try { + + dm = conn.domainLookupByName(vms[i]); + + DomainInfo.DomainState ps = dm.getInfo().state; + final PowerState state = convertToPowerState(ps); + String vmName = dm.getName(); + s_logger.trace("VM " + vmName + ": powerstate = " + ps + + "; vm state=" + state.toString()); + + vmStates.put(vmName, new HostVmStateReportEntry(state, conn.getHostName(), null)); + } catch (final LibvirtException e) { + s_logger.warn("Unable to get vms", e); + } finally { + try { + if (dm != null) { + dm.free(); + } + } catch (LibvirtException e) { + s_logger.trace("Ignoring libvirt error.", e); + } + } + } + + return vmStates; + } protected List getHostInfo() { final ArrayList info = new ArrayList(); @@ -4776,7 +4901,7 @@ ServerResource { Calendar _timestamp; } - private VmStatsEntry getVmStat(Connect conn, String vmName) + VmStatsEntry getVmStat(Connect conn, String vmName) throws LibvirtException { Domain dm = null; try { @@ -4821,10 +4946,10 @@ ServerResource { } if (oldStats != null) { - long deltarx = rx - oldStats._rx; + double deltarx = rx - oldStats._rx; if (deltarx > 0) stats.setNetworkReadKBs(deltarx / 1024); - long deltatx = tx - oldStats._tx; + double deltatx = tx - oldStats._tx; if (deltatx > 0) stats.setNetworkWriteKBs(deltatx / 1024); } @@ -4850,10 +4975,10 @@ ServerResource { long deltaiowr = io_wr - oldStats._io_wr; if (deltaiowr > 0) stats.setDiskWriteIOs(deltaiowr); - long deltabytesrd = bytes_rd - oldStats._bytes_rd; + double deltabytesrd = bytes_rd - oldStats._bytes_rd; if (deltabytesrd > 0) stats.setDiskReadKBs(deltabytesrd / 1024); - long deltabyteswr = bytes_wr - oldStats._bytes_wr; + double deltabyteswr = bytes_wr - oldStats._bytes_wr; if (deltabyteswr > 0) stats.setDiskWriteKBs(deltabyteswr / 1024); } diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index d6e8dc2fcc2..803ac328801 100644 --- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -19,21 +19,37 @@ package com.cloud.hypervisor.kvm.resource; -import com.cloud.agent.api.to.VirtualMachineTO; -import com.cloud.template.VirtualMachineTemplate.BootloaderType; -import com.cloud.utils.Pair; -import com.cloud.vm.VirtualMachine; - -import junit.framework.Assert; -import org.apache.commons.lang.SystemUtils; -import org.junit.Assume; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import java.util.Arrays; +import java.util.List; import java.util.Random; import java.util.UUID; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import junit.framework.Assert; + +import org.apache.commons.lang.SystemUtils; +import org.junit.Assume; +import org.junit.Test; +import org.libvirt.Connect; +import org.libvirt.Domain; +import org.libvirt.DomainBlockStats; +import org.libvirt.DomainInfo; +import org.libvirt.DomainInterfaceStats; +import org.libvirt.LibvirtException; +import org.libvirt.NodeInfo; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import com.cloud.agent.api.VmStatsEntry; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef; +import com.cloud.template.VirtualMachineTemplate.BootloaderType; +import com.cloud.utils.Pair; +import com.cloud.vm.VirtualMachine; public class LibvirtComputingResourceTest { @@ -210,4 +226,79 @@ public class LibvirtComputingResourceTest { uuid = lcr.getUuid(uuid); Assert.assertTrue(uuid.equals(oldUuid)); } + + private static final String VMNAME = "test"; + + @Test + public void testGetVmStat() throws LibvirtException { + Connect connect = Mockito.mock(Connect.class); + Domain domain = Mockito.mock(Domain.class); + DomainInfo domainInfo = new DomainInfo(); + Mockito.when(domain.getInfo()).thenReturn(domainInfo); + Mockito.when(connect.domainLookupByName(VMNAME)).thenReturn(domain); + NodeInfo nodeInfo = new NodeInfo(); + nodeInfo.cpus = 8; + nodeInfo.memory = 8 * 1024 * 1024; + nodeInfo.sockets = 2; + nodeInfo.threads = 2; + nodeInfo.model = "Foo processor"; + Mockito.when(connect.nodeInfo()).thenReturn(nodeInfo); + // this is testing the interface stats, returns an increasing number of sent and received bytes + Mockito.when(domain.interfaceStats(Mockito.anyString())).thenAnswer(new Answer() { + // increment with less than a KB, so this should be less than 1 KB + final static int increment = 1000; + int rx_bytes = 1000; + int tx_bytes = 1000; + + @Override + public DomainInterfaceStats answer(InvocationOnMock invocation) throws Throwable { + DomainInterfaceStats domainInterfaceStats = new DomainInterfaceStats(); + domainInterfaceStats.rx_bytes = (this.rx_bytes += increment); + domainInterfaceStats.tx_bytes = (this.tx_bytes += increment); + return domainInterfaceStats; + + } + + }); + + Mockito.when(domain.blockStats(Mockito.anyString())).thenAnswer(new Answer() { + // a little less than a KB + final static int increment = 1000; + + int rd_bytes = 0; + int wr_bytes = 1024; + @Override + public DomainBlockStats answer(InvocationOnMock invocation) throws Throwable { + DomainBlockStats domainBlockStats = new DomainBlockStats(); + + domainBlockStats.rd_bytes = (rd_bytes += increment); + domainBlockStats.wr_bytes = (wr_bytes += increment); + return domainBlockStats; + } + + }); + + LibvirtComputingResource libvirtComputingResource = new LibvirtComputingResource() { + @Override + protected List getInterfaces(Connect conn, String vmName) { + InterfaceDef interfaceDef = new InterfaceDef(); + return Arrays.asList(interfaceDef); + } + + @Override + public List getDisks(Connect conn, String vmName) { + DiskDef diskDef = new DiskDef(); + return Arrays.asList(diskDef); + } + + }; + libvirtComputingResource.getVmStat(connect, VMNAME); + VmStatsEntry vmStat = libvirtComputingResource.getVmStat(connect, VMNAME); + // network traffic as generated by the logic above, must be greater than zero + Assert.assertTrue(vmStat.getNetworkReadKBs() > 0); + Assert.assertTrue(vmStat.getNetworkWriteKBs() > 0); + // IO traffic as generated by the logic above, must be greater than zero + Assert.assertTrue(vmStat.getDiskReadKBs() > 0); + Assert.assertTrue(vmStat.getDiskWriteKBs() > 0); + } } diff --git a/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java b/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java index 2d0d67b2f41..32679c8ff13 100755 --- a/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java +++ b/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java @@ -35,7 +35,6 @@ import org.apache.log4j.Logger; import org.apache.xmlrpc.XmlRpcException; import com.trilead.ssh2.SCPClient; - import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; import com.cloud.agent.api.AttachIsoCommand; @@ -61,6 +60,7 @@ import com.cloud.agent.api.GetVmStatsCommand; import com.cloud.agent.api.GetVncPortAnswer; import com.cloud.agent.api.GetVncPortCommand; import com.cloud.agent.api.HostStatsEntry; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.MaintainAnswer; import com.cloud.agent.api.MaintainCommand; import com.cloud.agent.api.MigrateAnswer; @@ -131,6 +131,7 @@ import com.cloud.utils.script.Script; import com.cloud.utils.ssh.SSHCmdHelper; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VirtualMachine.State; import com.trilead.ssh2.SCPClient; @@ -153,11 +154,12 @@ public class OvmResourceBase implements ServerResource, HypervisorResource { boolean _canBridgeFirewall; static boolean _isHeartBeat = false; List _bridges = null; - protected HashMap _vms = new HashMap(50); - static HashMap _stateMaps; private final Map> _vmNetworkStats= new ConcurrentHashMap>(); private static String _ovsAgentPath = "/opt/ovs-agent-latest"; - + + // TODO vmsync { + static HashMap _stateMaps; + protected HashMap _vms = new HashMap(50); static { _stateMaps = new HashMap(); _stateMaps.put("RUNNING", State.Running); @@ -165,6 +167,16 @@ public class OvmResourceBase implements ServerResource, HypervisorResource { _stateMaps.put("ERROR", State.Error); _stateMaps.put("SUSPEND", State.Stopped); } + // TODO vmsync } + + static HashMap _powerStateMaps; + static { + _powerStateMaps = new HashMap(); + _powerStateMaps.put("RUNNING", PowerState.PowerOn); + _powerStateMaps.put("DOWN", PowerState.PowerOff); + _powerStateMaps.put("ERROR", PowerState.PowerUnknown); + _powerStateMaps.put("SUSPEND", PowerState.PowerOff); + } @Override public boolean configure(String name, Map params) @@ -303,6 +315,7 @@ public class OvmResourceBase implements ServerResource, HypervisorResource { //TODO: introudce PIF cmd.setPrivateIpAddress(_ip); cmd.setStorageIpAddress(_ip); + cmd.setHostVmStateReport(getHostVmStateReport()); String defaultBridge = OvmBridge.getBridgeByIp(_conn, _ip); if (_publicNetworkName == null) { @@ -397,7 +410,7 @@ public class OvmResourceBase implements ServerResource, HypervisorResource { try { OvmHost.ping(_conn); HashMap newStates = sync(); - return new PingRoutingCommand(getType(), id, newStates); + return new PingRoutingCommand(getType(), id, newStates, this.getHostVmStateReport()); } catch (XmlRpcException e) { s_logger.debug("Check agent status failed", e); return null; @@ -785,6 +798,25 @@ public class OvmResourceBase implements ServerResource, HypervisorResource { return state; } + private PowerState toPowerState(String vmName, String s) { + PowerState state = _powerStateMaps.get(s); + if (state == null) { + s_logger.debug("Unkown state " + s + " for " + vmName); + state = PowerState.PowerUnknown; + } + return state; + } + + protected HashMap getHostVmStateReport() throws XmlRpcException { + final HashMap vmStates = new HashMap(); + Map vms = OvmHost.getAllVms(_conn); + for (final Map.Entry entry : vms.entrySet()) { + PowerState state = toPowerState(entry.getKey(), entry.getValue()); + vmStates.put(entry.getKey(), new HostVmStateReportEntry(state, _conn.getIp(), null)); + } + return vmStates; + } + protected HashMap getAllVms() throws XmlRpcException { final HashMap vmStates = new HashMap(); Map vms = OvmHost.getAllVms(_conn); diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java index 28e235e556e..b4758a563f6 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java @@ -84,6 +84,7 @@ import javax.naming.ConfigurationException; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @Component @@ -567,7 +568,7 @@ public class MockVmManagerImpl extends ManagerBase implements MockVmManager { @Override public GetDomRVersionAnswer getDomRVersion(GetDomRVersionCmd cmd) { - return new GetDomRVersionAnswer(cmd, null, null, null); + return new GetDomRVersionAnswer(cmd, null, "CloudStack Release 4.2.0", UUID.randomUUID().toString()); } @Override diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java index 9a27d748a29..727e067e527 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java @@ -29,6 +29,7 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.CheckVirtualMachineAnswer; import com.cloud.agent.api.CheckVirtualMachineCommand; import com.cloud.agent.api.Command; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingRoutingWithNwGroupsCommand; import com.cloud.agent.api.ReadyAnswer; @@ -53,6 +54,7 @@ import com.cloud.simulator.MockVMVO; import com.cloud.storage.Storage.StorageResourceType; import com.cloud.storage.template.TemplateProp; import com.cloud.utils.Pair; +import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VirtualMachine.State; public class AgentRoutingResource extends AgentStorageResource { @@ -114,7 +116,7 @@ public class AgentRoutingResource extends AgentStorageResource { } final HashMap newStates = sync(); HashMap> nwGrpStates = _simMgr.syncNetworkGroups(hostGuid); - return new PingRoutingWithNwGroupsCommand(getType(), id, newStates, nwGrpStates); + return new PingRoutingWithNwGroupsCommand(getType(), id, newStates, getHostVmStateReport(), nwGrpStates); } @Override @@ -275,6 +277,18 @@ public class AgentRoutingResource extends AgentStorageResource { return info; } + + protected HashMap getHostVmStateReport() { + HashMap report = new HashMap(); + + for(String vmName : _runningVms.keySet()) { + report.put(vmName, new HostVmStateReportEntry(PowerState.PowerOn, agentHost.getName(), null)); + } + + + + return report; + } protected HashMap sync() { Map newStates; diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index 4c34ebc365b..3519ca1c4dc 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -1275,6 +1275,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { String vmSnapshotName = cmd.getTarget().getSnapshotName(); String vmSnapshotDesc = cmd.getTarget().getDescription(); boolean snapshotMemory = cmd.getTarget().getType() == VMSnapshot.Type.DiskAndMemory; + boolean quiescevm = cmd.getTarget().getQuiescevm(); VirtualMachineMO vmMo = null; VmwareContext context = hostService.getServiceContext(cmd); Map mapNewDisk = new HashMap(); @@ -1303,7 +1304,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { } else { if (vmMo.getSnapshotMor(vmSnapshotName) != null){ s_logger.debug("VM snapshot " + vmSnapshotName + " already exists"); - }else if (!vmMo.createSnapshot(vmSnapshotName, vmSnapshotDesc, snapshotMemory, true)) { + }else if (!vmMo.createSnapshot(vmSnapshotName, vmSnapshotDesc, snapshotMemory, quiescevm)) { return new CreateVMSnapshotAnswer(cmd, false, "Unable to create snapshot due to esxi internal failed"); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 03af0da51b1..26ef0475a83 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -46,6 +46,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import com.cloud.agent.api.routing.*; + import org.apache.log4j.Logger; import org.apache.log4j.NDC; @@ -161,6 +162,7 @@ import com.cloud.agent.api.GetVmStatsCommand; import com.cloud.agent.api.GetVncPortAnswer; import com.cloud.agent.api.GetVncPortCommand; import com.cloud.agent.api.HostStatsEntry; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.MaintainAnswer; import com.cloud.agent.api.MaintainCommand; import com.cloud.agent.api.ManageSnapshotAnswer; @@ -301,6 +303,7 @@ import com.cloud.utils.net.NetUtils; import com.cloud.utils.ssh.SshHelper; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachineName; import com.cloud.vm.VmDetailConstants; @@ -358,6 +361,17 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa protected StorageSubsystemCommandHandler storageHandler; + protected static HashMap s_powerStatesTable; + static { + s_powerStatesTable = new HashMap(); + s_powerStatesTable.put(VirtualMachinePowerState.POWERED_ON, PowerState.PowerOn); + s_powerStatesTable.put(VirtualMachinePowerState.POWERED_OFF, PowerState.PowerOff); + s_powerStatesTable.put(VirtualMachinePowerState.SUSPENDED, PowerState.PowerOn); + } + + // TODO vmsync { + // deprecated, will delete after full replacement + // protected static HashMap s_statesTable; static { s_statesTable = new HashMap(); @@ -365,6 +379,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa s_statesTable.put(VirtualMachinePowerState.POWERED_OFF, State.Stopped); s_statesTable.put(VirtualMachinePowerState.SUSPENDED, State.Stopped); } + // TODO vmsync } public Gson getGson() { return _gson; @@ -2559,7 +2574,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa long requestedMaxMemoryInMb = vmSpec.getMaxRam() / (1024 * 1024); // Check if VM is really running on hypervisor host - if (getVmState(vmMo) != State.Running) { + if (getVmPowerState(vmMo) != PowerState.PowerOn) { throw new CloudRuntimeException("Found that the VM " + vmMo.getVmName() + " is not running. Unable to scale-up this VM"); } @@ -2609,7 +2624,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa try { VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); - // mark VM as starting state so that sync() can know not to report stopped too early + // mark VM as starting state so that sync can know not to report stopped too early synchronized (_vms) { _vms.put(vmInternalCSName, State.Starting); } @@ -2639,7 +2654,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa boolean hasSnapshot = false; if (vmMo != null) { s_logger.info("VM " + vmInternalCSName + " already exists, tear down devices for reconfiguration"); - if (getVmState(vmMo) != State.Stopped) + if (getVmPowerState(vmMo) != PowerState.PowerOff) vmMo.safePowerOff(_shutdown_waitMs); // retrieve disk information before we tear down @@ -2662,7 +2677,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa takeVmFromOtherHyperHost(hyperHost, vmInternalCSName); - if (getVmState(vmMo) != State.Stopped) + if (getVmPowerState(vmMo) != PowerState.PowerOff) vmMo.safePowerOff(_shutdown_waitMs); diskInfoBuilder = vmMo.getDiskInfoBuilder(); @@ -3885,7 +3900,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa try { vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_NIC_MASK, "0"); - if (getVmState(vmMo) != State.Stopped) { + if (getVmPowerState(vmMo) != PowerState.PowerOff) { if (vmMo.safePowerOff(_shutdown_waitMs)) { state = State.Stopped; return new StopAnswer(cmd, "Stop VM " + cmd.getVmName() + " Succeed", true); @@ -5488,7 +5503,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa List networks = vmMo.getNetworksWithDetails(); // tear down all devices first before we destroy the VM to avoid accidently delete disk backing files - if (getVmState(vmMo) != State.Stopped) + if (getVmPowerState(vmMo) != PowerState.PowerOff) vmMo.safePowerOff(_shutdown_waitMs); vmMo.tearDownDevices(new Class[] { /* VirtualDisk.class, */ VirtualEthernetCard.class }); vmMo.destroy(); @@ -5813,86 +5828,85 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa @Override public PingCommand getCurrentStatus(long id) { - try { - HashMap newStates = sync(); - if (newStates == null) { - return null; - } - - try { - // take the chance to do left-over dummy VM cleanup from previous run - VmwareContext context = getServiceContext(); - VmwareHypervisorHost hyperHost = getHyperHost(context); - VmwareManager mgr = hyperHost.getContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME); - - if(hyperHost.isHyperHostConnected()) { - mgr.gcLeftOverVMs(context); - - s_logger.info("Scan hung worker VM to recycle"); - - int workerKey = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER); - int workerTagKey = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER_TAG); - String workerPropName = String.format("value[%d]", workerKey); - String workerTagPropName = String.format("value[%d]", workerTagKey); + gcAndKillHungWorkerVMs(); + + HashMap newStates = sync(); + if (newStates == null) { + return null; + } + return new PingRoutingCommand(getType(), id, newStates, syncHostVmStates()); + } + + private void gcAndKillHungWorkerVMs() { + try { + // take the chance to do left-over dummy VM cleanup from previous run + VmwareContext context = getServiceContext(); + VmwareHypervisorHost hyperHost = getHyperHost(context); + VmwareManager mgr = hyperHost.getContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME); - // GC worker that has been running for too long - ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost( - new String[] {"name", "config.template", workerPropName, workerTagPropName, - }); - if(ocs != null) { - for(ObjectContent oc : ocs) { - List props = oc.getPropSet(); - if(props != null) { - boolean template = false; - boolean isWorker = false; - String workerTag = null; + if(hyperHost.isHyperHostConnected()) { + mgr.gcLeftOverVMs(context); - for(DynamicProperty prop : props) { - if(prop.getName().equals("config.template")) { - template = (Boolean)prop.getVal(); - } else if(prop.getName().equals(workerPropName)) { - CustomFieldStringValue val = (CustomFieldStringValue)prop.getVal(); - if(val != null && val.getValue() != null && val.getValue().equalsIgnoreCase("true")) - isWorker = true; - } - else if(prop.getName().equals(workerTagPropName)) { - CustomFieldStringValue val = (CustomFieldStringValue)prop.getVal(); - workerTag = val.getValue(); - } + s_logger.info("Scan hung worker VM to recycle"); + + int workerKey = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER); + int workerTagKey = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER_TAG); + String workerPropName = String.format("value[%d]", workerKey); + String workerTagPropName = String.format("value[%d]", workerTagKey); + + // GC worker that has been running for too long + ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost( + new String[] {"name", "config.template", workerPropName, workerTagPropName, + }); + if(ocs != null) { + for(ObjectContent oc : ocs) { + List props = oc.getPropSet(); + if(props != null) { + boolean template = false; + boolean isWorker = false; + String workerTag = null; + + for(DynamicProperty prop : props) { + if(prop.getName().equals("config.template")) { + template = (Boolean)prop.getVal(); + } else if(prop.getName().equals(workerPropName)) { + CustomFieldStringValue val = (CustomFieldStringValue)prop.getVal(); + if(val != null && val.getValue() != null && val.getValue().equalsIgnoreCase("true")) + isWorker = true; } + else if(prop.getName().equals(workerTagPropName)) { + CustomFieldStringValue val = (CustomFieldStringValue)prop.getVal(); + workerTag = val.getValue(); + } + } - VirtualMachineMO vmMo = new VirtualMachineMO(hyperHost.getContext(), oc.getObj()); - if(!template && isWorker) { - boolean recycle = false; - recycle = mgr.needRecycle(workerTag); + VirtualMachineMO vmMo = new VirtualMachineMO(hyperHost.getContext(), oc.getObj()); + if(!template && isWorker) { + boolean recycle = false; + recycle = mgr.needRecycle(workerTag); - if(recycle) { - s_logger.info("Recycle pending worker VM: " + vmMo.getName()); + if(recycle) { + s_logger.info("Recycle pending worker VM: " + vmMo.getName()); - vmMo.powerOff(); - vmMo.destroy(); - } + vmMo.powerOff(); + vmMo.destroy(); } } } - } - } else { - s_logger.error("Host is no longer connected."); - return null; - } - } catch (Throwable e) { - if (e instanceof RemoteException) { - s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context"); - invalidateServiceContext(); - return null; - } - } - - return new PingRoutingCommand(getType(), id, newStates); + } + } + } else { + s_logger.error("Host is no longer connected."); + } - } finally { - recycleServiceContext(); - } + } catch (Throwable e) { + if (e instanceof RemoteException) { + s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context"); + invalidateServiceContext(); + } + } finally { + recycleServiceContext(); + } } @Override @@ -5935,7 +5949,14 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } cmd.setHypervisorType(HypervisorType.VMware); + + // TODO vmsync { + // deprecated after full replacement cmd.setStateChanges(changes); + // TODO vmsync} + + cmd.setHostVmStateReport(syncHostVmStates()); + cmd.setCluster(_cluster); cmd.setHypervisorVersion(hostApiVersion); @@ -6091,6 +6112,14 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } + protected HashMap syncHostVmStates() { + try { + return getHostVmStateReport(); + } catch(Exception e) { + return new HashMap(); + } + } + protected HashMap sync() { HashMap changes = new HashMap(); HashMap oldStates = null; @@ -6295,6 +6324,65 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return VirtualMachineGuestOsIdentifier.OTHER_GUEST; } + private HashMap getHostVmStateReport() throws Exception { + VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); + + int key = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME); + if(key == 0) { + s_logger.warn("Custom field " + CustomFieldConstants.CLOUD_VM_INTERNAL_NAME + " is not registered ?!"); + } + String instanceNameCustomField = "value[" + key + "]"; + + // CLOUD_VM_INTERNAL_NAME stores the internal CS generated vm name. This was earlier stored in name. Now, name can be either the hostname or + // the internal CS name, but the custom field CLOUD_VM_INTERNAL_NAME always stores the internal CS name. + ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost( + new String[] { "name", "runtime.powerState", "config.template", instanceNameCustomField } + ); + + HashMap newStates = new HashMap(); + if (ocs != null && ocs.length > 0) { + for (ObjectContent oc : ocs) { + List objProps = oc.getPropSet(); + if (objProps != null) { + + boolean isTemplate = false; + String name = null; + String VMInternalCSName = null; + VirtualMachinePowerState powerState = VirtualMachinePowerState.POWERED_OFF; + for (DynamicProperty objProp : objProps) { + if (objProp.getName().equals("config.template")) { + if (objProp.getVal().toString().equalsIgnoreCase("true")) { + isTemplate = true; + } + } else if (objProp.getName().equals("runtime.powerState")) { + powerState = (VirtualMachinePowerState) objProp.getVal(); + } else if (objProp.getName().equals("name")) { + name = (String) objProp.getVal(); + } else if(objProp.getName().contains(instanceNameCustomField)) { + if(objProp.getVal() != null) + VMInternalCSName = ((CustomFieldStringValue)objProp.getVal()).getValue(); + } + else { + assert (false); + } + } + + if (VMInternalCSName != null) + name = VMInternalCSName; + + if (!isTemplate) { + newStates.put( + name, + new HostVmStateReportEntry(convertPowerState(powerState), hyperHost.getHyperHostName(), null) + ); + } + } + } + } + return newStates; + } + + // TODO vmsync { private HashMap getVmStates() throws Exception { VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); @@ -6462,6 +6550,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } return vmResponseMap; } + // TODO vmsync } protected String networkUsage(final String privateIpAddress, final String option, final String ethName) { String args = null; @@ -6572,6 +6661,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return connect(vmname, ipAddress, 3922); } + // TODO vmsync { + // deprecated after full replacement private static State convertState(VirtualMachinePowerState powerState) { return s_statesTable.get(powerState); } @@ -6580,7 +6671,17 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo(); return convertState(runtimeInfo.getPowerState()); } + // TODO vmsync } + + private static PowerState convertPowerState(VirtualMachinePowerState powerState) { + return s_powerStatesTable.get(powerState); + } + public static PowerState getVmPowerState(VirtualMachineMO vmMo) throws Exception { + VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo(); + return convertPowerState(runtimeInfo.getPowerState()); + } + private static HostStatsEntry getHyperHostStats(VmwareHypervisorHost hyperHost) throws Exception { ComputeResourceSummary hardwareSummary = hyperHost.getHyperHostHardwareSummary(); if(hardwareSummary == null) diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index fbbbc13c6b3..b31b926256e 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -383,9 +383,7 @@ public class VmwareStorageProcessor implements StorageProcessor { // restoreVM - move the new ROOT disk into corresponding VM folder String vmInternalCSName = volume.getVmName(); if (dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmInternalCSName)) { - String oldRootDisk = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmInternalCSName, vmdkName); - if (oldRootDisk != null) - VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmInternalCSName, dsMo, vmdkName); + VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmInternalCSName, dsMo, vmdkName); } VolumeObjectTO newVol = new VolumeObjectTO(); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 69b7c9e07c7..7a112ae950d 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -63,6 +63,7 @@ import com.cloud.agent.api.GetVmStatsCommand; import com.cloud.agent.api.GetVncPortAnswer; import com.cloud.agent.api.GetVncPortCommand; import com.cloud.agent.api.HostStatsEntry; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.MaintainAnswer; import com.cloud.agent.api.MaintainCommand; import com.cloud.agent.api.ManageSnapshotAnswer; @@ -188,6 +189,7 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.snapshot.VMSnapshot; import com.google.gson.Gson; @@ -225,6 +227,7 @@ import com.xensource.xenapi.VLAN; import com.xensource.xenapi.VM; import com.xensource.xenapi.VMGuestMetrics; import com.xensource.xenapi.XenAPIObject; + import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; @@ -239,6 +242,7 @@ import org.xml.sax.InputSource; import javax.ejb.Local; import javax.naming.ConfigurationException; import javax.xml.parsers.DocumentBuilderFactory; + import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -347,6 +351,17 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } + protected static HashMap s_powerStatesTable; + static { + s_powerStatesTable = new HashMap(); + s_powerStatesTable.put(Types.VmPowerState.HALTED, PowerState.PowerOff); + s_powerStatesTable.put(Types.VmPowerState.PAUSED, PowerState.PowerOn); + s_powerStatesTable.put(Types.VmPowerState.RUNNING, PowerState.PowerOn); + s_powerStatesTable.put(Types.VmPowerState.SUSPENDED, PowerState.PowerOn); + s_powerStatesTable.put(Types.VmPowerState.UNRECOGNIZED, PowerState.PowerUnknown); + } + + // TODO vmsync { protected static HashMap s_statesTable; static { s_statesTable = new HashMap(); @@ -356,6 +371,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe s_statesTable.put(Types.VmPowerState.SUSPENDED, State.Running); s_statesTable.put(Types.VmPowerState.UNRECOGNIZED, State.Unknown); } + // TODO vmsync } public XsHost getHost() { return _host; @@ -2975,7 +2991,61 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe final State state = s_statesTable.get(ps); return state == null ? State.Unknown : state; } + + private static PowerState convertPowerState(Types.VmPowerState powerState) { + return s_powerStatesTable.get(powerState); + } + protected HashMap getHostVmStateReport(Connection conn) { + final HashMap vmStates = new HashMap(); + Map vm_map = null; + for (int i = 0; i < 2; i++) { + try { + vm_map = VM.getAllRecords(conn); //USE THIS TO GET ALL VMS FROM A CLUSTER + break; + } catch (final Throwable e) { + s_logger.warn("Unable to get vms", e); + } + try { + Thread.sleep(1000); + } catch (final InterruptedException ex) { + + } + } + + if (vm_map == null) { + return null; + } + for (VM.Record record: vm_map.values()) { + if (record.isControlDomain || record.isASnapshot || record.isATemplate) { + continue; // Skip DOM0 + } + + VmPowerState ps = record.powerState; + Host host = record.residentOn; + String xstoolsversion = getVMXenToolsVersion(record.platform); + String host_uuid = null; + if( ! isRefNull(host) ) { + try { + host_uuid = host.getUuid(conn); + } catch (BadServerResponse e) { + s_logger.error("Failed to get host uuid for host " + host.toWireString(), e); + } catch (XenAPIException e) { + s_logger.error("Failed to get host uuid for host " + host.toWireString(), e); + } catch (XmlRpcException e) { + s_logger.error("Failed to get host uuid for host " + host.toWireString(), e); + } + vmStates.put( + record.nameLabel, + new HostVmStateReportEntry(convertPowerState(ps), host_uuid, xstoolsversion) + ); + } + } + + return vmStates; + } + + // TODO vmsync { protected HashMap> getAllVms(Connection conn) { final HashMap> vmStates = new HashMap>(); Map vm_map = null; @@ -3025,6 +3095,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return vmStates; } + // TODO vmsync } protected State getVmState(Connection conn, final String vmName) { int retry = 3; @@ -4749,13 +4820,13 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } Connection conn = getConnection(); if (!_canBridgeFirewall && !_isOvs) { - return new PingRoutingCommand(getType(), id, null); + return new PingRoutingCommand(getType(), id, null, getHostVmStateReport(conn)); } else if (_isOvs) { List>ovsStates = ovsFullSyncStates(); - return new PingRoutingWithOvsCommand(getType(), id, null, ovsStates); + return new PingRoutingWithOvsCommand(getType(), id, null, getHostVmStateReport(conn), ovsStates); }else { HashMap> nwGrpStates = syncNetworkGroups(conn, id); - return new PingRoutingWithNwGroupsCommand(getType(), id, null, nwGrpStates); + return new PingRoutingWithNwGroupsCommand(getType(), id, null, getHostVmStateReport(conn), nwGrpStates); } } catch (Exception e) { s_logger.warn("Unable to get current status", e); @@ -5010,6 +5081,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe cmd.setHypervisorType(HypervisorType.XenServer); cmd.setCluster(_cluster); cmd.setPoolSync(false); + cmd.setHostVmStateReport(this.getHostVmStateReport(conn)); Pool pool; try { @@ -5963,7 +6035,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe Set vms = host.getResidentVMs(conn); for (VM vm : vms) { if (vm.getIsControlDomain(conn)) { - dom0Ram = vm.getMemoryDynamicMax(conn); + dom0Ram = vm.getMemoryStaticMax(conn); break; } } diff --git a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java index be7c77db55a..aa60ce6338f 100644 --- a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java +++ b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java @@ -18,16 +18,15 @@ */ package org.apache.cloudstack.storage.datastore.driver; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.*; import org.apache.log4j.Logger; -import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.image.BaseImageStoreDriverImpl; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; @@ -49,7 +48,6 @@ public class CloudStackImageStoreDriverImpl extends BaseImageStoreDriverImpl { @Inject EndPointSelector _epSelector; - @Override public DataStoreTO getStoreTO(DataStore store) { ImageStoreImpl nfsStore = (ImageStoreImpl) store; diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java index 327d87c6722..bf2899923ec 100644 --- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java @@ -18,26 +18,18 @@ */ package org.apache.cloudstack.storage.datastore.driver; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; import javax.inject.Inject; import com.cloud.storage.*; +import org.apache.cloudstack.engine.subsystem.api.storage.*; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.log4j.Logger; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; -import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; -import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; -import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; -import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.command.CommandResult; @@ -70,6 +62,13 @@ import com.cloud.utils.NumbersUtil; import com.cloud.vm.dao.VMInstanceDao; public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver { + @Override + public Map getCapabilities() { + Map caps = new HashMap(); + caps.put(DataStoreCapabilities.VOLUME_SNAPSHOT_QUIESCEVM.toString(), "false"); + return caps; + } + private static final Logger s_logger = Logger.getLogger(CloudStackPrimaryDataStoreDriverImpl.class); @Inject DiskOfferingDao diskOfferingDao; diff --git a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java index 8f4c7bbf202..fcd7855320b 100644 --- a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java @@ -43,6 +43,9 @@ import com.cloud.agent.api.to.DataTO; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.utils.exception.CloudRuntimeException; +import java.util.HashMap; +import java.util.Map; + public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver { private static final Logger s_logger = Logger.getLogger(SamplePrimaryDataStoreDriverImpl.class); @Inject @@ -56,6 +59,11 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver } + @Override + public Map getCapabilities() { + return null; + } + @Override public DataTO getTO(DataObject data) { return null; diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java index 1c726cd110b..4301bfa06e6 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java @@ -17,18 +17,13 @@ package org.apache.cloudstack.storage.datastore.driver; import java.text.NumberFormat; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.inject.Inject; -import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; -import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; -import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; -import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.*; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; @@ -61,6 +56,11 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { @Inject private AccountDao _accountDao; @Inject private AccountDetailsDao _accountDetailsDao; + @Override + public Map getCapabilities() { + return null; + } + @Override public DataTO getTO(DataObject data) { return null; diff --git a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml index f7a8d6795cd..2a080f90f18 100644 --- a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml +++ b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml @@ -144,7 +144,9 @@ - + + + diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index f70af5f9a05..903c48507a8 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -1023,6 +1023,9 @@ public class ApiResponseHelper implements ResponseGenerator { response.setPublicEndPort(Integer.toString(fwRule.getSourcePortEnd())); List cidrs = ApiDBUtils.findFirewallSourceCidrs(fwRule.getId()); response.setCidrList(StringUtils.join(cidrs, ",")); + + Network guestNtwk = ApiDBUtils.findNetworkById(fwRule.getNetworkId()); + response.setNetworkId(guestNtwk.getUuid()); IpAddress ip = ApiDBUtils.findIpAddressById(fwRule.getSourceIpAddressId()); response.setPublicIpAddressId(ip.getUuid()); @@ -2371,12 +2374,11 @@ public class ApiResponseHelper implements ResponseGenerator { IpAddress ip = ApiDBUtils.findIpAddressById(fwRule.getSourceIpAddressId()); response.setPublicIpAddressId(ip.getUuid()); response.setPublicIpAddress(ip.getAddress().addr()); - } else if (fwRule.getTrafficType() == FirewallRule.TrafficType.Egress) { - response.setPublicIpAddress(null); - Network network = ApiDBUtils.findNetworkById(fwRule.getNetworkId()); - response.setNetworkId(network.getUuid()); } - + + Network network = ApiDBUtils.findNetworkById(fwRule.getNetworkId()); + response.setNetworkId(network.getUuid()); + FirewallRule.State state = fwRule.getState(); String stateToSet = state.toString(); if (state.equals(FirewallRule.State.Revoke)) { diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 2b5b81d3eb5..35a539a8015 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -27,6 +27,7 @@ import javax.ejb.Local; import javax.inject.Inject; import com.cloud.hypervisor.Hypervisor; +import com.cloud.storage.DiskOfferingVO; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO; import org.apache.cloudstack.affinity.AffinityGroupResponse; @@ -82,6 +83,9 @@ import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.VolumeResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.query.QueryService; @@ -341,6 +345,8 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { @Inject ResourceTagDao _resourceTagDao; + @Inject + DataStoreManager dataStoreManager; /* * (non-Javadoc) @@ -1993,6 +1999,16 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { List poolResponses = ViewResponseHelper.createStoragePoolResponse(result.first().toArray( new StoragePoolJoinVO[result.first().size()])); + for(StoragePoolResponse poolResponse : poolResponses) { + DataStore store = dataStoreManager.getPrimaryDataStore(Integer.parseInt(poolResponse.getId())); + if (store != null) { + DataStoreDriver driver = store.getDriver(); + if (driver != null && driver.getCapabilities() != null) { + poolResponse.setCaps(driver.getCapabilities()); + } + } + } + response.setResponses(poolResponses, result.second()); return response; } @@ -2273,6 +2289,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { Filter searchFilter = new Filter(DiskOfferingJoinVO.class, "sortKey", isAscending, cmd.getStartIndex(), cmd.getPageSizeVal()); SearchCriteria sc = _diskOfferingJoinDao.createSearchCriteria(); + sc.addAnd("type", Op.EQ, DiskOfferingVO.Type.Disk); Account account = CallContext.current().getCallingAccount(); Object name = cmd.getDiskOfferingName(); diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index a9b9ae410d6..7f73b2fab63 100755 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -28,6 +28,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; + import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; @@ -69,7 +70,6 @@ import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.StorageManager; import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.VMTemplatePoolDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.DateUtil; @@ -474,19 +474,6 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, } - private long getVMSnapshotAllocatedCapacity(StoragePoolVO pool){ - List volumes = _volumeDao.findByPoolId(pool.getId()); - long totalSize = 0; - for (VolumeVO volume : volumes) { - if(volume.getInstanceId() == null) - continue; - Long chainSize = volume.getVmSnapshotChainSize(); - if(chainSize != null) - totalSize += chainSize; - } - return totalSize; - } - @Override public long getAllocatedPoolCapacity(StoragePoolVO pool, VMTemplateVO templateForVmCreation){ @@ -495,7 +482,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, long totalAllocatedSize = sizes.second() + sizes.first() * _extraBytesPerVolume; // Get size for VM Snapshots - totalAllocatedSize = totalAllocatedSize + getVMSnapshotAllocatedCapacity(pool); + totalAllocatedSize = totalAllocatedSize + _volumeDao.getVMSnapshotSizeByPool(pool.getId()); // Iterate through all templates on this storage pool boolean tmpinstalled = false; @@ -602,9 +589,10 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, CapacityVO cpuCap = _capacityDao.findByHostIdType(host.getId(), CapacityVO.CAPACITY_TYPE_CPU); CapacityVO memCap = _capacityDao.findByHostIdType(host.getId(), CapacityVO.CAPACITY_TYPE_MEMORY); - if (cpuCap != null && memCap != null){ - + if ( host.getTotalMemory() != null ) { + memCap.setTotalCapacity(host.getTotalMemory()); + } long hostTotalCpu = host.getCpus().longValue() * host.getSpeed().longValue(); if (cpuCap.getTotalCapacity() != hostTotalCpu) { @@ -976,6 +964,6 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {CpuOverprovisioningFactor, MemOverprovisioningFactor}; + return new ConfigKey[] {CpuOverprovisioningFactor, MemOverprovisioningFactor, StorageCapacityDisableThreshold, StorageOverprovisioningFactor, StorageAllocatedCapacityDisableThreshold}; } } diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index bc805b7043e..fd26ff0495b 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -57,8 +57,6 @@ public enum Config { VlanCapacityThreshold("Alert", ManagementServer.class, Float.class, "zone.vlan.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of Zone Vlan utilization above which alerts will be sent about low number of Zone Vlans.", null), DirectNetworkPublicIpCapacityThreshold("Alert", ManagementServer.class, Float.class, "zone.directnetwork.publicip.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of Direct Network Public Ip Utilization above which alerts will be sent about low number of direct network public ips.", null), LocalStorageCapacityThreshold("Alert", ManagementServer.class, Float.class, "cluster.localStorage.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of local storage utilization above which alerts will be sent about low local storage available.", null), - CPUCapacityDisableThreshold("Alert", ManagementServer.class, Float.class, "cluster.cpu.allocated.capacity.disablethreshold", "0.85", "Percentage (as a value between 0 and 1) of cpu utilization above which allocators will disable using the cluster for low cpu available. Keep the corresponding notification threshold lower than this to be notified beforehand.", null, ConfigKey.Scope.Cluster.toString()), - MemoryCapacityDisableThreshold("Alert", ManagementServer.class, Float.class, "cluster.memory.allocated.capacity.disablethreshold", "0.85", "Percentage (as a value between 0 and 1) of memory utilization above which allocators will disable using the cluster for low memory available. Keep the corresponding notification threshold lower than this to be notified beforehand.", null, ConfigKey.Scope.Cluster.toString()), // Storage diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 82256ca952e..21651ad3792 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -36,6 +36,8 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.deploy.DeploymentClusterPlanner; +import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.log4j.Logger; import org.apache.cloudstack.acl.SecurityChecker; @@ -117,6 +119,7 @@ import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.PodVlanMapDao; import com.cloud.dc.dao.VlanDao; import com.cloud.deploy.DataCenterDeployment; +import com.cloud.deploy.DeploymentPlanner; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; @@ -215,6 +218,8 @@ ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, Co @Inject ConfigurationDao _configDao; @Inject + ConfigDepot _configDepot; + @Inject HostPodDao _podDao; @Inject AccountVlanMapDao _accountVlanMapDao; @@ -372,8 +377,8 @@ ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, Co weightBasedParametersForValidation.add(Config.LocalStorageCapacityThreshold.key()); weightBasedParametersForValidation.add(CapacityManager.StorageAllocatedCapacityDisableThreshold.key()); weightBasedParametersForValidation.add(CapacityManager.StorageCapacityDisableThreshold.key()); - weightBasedParametersForValidation.add(Config.CPUCapacityDisableThreshold.key()); - weightBasedParametersForValidation.add(Config.MemoryCapacityDisableThreshold.key()); + weightBasedParametersForValidation.add(DeploymentClusterPlanner.ClusterCPUCapacityDisableThreshold.key()); + weightBasedParametersForValidation.add(DeploymentClusterPlanner.ClusterMemoryCapacityDisableThreshold.key()); weightBasedParametersForValidation.add(Config.AgentLoadThreshold.key()); weightBasedParametersForValidation.add(Config.VmUserDispersionWeight.key()); @@ -625,8 +630,17 @@ ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, Co + (((name.toLowerCase()).contains("password")) ? "*****" : (((value == null) ? "" : value)))); // check if config value exists ConfigurationVO config = _configDao.findByName(name); + String catergory = null; + + // FIX ME - All configuration parameters are not moved from config.java to configKey if (config == null) { - throw new InvalidParameterValueException("Config parameter with name " + name + " doesn't exist"); + if ( _configDepot.get(name) == null ) { + s_logger.warn("Probably the component manager where configuration variable " + name + " is defined needs to implement Configurable interface"); + throw new InvalidParameterValueException("Config parameter with name " + name + " doesn't exist"); + } + catergory = _configDepot.get(name).category(); + } else { + catergory = config.getCategory(); } if (value == null) { @@ -667,7 +681,7 @@ ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, Co "cannot handle multiple IDs, provide only one ID corresponding to the scope"); } - String updatedValue = updateConfiguration(userId, name, config.getCategory(), value, scope, id); + String updatedValue = updateConfiguration(userId, name, catergory, value, scope, id); if ((value == null && updatedValue == null) || updatedValue.equalsIgnoreCase(value)) { return _configDao.findByName(name); } else { diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index 64b1124d6b8..3707d3d9065 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -29,6 +29,8 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; @@ -83,7 +85,7 @@ import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; @Local(value=DeploymentPlanner.class) -public class FirstFitPlanner extends PlannerBase implements DeploymentClusterPlanner { +public class FirstFitPlanner extends PlannerBase implements DeploymentClusterPlanner, Configurable{ private static final Logger s_logger = Logger.getLogger(FirstFitPlanner.class); @Inject protected HostDao _hostDao; @Inject protected DataCenterDao _dcDao; @@ -246,11 +248,11 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentClusterPla // if he changes these values Map disableThresholdMap = new HashMap(); - String cpuDisableThresholdString = _configDao.getValue(Config.CPUCapacityDisableThreshold.key()); + String cpuDisableThresholdString = ClusterCPUCapacityDisableThreshold.value().toString(); float cpuDisableThreshold = NumbersUtil.parseFloat(cpuDisableThresholdString, 0.85F); disableThresholdMap.put(Capacity.CAPACITY_TYPE_CPU, cpuDisableThreshold); - String memoryDisableThresholdString = _configDao.getValue(Config.MemoryCapacityDisableThreshold.key()); + String memoryDisableThresholdString = ClusterMemoryCapacityDisableThreshold.value().toString(); float memoryDisableThreshold = NumbersUtil.parseFloat(memoryDisableThresholdString, 0.85F); disableThresholdMap.put(Capacity.CAPACITY_TYPE_MEMORY, memoryDisableThreshold); @@ -283,10 +285,10 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentClusterPla } if (capacity == Capacity.CAPACITY_TYPE_CPU) { clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(capacity, - plan.getDataCenterId(), Config.CPUCapacityDisableThreshold.key(), cpu_requested); + plan.getDataCenterId(), ClusterCPUCapacityDisableThreshold.key(), cpu_requested); } else if (capacity == Capacity.CAPACITY_TYPE_MEMORY) { clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(capacity, - plan.getDataCenterId(), Config.MemoryCapacityDisableThreshold.key(), ram_requested); + plan.getDataCenterId(), ClusterMemoryCapacityDisableThreshold.key(), ram_requested); } if (clustersCrossingThreshold != null && clustersCrossingThreshold.size() != 0) { @@ -522,4 +524,14 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentClusterPla DeploymentPlan plan, ExcludeList avoid) throws InsufficientServerCapacityException { return PlannerResourceUsage.Shared; } + + @Override + public String getConfigComponentName() { + return DeploymentClusterPlanner.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[] {ClusterCPUCapacityDisableThreshold, ClusterMemoryCapacityDisableThreshold}; + } } diff --git a/server/src/com/cloud/hypervisor/kvm/discoverer/KvmDummyResourceBase.java b/server/src/com/cloud/hypervisor/kvm/discoverer/KvmDummyResourceBase.java index 240ea6ce316..d6fde31833d 100644 --- a/server/src/com/cloud/hypervisor/kvm/discoverer/KvmDummyResourceBase.java +++ b/server/src/com/cloud/hypervisor/kvm/discoverer/KvmDummyResourceBase.java @@ -23,6 +23,7 @@ import javax.naming.ConfigurationException; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; @@ -46,7 +47,9 @@ public class KvmDummyResourceBase extends ServerResourceBase implements ServerRe @Override public StartupCommand[] initialize() { - StartupRoutingCommand cmd = new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.KVM, new HashMap(), new HashMap()); + StartupRoutingCommand cmd = new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.KVM, + new HashMap(), new HashMap(), + new HashMap()); cmd.setDataCenter(_zoneId); cmd.setPod(_podId); cmd.setCluster(_clusterId); diff --git a/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java b/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java index 5f7ad4ba9a8..cf1254bfef0 100644 --- a/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java +++ b/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java @@ -27,6 +27,8 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.api.ResourceDetail; import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; import org.apache.cloudstack.resourcedetail.dao.FirewallRuleDetailsDao; +import org.apache.cloudstack.resourcedetail.dao.RemoteAccessVpnDetailsDao; +import org.apache.cloudstack.resourcedetail.dao.UserIpAddressDetailsDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -75,6 +77,10 @@ public class ResourceMetaDataManagerImpl extends ManagerBase implements Resource StoragePoolDetailsDao _storageDetailsDao; @Inject FirewallRuleDetailsDao _firewallRuleDetailsDao; + @Inject + UserIpAddressDetailsDao _userIpAddressDetailsDao; + @Inject + RemoteAccessVpnDetailsDao _vpnDetailsDao; private static Map> _daoMap= new HashMap>(); @@ -91,7 +97,11 @@ public class ResourceMetaDataManagerImpl extends ManagerBase implements Resource _daoMap.put(ResourceObjectType.Zone, _dcDetailsDao); _daoMap.put(ResourceObjectType.Storage, _storageDetailsDao); _daoMap.put(ResourceObjectType.FirewallRule, _firewallRuleDetailsDao); - + _daoMap.put(ResourceObjectType.PublicIpAddress, _userIpAddressDetailsDao); + _daoMap.put(ResourceObjectType.PortForwardingRule, _firewallRuleDetailsDao); + _daoMap.put(ResourceObjectType.LoadBalancer, _firewallRuleDetailsDao); + _daoMap.put(ResourceObjectType.RemoteAccessVpn, _vpnDetailsDao); + return true; } diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java index 8d54541dd62..3e0cd774710 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java @@ -778,7 +778,20 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase String loadBalancingIpAddress = existedGuestIp; if (loadBalancingIpAddress == null) { - loadBalancingIpAddress = _ipAddrMgr.acquireGuestIpAddress(network, null); + if (network.getGuestType() == Network.GuestType.Isolated) { + loadBalancingIpAddress = _ipAddrMgr.acquireGuestIpAddress(network, null); + } else if (network.getGuestType() == Network.GuestType.Shared) { + try { + PublicIp directIp = _ipAddrMgr.assignPublicIpAddress(network.getDataCenterId(), + null, _accountDao.findById(network.getAccountId()), VlanType.DirectAttached, network.getId(), + null, true); + loadBalancingIpAddress = directIp.getAddress().addr(); + } catch (InsufficientCapacityException capException) { + String msg = "Ran out of guest IP addresses from the shared network."; + s_logger.error(msg); + throw new ResourceUnavailableException(msg, DataCenter.class, network.getDataCenterId()); + } + } } if (loadBalancingIpAddress == null) { diff --git a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java index ccceb8dc76e..6ccf5003e5c 100644 --- a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java @@ -27,13 +27,12 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; -import org.apache.cloudstack.api.command.user.firewall.ListEgressFirewallRulesCmd; import org.apache.cloudstack.api.command.user.firewall.ListFirewallRulesCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.configuration.Config; import com.cloud.domain.dao.DomainDao; @@ -70,7 +69,6 @@ import com.cloud.network.rules.FirewallRule.State; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.PortForwardingRuleVO; -import com.cloud.network.rules.StaticNat; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.VpcManager; import com.cloud.projects.Project.ListProjectResourcesCriteria; @@ -88,11 +86,11 @@ import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.Transaction; import com.cloud.utils.db.TransactionCallbackNoReturn; import com.cloud.utils.db.TransactionCallbackWithException; import com.cloud.utils.db.TransactionStatus; -import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.UserVmVO; @@ -256,7 +254,7 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, public Pair, Integer> listFirewallRules(ListFirewallRulesCmd cmd) { Long ipId = cmd.getIpAddressId(); Long id = cmd.getId(); - Long networkId = null; + Long networkId = cmd.getNetworkId(); Map tags = cmd.getTags(); FirewallRule.TrafficType trafficType = cmd.getTrafficType(); @@ -283,15 +281,10 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, sb.and("id", sb.entity().getId(), Op.EQ); sb.and("trafficType", sb.entity().getTrafficType(), Op.EQ); - if (cmd instanceof ListEgressFirewallRulesCmd ) { - networkId =((ListEgressFirewallRulesCmd)cmd).getNetworkId(); - sb.and("networkId", sb.entity().getNetworkId(), Op.EQ); - } else { + sb.and("networkId", sb.entity().getNetworkId(), Op.EQ); sb.and("ip", sb.entity().getSourceIpAddressId(), Op.EQ); - } sb.and("purpose", sb.entity().getPurpose(), Op.EQ); - if (tags != null && !tags.isEmpty()) { SearchBuilder tagSearch = _resourceTagDao.createSearchBuilder(); for (int count=0; count < tags.size(); count++) { @@ -323,10 +316,10 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, if (ipId != null) { sc.setParameters("ip", ipId); - } else if (cmd instanceof ListEgressFirewallRulesCmd) { - if (networkId != null) { - sc.setParameters("networkId", networkId); - } + } + + if (networkId != null) { + sc.setParameters("networkId", networkId); } sc.setParameters("purpose", Purpose.Firewall); diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index b8d0babe3f9..806e3afd171 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -17,104 +17,26 @@ package com.cloud.network.router; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TimeZone; -import java.util.UUID; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - +import com.cloud.agent.AgentManager; +import com.cloud.agent.Listener; +import com.cloud.agent.api.*; +import com.cloud.agent.api.check.CheckSshAnswer; +import com.cloud.agent.api.check.CheckSshCommand; +import com.cloud.agent.api.routing.*; import com.cloud.agent.api.to.*; +import com.cloud.agent.manager.Commands; +import com.cloud.alert.AlertManager; import com.cloud.api.ApiAsyncJobDispatcher; import com.cloud.api.ApiDispatcher; import com.cloud.api.ApiGsonHelper; -import com.cloud.maint.Version; -import com.cloud.utils.component.ComponentContext; -import org.apache.cloudstack.api.command.admin.router.RebootRouterCmd; -import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; -import org.apache.cloudstack.framework.config.ConfigDepot; -import org.apache.cloudstack.framework.config.ConfigKey; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.framework.jobs.AsyncJobManager; -import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; -import org.apache.cloudstack.managed.context.ManagedContextRunnable; -import org.apache.cloudstack.utils.identity.ManagementServerNode; -import org.apache.cloudstack.api.command.admin.router.UpgradeRouterTemplateCmd; -import org.apache.log4j.Logger; - -import com.cloud.agent.AgentManager; -import com.cloud.agent.Listener; -import com.cloud.agent.api.AgentControlAnswer; -import com.cloud.agent.api.AgentControlCommand; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.BumpUpPriorityCommand; -import com.cloud.agent.api.CheckRouterAnswer; -import com.cloud.agent.api.CheckRouterCommand; -import com.cloud.agent.api.CheckS2SVpnConnectionsAnswer; -import com.cloud.agent.api.CheckS2SVpnConnectionsCommand; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.GetDomRVersionAnswer; -import com.cloud.agent.api.GetDomRVersionCmd; -import com.cloud.agent.api.ModifySshKeysCommand; -import com.cloud.agent.api.NetworkUsageAnswer; -import com.cloud.agent.api.NetworkUsageCommand; -import com.cloud.agent.api.PvlanSetupCommand; -import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.check.CheckSshAnswer; -import com.cloud.agent.api.check.CheckSshCommand; -import com.cloud.agent.api.routing.CreateIpAliasCommand; -import com.cloud.agent.api.routing.DeleteIpAliasCommand; -import com.cloud.agent.api.routing.DhcpEntryCommand; -import com.cloud.agent.api.routing.DnsMasqConfigCommand; -import com.cloud.agent.api.routing.IpAliasTO; -import com.cloud.agent.api.routing.IpAssocCommand; -import com.cloud.agent.api.routing.LoadBalancerConfigCommand; -import com.cloud.agent.api.routing.NetworkElementCommand; -import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; -import com.cloud.agent.api.routing.SavePasswordCommand; -import com.cloud.agent.api.routing.SetFirewallRulesCommand; -import com.cloud.agent.api.routing.SetMonitorServiceCommand; -import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; -import com.cloud.agent.api.routing.SetPortForwardingRulesVpcCommand; -import com.cloud.agent.api.routing.SetStaticNatRulesCommand; -import com.cloud.agent.api.routing.VmDataCommand; -import com.cloud.agent.api.routing.VpnUsersCfgCommand; -import com.cloud.agent.manager.Commands; -import com.cloud.alert.AlertManager; import com.cloud.cluster.ClusterManager; import com.cloud.cluster.ManagementServerHostVO; import com.cloud.cluster.dao.ManagementServerHostDao; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.ZoneConfig; -import com.cloud.dc.ClusterVO; -import com.cloud.dc.DataCenter; +import com.cloud.dc.*; import com.cloud.dc.DataCenter.NetworkType; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.HostPodVO; -import com.cloud.dc.Pod; -import com.cloud.dc.Vlan; -import com.cloud.dc.VlanVO; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; @@ -125,81 +47,34 @@ import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; -import com.cloud.exception.AgentUnavailableException; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.ConnectionException; -import com.cloud.exception.InsufficientAddressCapacityException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InsufficientServerCapacityException; -import com.cloud.exception.InsufficientVirtualNetworkCapcityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.OperationTimedoutException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.exception.StorageUnavailableException; +import com.cloud.exception.*; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.network.IpAddress; -import com.cloud.network.IpAddressManager; -import com.cloud.network.Network; +import com.cloud.maint.Version; +import com.cloud.network.*; import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; -import com.cloud.network.NetworkModel; -import com.cloud.network.NetworkService; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.TrafficType; -import com.cloud.network.PhysicalNetworkServiceProvider; -import com.cloud.network.PublicIpAddress; -import com.cloud.network.RemoteAccessVpn; -import com.cloud.network.Site2SiteCustomerGateway; -import com.cloud.network.Site2SiteVpnConnection; -import com.cloud.network.SshKeysDistriMonitor; -import com.cloud.network.VirtualNetworkApplianceService; -import com.cloud.network.VirtualRouterProvider; import com.cloud.network.VirtualRouterProvider.Type; -import com.cloud.network.VpnUser; -import com.cloud.network.VpnUserVO; import com.cloud.network.addr.PublicIp; -import com.cloud.network.dao.FirewallRulesDao; -import com.cloud.network.dao.IPAddressDao; -import com.cloud.network.dao.IPAddressVO; -import com.cloud.network.dao.LoadBalancerDao; -import com.cloud.network.dao.LoadBalancerVMMapDao; -import com.cloud.network.dao.LoadBalancerVO; -import com.cloud.network.dao.MonitoringServiceVO; -import com.cloud.network.dao.NetworkDao; -import com.cloud.network.dao.NetworkVO; -import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; -import com.cloud.network.dao.RemoteAccessVpnDao; -import com.cloud.network.dao.Site2SiteCustomerGatewayDao; -import com.cloud.network.dao.Site2SiteVpnConnectionDao; -import com.cloud.network.dao.Site2SiteVpnConnectionVO; -import com.cloud.network.dao.Site2SiteVpnGatewayDao; -import com.cloud.network.dao.UserIpv6AddressDao; -import com.cloud.network.dao.VirtualRouterProviderDao; -import com.cloud.network.dao.VpnUserDao; -import com.cloud.network.dao.MonitoringServiceDao; +import com.cloud.network.dao.*; import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; -import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; import com.cloud.network.lb.LoadBalancingRule.LbSslCert; +import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.router.VirtualRouter.RedundantState; import com.cloud.network.router.VirtualRouter.Role; -import com.cloud.network.rules.FirewallRule; -import com.cloud.network.MonitoringService; +import com.cloud.network.rules.*; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.LoadBalancerContainer.Scheme; -import com.cloud.network.rules.PortForwardingRule; -import com.cloud.network.rules.RulesManager; -import com.cloud.network.rules.StaticNat; -import com.cloud.network.rules.StaticNatImpl; -import com.cloud.network.rules.StaticNatRule; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpn.Site2SiteVpnManager; import com.cloud.offering.NetworkOffering; @@ -216,12 +91,7 @@ import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.GuestOSDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.User; -import com.cloud.user.UserStatisticsVO; -import com.cloud.user.UserStatsLogVO; -import com.cloud.user.UserVO; +import com.cloud.user.*; import com.cloud.user.dao.UserDao; import com.cloud.user.dao.UserStatisticsDao; import com.cloud.user.dao.UserStatsLogDao; @@ -230,52 +100,45 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.PasswordGenerator; import com.cloud.utils.StringUtils; +import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.EntityManager; -import com.cloud.utils.db.Filter; -import com.cloud.utils.db.GlobalLock; -import com.cloud.utils.db.JoinBuilder; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.db.TransactionCallbackNoReturn; -import com.cloud.utils.db.TransactionStatus; +import com.cloud.utils.db.*; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.Ip; import com.cloud.utils.net.MacAddress; import com.cloud.utils.net.NetUtils; -import com.cloud.vm.DomainRouterVO; -import com.cloud.vm.Nic; -import com.cloud.vm.NicIpAlias; -import com.cloud.vm.NicProfile; -import com.cloud.vm.NicVO; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.ReservationContextImpl; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachine; +import com.cloud.vm.*; import com.cloud.vm.VirtualMachine.State; -import com.cloud.vm.VirtualMachineGuru; -import com.cloud.vm.VirtualMachineManager; -import com.cloud.vm.VirtualMachineName; -import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachineProfile.Param; -import com.cloud.vm.dao.DomainRouterDao; -import com.cloud.vm.dao.NicDao; -import com.cloud.vm.dao.NicIpAliasDao; -import com.cloud.vm.dao.NicIpAliasVO; -import com.cloud.vm.dao.UserVmDao; -import com.cloud.vm.dao.UserVmDetailsDao; -import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.vm.dao.*; +import org.apache.cloudstack.api.command.admin.router.RebootRouterCmd; +import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd; +import org.apache.cloudstack.api.command.admin.router.UpgradeRouterTemplateCmd; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.apache.cloudstack.framework.config.ConfigDepot; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.framework.jobs.AsyncJobManager; +import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.cloudstack.utils.identity.ManagementServerNode; +import org.apache.log4j.Logger; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.*; +import java.util.concurrent.*; /** * VirtualNetworkApplianceManagerImpl manages the different types of virtual network appliances available in the Cloud Stack. */ @Local(value = { VirtualNetworkApplianceManager.class, VirtualNetworkApplianceService.class }) public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements VirtualNetworkApplianceManager, VirtualNetworkApplianceService, - VirtualMachineGuru, Listener { + VirtualMachineGuru, Listener, Configurable { private static final Logger s_logger = Logger.getLogger(VirtualNetworkApplianceManagerImpl.class); @Inject @@ -2198,6 +2061,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V try { int priority = getUpdatedPriority(guestNetwork, routers, router); router.setPriority(priority); + router = _routerDao.persist(router); } catch (InsufficientVirtualNetworkCapcityException e) { s_logger.error("Failed to get update priority!", e); throw new CloudRuntimeException("Failed to get update priority!"); @@ -2347,12 +2211,12 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V finalizeUserDataAndDhcpOnStart(cmds, router, provider, guestNetworkId); } - finalizeMonitorServiceOnStrat(cmds, router, provider, routerGuestNtwkIds.get(0)); + finalizeMonitorServiceOnStrat(cmds, profile, router, provider, routerGuestNtwkIds.get(0)); return true; } - private void finalizeMonitorServiceOnStrat(Commands cmds, DomainRouterVO router, Provider provider, long networkId) { + private void finalizeMonitorServiceOnStrat(Commands cmds, VirtualMachineProfile profile, DomainRouterVO router, Provider provider, long networkId) { NetworkVO network = _networkDao.findById(networkId); @@ -2385,18 +2249,18 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V servicesTO.add(serviceTO); } + // TODO : This is a hacking fix + // at VR startup time, information in VirtualMachineProfile may not updated to DB yet, + // getRouterControlIp() may give wrong IP under basic network mode in VMware environment + NicProfile controlNic = getControlNic(profile); SetMonitorServiceCommand command = new SetMonitorServiceCommand(servicesTO); - command.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId())); + command.setAccessDetail(NetworkElementCommand.ROUTER_IP, controlNic.getIp4Address()); command.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, getRouterIpInNetwork(networkId, router.getId())); command.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); cmds.addCommand("monitor", command); } - - - - protected NicProfile getControlNic(VirtualMachineProfile profile) { DomainRouterVO router = _routerDao.findById(profile.getId()); DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId()); @@ -2799,7 +2663,11 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V throws StorageUnavailableException, InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { s_logger.debug("Starting router " + router); - _itMgr.start(router.getUuid(), params, planToDeploy); + try { + _itMgr.advanceStart(router.getUuid(), params, planToDeploy); + } catch (OperationTimedoutException e) { + throw new ResourceUnavailableException("Starting router " + router + " failed! " + e.toString(), DataCenter.class, router.getDataCenterId()); + } if (router.isStopPending()) { s_logger.info("Clear the stop pending flag of router " + router.getHostName() + " after start router successfully!"); router.setStopPending(false); @@ -4230,4 +4098,14 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } return jobIds; } + + @Override + public String getConfigComponentName() { + return VirtualNetworkApplianceManagerImpl.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[] {UseExternalDnsServers}; + } } diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index ecfce575fd0..1396e42f4d3 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -1361,6 +1361,16 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian public List getVpcRouters(long vpcId) { return _routerDao.listByVpcId(vpcId); } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } @Override public String[] applyVpnUsers(RemoteAccessVpn vpn, List users, VirtualRouter router) throws ResourceUnavailableException { diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 2ea10211cce..580893876a2 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -25,10 +25,10 @@ import java.util.Set; import javax.ejb.Local; import javax.inject.Inject; -import org.apache.log4j.Logger; import org.apache.cloudstack.api.command.user.firewall.ListPortForwardingRulesCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.apache.log4j.Logger; import com.cloud.configuration.ConfigurationManager; import com.cloud.domain.dao.DomainDao; @@ -75,10 +75,10 @@ import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.TransactionCallbackNoReturn; -import com.cloud.utils.db.TransactionCallbackWithException; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallbackNoReturn; +import com.cloud.utils.db.TransactionCallbackWithException; import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn; import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; @@ -783,6 +783,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules Long ipId = cmd.getIpAddressId(); Long id = cmd.getId(); Map tags = cmd.getTags(); + Long networkId = cmd.getNetworkId(); Account caller = CallContext.current().getCallingAccount(); List permittedAccounts = new ArrayList(); @@ -808,6 +809,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules sb.and("id", sb.entity().getId(), Op.EQ); sb.and("ip", sb.entity().getSourceIpAddressId(), Op.EQ); sb.and("purpose", sb.entity().getPurpose(), Op.EQ); + sb.and("networkId", sb.entity().getNetworkId(), Op.EQ); if (tags != null && !tags.isEmpty()) { SearchBuilder tagSearch = _resourceTagDao.createSearchBuilder(); @@ -842,6 +844,10 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules if (ipId != null) { sc.setParameters("ip", ipId); } + + if (networkId != null) { + sc.setParameters("networkId", networkId); + } sc.setParameters("purpose", Purpose.PortForwarding); diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 017d38df3bb..2e0737d1278 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -1420,10 +1420,9 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis Network privateNtwk = null; if (BroadcastDomainType.getSchemeValue(BroadcastDomainType.fromString(broadcastUri)) == BroadcastDomainType.Lswitch) { String cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask); - privateNtwk = _ntwkDao.getPrivateNetwork(broadcastUri, cidr, gatewayOwnerId, dcId, networkOfferingId); - s_logger.info("found and using existing network for vpc " + vpc + ": " + broadcastUri); + // if the dcid is different we get no network so next we try to create it } if (privateNtwk == null) { s_logger.info("creating new network for vpc " + vpc + " using broadcast uri: " + broadcastUri); @@ -1431,6 +1430,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis privateNtwk = _ntwkSvc.createPrivateNetwork(networkName, networkName, physicalNetworkIdFinal, broadcastUri, ipAddress, null, gateway, netmask, gatewayOwnerId, vpcId, isSourceNat, networkOfferingId); } else { // create the nic/ip as createPrivateNetwork doesn''t do that work for us now + s_logger.info("found and using existing network for vpc " + vpc + ": " + broadcastUri); DataCenterVO dc = _dcDao.lockRow(physNetFinal.getDataCenterId(), true); //add entry to private_ip_address table diff --git a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java index 504e5e88f45..dd18f74988e 100755 --- a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java +++ b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java @@ -25,13 +25,13 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.log4j.Logger; import org.apache.cloudstack.api.command.user.vpn.ListRemoteAccessVpnsCmd; import org.apache.cloudstack.api.command.user.vpn.ListVpnUsersCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.log4j.Logger; import com.cloud.configuration.Config; import com.cloud.domain.DomainVO; @@ -81,10 +81,10 @@ import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.TransactionCallback; -import com.cloud.utils.db.TransactionCallbackNoReturn; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionCallbackNoReturn; import com.cloud.utils.db.TransactionCallbackWithException; import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.net.NetUtils; @@ -109,8 +109,9 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc @Inject FirewallManager _firewallMgr; @Inject UsageEventDao _usageEventDao; @Inject ConfigurationDao _configDao; - @Inject List _vpnServiceProviders; - @Inject ConfigurationServer _configServer; + List _vpnServiceProviders; + + @Inject ConfigurationServer _configServer; @Inject VpcDao _vpcDao; int _userLimit; @@ -592,6 +593,8 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc // do some parameter validation Account caller = CallContext.current().getCallingAccount(); Long ipAddressId = cmd.getPublicIpId(); + Long vpnId = cmd.getId(); + Long networkId = cmd.getNetworkId(); List permittedAccounts = new ArrayList(); if (ipAddressId != null) { @@ -619,6 +622,8 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); sb.and("serverAddressId", sb.entity().getServerAddressId(), Op.EQ); + sb.and("id", sb.entity().getId(), Op.EQ); + sb.and("networkId", sb.entity().getNetworkId(), Op.EQ); sb.and("state", sb.entity().getState(), Op.EQ); SearchCriteria sc = sb.create(); @@ -630,6 +635,14 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc if (ipAddressId != null) { sc.setParameters("serverAddressId", ipAddressId); } + + if (vpnId != null) { + sc.setParameters("id", vpnId); + } + + if (networkId != null) { + sc.setParameters("networkId", networkId); + } Pair, Integer> result = _remoteAccessVpnDao.searchAndCount(sc, filter); return new Pair, Integer> (result.first(), result.second()); @@ -683,4 +696,14 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc public ConfigKey[] getConfigKeys() { return new ConfigKey[] {RemoteAccessVpnClientIpRange}; } + + public List getVpnServiceProviders() { + return _vpnServiceProviders; + } + + public void setVpnServiceProviders( + List vpnServiceProviders) { + this._vpnServiceProviders = vpnServiceProviders; + } + } diff --git a/server/src/com/cloud/resource/DummyHostServerResource.java b/server/src/com/cloud/resource/DummyHostServerResource.java index 977dbbf6e19..1d58c80d221 100644 --- a/server/src/com/cloud/resource/DummyHostServerResource.java +++ b/server/src/com/cloud/resource/DummyHostServerResource.java @@ -23,6 +23,7 @@ import javax.naming.ConfigurationException; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingRoutingCommand; import com.cloud.agent.api.StartupCommand; @@ -57,7 +58,8 @@ public class DummyHostServerResource extends ServerResourceBase { @Override public PingCommand getCurrentStatus(long id) { HashMap newStates = new HashMap(); - return new PingRoutingCommand(com.cloud.host.Host.Type.Routing, id, newStates); + return new PingRoutingCommand(com.cloud.host.Host.Type.Routing, id, newStates, + new HashMap()); } @Override diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index 8459adafb13..4020926640d 100755 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -44,6 +44,7 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigDepotAdmin; +import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.config.impl.ConfigurationVO; import org.apache.commons.codec.binary.Base64; @@ -771,9 +772,9 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio public List getConfigListByScope(String scope, Long resourceId) { // Getting the list of parameters defined at the scope - List configList = Config.getConfigListByScope(scope); + List> configList = _configDepot.getConfigListByScope(scope); List configVOList = new ArrayList(); - for (Config param:configList){ + for (ConfigKey param:configList){ ConfigurationVO configVo = _configDao.findByName(param.toString()); configVo.setValue(_configDepot.get(param.toString()).valueIn(resourceId).toString()); configVOList.add(configVo); diff --git a/server/src/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/com/cloud/template/HypervisorTemplateAdapter.java index b33a19225ef..f9819970298 100755 --- a/server/src/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/com/cloud/template/HypervisorTemplateAdapter.java @@ -233,11 +233,7 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { CreateTemplateContext context) { TemplateApiResult result = callback.getResult(); TemplateInfo template = context.template; - if (result.isFailed()) { - // failed in creating template, we need to remove those already - // populated template entry - _tmpltDao.remove(template.getId()); - } else { + if (result.isSuccess()) { VMTemplateVO tmplt = _tmpltDao.findById(template.getId()); long accountId = tmplt.getAccountId(); if (template.getSize() != null) { diff --git a/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java b/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java index 53dae507bbb..74adb373e57 100644 --- a/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java +++ b/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java @@ -24,16 +24,20 @@ import com.cloud.network.rules.LoadBalancer; import com.cloud.user.dao.AccountDao; import com.cloud.utils.db.EntityManager; import com.cloud.utils.exception.CloudRuntimeException; + import org.apache.cloudstack.api.command.user.loadbalancer.DeleteSslCertCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListSslCertsCmd; import org.apache.cloudstack.api.command.user.loadbalancer.UploadSslCertCmd; import org.apache.cloudstack.api.response.SslCertResponse; + import com.cloud.exception.InvalidParameterValueException; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.utils.db.DB; + import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.context.CallContext; +import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMReader; @@ -45,6 +49,7 @@ import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.ejb.Local; import javax.inject.Inject; + import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; @@ -228,7 +233,7 @@ public class CertServiceImpl implements CertService { } } catch (IOException e) { - throw new IllegalArgumentException("Parsing certificate/key failed: " + e.getMessage()); + throw new IllegalArgumentException("Parsing certificate/key failed: " + e.getMessage(), e); } validateCert(cert, _chain != null? true: false); @@ -273,7 +278,7 @@ public class CertServiceImpl implements CertService { try { ((X509Certificate)cert).checkValidity(); } catch (Exception e) { - throw new IllegalArgumentException("Certificate expired or not valid"); + throw new IllegalArgumentException("Certificate expired or not valid", e); } if( !chain_present ) { @@ -281,7 +286,7 @@ public class CertServiceImpl implements CertService { try { cert.verify(pubKey); } catch (Exception e) { - throw new IllegalArgumentException("No chain given and certificate not self signed"); + throw new IllegalArgumentException("No chain given and certificate not self signed", e); } } } @@ -309,15 +314,15 @@ public class CertServiceImpl implements CertService { throw new IllegalArgumentException("Bad public-private key"); } catch (BadPaddingException e) { - throw new IllegalArgumentException("Bad public-private key"); + throw new IllegalArgumentException("Bad public-private key", e); } catch (IllegalBlockSizeException e) { - throw new IllegalArgumentException("Bad public-private key"); + throw new IllegalArgumentException("Bad public-private key", e); } catch (NoSuchPaddingException e) { - throw new IllegalArgumentException("Bad public-private key"); + throw new IllegalArgumentException("Bad public-private key", e); } catch (InvalidKeyException e) { - throw new IllegalArgumentException("Invalid public-private key"); + throw new IllegalArgumentException("Invalid public-private key", e); } catch (NoSuchAlgorithmException e) { - throw new IllegalArgumentException("Invalid algorithm for public-private key"); + throw new IllegalArgumentException("Invalid algorithm for public-private key", e); } } @@ -363,11 +368,11 @@ public class CertServiceImpl implements CertService { CertPathBuilder builder = CertPathBuilder.getInstance("PKIX"); builder.build(params); } catch (InvalidAlgorithmParameterException e) { - throw new IllegalArgumentException("Invalid certificate chain",null); + throw new IllegalArgumentException("Invalid certificate chain", e); } catch (CertPathBuilderException e) { - throw new IllegalArgumentException("Invalid certificate chain",null); + throw new IllegalArgumentException("Invalid certificate chain", e); } catch (NoSuchAlgorithmException e) { - throw new IllegalArgumentException("Invalid certificate chain",null); + throw new IllegalArgumentException("Invalid certificate chain", e); } } @@ -380,7 +385,12 @@ public class CertServiceImpl implements CertService { pGet = new KeyPassword(password.toCharArray()); PEMReader privateKey = new PEMReader(new StringReader(key), pGet); - Object obj = privateKey.readObject(); + Object obj = null; + try { + obj = privateKey.readObject(); + } finally { + IOUtils.closeQuietly(privateKey); + } try { @@ -389,9 +399,8 @@ public class CertServiceImpl implements CertService { return (PrivateKey) obj; - }catch (Exception e){ - e.printStackTrace(); - throw new IOException("Invalid Key format or invalid password."); + } catch (Exception e){ + throw new IOException("Invalid Key format or invalid password.", e); } } @@ -402,6 +411,8 @@ public class CertServiceImpl implements CertService { return (Certificate) certPem.readObject(); } catch (Exception e) { throw new InvalidParameterValueException("Invalid Certificate format. Expected X509 certificate"); + } finally { + IOUtils.closeQuietly(certPem); } } @@ -419,7 +430,7 @@ public class CertServiceImpl implements CertService { } } if ( certs.size() == 0 ) - throw new IllegalArgumentException("Unable to decode certificate chain",null); + throw new IllegalArgumentException("Unable to decode certificate chain"); return certs; } diff --git a/server/test/org/apache/cloudstack/network/lb/CertServiceTest.java b/server/test/org/apache/cloudstack/network/lb/CertServiceTest.java index e47fc013f05..a37e6261531 100644 --- a/server/test/org/apache/cloudstack/network/lb/CertServiceTest.java +++ b/server/test/org/apache/cloudstack/network/lb/CertServiceTest.java @@ -16,43 +16,46 @@ // under the License. package org.apache.cloudstack.network.lb; -import com.cloud.network.dao.*; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.AccountVO; -import com.cloud.user.UserVO; -import com.cloud.user.dao.AccountDao; -import com.cloud.utils.db.EntityManager; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.db.TransactionLegacy; -import junit.framework.TestCase; -import org.apache.cloudstack.api.command.user.loadbalancer.DeleteSslCertCmd; -import org.apache.cloudstack.api.command.user.loadbalancer.UploadSslCertCmd; -import org.apache.cloudstack.context.CallContext; -import org.apache.log4j.Logger; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; +import static org.apache.commons.io.FileUtils.readFileToString; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.when; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.net.URLEncoder; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.UUID; -import static org.apache.commons.io.FileUtils.readFileToString; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.when; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteSslCertCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.UploadSslCertCmd; +import org.apache.cloudstack.context.CallContext; +import org.junit.After; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; -public class CertServiceTest extends TestCase { +import com.cloud.network.dao.LoadBalancerCertMapDao; +import com.cloud.network.dao.LoadBalancerCertMapVO; +import com.cloud.network.dao.LoadBalancerVO; +import com.cloud.network.dao.SslCertDao; +import com.cloud.network.dao.SslCertVO; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.UserVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.db.TransactionLegacy; - private static final Logger s_logger = Logger.getLogger( CertServiceTest.class); +public class CertServiceTest { - @Override @Before public void setUp() { Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString()); @@ -60,59 +63,35 @@ public class CertServiceTest extends TestCase { CallContext.register(user, account); } - @Override @After public void tearDown() { CallContext.unregister(); } - @Test - public void testUploadSslCert() throws Exception { - - /* Test1 : Given a Certificate in bad format (Not PEM), upload should fail */ - runUploadSslCertBadFormat(); - - /* Test2: Given a Certificate which is not X509, upload should fail */ - runUploadSslCertNotX509(); - - /* Test3: Given an expired certificate, upload should fail */ - runUploadSslCertExpiredCert(); - - /* Test4: Given a private key which has a different algorithm than the certificate, - upload should fail. - */ - runUploadSslCertBadkeyAlgo(); - - /* Test5: Given a private key which does not match the public key in the certificate, - upload should fail - */ - runUploadSslCertBadkeyPair(); - - /* Test6: Given an encrypted private key with a bad password. Upload should fail. */ - runUploadSslCertBadPassword(); - - /* Test7: If no chain is given, the certificate should be self signed. Else, uploadShould Fail */ - runUploadSslCertNoChain(); - - /* Test8: Chain is given but does not have root certificate */ - runUploadSslCertNoRootCert(); - - /* Test9: The chain given is not the correct chain for the certificate */ - runUploadSslCertBadChain(); - - /* Test10: Given a Self-signed Certificate with encrypted key, upload should succeed */ - runUploadSslCertSelfSignedNoPassword(); - - /* Test11: Given a Self-signed Certificate with non-encrypted key, upload should succeed */ - runUploadSslCertSelfSignedWithPassword(); - - /* Test12: Given a certificate signed by a CA and a valid CA chain, upload should succeed */ - runUploadSslCertWithCAChain(); - + /** + * JCE is known to be working fine without additional configuration in OpenJDK. + * This checks if the tests are running in OpenJDK; + * @return true if openjdk environment + */ + static boolean isOpenJdk() { + //TODO: find a better way for OpenJDK detection + return System.getProperty("java.home").toLowerCase().contains("openjdk"); } - private void runUploadSslCertWithCAChain() throws Exception { - //To change body of created methods use File | Settings | File Templates. + /** + * One can run the tests on Oracle JDK after installing JCE by specifying -Dcloudstack.jce.enabled=true + * @return true if the jce enable property was set to true + */ + static boolean isJCEInstalled() { + return Boolean.getBoolean("cloudstack.jce.enabled"); + } + + @Test + /** + * Given a certificate signed by a CA and a valid CA chain, upload should succeed + */ + public void runUploadSslCertWithCAChain() throws Exception { + Assume.assumeTrue(isOpenJdk() || isJCEInstalled()); TransactionLegacy txn = TransactionLegacy.open("runUploadSslCertWithCAChain"); @@ -165,7 +144,11 @@ public class CertServiceTest extends TestCase { certService.uploadSslCert(uploadCmd); } - private void runUploadSslCertSelfSignedWithPassword() throws Exception { + @Test + /** + * Given a Self-signed Certificate with non-encrypted key, upload should succeed + */ + public void runUploadSslCertSelfSignedWithPassword() throws Exception { TransactionLegacy txn = TransactionLegacy.open("runUploadSslCertSelfSignedWithPassword"); @@ -212,7 +195,11 @@ public class CertServiceTest extends TestCase { certService.uploadSslCert(uploadCmd); } - private void runUploadSslCertSelfSignedNoPassword() throws Exception { + @Test + /** + * Given a Self-signed Certificate with encrypted key, upload should succeed + */ + public void runUploadSslCertSelfSignedNoPassword() throws Exception { TransactionLegacy txn = TransactionLegacy.open("runUploadSslCertSelfSignedNoPassword"); @@ -255,8 +242,10 @@ public class CertServiceTest extends TestCase { } - private void runUploadSslCertBadChain() throws IOException, IllegalAccessException, NoSuchFieldException { - //To change body of created methods use File | Settings | File Templates. + @Test + public void runUploadSslCertBadChain() throws IOException, IllegalAccessException, NoSuchFieldException { + Assume.assumeTrue(isOpenJdk() || isJCEInstalled()); + String certFile = getClass().getResource("/certs/rsa_ca_signed.crt").getFile(); String keyFile = getClass().getResource("/certs/rsa_ca_signed.key").getFile(); String chainFile = getClass().getResource("/certs/rsa_self_signed.crt").getFile(); @@ -300,14 +289,17 @@ public class CertServiceTest extends TestCase { try { certService.uploadSslCert(uploadCmd); + fail("The chain given is not the correct chain for the certificate"); } catch (Exception e) { assertTrue(e.getMessage().contains("Invalid certificate chain")); } } - private void runUploadSslCertNoRootCert() throws IOException, IllegalAccessException, NoSuchFieldException { + @Test + public void runUploadSslCertNoRootCert() throws IOException, IllegalAccessException, NoSuchFieldException { + + Assume.assumeTrue(isOpenJdk() || isJCEInstalled()); - //To change body of created methods use File | Settings | File Templates. String certFile = getClass().getResource("/certs/rsa_ca_signed.crt").getFile(); String keyFile = getClass().getResource("/certs/rsa_ca_signed.key").getFile(); String chainFile = getClass().getResource("/certs/rsa_ca_signed2.crt").getFile(); @@ -351,14 +343,18 @@ public class CertServiceTest extends TestCase { try { certService.uploadSslCert(uploadCmd); + fail("Chain is given but does not have root certificate"); } catch (Exception e) { assertTrue(e.getMessage().contains("No root certificates found")); } } - private void runUploadSslCertNoChain() throws IOException, IllegalAccessException, NoSuchFieldException { + @Test + public void runUploadSslCertNoChain() throws IOException, IllegalAccessException, NoSuchFieldException { + Assume.assumeTrue(isOpenJdk() || isJCEInstalled()); + String certFile = getClass().getResource("/certs/rsa_ca_signed.crt").getFile(); String keyFile = getClass().getResource("/certs/rsa_ca_signed.key").getFile(); String password = "user"; @@ -394,16 +390,17 @@ public class CertServiceTest extends TestCase { passField.setAccessible(true); passField.set(uploadCmd, password); - try { certService.uploadSslCert(uploadCmd); + fail("If no chain is given, the certificate should be self signed. Else, uploadShould Fail"); } catch (Exception e) { assertTrue(e.getMessage().contains("No chain given and certificate not self signed")); } } - private void runUploadSslCertBadPassword() throws IOException, IllegalAccessException, NoSuchFieldException { + @Test + public void runUploadSslCertBadPassword() throws IOException, IllegalAccessException, NoSuchFieldException { String certFile = getClass().getResource("/certs/rsa_self_signed_with_pwd.crt").getFile(); String keyFile = getClass().getResource("/certs/rsa_self_signed_with_pwd.key").getFile(); @@ -443,13 +440,15 @@ public class CertServiceTest extends TestCase { try { certService.uploadSslCert(uploadCmd); + fail("Given an encrypted private key with a bad password. Upload should fail."); } catch (Exception e) { assertTrue(e.getMessage().contains("please check password and data")); } } - private void runUploadSslCertBadkeyPair() throws IOException, IllegalAccessException, NoSuchFieldException { + @Test + public void runUploadSslCertBadkeyPair() throws IOException, IllegalAccessException, NoSuchFieldException { // Reading appropritate files String certFile = getClass().getResource("/certs/rsa_self_signed.crt").getFile(); String keyFile = getClass().getResource("/certs/rsa_random_pkey.key").getFile(); @@ -487,7 +486,8 @@ public class CertServiceTest extends TestCase { } } - private void runUploadSslCertBadkeyAlgo() throws IOException, IllegalAccessException, NoSuchFieldException { + @Test + public void runUploadSslCertBadkeyAlgo() throws IOException, IllegalAccessException, NoSuchFieldException { // Reading appropritate files String certFile = getClass().getResource("/certs/rsa_self_signed.crt").getFile(); @@ -521,12 +521,14 @@ public class CertServiceTest extends TestCase { try { certService.uploadSslCert(uploadCmd); + fail("Given a private key which has a different algorithm than the certificate, upload should fail"); } catch (Exception e) { assertTrue(e.getMessage().contains("Public and private key have different algorithms")); } } - private void runUploadSslCertExpiredCert() throws IOException, IllegalAccessException, NoSuchFieldException { + @Test + public void runUploadSslCertExpiredCert() throws IOException, IllegalAccessException, NoSuchFieldException { // Reading appropritate files String certFile = getClass().getResource("/certs/expired_cert.crt").getFile(); @@ -560,12 +562,14 @@ public class CertServiceTest extends TestCase { try { certService.uploadSslCert(uploadCmd); + fail("Given an expired certificate, upload should fail"); } catch (Exception e) { assertTrue(e.getMessage().contains("Certificate expired")); } } - private void runUploadSslCertNotX509() throws IOException, IllegalAccessException, NoSuchFieldException { + @Test + public void runUploadSslCertNotX509() throws IOException, IllegalAccessException, NoSuchFieldException { // Reading appropritate files String certFile = getClass().getResource("/certs/non_x509_pem.crt").getFile(); String keyFile = getClass().getResource("/certs/rsa_self_signed.key").getFile(); @@ -598,12 +602,14 @@ public class CertServiceTest extends TestCase { try { certService.uploadSslCert(uploadCmd); + fail("Given a Certificate which is not X509, upload should fail"); } catch (Exception e) { assertTrue(e.getMessage().contains("Expected X509 certificate")); } } - private void runUploadSslCertBadFormat() throws IOException, IllegalAccessException, NoSuchFieldException { + @Test + public void runUploadSslCertBadFormat() throws IOException, IllegalAccessException, NoSuchFieldException { // Reading appropritate files String certFile = getClass().getResource("/certs/bad_format_cert.crt").getFile(); @@ -637,6 +643,7 @@ public class CertServiceTest extends TestCase { try { certService.uploadSslCert(uploadCmd); + fail("Given a Certificate in bad format (Not PEM), upload should fail"); } catch (Exception e) { assertTrue(e.getMessage().contains("Invalid certificate format")); } @@ -644,20 +651,10 @@ public class CertServiceTest extends TestCase { @Test - public void testDeleteSslCert() throws Exception { - /* Test1: Delete with an invalid ID should fail */ - runDeleteSslCertInvalidId(); - - /* Test2: Delete with a cert id bound to a lb should fail */ - runDeleteSslCertBoundCert(); - - /* Test3: Delete with a valid Id should succeed */ - runDeleteSslCertValid(); - - - } - - private void runDeleteSslCertValid() throws Exception { + /** + * Delete with a valid Id should succeed + */ + public void runDeleteSslCertValid() throws Exception { TransactionLegacy txn = TransactionLegacy.open("runDeleteSslCertValid"); @@ -690,7 +687,8 @@ public class CertServiceTest extends TestCase { certService.deleteSslCert(deleteCmd); } - private void runDeleteSslCertBoundCert() throws NoSuchFieldException, IllegalAccessException { + @Test + public void runDeleteSslCertBoundCert() throws NoSuchFieldException, IllegalAccessException { TransactionLegacy txn = TransactionLegacy.open("runDeleteSslCertBoundCert"); @@ -731,6 +729,7 @@ public class CertServiceTest extends TestCase { try { certService.deleteSslCert(deleteCmd); + fail("Delete with a cert id bound to a lb should fail"); }catch (Exception e){ assertTrue(e.getMessage().contains("Certificate in use by a loadbalancer")); } @@ -738,7 +737,8 @@ public class CertServiceTest extends TestCase { } - private void runDeleteSslCertInvalidId() throws NoSuchFieldException, IllegalAccessException { + @Test + public void runDeleteSslCertInvalidId() throws NoSuchFieldException, IllegalAccessException { TransactionLegacy txn = TransactionLegacy.open("runDeleteSslCertInvalidId"); @@ -768,6 +768,7 @@ public class CertServiceTest extends TestCase { try { certService.deleteSslCert(deleteCmd); + fail("Delete with an invalid ID should fail"); }catch (Exception e){ assertTrue(e.getMessage().contains("Invalid certificate id")); } diff --git a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java index d7ac3f7ce80..78a2336626d 100644 --- a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java +++ b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java @@ -24,6 +24,7 @@ import javax.inject.Inject; import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.affinity.AffinityGroupService; import org.apache.cloudstack.affinity.dao.AffinityGroupDao; +import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.region.PortableIpDaoImpl; import org.apache.cloudstack.region.dao.RegionDaoImpl; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl; @@ -308,6 +309,11 @@ public class ChildTestConfiguration { return Mockito.mock(ConfigurationDao.class); } + @Bean + public ConfigDepot configDepot() { + return Mockito.mock(ConfigDepot.class); + } + @Bean public CallContext userContext() { return Mockito.mock(CallContext.class); diff --git a/services/console-proxy-rdp/rdpconsole/pom.xml b/services/console-proxy-rdp/rdpconsole/pom.xml index 71d0241d671..02e469f4f58 100644 --- a/services/console-proxy-rdp/rdpconsole/pom.xml +++ b/services/console-proxy-rdp/rdpconsole/pom.xml @@ -21,16 +21,39 @@ 4.0.0 rdpclient cloudstack-service-console-proxy-rdpclient - 4.3.0-SNAPSHOT jar - Apache CloudStack Console Proxy - RDP Client - http://maven.apache.org + + + org.apache.cloudstack + cloudstack-services + 4.3.0-SNAPSHOT + ../../pom.xml + UTF-8 + + + ${basedir}/src/main/java + ${basedir}/src/main/scripts + ${basedir}/src/test/java + ${basedir}/target/classes + ${basedir}/target/test-classes + + + ${basedir}/src/main/resources + + + + + ${basedir}/src/test/resources + + + + junit diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/SocketWrapper.java b/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/SocketWrapper.java index 2ddf0b635b9..c23edd8f42f 100644 --- a/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/SocketWrapper.java +++ b/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/SocketWrapper.java @@ -133,7 +133,7 @@ public class SocketWrapper extends PipelineImpl { sslContext.init(null, new TrustManager[] { new TrustAllX509TrustManager() }, null); SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); - sslSocket = (SSLSocket) sslSocketFactory.createSocket(socket, address.getHostString(), address.getPort(), true); + sslSocket = (SSLSocket) sslSocketFactory.createSocket(socket, address.getHostName(), address.getPort(), true); sslSocket.startHandshake(); InputStream sis = sslSocket.getInputStream(); diff --git a/services/console-proxy-rdp/rdpconsole/src/test/java/rdpclient/MockServerTest.java b/services/console-proxy-rdp/rdpconsole/src/test/java/rdpclient/MockServerTest.java index cba01fd6a49..89eed8a7c44 100644 --- a/services/console-proxy-rdp/rdpconsole/src/test/java/rdpclient/MockServerTest.java +++ b/services/console-proxy-rdp/rdpconsole/src/test/java/rdpclient/MockServerTest.java @@ -154,7 +154,7 @@ public class MockServerTest extends TestCase { //System.setProperty("javax.net.debug", "ssl"); final SSLSocketFactory sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); - SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(socket, address.getHostString(), address.getPort(), true); + SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(socket, address.getHostName(), address.getPort(), true); sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites()); sslSocket.startHandshake(); diff --git a/services/pom.xml b/services/pom.xml index c2f7f88ad88..5d1403b18c8 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -32,6 +32,7 @@ console-proxy + console-proxy-rdp/rdpconsole secondary-storage diff --git a/setup/db/db/schema-420to421.sql b/setup/db/db/schema-420to421.sql index d429b30c014..1d2848535bf 100644 --- a/setup/db/db/schema-420to421.sql +++ b/setup/db/db/schema-420to421.sql @@ -221,3 +221,6 @@ CREATE VIEW `cloud`.`user_vm_view` AS update `cloud`.`volumes` v, `cloud`.`volume_host_ref` vhr set v.format=vhr.format where v.id=vhr.volume_id and v.format is null; +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'baremetal.ipmi.lan.interface', 'default', 'option specified in -I option of impitool. candidates are: open/bmc/lipmi/lan/lanplus/free/imb, see ipmitool man page for details. default valule "default" means using default option of ipmitool'); +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'baremetal.ipmi.fail.retry', 'default', "ipmi interface will be temporary out of order after power opertions(e.g. cycle, on), it leads following commands fail immediately. The value specifies retry times before accounting it as real failure"); +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'vmware.hung.wokervm.timeout', '7200', 'Worker VM timeout in seconds'); diff --git a/setup/db/db/schema-421to430.sql b/setup/db/db/schema-421to430.sql index dbfab4a5bb8..1c305f9d657 100644 --- a/setup/db/db/schema-421to430.sql +++ b/setup/db/db/schema-421to430.sql @@ -52,6 +52,15 @@ CREATE TABLE `cloud`.`vm_snapshot_details` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +DROP TABLE IF EXISTS `cloud`.`snapshot_details`; +CREATE TABLE `cloud`.`snapshot_details` ( + `id` bigint unsigned UNIQUE NOT NULL, + `snapshot_id` bigint unsigned NOT NULL, + `name` varchar(255) NOT NULL, + `value` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + CREATE TABLE `cloud`.`vm_work_job` ( `id` bigint unsigned UNIQUE NOT NULL, `step` char(32) NOT NULL COMMENT 'state', @@ -619,3 +628,23 @@ CREATE TABLE `cloud`.`usage_event_details` ( PRIMARY KEY (`id`), CONSTRAINT `fk_usage_event_details__usage_event_id` FOREIGN KEY `fk_usage_event_details__usage_event_id`(`usage_event_id`) REFERENCES `usage_event`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`user_ip_address_details` ( + `id` bigint unsigned NOT NULL auto_increment, + `user_ip_address_id` bigint unsigned NOT NULL COMMENT 'User ip address id', + `name` varchar(255) NOT NULL, + `value` varchar(1024) NOT NULL, + `display` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'True if the detail can be displayed to the end user', + PRIMARY KEY (`id`), + CONSTRAINT `fk_user_ip_address_details__user_ip_address_id` FOREIGN KEY `fk_user_ip_address_details__user_ip_address_id`(`user_ip_address_id`) REFERENCES `user_ip_address`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`remote_access_vpn_details` ( + `id` bigint unsigned NOT NULL auto_increment, + `remote_access_vpn_id` bigint unsigned NOT NULL COMMENT 'Remote access vpn id', + `name` varchar(255) NOT NULL, + `value` varchar(1024) NOT NULL, + `display` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'True if the detail can be displayed to the end user', + PRIMARY KEY (`id`), + CONSTRAINT `fk_remote_access_vpn_details__remote_access_vpn_id` FOREIGN KEY `fk_remote_access_vpn_details__remote_access_vpn_id`(`remote_access_vpn_id`) REFERENCES `remote_access_vpn`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/setup/db/hypervisor_capabilities.simulator.sql b/setup/db/hypervisor_capabilities.simulator.sql new file mode 100755 index 00000000000..32f9aaa7351 --- /dev/null +++ b/setup/db/hypervisor_capabilities.simulator.sql @@ -0,0 +1,19 @@ +-- 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. + + +INSERT INTO `cloud`.`hypervisor_capabilities` (uuid, hypervisor_type, hypervisor_version, max_guests_limit, security_group_enabled, max_data_volumes_limit, max_hosts_per_cluster, storage_motion_supported, vm_snapshot_enabled) values (UUID(), 'Simulator', 'default', 50, 1, 6, NULL, 0, 1); diff --git a/systemvm/patches/debian/config/opt/cloud/bin/monitor_service.sh b/systemvm/patches/debian/config/opt/cloud/bin/monitor_service.sh index a2b789cac8f..c4d99d2207e 100755 --- a/systemvm/patches/debian/config/opt/cloud/bin/monitor_service.sh +++ b/systemvm/patches/debian/config/opt/cloud/bin/monitor_service.sh @@ -64,7 +64,7 @@ crontab -l | grep -v monitorServices.py | crontab - create_config $config #add cron job -(crontab -l ; echo "*/3 * * * * python /root/monitorServices.py") | crontab - +(crontab -l ;echo -e "SHELL=/bin/bash\nPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n */1 * * * * /usr/bin/python /root/monitorServices.py") | crontab - unlock_exit 0 $lock $locked diff --git a/systemvm/patches/debian/config/root/monitorServices.py b/systemvm/patches/debian/config/root/monitorServices.py index f0c2afe83a6..2cec672f0ce 100755 --- a/systemvm/patches/debian/config/root/monitorServices.py +++ b/systemvm/patches/debian/config/root/monitorServices.py @@ -62,8 +62,13 @@ def getConfig( config_file_path = "/etc/monitor.conf" ): return process_dict def printd (msg): + return 0 - print msg + + f= open(monitor_log,'r+') + f.seek(0, 2) + f.write(str(msg)+"\n") + f.close() def raisealert(severity, msg, process_name=None): #timeStr=str(time.ctime()) @@ -76,12 +81,6 @@ def raisealert(severity, msg, process_name=None): pout = Popen(msg, shell=True, stdout=PIPE) - #f= open(monitor_log,'r+') - #f.seek(0, 2) - #f.write(str(log)) - #f.close() - - def isPidMatchPidFile(pidfile, pids): if pids is None or isinstance(pids,list) != True or len(pids) == 0: @@ -119,7 +118,7 @@ def checkProcessStatus( process ): service_name = process.get('servicename') pidfile = process.get('pidfile') #temp_out = None - restartFailed=0 + restartFailed=False pidFileMatched=1 cmd='' if process_name is None: @@ -186,34 +185,32 @@ def checkProcessStatus( process ): for pid in pids: cmd = 'kill -9 '+pid; printd(cmd) - Popen(cmd, shell=True, stdout=PIPE) + Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT) cmd = 'service ' + service_name + ' restart' - try: - time.sleep(1) - return_val= check_call(cmd , shell=True) - except CalledProcessError: - restartFailed=1 - msg="service "+ process_name +" restart failed" - printd(msg) - continue + + time.sleep(1) + #return_val= check_call(cmd , shell=True) + + cout = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT) + return_val = cout.wait() if return_val == 0: printd("The process" + process_name +" recovered successfully ") msg="The process " +process_name+" is recovered successfully " - raisealert(log.INFO,process_name,msg) + raisealert(log.INFO,msg,process_name) break; else: #retry restarting the process for few tries printd("process restart failing trying again ....") - restartFailed=1 + restartFailed=True time.sleep(1) continue #for end here - if restartFailed == 1: - msg="The process %s recover failed ", process_name; + if restartFailed == True: + msg="The process %s recover failed "%process_name raisealert(log.ALERT,process_name,msg) printd("Restart failed after number of retries") diff --git a/test/integration/component/test_assign_vm.py b/test/integration/component/test_assign_vm.py index 55c174b7f2b..cbdce7325fc 100644 --- a/test/integration/component/test_assign_vm.py +++ b/test/integration/component/test_assign_vm.py @@ -150,7 +150,7 @@ class TestVMOwnership(cloudstackTestCase): cls.service_offering = ServiceOffering.create(cls.api_client, cls.services["service_offering"]) # Cleanup - cls._cleanup = [cls.service_offering] + cls._cleanup.append(cls.service_offering) # Create domain, account, user, project and volumes. cls.domain_account_user1 = create_domain_account_user() cls.domain_account_user2 = create_domain_account_user() diff --git a/test/integration/component/test_base_image_updation.py b/test/integration/component/test_base_image_updation.py index 8a993505559..b70bea5b546 100644 --- a/test/integration/component/test_base_image_updation.py +++ b/test/integration/component/test_base_image_updation.py @@ -281,6 +281,7 @@ class TestBaseImageUpdate(cloudstackTestCase): return + @attr(tags=["advanced", "basic"]) def test_01_deploy_instance_with_is_volatile_offering(self): """ Test deploy an instance with service offerings with IsVolatile set. """ @@ -311,6 +312,7 @@ class TestBaseImageUpdate(cloudstackTestCase): ) return + @attr(tags=["advanced", "basic"]) def test_02_reboot_instance_with_is_volatile_offering(self): """ Test rebooting instances created with isVolatile service offerings """ @@ -388,6 +390,7 @@ class TestBaseImageUpdate(cloudstackTestCase): return + @attr(tags=["advanced", "basic"]) def test_03_restore_vm_with_new_template(self): """ Test restoring a vm with different template than the one it was created with """ @@ -503,6 +506,7 @@ class TestBaseImageUpdate(cloudstackTestCase): return + @attr(tags=["advanced", "basic"]) def test_04_reoccuring_snapshot_rules(self): """ 1) Create a VM using the Service offering IsVolatile enabled diff --git a/test/integration/component/test_blocker_bugs.py b/test/integration/component/test_blocker_bugs.py index 62800f8be03..5488ddbf6e7 100644 --- a/test/integration/component/test_blocker_bugs.py +++ b/test/integration/component/test_blocker_bugs.py @@ -630,7 +630,7 @@ class TestRouterRestart(cloudstackTestCase): # No need return - @attr(tags = ["advanced", "basic", "sg", "advancedns", "eip"]) + @attr(tags = ["advanced", "advancedns", "eip"]) def test_01_restart_network_cleanup(self): """TS_BUG_008-Test restart network """ diff --git a/test/integration/component/test_egress_rules.py b/test/integration/component/test_egress_rules.py index 34995ffd1a0..590f72a7cd3 100644 --- a/test/integration/component/test_egress_rules.py +++ b/test/integration/component/test_egress_rules.py @@ -523,7 +523,7 @@ class TestDefaultGroupEgress(cloudstackTestCase): # CIDR: 0.0.0.0/0 # 5. deployVirtualMachine into this security group (ssh) # 6. deployed VM should be Running, ssh should be allowed into the VM, - # ping out to google.com from the VM should fail, + # ping out to google.com from the VM should be successful, # ssh from within VM to mgt server should pass security_group = SecurityGroup.create( @@ -617,7 +617,7 @@ class TestDefaultGroupEgress(cloudstackTestCase): result = str(res) self.assertEqual( - result.count("0 received"), + result.count("1 received"), 1, "Ping to outside world from VM should be successful" ) @@ -625,8 +625,8 @@ class TestDefaultGroupEgress(cloudstackTestCase): try: self.debug("SSHing into management server from VM") res = ssh.execute("ssh %s@%s" % ( - self.services["mgmt_server"]["username"], - self.services["mgmt_server"]["ipaddress"] + self.apiclient.connection.user, + self.apiclient.connection.mgtSvr )) self.debug("SSH result: %s" % str(res)) @@ -725,7 +725,7 @@ class TestDefaultGroupEgressAfterDeploy(cloudstackTestCase): # 5. authorizeSecurityGroupEgress to allow ssh access only out to # CIDR: 0.0.0.0/0 # 6. deployed VM should be Running, ssh should be allowed into the VM, - # ping out to google.com from the VM should fail + # ping out to google.com from the VM should be successful security_group = SecurityGroup.create( self.apiclient, @@ -819,7 +819,7 @@ class TestDefaultGroupEgressAfterDeploy(cloudstackTestCase): result = str(res) self.assertEqual( - result.count("0 received"), + result.count("1 received"), 1, "Ping to outside world from VM should be successful" ) @@ -907,7 +907,7 @@ class TestRevokeEgressRule(cloudstackTestCase): # CIDR: 0.0.0.0/0 # 5. deployVirtualMachine into this security group (ssh) # 6. deployed VM should be Running, ssh should be allowed into the VM, - # ping out to google.com from the VM should fail, + # ping out to google.com from the VM should be successful, # ssh from within VM to mgt server should pass # 7. Revoke egress rule. Verify ping and SSH access to management server # is restored @@ -1005,7 +1005,7 @@ class TestRevokeEgressRule(cloudstackTestCase): result = str(res) self.assertEqual( - result.count("0 received"), + result.count("1 received"), 1, "Ping to outside world from VM should be successful" ) @@ -1014,7 +1014,7 @@ class TestRevokeEgressRule(cloudstackTestCase): self.debug("SSHing into management server from VM") res = ssh.execute("ssh %s@%s" % ( self.services["mgmt_server"]["username"], - self.services["mgmt_server"]["ipaddress"] + self.apiclient.connection.mgtSvr )) self.debug("SSH result: %s" % str(res)) @@ -1062,16 +1062,16 @@ class TestRevokeEgressRule(cloudstackTestCase): result = str(res) self.assertEqual( - result.count("1 received"), + result.count("0 received"), 1, - "Ping to outside world from VM should be successful" + "Ping to outside world from VM should fail" ) try: self.debug("SSHing into management server from VM") res = ssh.execute("ssh %s@%s" % ( self.services["mgmt_server"]["username"], - self.services["mgmt_server"]["ipaddress"] + self.apiclient.connection.mgtSvr )) self.debug("SSH result: %s" % str(res)) @@ -1439,8 +1439,7 @@ class TestMultipleAccountsEgressRuleNeg(cloudstackTestCase): try: self.debug("SSHing into VM type B from VM A") self.debug("VM IP: %s" % self.virtual_machineB.ssh_ip) - res = ssh.execute("ssh %s@%s" % ( - self.services["virtual_machine"]["username"], + res = ssh.execute("ssh -o 'BatchMode=yes' %s" % ( self.virtual_machineB.ssh_ip )) self.debug("SSH result: %s" % str(res)) @@ -1450,10 +1449,14 @@ class TestMultipleAccountsEgressRuleNeg(cloudstackTestCase): (self.virtual_machineA.ipaddress, e) ) result = str(res) - self.assertEqual( - result.count("Connection timed out"), - 1, - "SSH into management server from VM should not be successful" + + # SSH failure may result in one of the following three error messages + ssh_failure_result_set = ["ssh: connect to host %s port 22: No route to host" % self.virtual_machineB.ssh_ip, + "ssh: connect to host %s port 22: Connection timed out" % self.virtual_machineB.ssh_ip, + "Host key verification failed."] + + self.assertFalse(set(res).isdisjoint(ssh_failure_result_set), + "SSH into VM of other account should not be successful" ) return diff --git a/test/integration/component/test_netscaler_lb.py b/test/integration/component/test_netscaler_lb.py index 5a8d6a4f6b5..26df5459b51 100644 --- a/test/integration/component/test_netscaler_lb.py +++ b/test/integration/component/test_netscaler_lb.py @@ -149,6 +149,7 @@ class TestLbSourceNat(cloudstackTestCase): @classmethod def setUpClass(cls): + cls._cleanup = [] cls.api_client = super( TestLbSourceNat, cls @@ -164,9 +165,7 @@ class TestLbSourceNat(cloudstackTestCase): ) try: cls.netscaler = add_netscaler(cls.api_client, cls.zone.id, cls.services["netscaler"]) - cls._cleanup = [ - cls.netscaler - ] + cls._cleanup.append(cls.netscaler) cls.network_offering = NetworkOffering.create( cls.api_client, cls.services["network_offering"], @@ -359,6 +358,7 @@ class TestLbOnIpWithPf(cloudstackTestCase): @classmethod def setUpClass(cls): + cls._cleanup = [] cls.api_client = super( TestLbOnIpWithPf, cls @@ -374,9 +374,7 @@ class TestLbOnIpWithPf(cloudstackTestCase): ) try: cls.netscaler = add_netscaler(cls.api_client, cls.zone.id, cls.services["netscaler"]) - cls._cleanup = [ - cls.netscaler - ] + cls._cleanup.append(cls.netscaler) cls.network_offering = NetworkOffering.create( cls.api_client, cls.services["network_offering"], @@ -573,6 +571,7 @@ class TestPfOnIpWithLb(cloudstackTestCase): @classmethod def setUpClass(cls): + cls._cleanup = [] cls.api_client = super( TestPfOnIpWithLb, cls @@ -588,9 +587,7 @@ class TestPfOnIpWithLb(cloudstackTestCase): ) try: cls.netscaler = add_netscaler(cls.api_client, cls.zone.id, cls.services["netscaler"]) - cls._cleanup = [ - cls.netscaler - ] + cls._cleanup.append(cls.netscaler) cls.network_offering = NetworkOffering.create( cls.api_client, cls.services["network_offering"], @@ -788,6 +785,7 @@ class TestLbOnNonSourceNat(cloudstackTestCase): @classmethod def setUpClass(cls): + cls._cleanup = [] cls.api_client = super( TestLbOnNonSourceNat, cls @@ -803,9 +801,7 @@ class TestLbOnNonSourceNat(cloudstackTestCase): ) try: cls.netscaler = add_netscaler(cls.api_client, cls.zone.id, cls.services["netscaler"]) - cls._cleanup = [ - cls.netscaler - ] + cls._cleanup.append(cls.netscaler) cls.network_offering = NetworkOffering.create( cls.api_client, cls.services["network_offering"], @@ -1006,6 +1002,7 @@ class TestAddMultipleVmsLb(cloudstackTestCase): @classmethod def setUpClass(cls): + cls._cleanup = [] cls.api_client = super( TestAddMultipleVmsLb, cls @@ -1021,9 +1018,7 @@ class TestAddMultipleVmsLb(cloudstackTestCase): ) try: cls.netscaler = add_netscaler(cls.api_client, cls.zone.id, cls.services["netscaler"]) - cls._cleanup = [ - cls.netscaler - ] + cls._cleanup.append(cls.netscaler) cls.network_offering = NetworkOffering.create( cls.api_client, cls.services["network_offering"], @@ -1286,6 +1281,7 @@ class TestMultipleLbRules(cloudstackTestCase): @classmethod def setUpClass(cls): + cls._cleanup = [] cls.api_client = super( TestMultipleLbRules, cls @@ -1301,9 +1297,7 @@ class TestMultipleLbRules(cloudstackTestCase): ) try: cls.netscaler = add_netscaler(cls.api_client, cls.zone.id, cls.services["netscaler"]) - cls._cleanup = [ - cls.netscaler - ] + cls._cleanup.append(cls.netscaler) cls.network_offering = NetworkOffering.create( cls.api_client, cls.services["network_offering"], @@ -1606,6 +1600,7 @@ class TestMultipleLbRulesSameIp(cloudstackTestCase): @classmethod def setUpClass(cls): + cls._cleanup = [] cls.api_client = super( TestMultipleLbRulesSameIp, cls @@ -1619,11 +1614,10 @@ class TestMultipleLbRulesSameIp(cloudstackTestCase): cls.zone.id, cls.services["ostype"] ) + try: cls.netscaler = add_netscaler(cls.api_client, cls.zone.id, cls.services["netscaler"]) - cls._cleanup = [ - cls.netscaler - ] + cls._cleanup.append(cls.netscaler) cls.network_offering = NetworkOffering.create( cls.api_client, cls.services["network_offering"], diff --git a/test/integration/component/test_netscaler_lb_algo.py b/test/integration/component/test_netscaler_lb_algo.py index a5e1fe80b7b..3c18fcd36d9 100644 --- a/test/integration/component/test_netscaler_lb_algo.py +++ b/test/integration/component/test_netscaler_lb_algo.py @@ -116,6 +116,7 @@ class TestLbWithRoundRobin(cloudstackTestCase): @classmethod def setUpClass(cls): + cls._cleanup = [] cls.api_client = super( TestLbWithRoundRobin, cls @@ -131,9 +132,7 @@ class TestLbWithRoundRobin(cloudstackTestCase): ) try: cls.netscaler = add_netscaler(cls.api_client, cls.zone.id, cls.services["netscaler"]) - cls._cleanup = [ - cls.netscaler - ] + cls._cleanup.append(cls.netscaler) cls.network_offering = NetworkOffering.create( cls.api_client, cls.services["network_offering"], @@ -330,6 +329,7 @@ class TestLbWithLeastConn(cloudstackTestCase): @classmethod def setUpClass(cls): + cls._cleanup = [] cls.api_client = super( TestLbWithLeastConn, cls @@ -345,9 +345,7 @@ class TestLbWithLeastConn(cloudstackTestCase): ) try: cls.netscaler = add_netscaler(cls.api_client, cls.zone.id, cls.services["netscaler"]) - cls._cleanup = [ - cls.netscaler - ] + cls._cleanup.append(cls.netscaler) cls.network_offering = NetworkOffering.create( cls.api_client, cls.services["network_offering"], diff --git a/test/integration/component/test_network_offering.py b/test/integration/component/test_network_offering.py index 04777b0c2a8..33c43059334 100644 --- a/test/integration/component/test_network_offering.py +++ b/test/integration/component/test_network_offering.py @@ -25,7 +25,6 @@ from marvin.cloudstackAPI import * from marvin.integration.lib.utils import * from marvin.integration.lib.base import * from marvin.integration.lib.common import * -from marvin.sshClient import SshClient import datetime diff --git a/test/integration/component/test_portable_ip.py b/test/integration/component/test_portable_ip.py index a532b362751..14b6dacaa96 100644 --- a/test/integration/component/test_portable_ip.py +++ b/test/integration/component/test_portable_ip.py @@ -807,13 +807,11 @@ class TestAssociatePublicIp(cloudstackTestCase): try: self.debug("Trying to SSH to ip: %s" % portableip.ipaddress.ipaddress) - - SshClient( - portableip.ipaddress.ipaddress, - self.services['natrule']["publicport"], - self.virtual_machine.username, - self.virtual_machine.password - ) + SshClient(portableip.ipaddress.ipaddress, + self.services['natrule']["publicport"], + self.virtual_machine.username, + self.virtual_machine.password + ) except Exception as e: self.fail("Exception while SSHing : %s" % e) @@ -1532,13 +1530,11 @@ class TestPortableIpTransferAcrossNetworks(cloudstackTestCase): try: self.debug("Trying to SSH to ip: %s" % portableip.ipaddress.ipaddress) - - SshClient( - portableip.ipaddress.ipaddress, - self.services['natrule']["publicport"], - self.virtual_machine2.username, - self.virtual_machine2.password - ) + SshClient(portableip.ipaddress.ipaddress, + self.services['natrule']["publicport"], + self.virtual_machine2.username, + self.virtual_machine2.password + ) except Exception as e: self.fail("Exception while SSHing : %s" % e) diff --git a/test/integration/component/test_project_limits.py b/test/integration/component/test_project_limits.py index c6df7f37dc7..c497311c94a 100644 --- a/test/integration/component/test_project_limits.py +++ b/test/integration/component/test_project_limits.py @@ -763,9 +763,9 @@ class TestResourceLimitsProject(cloudstackTestCase): # Get the Root disk of VM volumes = list_volumes( self.apiclient, + virtualmachineid=virtual_machine_1.id, projectid=self.project.id, - type='ROOT', - listall=True + type='ROOT' ) self.assertEqual( isinstance(volumes, list), @@ -902,9 +902,9 @@ class TestResourceLimitsProject(cloudstackTestCase): # Get the Root disk of VM volumes = list_volumes( self.apiclient, + virtualmachineid=virtual_machine_1.id, projectid=self.project.id, - type='ROOT', - listall=True + type='ROOT' ) self.assertEqual( isinstance(volumes, list), @@ -1014,7 +1014,7 @@ class TestMaxProjectNetworks(cloudstackTestCase): return @attr(tags=["advanced", "advancedns", "simulator", - "api", "basic", "eip", "sg"]) + "api", "eip"]) def test_maxAccountNetworks(self): """Test Limit number of guest account specific networks """ diff --git a/test/integration/component/test_resource_limits.py b/test/integration/component/test_resource_limits.py index 377aa7463b1..07fc5a5ce72 100644 --- a/test/integration/component/test_resource_limits.py +++ b/test/integration/component/test_resource_limits.py @@ -1401,7 +1401,7 @@ class TestMaxAccountNetworks(cloudstackTestCase): return @attr(tags=["advanced", "advancedns", "simulator", - "api", "basic", "eip", "sg"]) + "api", "eip"]) def test_maxAccountNetworks(self): """Test Limit number of guest account specific networks """ diff --git a/test/integration/component/test_security_groups.py b/test/integration/component/test_security_groups.py index c90ccf6ee28..8e0739658ae 100644 --- a/test/integration/component/test_security_groups.py +++ b/test/integration/component/test_security_groups.py @@ -656,12 +656,11 @@ class TestRevokeIngressRule(cloudstackTestCase): # SSH Attempt to VM should fail with self.assertRaises(Exception): self.debug("SSH into VM: %s" % self.virtual_machine.id) - SshClient( - self.virtual_machine.ssh_ip, - self.virtual_machine.ssh_port, - self.virtual_machine.username, - self.virtual_machine.password - ) + SshClient(self.virtual_machine.ssh_ip, + self.virtual_machine.ssh_port, + self.virtual_machine.username, + self.virtual_machine.password + ) return diff --git a/test/integration/component/test_shared_networks.py b/test/integration/component/test_shared_networks.py index 66a9d266dac..28468c90074 100644 --- a/test/integration/component/test_shared_networks.py +++ b/test/integration/component/test_shared_networks.py @@ -1696,25 +1696,19 @@ class TestSharedNetworks(cloudstackTestCase): self.debug("Shared Network created: %s" % self.network.id) - try: + with self.assertRaises(Exception): self.project2_admin_account_virtual_machine = VirtualMachine.create( self.api_client, self.services["virtual_machine"], - accountid=self.admin_account.name, - domainid=self.admin_account.domainid, networkids=self.network.id, projectid=self.project2.id, serviceofferingid=self.service_offering.id ) - self.fail("Virtual Machine got created in admin account with network specified but the network used is of scope project and the project2 is not assigned for the network.") - except Exception as e: - self.debug("Virtual Machine creation failed as network used have scoped only for project project1. Exception: %s" % e) - + self.debug("Deploying a vm to project other than the one in which \ + network is created raised an Exception as expected") self.project1_admin_account_virtual_machine = VirtualMachine.create( self.api_client, self.services["virtual_machine"], - accountid=self.admin_account.name, - domainid=self.admin_account.domainid, networkids=self.network.id, projectid=self.project1.id, serviceofferingid=self.service_offering.id diff --git a/test/integration/component/test_snapshot_limits.py b/test/integration/component/test_snapshot_limits.py index e52a893587c..a1bf1ba2f50 100644 --- a/test/integration/component/test_snapshot_limits.py +++ b/test/integration/component/test_snapshot_limits.py @@ -21,7 +21,6 @@ from marvin.cloudstackAPI import * from marvin.integration.lib.utils import * from marvin.integration.lib.base import * from marvin.integration.lib.common import * -from marvin.sshClient import SshClient from marvin.integration.lib.utils import is_snapshot_on_nfs import os diff --git a/test/integration/component/test_stopped_vm.py b/test/integration/component/test_stopped_vm.py index 5a5c2981e2f..4ba94bfc293 100644 --- a/test/integration/component/test_stopped_vm.py +++ b/test/integration/component/test_stopped_vm.py @@ -22,7 +22,6 @@ import marvin from nose.plugins.attrib import attr from marvin.cloudstackTestCase import * from marvin.cloudstackAPI import * -from marvin.sshClient import SshClient from marvin.integration.lib.utils import * from marvin.integration.lib.base import * from marvin.integration.lib.common import * @@ -771,7 +770,7 @@ class TestDeployVM(cloudstackTestCase): type='DATADISK', account=self.account.name, domainid=self.account.domainid, - listall=True + virtualmachineid=self.virtual_machine_2.id ) self.assertEqual( isinstance(volumes, list), @@ -1257,7 +1256,7 @@ class TestRouterStateAfterDeploy(cloudstackTestCase): except Exception as e: self.debug("Warning! Exception in tearDown: %s" % e) - @attr(tags = ["advanced", "eip", "advancedns", "basic", "sg"]) + @attr(tags = ["advanced", "eip", "advancedns"]) def test_01_deploy_vm_no_startvm(self): """Test Deploy Virtual Machine with no startVM parameter """ diff --git a/test/integration/component/test_storage_motion.py b/test/integration/component/test_storage_motion.py index bae5acf5514..194ba977090 100644 --- a/test/integration/component/test_storage_motion.py +++ b/test/integration/component/test_storage_motion.py @@ -20,7 +20,6 @@ import marvin from marvin.cloudstackTestCase import * from marvin.cloudstackAPI import * -from marvin.sshClient import SshClient from marvin.integration.lib.utils import * from marvin.integration.lib.base import * from marvin.integration.lib.common import * diff --git a/test/integration/component/test_templates.py b/test/integration/component/test_templates.py index af86d32a3bd..91de9b3ea64 100644 --- a/test/integration/component/test_templates.py +++ b/test/integration/component/test_templates.py @@ -24,7 +24,6 @@ from marvin.cloudstackAPI import * from marvin.integration.lib.utils import * from marvin.integration.lib.base import * from marvin.integration.lib.common import * -from marvin.sshClient import SshClient import urllib from random import random #Import System modules diff --git a/test/integration/component/test_vmware_drs.py b/test/integration/component/test_vmware_drs.py new file mode 100644 index 00000000000..8eeb2c322a9 --- /dev/null +++ b/test/integration/component/test_vmware_drs.py @@ -0,0 +1,713 @@ +# 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. + +""" P1 for VMware DRS testing +""" +#Import Local Modules +import marvin +from nose.plugins.attrib import attr + +from marvin.cloudstackTestCase import cloudstackTestCase, unittest + +from marvin.integration.lib.base import (Account, + AffinityGroup, + Host, + VirtualMachine, + ServiceOffering) + +from marvin.integration.lib.commom import (get_zone, + get_template, + get_domain, + get_pod + ) + +from marvin.integration.lib.utils import (validateList, + cleanup_resources, + random_gen) + +from marvin.cloudstackAPI import (prepareHostForMaintenance, + cancelHostMaintenance, + migrateVirtualMachine) + +from marvin.codes import PASS + + +#Import System modules +import time + + +class Services: + """Test vmware DRS services + """ + + def __init__(self): + self.services = { + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended in create account to + # ensure unique username generated each time + "password": "password", + }, + "virtual_machine": + { + "displayname": "testserver", + "username": "root", # VM creds for SSH + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "service_offering": + { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 100, # in MHz + "memory": 2048, # In MBs + }, + "service_offering_max_memory": + { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 100, # in MHz + "memory": 128, # In MBs + }, + "host_anti_affinity": { + "name": "", + "type": "host anti-affinity", + }, + "host_affinity": { + "name": "", + "type": "host affinity", + }, + "sleep": 60, + "timeout": 10, + "ostype": 'CentOS 5.3 (64-bit)', + # CentOS 5.3 (64-bit) + } + +class TestVMPlacement(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + + cls.api_client = super( + TestVMPlacement, + cls + ).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain and templates + cls.domain = get_domain( + cls.api_client, + cls.services + ) + cls.zone = get_zone( + cls.api_client, + cls.services + ) + cls.pod = get_pod( + cls.api_client, + zoneid=cls.zone.id, + services=cls.services + ) + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.services["virtual_machine"]["template"] = cls.template.id + + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"], + offerha=True + ) + cls._cleanup = [ + cls.service_offering, + ] + return + + @classmethod + def tearDownClass(cls): + try: + #Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.account = Account.create( + self.apiclient, + self.services["account"], + admin=True, + domainid=self.domain.id + ) + self.cleanup = [self.account] + return + + def tearDown(self): + try: + #Clean up, terminate the created accounts, domains etc + cleanup_resources(self.apiclient, self.cleanup) + #self.testClient.close() + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags = ["advanced", "vmware", "multihost"]) + def test_vm_creation_in_fully_automated_mode(self): + """ Test VM Creation in automation mode = Fully automated + This test requires following preconditions: + - DRS Cluster is configured in "Fully automated" mode + """ + # Validate the following + # 1. Create a new VM in a host which is almost fully utilized + # 2 Automatically places VM on the other host + # 3. VM state is running after deployment + + hosts = Host.list( + self.apiclient, + zoneid=self.zone.id, + resourcestate='Enabled', + type='Routing' + ) + self.assertEqual( + isinstance(hosts, list), + True, + "List hosts should return valid host response" + ) + self.assertGreaterEqual( + len(hosts), + 2, + "There must be two hosts present in a cluster" + ) + + host_1 = hosts[0] + + #Convert available memory( Keep some margin) into MBs and assign to service offering + self.services["service_offering_max_memory"]["memory"] = int((int(hosts[0].memorytotal) - int(hosts[0].memoryused))/1048576 - 1024) + + self.debug("max memory: %s" % self.services["service_offering_max_memory"]["memory"]) + + service_offering_max_memory = ServiceOffering.create( + self.apiclient, + self.services["service_offering_max_memory"] + ) + + VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=service_offering_max_memory.id, + hostid = host_1.id + ) + + # Host 1 has only 1024 MB memory available now after deploying the instance + # We are trying to deploy an instance with 2048 MB memory, this should automatically + # get deployed on other host which has the enough capacity + + self.debug("Trying to deploy instance with memory requirement more than that is available on\ + the first host") + + self.debug("Deploying VM in account: %s" % self.account.name) + # Spawn an instance in that network + virtual_machine = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id + ) + vms = VirtualMachine.list( + self.apiclient, + id=virtual_machine.id, + listall=True + ) + self.assertEqual( + isinstance(vms, list), + True, + "List VMs should return valid response for deployed VM" + ) + self.assertNotEqual( + len(vms), + 0, + "List VMs should return valid response for deployed VM" + ) + vm = vms[0] + self.assertEqual( + vm.state, + "Running", + "Deployed VM should be in RUnning state" + ) + self.assertNotEqual( + vm.hostid, + host_1.id, + "Host Ids of two should not match as one host is full" + ) + + self.debug("The host ids of two virtual machines are different as expected\ + they are %s and %s" % (vm.hostid, host_1.id)) + return + +@unittest.skip("Skipping... Not tested due to unavailibility of multihosts setup - 3 hosts in a cluster") +class TestAntiAffinityRules(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + + cls.api_client = super( + TestAntiAffinityRules, + cls + ).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain and templates + cls.domain = get_domain( + cls.api_client, + cls.services + ) + cls.zone = get_zone( + cls.api_client, + cls.services + ) + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.services["virtual_machine"]["template"] = cls.template.id + + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"], + offerha=True + ) + + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + cls._cleanup = [cls.account] + return + + @classmethod + def tearDownClass(cls): + try: + #Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + #Clean up, terminate the created accounts, domains etc + cleanup_resources(self.apiclient, self.cleanup) + #self.testClient.close() + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def create_aff_grp(self, aff_grp=None, + acc=None, domainid=None): + + aff_grp["name"] = "aff_grp_" + random_gen(size=6) + + try: + aff_grp = AffinityGroup.create(self.apiclient, + aff_grp, acc, domainid) + return aff_grp + except Exception as e: + raise Exception("Error: Creation of Affinity Group failed : %s" %e) + + @attr(tags = ["advanced", "vmware", "multihost"]) + def test_vmware_anti_affinity(self): + """ Test Set up anti-affinity rules + + The test requires following pre-requisites + - VMWare cluster configured in fully automated mode + """ + + # Validate the following + # 1. Deploy VMs on host 1 and 2 + # 2. Enable maintenance mode for host 1 + # 3. VM should be migrated to 3rd host + + hosts = Host.list( + self.apiclient, + zoneid=self.zone.id, + resourcestate='Enabled', + type='Routing' + ) + self.assertEqual( + isinstance(hosts, list), + True, + "List hosts should return valid host response" + ) + + self.debug(len(hosts)) + + self.assertGreaterEqual( + len(hosts), + 3, + "There must be at least 3 hosts present in a cluster" + ) + + aff_grp = self.create_aff_grp(aff_grp=self.services["host_anti_affinity"], acc=self.account.name, domainid=self.domain.id) + + vm_1 = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + accountid=self.account.name, + domainid=self.domain.id, + serviceofferingid=self.service_offering.id, + affinitygroupnames=[aff_grp.name] + ) + + vm_2 = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + accountid=self.account.name, + domainid=self.domain.id, + serviceofferingid=self.service_offering.id, + affinitygroupnames=[aff_grp.name] + ) + + host_1 = vm_1.hostid + + host_2 = vm_2.hostid + + vms = VirtualMachine.list( + self.apiclient, + id=vm_1.id, + listall=True + ) + vm_list_validation_result = validateList(vms) + + self.assertEqual(vm_list_validation_result[0], PASS, "vm list validation failed due to %s" % + vm_list_validation_result[1]) + + virtual_machine_1 = vm_list_validation_result[1] + + self.debug("VM State: %s" % virtual_machine_1.state) + self.assertEqual( + virtual_machine_1.state, + "Running", + "Deployed VM should be in RUnning state" + ) + + vms = VirtualMachine.list( + self.apiclient, + id=vm_2.id, + listall=True + ) + vm_list_validation_result = validateList(vms) + + self.assertEqual(vm_list_validation_result[0], PASS, "vm list validation failed due to %s" % + vm_list_validation_result[1]) + + virtual_machine_2 = vm_list_validation_result[1] + + self.debug("VM %s State: %s" % ( + virtual_machine_2.name, + virtual_machine_2.state + )) + self.assertEqual( + virtual_machine_2.state, + "Running", + "Deployed VM should be in RUnning state" + ) + self.debug("Enabling maintenance mode on host_1: %s" % host_1) + + cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() + cmd.id = host_1 + self.apiclient.prepareHostForMaintenance(cmd) + + timeout = self.services["timeout"] + while True: + hosts = Host.list( + self.apiclient, + zoneid=self.zone.id, + type='Routing', + id=host_1 + ) + host_list_validation_result = validateList(hosts) + + self.assertEqual(host_list_validation_result[0], PASS, "host list validation failed due to %s" + % host_list_validation_result[2]) + + host = host_list_validation_result[1] + + if host.resourcestate == 'Maintenance': + break + elif timeout == 0: + self.fail("Failed to put host: %s in maintenance mode" % host.name) + + time.sleep(self.services["sleep"]) + timeout = timeout - 1 + + vms = VirtualMachine.list( + self.apiclient, + id=virtual_machine_1.id, + listall=True + ) + vm_list_validation_result = validateList(vms) + + self.assertEqual(vm_list_validation_result[0], PASS, "vm list validation failed due to %s" % + vm_list_validation_result[2]) + + vm = vm_list_validation_result[0] + + self.assertEqual( + vm.state, + "Running", + "Deployed VM should be in RUnning state" + ) + self.assertNotEqual( + vm.hostid, + host_2, + "The host name should not match with second host name" + ) + + self.debug("Canceling host maintenance for ID: %s" % host_1.id) + cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() + cmd.id = host_1.id + self.apiclient.cancelHostMaintenance(cmd) + self.debug("Maintenance mode canceled for host: %s" % host_1.id) + + return + +@unittest.skip("Skipping...Host Affinity feature not available yet in cloudstack") +class TestAffinityRules(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + + cls.api_client = super( + TestAffinityRules, + cls + ).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain and templates + cls.domain = get_domain( + cls.api_client, + cls.services + ) + cls.zone = get_zone( + cls.api_client, + cls.services + ) + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.services["virtual_machine"]["template"] = cls.template.id + + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"], + offerha=True + ) + + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + cls._cleanup = [cls.account] + return + + @classmethod + def tearDownClass(cls): + try: + #Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + # Clean up, terminate the created accounts, domains etc + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def create_aff_grp(self, aff_grp=None, + acc=None, domainid=None): + + aff_grp["name"] = "aff_grp_" + random_gen(size=6) + + try: + aff_grp = AffinityGroup.create(self.apiclient, + aff_grp, acc, domainid) + return aff_grp + except Exception as e: + raise Exception("Error: Creation of Affinity Group failed : %s" %e) + + @attr(tags = ["advanced", "vmware", "multihost"]) + def test_vmware_affinity(self): + """ Test Set up affinity rules + + The test requires following pre-requisites + - VMWare cluster configured in fully automated mode + """ + + # Validate the following + # 1. Deploy 2 VMs on same hosts + # 2. Migrate one VM from one host to another + # 3. The second VM should also get migrated + + hosts = Host.list( + self.apiclient, + zoneid=self.zone.id, + resourcestate='Enabled', + type='Routing' + ) + self.assertEqual( + isinstance(hosts, list), + True, + "List hosts should return valid host response" + ) + self.assertGreaterEqual( + len(hosts), + 2, + "There must be two hosts present in a cluster" + ) + + host_1 = hosts[0].id + + host_2 = hosts[1].id + + aff_grp = self.create_aff_grp(aff_grp=self.services["host_affinity"], acc=self.account.name, domainid=self.domain.id) + + vm_1 = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + accountid=self.account.name, + domainid=self.domain.id, + serviceofferingid=self.service_offering.id, + affinitygroupnames=[aff_grp.name], + hostid = host_1 + ) + + vm_2 = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + accountid=self.account.name, + domainid=self.domain.id, + serviceofferingid=self.service_offering.id, + affinitygroupnames=[aff_grp.name] + ) + + vms = VirtualMachine.list( + self.apiclient, + id= vm_1.id, + listall=True + ) + + vm_list_validation_result = validateList(vms) + + self.assertEqual(vm_list_validation_result[0], PASS, "vm list validation failed due to %s" % + vm_list_validation_result[2]) + + virtual_machine_1 = vm_list_validation_result[1] + + self.assertEqual( + virtual_machine_1.state, + "Running", + "Deployed VM should be in RUnning state" + ) + + self.debug("Deploying VM on account: %s" % self.account.name) + + vms = VirtualMachine.list( + self.apiclient, + id=vm_2.id, + listall=True + ) + vm_list_validation_result = validateList(vms) + + self.assertEqual(vm_list_validation_result[0], PASS, "vm list validation failed due to %s" % + vm_list_validation_result[2]) + + virtual_machine_2 = vm_list_validation_result[1] + + self.assertEqual( + virtual_machine_2.state, + "Running", + "Deployed VM should be in RUnning state" + ) + + self.debug("Migrate VM from host_1 to host_2") + cmd = migrateVirtualMachine.migrateVirtualMachineCmd() + cmd.virtualmachineid = virtual_machine_2.id + cmd.hostid = host_2 + self.apiclient.migrateVirtualMachine(cmd) + self.debug("Migrated VM from host_1 to host_2") + + vms = VirtualMachine.list( + self.apiclient, + hostid=host_2, + listall=True + ) + vm_list_validation_result = validateList(vms) + + self.assertEqual(vm_list_validation_result[0], PASS, "vm list validation failed due to %s" % + vm_list_validation_result[2]) + + vmids = [vm.id for vm in vms] + + self.assertIn( + virtual_machine_1.id, + vmids, + "VM 1 should be successfully migrated to host 2" + ) + self.assertIn( + virtual_machine_2.id, + vmids, + "VM 2 should be automatically migrated to host 2" + ) + return diff --git a/test/integration/component/test_vpc_network.py b/test/integration/component/test_vpc_network.py index 9f5e6f623f0..c918f54043d 100644 --- a/test/integration/component/test_vpc_network.py +++ b/test/integration/component/test_vpc_network.py @@ -25,7 +25,6 @@ from marvin.cloudstackAPI import * from marvin.integration.lib.utils import * from marvin.integration.lib.base import * from marvin.integration.lib.common import * -from marvin.sshClient import SshClient import datetime # For more info on ddt refer to http://ddt.readthedocs.org/en/latest/api.html#module-ddt from ddt import ddt, data diff --git a/test/integration/component/test_vpc_routers.py b/test/integration/component/test_vpc_routers.py index 8ed99ca3c36..a83662740db 100644 --- a/test/integration/component/test_vpc_routers.py +++ b/test/integration/component/test_vpc_routers.py @@ -25,7 +25,6 @@ from marvin.cloudstackAPI import * from marvin.integration.lib.utils import * from marvin.integration.lib.base import * from marvin.integration.lib.common import * -from marvin.sshClient import SshClient import datetime diff --git a/test/integration/component/test_vpc_vm_life_cycle.py b/test/integration/component/test_vpc_vm_life_cycle.py index cc65eedff8a..60a8971189f 100644 --- a/test/integration/component/test_vpc_vm_life_cycle.py +++ b/test/integration/component/test_vpc_vm_life_cycle.py @@ -25,7 +25,6 @@ from marvin.cloudstackAPI import * from marvin.integration.lib.utils import * from marvin.integration.lib.base import * from marvin.integration.lib.common import * -from marvin.sshClient import SshClient from marvin.codes import PASS import time @@ -58,7 +57,7 @@ class Services: "cpunumber": 1, "cpuspeed": 100, "memory": 128, - "tags": "HOST_TAGS_HERE" + "hosttags": "host1" }, "service_offering_2": { "name": "Tiny Instance- tagged host 2", @@ -66,7 +65,7 @@ class Services: "cpunumber": 1, "cpuspeed": 100, "memory": 128, - "tags": "HOST_TAGS_HERE" + "hosttags": "host2" }, "network_offering": { "name": 'VPC Network offering', @@ -2717,3 +2716,952 @@ class TestVMLifeCycleStoppedVPCVR(cloudstackTestCase): listall=True ) return + +class TestVMLifeCycleDiffHosts(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + try: + + cls.api_client = super( + TestVMLifeCycleDiffHosts, + cls + ).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.services["virtual_machine"]["template"] = cls.template.id + + hosts = list_hosts(cls.api_client) + + assert isinstance(hosts, list), "list_hosts should return a list response,\ + instead got %s" % hosts + + if len(hosts) < 3: + raise Exception("Minimum 3 hosts should be available to run this test suite") + + Host.update(cls.api_client, id=hosts[0].id, hosttags="host1") + + Host.update(cls.api_client, id=hosts[1].id, hosttags="host1") + + Host.update(cls.api_client, id=hosts[2].id, hosttags="host2") + + cls.service_offering_1 = ServiceOffering.create( + cls.api_client, + cls.services["service_offering_1"] + ) + cls.service_offering_2 = ServiceOffering.create( + cls.api_client, + cls.services["service_offering_2"] + ) + + cls.account = Account.create( + cls.api_client, + cls.services["account"], + admin=True, + domainid=cls.domain.id + ) + + cls.vpc_off = VpcOffering.create( + cls.api_client, + cls.services["vpc_offering"] + ) + + cls.vpc_off.update(cls.api_client, state='Enabled') + + cls.services["vpc"]["cidr"] = '10.1.1.1/16' + cls.vpc = VPC.create( + cls.api_client, + cls.services["vpc"], + vpcofferingid=cls.vpc_off.id, + zoneid=cls.zone.id, + account=cls.account.name, + domainid=cls.account.domainid + ) + + cls.nw_off = NetworkOffering.create( + cls.api_client, + cls.services["network_offering"], + conservemode=False + ) + # Enable Network offering + cls.nw_off.update(cls.api_client, state='Enabled') + + # Creating network using the network offering created + cls.network_1 = Network.create( + cls.api_client, + cls.services["network"], + accountid=cls.account.name, + domainid=cls.account.domainid, + networkofferingid=cls.nw_off.id, + zoneid=cls.zone.id, + gateway='10.1.1.1', + vpcid=cls.vpc.id + ) + cls.nw_off_no_lb = NetworkOffering.create( + cls.api_client, + cls.services["network_offering_no_lb"], + conservemode=False + ) + # Enable Network offering + cls.nw_off_no_lb.update(cls.api_client, state='Enabled') + + # Creating network using the network offering created + cls.network_2 = Network.create( + cls.api_client, + cls.services["network"], + accountid=cls.account.name, + domainid=cls.account.domainid, + networkofferingid=cls.nw_off_no_lb.id, + zoneid=cls.zone.id, + gateway='10.1.2.1', + vpcid=cls.vpc.id + ) + # Spawn an instance in that network + cls.vm_1 = VirtualMachine.create( + cls.api_client, + cls.services["virtual_machine"], + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering_1.id, + networkids=[str(cls.network_1.id)] + ) + # Spawn an instance in that network + cls.vm_2 = VirtualMachine.create( + cls.api_client, + cls.services["virtual_machine"], + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering_1.id, + networkids=[str(cls.network_1.id)] + ) + + cls.vm_3 = VirtualMachine.create( + cls.api_client, + cls.services["virtual_machine"], + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering_2.id, + networkids=[str(cls.network_2.id)] + ) + + cls.public_ip_static = PublicIPAddress.create( + cls.api_client, + accountid=cls.account.name, + zoneid=cls.zone.id, + domainid=cls.account.domainid, + networkid=cls.network_1.id, + vpcid=cls.vpc.id + ) + StaticNATRule.enable( + cls.api_client, + ipaddressid=cls.public_ip_static.ipaddress.id, + virtualmachineid=cls.vm_1.id, + networkid=cls.network_1.id + ) + + cls.public_ip_1 = PublicIPAddress.create( + cls.api_client, + accountid=cls.account.name, + zoneid=cls.zone.id, + domainid=cls.account.domainid, + networkid=cls.network_1.id, + vpcid=cls.vpc.id + ) + + cls.nat_rule = NATRule.create( + cls.api_client, + cls.vm_1, + cls.services["natrule"], + ipaddressid=cls.public_ip_1.ipaddress.id, + openfirewall=False, + networkid=cls.network_1.id, + vpcid=cls.vpc.id + ) + + cls.public_ip_2 = PublicIPAddress.create( + cls.api_client, + accountid=cls.account.name, + zoneid=cls.zone.id, + domainid=cls.account.domainid, + networkid=cls.network_1.id, + vpcid=cls.vpc.id + ) + + cls.lb_rule = LoadBalancerRule.create( + cls.api_client, + cls.services["lbrule"], + ipaddressid=cls.public_ip_2.ipaddress.id, + accountid=cls.account.name, + networkid=cls.network_1.id, + vpcid=cls.vpc.id, + domainid=cls.account.domainid + ) + cls.lb_rule.assign(cls.api_client, [cls.vm_1, cls.vm_2]) + + # Opening up the ports in VPC + cls.nwacl_nat = NetworkACL.create( + cls.api_client, + networkid=cls.network_1.id, + services=cls.services["natrule"], + traffictype='Ingress' + ) + + cls.nwacl_lb = NetworkACL.create( + cls.api_client, + networkid=cls.network_1.id, + services=cls.services["lbrule"], + traffictype='Ingress' + ) + + cls.nwacl_internet = NetworkACL.create( + cls.api_client, + networkid=cls.network_1.id, + services=cls.services["icmp_rule"], + traffictype='Egress' + ) + cls._cleanup = [ + cls.service_offering_1, + cls.service_offering_2, + cls.nw_off, + cls.nw_off_no_lb, + ] + + except Exception as e: + raise Exception("Warning: Exception during setup : %s" % e) + + return + + @classmethod + def tearDownClass(cls): + try: + cls.account.delete(cls.api_client) + wait_for_cleanup(cls.api_client, ["account.cleanup.interval"]) + #Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + + # Waiting for network cleanup to delete vpc offering + wait_for_cleanup(cls.api_client, ["network.gc.wait", + "network.gc.interval"]) + cls.vpc_off.delete(cls.api_client) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + #Clean up, terminate the created network offerings + cleanup_resources(self.apiclient, self.cleanup) + wait_for_cleanup(self.apiclient, [ + "network.gc.interval", + "network.gc.wait"]) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def validate_vm_deployment(self): + """Validates VM deployment on different hosts""" + + vms = VirtualMachine.list( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid, + networkid=self.network_1.id, + listall=True + ) + self.assertEqual( + isinstance(vms, list), + True, + "List VMs shall return a valid response" + ) + host_1 = vms[0].hostid + self.debug("Host for network 1: %s" % vms[0].hostid) + + vms = VirtualMachine.list( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid, + networkid=self.network_2.id, + listall=True + ) + self.assertEqual( + isinstance(vms, list), + True, + "List VMs shall return a valid response" + ) + host_2 = vms[0].hostid + self.debug("Host for network 2: %s" % vms[0].hostid) + + self.assertNotEqual( + host_1, + host_2, + "Both the virtual machines should be deployed on diff hosts " + ) + return + + def validate_vpc_offering(self, vpc_offering): + """Validates the VPC offering""" + + self.debug("Check if the VPC offering is created successfully?") + vpc_offs = VpcOffering.list( + self.apiclient, + id=vpc_offering.id + ) + self.assertEqual( + isinstance(vpc_offs, list), + True, + "List VPC offerings should return a valid list" + ) + self.assertEqual( + vpc_offering.name, + vpc_offs[0].name, + "Name of the VPC offering should match with listVPCOff data" + ) + self.debug( + "VPC offering is created successfully - %s" % + vpc_offering.name) + return + + def validate_vpc_network(self, network, state=None): + """Validates the VPC network""" + + self.debug("Check if the VPC network is created successfully?") + vpc_networks = VPC.list( + self.apiclient, + id=network.id + ) + self.assertEqual( + isinstance(vpc_networks, list), + True, + "List VPC network should return a valid list" + ) + self.assertEqual( + network.name, + vpc_networks[0].name, + "Name of the VPC network should match with listVPC data" + ) + if state: + self.assertEqual( + vpc_networks[0].state, + state, + "VPC state should be '%s'" % state + ) + self.debug("VPC network validated - %s" % network.name) + return + + def validate_network_rules(self): + """Validates if the network rules work properly or not?""" + for ip in [self.public_ip_1.ipaddress.ipaddress, self.public_ip_2.ipaddress.ipaddress, self.public_ip_static.ipaddress.ipaddress]: + try: + self.debug("Checking if we can SSH into VM_1 through %s?" % + (ip)) + ssh = self.vm_1.get_ssh_client( + ipaddress=ip, + reconnect=True) + + self.assertNotEqual(ssh, None, + "SSH client should be returned successfully") + + self.debug("SSH into VM is successfully") + + self.debug("Verifying if we can ping to outside world from VM?") + # Ping to outsite world + res = ssh.execute("ping -c 1 www.google.com") + # res = 64 bytes from maa03s17-in-f20.1e100.net (74.125.236.212): + # icmp_req=1 ttl=57 time=25.9 ms + # --- www.l.google.com ping statistics --- + # 1 packets transmitted, 1 received, 0% packet loss, time 0ms + # rtt min/avg/max/mdev = 25.970/25.970/25.970/0.000 ms + result = str(res) + self.assertEqual( + result.count("1 received"), + 1, + "Ping to outside world from VM should be successful" + ) + except Exception as e: + self.fail("Failed to SSH into VM - %s, %s" % + (ip, e)) + + return + + @attr(tags=["advanced","multihost", "intervlan"]) + def test_01_deploy_instance_in_network(self): + """ Test deploy an instance in VPC networks + """ + + # Validate the following + # 1. Create a VPC with cidr - 10.1.1.1/16 + # 2. Add network1(10.1.1.1/24) and network2(10.1.2.1/24) to this VPC. + # Steps: + # 1. Deploy vm1 and vm2 in network1 and vm3 and vm4 in network2 using + # the default CentOS 6.2 Template + + self.validate_vm_deployment() + self.debug("Check if deployed VMs are in running state?") + vms = VirtualMachine.list( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid, + listall=True + ) + self.assertEqual( + isinstance(vms, list), + True, + "List VMs should return a valid response" + ) + for vm in vms: + self.debug("VM name: %s, VM state: %s" % (vm.name, vm.state)) + self.assertEqual( + vm.state, + "Running", + "Vm state should be running for each VM deployed" + ) + return + + @attr(tags=["advanced","multihost", "intervlan"]) + def test_02_stop_instance_in_network(self): + """ Test stop an instance in VPC networks + """ + + # Validate the following + # 1. Stop the virtual machines. + # 2. Rules should be still configured on virtual router. + + self.debug("Stopping the virtual machines in account: %s" % + self.account.name) + try: + self.vm_1.stop(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.vm_1.id + ) + + vm_response = list_vm_response[0] + + self.assertEqual( + vm_response.state, + 'Stopped', + "VM state should be stopped" + ) + + self.vm_2.stop(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.vm_2.id + ) + + vm_response = list_vm_response[0] + + self.assertEqual( + vm_response.state, + 'Stopped', + "VM state should be stopped" + ) + + except Exception as e: + self.fail("Failed to stop the virtual instances, %s" % e) + + # Check if the network rules still exists after Vm stop + self.debug("Checking if NAT rules ") + nat_rules = NATRule.list( + self.apiclient, + id=self.nat_rule.id, + listall=True + ) + self.assertEqual( + isinstance(nat_rules, list), + True, + "List NAT rules shall return a valid list" + ) + + lb_rules = LoadBalancerRule.list( + self.apiclient, + id=self.lb_rule.id, + listall=True + ) + self.assertEqual( + isinstance(lb_rules, list), + True, + "List LB rules shall return a valid list" + ) + return + + @attr(tags=["advanced","multihost", "intervlan"]) + def test_03_start_instance_in_network(self): + """ Test start an instance in VPC networks + """ + + # Validate the following + # 1. Start the virtual machines. + # 2. Vm should be started successfully. + # 3. Make sure that all the PF,LB and Static NAT rules on this VM + # works as expected. + # 3. Make sure that we are able to access google.com from this user Vm + + self.debug("Starting the virtual machines in account: %s" % + self.account.name) + try: + self.vm_1.start(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.vm_1.id + ) + + vm_response = list_vm_response[0] + + self.assertEqual( + vm_response.state, + 'Running', + "VM state should be running" + ) + + self.vm_2.start(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.vm_2.id + ) + + vm_response = list_vm_response[0] + + self.assertEqual( + vm_response.state, + 'Running', + "VM state should be running" + ) + + except Exception as e: + self.fail("Failed to start the virtual instances, %s" % e) + self.debug("Validating if the network rules work properly or not?") + self.validate_network_rules() + return + + @attr(tags=["advanced","multihost", "intervlan"]) + def test_04_reboot_instance_in_network(self): + """ Test reboot an instance in VPC networks + """ + + # Validate the following + # 1. Reboot the virtual machines. + # 2. Vm should be started successfully. + # 3. Make sure that all the PF,LB and Static NAT rules on this VM + # works as expected. + # 3. Make sure that we are able to access google.com from this user Vm + + self.debug("Validating if the network rules work properly or not?") + self.validate_network_rules() + + self.debug("Starting the virtual machines in account: %s" % + self.account.name) + try: + self.vm_1.reboot(self.apiclient) + self.vm_2.reboot(self.apiclient) + except Exception as e: + self.fail("Failed to reboot the virtual instances, %s" % e) + + self.debug("Validating if the network rules work properly or not?") + self.validate_network_rules() + return + + @attr(tags=["advanced","multihost", "intervlan"]) + def test_05_destroy_instance_in_network(self): + """ Test destroy an instance in VPC networks + """ + + # Validate the following + # 1. Destory the virtual machines. + # 2. Rules should be still configured on virtual router. + # 3. Recover the virtual machines. + # 4. Vm should be in stopped state. State both the instances + # 5. Make sure that all the PF,LB and Static NAT rules on this VM + # works as expected. + # 6. Make sure that we are able to access google.com from this user Vm + + self.debug("Validating if the network rules work properly or not?") + self.validate_network_rules() + + self.debug("Destroying the virtual machines in account: %s" % + self.account.name) + try: + self.vm_1.delete(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.vm_1.id + ) + + vm_response = list_vm_response[0] + + self.assertEqual( + vm_response.state, + 'Destroyed', + "VM state should be destroyed" + ) + + self.vm_2.delete(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.vm_2.id + ) + + vm_response = list_vm_response[0] + + self.assertEqual( + vm_response.state, + 'Destroyed', + "VM state should be destroyed" + ) + + except Exception as e: + self.fail("Failed to stop the virtual instances, %s" % e) + + # Check if the network rules still exists after Vm stop + self.debug("Checking if NAT rules ") + nat_rules = NATRule.list( + self.apiclient, + id=self.nat_rule.id, + listall=True + ) + self.assertEqual( + isinstance(nat_rules, list), + True, + "List NAT rules shall return a valid list" + ) + + lb_rules = LoadBalancerRule.list( + self.apiclient, + id=self.lb_rule.id, + listall=True + ) + self.assertEqual( + isinstance(lb_rules, list), + True, + "List LB rules shall return a valid list" + ) + + self.debug("Recovering the expunged virtual machines in account: %s" % + self.account.name) + try: + self.vm_1.recover(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.vm_1.id + ) + + vm_response = list_vm_response[0] + + self.assertEqual( + vm_response.state, + 'Stopped', + "VM state should be stopped" + ) + + self.vm_2.recover(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.vm_2.id + ) + + vm_response = list_vm_response[0] + + self.assertEqual( + vm_response.state, + 'Stopped', + "VM state should be stopped" + ) + except Exception as e: + self.fail("Failed to recover the virtual instances, %s" % e) + + self.debug("Starting the two instances..") + try: + self.vm_1.start(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.vm_1.id + ) + + vm_response = list_vm_response[0] + + self.assertEqual( + vm_response.state, + 'Running', + "VM state should be running" + ) + + self.vm_2.start(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.vm_2.id + ) + + vm_response = list_vm_response[0] + + self.assertEqual( + vm_response.state, + 'Running', + "VM state should be running" + ) + except Exception as e: + self.fail("Failed to start the instances, %s" % e) + + # Wait until vms are up + time.sleep(120) + self.debug("Validating if the network rules work properly or not?") + self.validate_network_rules() + + return + + @attr(tags=["advanced","multihost", "intervlan"]) + def test_06_migrate_instance_in_network(self): + """ Test migrate an instance in VPC networks + """ + + # Validate the following + # 1. Migrate the virtual machines to other hosts + # 2. Vm should be in stopped state. State both the instances + # 3. Make sure that all the PF,LB and Static NAT rules on this VM + # works as expected. + # 3. Make sure that we are able to access google.com from this user Vm + + self.debug("Checking if the host is available for migration?") + hosts = Host.listForMigration( + self.apiclient, + virtualmachineid=self.vm_1.id, + ) + self.debug("Hosts vm can be migrated to are : %s" %(hosts)) + self.assertEqual( + isinstance(hosts, list), + True, + "List hosts should return a valid list" + ) + # Remove the host of current VM from the hosts list + hosts[:] = [host for host in hosts if host.id != self.vm_1.hostid] + if len(hosts) <= 0: + self.skipTest( + "No host available for migration. Test requires atleast 2 hosts tagged with host1") + + host = hosts[0] + + self.debug("Validating if the network rules work properly or not?") + self.validate_network_rules() + + self.debug("Migrating VM-ID: %s to Host: %s" % ( + self.vm_1.id, + host.id + )) + + try: + self.vm_1.migrate(self.apiclient, hostid=host.id) + except Exception as e: + self.fail("Failed to migrate instance, %s" % e) + + self.debug("Validating if the network rules work properly or not?") + self.validate_network_rules() + return + + @attr(tags=["advanced","multihost", "intervlan"]) + def test_07_user_data(self): + """ Test user data in virtual machines + """ + + # Validate the following + # 1. Create a VPC with cidr - 10.1.1.1/16 + # 2. Add network1(10.1.1.1/24) and network2(10.1.2.1/24) to this VPC. + # 3. Deploy a vm in network1 and a vm in network2 using userdata + # Steps + # 1.Query for the user data for both the user vms from both networks + # User should be able to query the user data for the vms belonging to + # both the networks from the VR + self.debug("Checking if we can SSH into VM_1 through %s" % + (self.public_ip_2.ipaddress.ipaddress)) + try: + ssh = self.vm_1.get_ssh_client( + ipaddress=self.public_ip_2.ipaddress.ipaddress, + reconnect=True) + + self.assertNotEqual(ssh, None, + "get_ssh_client should return ssh handle") + + self.debug("SSH into VM is successfully") + except Exception as e: + self.fail("Failed to SSH into instance: %s" % e) + + self.debug("check the userdata with that of present in router") + try: + cmds = [ + "wget http://%s/latest/user-data" % self.network_1.gateway, + "cat user-data", + ] + for c in cmds: + result = ssh.execute(c) + self.debug("%s: %s" % (c, result)) + except Exception as e: + self.fail("Failed to SSH in Virtual machine: %s" % e) + + res = str(result) + self.assertEqual( + res.count( + self.services["virtual_machine"]["userdata"]), + 1, + "Verify user data from router" + ) + return + + @attr(tags=["advanced","multihost", "intervlan"]) + def test_08_meta_data(self): + """ Test meta data in virtual machines + """ + + # Validate the following + # 1. Create a VPC with cidr - 10.1.1.1/16 + # 2. Add network1(10.1.1.1/24) and network2(10.1.2.1/24) to this VPC. + # 3. Deploy a vm in network1 and a vm in network2 using userdata + # Steps + # 1.Query for the meta data for both the user vms from both networks + # User should be able to query the user data for the vms belonging to + # both the networks from the VR + self.debug("Checking if we can SSH into VM_1 through %s" % + (self.public_ip_2.ipaddress.ipaddress)) + try: + ssh = self.vm_1.get_ssh_client( + ipaddress=self.public_ip_2.ipaddress.ipaddress, + reconnect=True) + + self.assertNotEqual(ssh, None, + "get_ssh_client should return ssh handle") + + self.debug("SSH into VM is successfully") + except Exception as e: + self.fail("Failed to SSH into instance: %s" % e) + + self.debug("check the metadata with that of present in router") + try: + cmds = [ + "wget http://%s/latest/vm-id" % self.network_1.gateway, + "cat vm-id", + ] + for c in cmds: + result = ssh.execute(c) + self.debug("%s: %s" % (c, result)) + except Exception as e: + self.fail("Failed to SSH in Virtual machine: %s" % e) + + res = str(result) + self.assertNotEqual( + res, + None, + "Meta data should be returned from router" + ) + return + + @attr(tags=["advanced","multihost", "intervlan"]) + def test_09_expunge_instance_in_network(self): + """ Test expunge an instance in VPC networks + """ + + # Validate the following + # 1. Recover the virtual machines. + # 2. Vm should be in stopped state. State both the instances + # 3. Make sure that all the PF,LB and Static NAT rules on this VM + # works as expected. + # 3. Make sure that we are able to access google.com from this user Vm + + self.debug("Validating if the network rules work properly or not?") + self.validate_network_rules() + + self.debug("Delete virtual machines in account: %s" % + self.account.name) + try: + self.vm_1.delete(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.vm_1.id + ) + + vm_response = list_vm_response[0] + + self.assertEqual( + vm_response.state, + 'Destroyed', + "VM state should be destroyed" + ) + + self.vm_2.delete(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.vm_2.id + ) + + vm_response = list_vm_response[0] + + self.assertEqual( + vm_response.state, + 'Destroyed', + "VM state should be destroyed" + ) + + self.vm_3.delete(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.vm_3.id + ) + + vm_response = list_vm_response[0] + + self.assertEqual( + vm_response.state, + 'Destroyed', + "VM state should be destroyed" + ) + except Exception as e: + self.fail("Failed to destroy the virtual instances, %s" % e) + + self.debug( + "Waiting for expunge interval to cleanup the network and VMs") + + wait_for_cleanup( + self.apiclient, + ["expunge.interval", "expunge.delay"] + ) + + # Check if the network rules still exists after Vm stop + self.debug("Checking if NAT rules existed") + with self.assertRaises(Exception): + NATRule.list( + self.apiclient, + id=self.nat_rule.id, + listall=True + ) + + LoadBalancerRule.list( + self.apiclient, + id=self.lb_rule.id, + listall=True + ) + return diff --git a/test/integration/component/test_vpc_vms_deployment.py b/test/integration/component/test_vpc_vms_deployment.py index ebf3b317d2b..c4811ed98cd 100644 --- a/test/integration/component/test_vpc_vms_deployment.py +++ b/test/integration/component/test_vpc_vms_deployment.py @@ -25,7 +25,6 @@ from marvin.cloudstackAPI import * from marvin.integration.lib.utils import * from marvin.integration.lib.base import * from marvin.integration.lib.common import * -from marvin.sshClient import SshClient import datetime diff --git a/test/integration/smoke/test_network.py b/test/integration/smoke/test_network.py index 09d6437cd86..732fe158257 100644 --- a/test/integration/smoke/test_network.py +++ b/test/integration/smoke/test_network.py @@ -460,7 +460,7 @@ class TestPortForwarding(cloudstackTestCase): "SSHing into VM with IP address %s after NAT rule deletion" % self.virtual_machine.ipaddress) - SshClient( + SshClient( src_nat_ip_addr.ipaddress, self.virtual_machine.ssh_port, self.virtual_machine.username, @@ -578,7 +578,7 @@ class TestPortForwarding(cloudstackTestCase): "SSHing into VM with IP address %s after NAT rule deletion" % self.virtual_machine.ipaddress) - SshClient( + SshClient( ip_address.ipaddress.ipaddress, self.virtual_machine.ssh_port, self.virtual_machine.username, @@ -741,7 +741,7 @@ class TestRebootRouter(cloudstackTestCase): try: self.debug("SSH into VM (ID : %s ) after reboot" % self.vm_1.id) - SshClient( + SshClient( self.public_ip.ipaddress.ipaddress, self.services["natrule"]["publicport"], self.vm_1.username, diff --git a/tools/appliance/definitions/systemvm64template/postinstall.sh b/tools/appliance/definitions/systemvm64template/postinstall.sh index 3755b525aab..d9ce8a17163 100644 --- a/tools/appliance/definitions/systemvm64template/postinstall.sh +++ b/tools/appliance/definitions/systemvm64template/postinstall.sh @@ -36,7 +36,7 @@ install_packages() { apt-get --no-install-recommends -q -y --force-yes install rsyslog logrotate cron chkconfig insserv net-tools ifupdown vim-tiny netbase iptables apt-get --no-install-recommends -q -y --force-yes install openssh-server openssl e2fsprogs dhcp3-client tcpdump socat wget # apt-get --no-install-recommends -q -y --force-yes install grub-legacy - apt-get --no-install-recommends -q -y --force-yes install python bzip2 sed gawk diffutils grep gzip less tar telnet ftp rsync traceroute psmisc lsof procps monit inetutils-ping iputils-arping httping + apt-get --no-install-recommends -q -y --force-yes install python bzip2 sed gawk diffutils grep gzip less tar telnet ftp rsync traceroute psmisc lsof procps inetutils-ping iputils-arping httping apt-get --no-install-recommends -q -y --force-yes install dnsutils zip unzip ethtool uuid file iproute acpid virt-what sudo # sysstat @@ -220,7 +220,6 @@ configure_services() { chkconfig cloud-passwd-srvr off chkconfig --add cloud chkconfig cloud off - chkconfig monit off chkconfig xl2tpd off } diff --git a/tools/appliance/definitions/systemvmtemplate/postinstall.sh b/tools/appliance/definitions/systemvmtemplate/postinstall.sh index 1309d47a9f5..9ea009c5de3 100644 --- a/tools/appliance/definitions/systemvmtemplate/postinstall.sh +++ b/tools/appliance/definitions/systemvmtemplate/postinstall.sh @@ -35,7 +35,7 @@ install_packages() { apt-get --no-install-recommends -q -y --force-yes install rsyslog logrotate cron chkconfig insserv net-tools ifupdown vim-tiny netbase iptables apt-get --no-install-recommends -q -y --force-yes install openssh-server openssl e2fsprogs dhcp3-client tcpdump socat wget # apt-get --no-install-recommends -q -y --force-yes install grub-legacy - apt-get --no-install-recommends -q -y --force-yes install python bzip2 sed gawk diffutils grep gzip less tar telnet ftp rsync traceroute psmisc lsof procps monit inetutils-ping iputils-arping httping + apt-get --no-install-recommends -q -y --force-yes install python bzip2 sed gawk diffutils grep gzip less tar telnet ftp rsync traceroute psmisc lsof procps inetutils-ping iputils-arping httping apt-get --no-install-recommends -q -y --force-yes install dnsutils zip unzip ethtool uuid file iproute acpid virt-what sudo # sysstat @@ -219,7 +219,6 @@ configure_services() { chkconfig cloud-passwd-srvr off chkconfig --add cloud chkconfig cloud off - chkconfig monit off chkconfig xl2tpd off } diff --git a/tools/marvin/marvin/asyncJobMgr.py b/tools/marvin/marvin/asyncJobMgr.py index 0d7939ce845..e24170e18ff 100644 --- a/tools/marvin/marvin/asyncJobMgr.py +++ b/tools/marvin/marvin/asyncJobMgr.py @@ -88,7 +88,7 @@ class workThread(threading.Thread): time.mktime(jobstatus.endTime.timetuple()) - time.mktime( jobstatus.startTime.timetuple()) else: - result = self.connection.marvin_request(cmd) + result = self.connection.marvinRequest(cmd) if result is None: jobstatus.status = False else: diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py index 2c027c36879..23f81fb48c2 100644 --- a/tools/marvin/marvin/cloudstackConnection.py +++ b/tools/marvin/marvin/cloudstackConnection.py @@ -36,7 +36,7 @@ class cloudConnection(object): """ Connections to make API calls to the cloudstack management server """ def __init__(self, mgmtDet, asyncTimeout=3600, logging=None, - scheme='http', path='client/api'): + path='client/api'): self.loglevel() # Turn off requests logs self.apiKey = mgmtDet.apiKey self.securityKey = mgmtDet.securityKey @@ -49,7 +49,8 @@ class cloudConnection(object): self.logging = logging self.path = path self.retries = 5 - self.protocol = scheme + self.mgtDetails = mgmtDet + self.protocol = "http" self.asyncTimeout = asyncTimeout self.auth = True if self.port == 8096 or \ @@ -61,11 +62,9 @@ class cloudConnection(object): % (self.protocol, self.mgtSvr, self.port, self.path) def __copy__(self): - return cloudConnection(self.mgtSvr, self.port, self.user, - self.passwd, self.apiKey, - self.securityKey, - self.asyncTimeout, self.logging, - self.protocol, + return cloudConnection(self.mgtDetails, + self.asyncTimeout, + self.logging, self.path) def loglevel(self, lvl=logging.WARNING): @@ -272,6 +271,8 @@ class cloudConnection(object): self.auth, payload=payload, method=method) + if response is None: + return None self.logging.debug("Request: %s Response: %s" % (response.url, response.text)) try: diff --git a/tools/marvin/marvin/cloudstackTestClient.py b/tools/marvin/marvin/cloudstackTestClient.py index 3e833c7ecfd..8a41fad4473 100644 --- a/tools/marvin/marvin/cloudstackTestClient.py +++ b/tools/marvin/marvin/cloudstackTestClient.py @@ -23,6 +23,7 @@ import random import string import hashlib from configGenerator import ConfigManager +from marvin.integration.lib.utils import random_gen ''' @Desc : CloudStackTestClient is encapsulated class for getting various \ @@ -41,8 +42,9 @@ class cloudstackTestClient(object): dbSvrDetails, asyncTimeout=3600, defaultWorkerThreads=10, logging=None): + self.mgmtDetails = mgmtDetails self.connection = \ - cloudstackConnection.cloudConnection(mgmtDetails, + cloudstackConnection.cloudConnection(self.mgmtDetails, asyncTimeout, logging) self.apiClient =\ @@ -124,7 +126,7 @@ class cloudstackTestClient(object): createAcctCmd = createAccount.createAccountCmd() createAcctCmd.accounttype = acctType createAcctCmd.domainid = domId - createAcctCmd.email = "test-" + self.random_gen()\ + createAcctCmd.email = "test-" + random_gen()\ + "@cloudstack.org" createAcctCmd.firstname = UserName createAcctCmd.lastname = UserName @@ -148,12 +150,12 @@ class cloudstackTestClient(object): apiKey = registerUserRes.apikey securityKey = registerUserRes.secretkey + mgtDetails = self.mgmtDetails + mgtDetails.apiKey = apiKey + mgtDetails.securityKey = securityKey + newUserConnection =\ - cloudstackConnection.cloudConnection(self.connection.mgtSvr, - self.connection.port, - self.connection.user, - self.connection.passwd, - apiKey, securityKey, + cloudstackConnection.cloudConnection(mgtDetails, self.connection.asyncTimeout, self.connection.logging) self.userApiClient =\ diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index 10c636c7660..b03c552427f 100755 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -742,7 +742,7 @@ class Volume: cmd.url = services["url"] return Volume(apiclient.uploadVolume(cmd).__dict__) - def wait_for_upload(self, apiclient, timeout=5, interval=60): + def wait_for_upload(self, apiclient, timeout=10, interval=60): """Wait for upload""" # Sleep to ensure template is in proper state before download time.sleep(interval) @@ -1860,6 +1860,14 @@ class Host: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.findHostsForMigration(cmd)) + @classmethod + def update(cls, apiclient, **kwargs): + """Update host information""" + + cmd = updateHost.updateHostCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.updateHost(cmd)) + class StoragePool: """Manage Storage pools (Primary Storage)""" diff --git a/tools/marvin/marvin/integration/lib/utils.py b/tools/marvin/marvin/integration/lib/utils.py index 0fe3c26adbf..d046235cee8 100644 --- a/tools/marvin/marvin/integration/lib/utils.py +++ b/tools/marvin/marvin/integration/lib/utils.py @@ -157,10 +157,7 @@ def fetch_api_client(config_file='datacenterCfg'): asyncTimeout = 3600 return cloudstackAPIClient.CloudStackAPIClient( marvin.cloudstackConnection.cloudConnection( - mgt.mgtSvrIp, - mgt.port, - mgt.apiKey, - mgt.securityKey, + mgt, asyncTimeout, testClientLogger ) diff --git a/tools/marvin/marvin/sandbox/demo/__init__.py b/tools/marvin/marvin/sandbox/demo/__init__.py new file mode 100644 index 00000000000..00ae6c00d2e --- /dev/null +++ b/tools/marvin/marvin/sandbox/demo/__init__.py @@ -0,0 +1,17 @@ +# 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. + diff --git a/tools/marvin/marvin/sandbox/demo/live/__init__.py b/tools/marvin/marvin/sandbox/demo/live/__init__.py new file mode 100644 index 00000000000..00ae6c00d2e --- /dev/null +++ b/tools/marvin/marvin/sandbox/demo/live/__init__.py @@ -0,0 +1,17 @@ +# 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. + diff --git a/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/utils.py b/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/utils.py index f26d2c0212b..0c7ca497ded 100644 --- a/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/utils.py +++ b/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/utils.py @@ -76,10 +76,7 @@ def fetch_api_client(config_file='datacenterCfg'): asyncTimeout = 3600 return cloudstackAPIClient.CloudStackAPIClient( cloudstackConnection.cloudConnection( - mgt.mgtSvrIp, - mgt.port, - mgt.apiKey, - mgt.securityKey, + mgt, asyncTimeout, testClientLogger ) diff --git a/tools/transifex/.tx/config b/tools/transifex/.tx/config index 9c495cce520..102a47e29d4 100644 --- a/tools/transifex/.tx/config +++ b/tools/transifex/.tx/config @@ -30,3 +30,19 @@ trans.pt_BR = work-dir/messages_pt_BR.properties trans.ru_RU = work-dir/messages_ru_RU.properties trans.zh_CN = work-dir/messages_zh_CN.properties +[CloudStack_UI.43xmessagesproperties] +source_file = work-dir/messages.properties +source_lang = en +trans.ar = work-dir/messages_ar.properties +trans.ca = work-dir/messages_ca.properties +trans.de_DE = work-dir/messages_de_DE.properties +trans.es = work-dir/messages_es.properties +trans.fr_FR = work-dir/messages_fr_FR.properties +trans.it_IT = work-dir/messages_it_IT.properties +trans.ja = work-dir/messages_ja.properties +trans.ko_KR = work-dir/messages_ko_KR.properties +trans.nb_NO = work-dir/messages_nb_NO.properties +trans.pt_BR = work-dir/messages_pt_BR.properties +trans.ru_RU = work-dir/messages_ru_RU.properties +trans.zh_CN = work-dir/messages_zh_CN.properties + diff --git a/ui/scripts/regions.js b/ui/scripts/regions.js index 28f241ca848..ac573b74025 100644 --- a/ui/scripts/regions.js +++ b/ui/scripts/regions.js @@ -475,8 +475,33 @@ path: 'regions.lbUnderGSLB', label: 'assigned load balancing' }, - actions: { - remove: { + actions: { + edit: { + label: 'label.edit', + action: function(args) { + var data = { + id: args.context.GSLB[0].id, + description: args.data.description, + gslblbmethod: args.data.gslblbmethod + }; + $.ajax({ + url: createURL('updateGlobalLoadBalancerRule'), + data: data, + success: function(json) { + var jid = json.updategloballoadbalancerruleresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + remove: { label: 'delete GSLB', messages: { confirm: function(args) { @@ -517,13 +542,30 @@ } }, { description: { - label: 'label.description' + label: 'label.description', + isEditable: true }, gslbdomainname: { label: 'GSLB Domain Name' }, gslblbmethod: { - label: 'Algorithm' + label: 'Algorithm', + isEditable: true, + select: function(args) { + var array1 = [{ + id: 'roundrobin', + description: 'roundrobin' + }, { + id: 'leastconn', + description: 'leastconn' + }, { + id: 'proximity', + description: 'proximity' + }]; + args.response.success({ + data: array1 + }); + } }, gslbservicetype: { label: 'Service Type' diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index 95fc5583ff6..c9c4a4113cb 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -1188,6 +1188,15 @@ var addExtraPropertiesToUcsBladeObject = function(jsonObj) { jsonObj.bladeid = array1[2]; } +var processPropertiesInImagestoreObject = function(jsonObj) { + if (jsonObj.url != undefined) { + var url = jsonObj.url; //e.g. 'cifs://10.1.1.1/aaa/aaa2/aaa3?user=bbb&password=ccc&domain=ddd' + var passwordIndex = url.indexOf('&password='); //38 + var domainIndex = url.indexOf('&domain='); //51 + jsonObj.url = url.substring(0, passwordIndex) + url.substring(domainIndex); //remove '&password=ccc' from jsonObj.url + } +} + //find service object in network object function ipFindNetworkServiceByName(pName, networkObj) { @@ -1228,6 +1237,17 @@ var addExtraPropertiesToUcsBladeObject = function(jsonObj) { return url; } + function smbURL(server, path, smbUsername, smbPassword, smbDomain) { + var url = ''; + if (server.indexOf('://') == -1) { + url += 'cifs://'; + } + + url += (server + path + '?user=' + smbUsername + '&password=' + smbPassword + '&domain=' + smbDomain); + + return url; + } + function presetupURL(server, path) { var url; if (server.indexOf("://") == -1) diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js index 314621e3368..22330e80b9c 100644 --- a/ui/scripts/storage.js +++ b/ui/scripts/storage.js @@ -1900,7 +1900,7 @@ allowedActions.push("takeSnapshot"); allowedActions.push("recurringSnapshot"); } else { - if(jsonObj.vmstate == 'Stopped') { + if(jsonObj.vmstate == 'Stopped' || jsonObj.virtualmachineid == undefined) { //volume of stopped VM, or detached volume allowedActions.push("takeSnapshot"); } } diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 8f943e2e751..a211a7f2b60 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -6061,6 +6061,10 @@ args.response.success({ data: args.context.physicalResources[0] }); + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); } }); }, @@ -7254,8 +7258,14 @@ url: createURL('listImageStores' + searchByArgs), data: data, success: function(json) { - args.response.success({ - data: json.listimagestoresresponse.imagestore + var items = json.listimagestoresresponse.imagestore; + if (items != undefined) { + for (var i = 0; i < items.length; i++) { + processPropertiesInImagestoreObject(items[i]); + } + } + args.response.success({ + data: items }); }, error: function(json) { @@ -7263,19 +7273,6 @@ } }); } - - /* - , - detailView: { - updateContext: function (args) { - return { - zones: [{}] - }; - - } - } - */ - } }, cacheStorage: { @@ -13531,7 +13528,7 @@ items.push({ id: "nfs", description: "nfs" - }); + }); items.push({ id: "SharedMountPoint", description: "SharedMountPoint" @@ -13552,7 +13549,7 @@ items.push({ id: "nfs", description: "nfs" - }); + }); items.push({ id: "PreSetup", description: "PreSetup" @@ -13569,7 +13566,7 @@ items.push({ id: "nfs", description: "nfs" - }); + }); items.push({ id: "vmfs", description: "vmfs" @@ -13577,12 +13574,21 @@ args.response.success({ data: items }); + } else if (selectedClusterObj.hypervisortype == "Hyperv") { + var items = []; + items.push({ + id: "SMB", + description: "SMB/cifs" + }); + args.response.success({ + data: items + }); } else if (selectedClusterObj.hypervisortype == "Ovm") { var items = []; items.push({ id: "nfs", description: "nfs" - }); + }); items.push({ id: "ocfs2", description: "ocfs2" @@ -13595,7 +13601,7 @@ items.push({ id: "nfs", description: "nfs" - }); + }); items.push({ id: "SharedMountPoint", description: "SharedMountPoint" @@ -13617,26 +13623,71 @@ return; - if (protocol == "nfs") { - //$("#add_pool_server_container", $dialogAddPool).show(); - $form.find('.form-item[rel=server]').css('display', 'inline-block'); - //$dialogAddPool.find("#add_pool_nfs_server").val(""); + if (protocol == "nfs") { + $form.find('.form-item[rel=server]').css('display', 'inline-block'); $form.find('.form-item[rel=server]').find(".value").find("input").val(""); - - //$('li[input_group="nfs"]', $dialogAddPool).show(); - $form.find('.form-item[rel=path]').css('display', 'inline-block'); - //$dialogAddPool.find("#add_pool_path_container").find("label").text(g_dictionary["label.path"]+":"); + + $form.find('.form-item[rel=path]').css('display', 'inline-block'); var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); $form.find('.form-item[rel=path]').find(".name").find("label").text("Path:").prepend($required); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + $form.find('.form-item[rel=iqn]').hide(); $form.find('.form-item[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=volumegroup]').hide(); + + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=rbdmonitor]').hide(); + $form.find('.form-item[rel=rbdpool]').hide(); + $form.find('.form-item[rel=rbdid]').hide(); + $form.find('.form-item[rel=rbdsecret]').hide(); + } else if (protocol == "SMB") { //"SMB" show almost the same fields as "nfs" does, except 3 more SMB-specific fields. + $form.find('.form-item[rel=server]').css('display', 'inline-block'); + $form.find('.form-item[rel=server]').find(".value").find("input").val(""); + + $form.find('.form-item[rel=path]').css('display', 'inline-block'); + var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); + $form.find('.form-item[rel=path]').find(".name").find("label").text("Path:").prepend($required); + + $form.find('.form-item[rel=smbUsername]').css('display', 'inline-block'); + $form.find('.form-item[rel=smbPassword]').css('display', 'inline-block'); + $form.find('.form-item[rel=smbDomain]').css('display', 'inline-block'); + + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + + $form.find('.form-item[rel=volumegroup]').hide(); + + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); + + $form.find('.form-item[rel=rbdmonitor]').hide(); + $form.find('.form-item[rel=rbdpool]').hide(); + $form.find('.form-item[rel=rbdid]').hide(); + $form.find('.form-item[rel=rbdsecret]').hide(); + } else if (protocol == "ocfs2") { //ocfs2 is the same as nfs, except no server field. + $form.find('.form-item[rel=server]').hide(); + $form.find('.form-item[rel=server]').find(".value").find("input").val(""); + + $form.find('.form-item[rel=path]').css('display', 'inline-block'); + var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); + $form.find('.form-item[rel=path]').find(".name").find("label").text("Path:").prepend($required); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + + $form.find('.form-item[rel=volumegroup]').hide(); + $form.find('.form-item[rel=vCenterDataCenter]').hide(); $form.find('.form-item[rel=vCenterDataStore]').hide(); @@ -13644,53 +13695,23 @@ $form.find('.form-item[rel=rbdpool]').hide(); $form.find('.form-item[rel=rbdid]').hide(); $form.find('.form-item[rel=rbdsecret]').hide(); - } else if (protocol == "ocfs2") { //ocfs2 is the same as nfs, except no server field. - //$dialogAddPool.find("#add_pool_server_container").hide(); - $form.find('.form-item[rel=server]').hide(); - //$dialogAddPool.find("#add_pool_nfs_server").val(""); - $form.find('.form-item[rel=server]').find(".value").find("input").val(""); - - //$('li[input_group="nfs"]', $dialogAddPool).show(); - $form.find('.form-item[rel=path]').css('display', 'inline-block'); - //$dialogAddPool.find("#add_pool_path_container").find("label").text(g_dictionary["label.path"]+":"); - var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); - $form.find('.form-item[rel=path]').find(".name").find("label").text("Path:").prepend($required); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); - $form.find('.form-item[rel=iqn]').hide(); - $form.find('.form-item[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); - $form.find('.form-item[rel=volumegroup]').hide(); - - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); - $form.find('.form-item[rel=vCenterDataCenter]').hide(); - $form.find('.form-item[rel=vCenterDataStore]').hide(); - - $form.find('.form-item[rel=rbdmonitor]').hide(); - $form.find('.form-item[rel=rbdpool]').hide(); - $form.find('.form-item[rel=rbdid]').hide(); - $form.find('.form-item[rel=rbdsecret]').hide(); - } else if (protocol == "PreSetup") { - //$dialogAddPool.find("#add_pool_server_container").hide(); - $form.find('.form-item[rel=server]').hide(); - //$dialogAddPool.find("#add_pool_nfs_server").val("localhost"); + } else if (protocol == "PreSetup") { + $form.find('.form-item[rel=server]').hide(); $form.find('.form-item[rel=server]').find(".value").find("input").val("localhost"); - - //$('li[input_group="nfs"]', $dialogAddPool).show(); - $form.find('.form-item[rel=path]').css('display', 'inline-block'); - //$dialogAddPool.find("#add_pool_path_container").find("label").text(g_dictionary["label.SR.name"]+":"); + + $form.find('.form-item[rel=path]').css('display', 'inline-block'); var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); $form.find('.form-item[rel=path]').find(".name").find("label").text("SR Name-Label:").prepend($required); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + $form.find('.form-item[rel=iqn]').hide(); $form.find('.form-item[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=volumegroup]').hide(); - - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=vCenterDataCenter]').hide(); $form.find('.form-item[rel=vCenterDataStore]').hide(); @@ -13698,23 +13719,21 @@ $form.find('.form-item[rel=rbdpool]').hide(); $form.find('.form-item[rel=rbdid]').hide(); $form.find('.form-item[rel=rbdsecret]').hide(); - } else if (protocol == "iscsi") { - //$dialogAddPool.find("#add_pool_server_container").show(); - $form.find('.form-item[rel=server]').css('display', 'inline-block'); - //$dialogAddPool.find("#add_pool_nfs_server").val(""); + } else if (protocol == "iscsi") { + $form.find('.form-item[rel=server]').css('display', 'inline-block'); $form.find('.form-item[rel=server]').find(".value").find("input").val(""); - - //$('li[input_group="nfs"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=path]').hide(); - - //$('li[input_group="iscsi"]', $dialogAddPool).show(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + $form.find('.form-item[rel=iqn]').css('display', 'inline-block'); $form.find('.form-item[rel=lun]').css('display', 'inline-block'); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=volumegroup]').hide(); - - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=vCenterDataCenter]').hide(); $form.find('.form-item[rel=vCenterDataStore]').hide(); @@ -13722,23 +13741,21 @@ $form.find('.form-item[rel=rbdpool]').hide(); $form.find('.form-item[rel=rbdid]').hide(); $form.find('.form-item[rel=rbdsecret]').hide(); - } else if ($(this).val() == "clvm") { - //$("#add_pool_server_container", $dialogAddPool).hide(); - $form.find('.form-item[rel=server]').hide(); - //$dialogAddPool.find("#add_pool_nfs_server").val("localhost"); + } else if ($(this).val() == "clvm") { + $form.find('.form-item[rel=server]').hide(); $form.find('.form-item[rel=server]').find(".value").find("input").val("localhost"); - - //$('li[input_group="nfs"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=path]').hide(); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + $form.find('.form-item[rel=iqn]').hide(); $form.find('.form-item[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).show(); + $form.find('.form-item[rel=volumegroup]').css('display', 'inline-block'); - - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=vCenterDataCenter]').hide(); $form.find('.form-item[rel=vCenterDataStore]').hide(); @@ -13746,23 +13763,21 @@ $form.find('.form-item[rel=rbdpool]').hide(); $form.find('.form-item[rel=rbdid]').hide(); $form.find('.form-item[rel=rbdsecret]').hide(); - } else if (protocol == "vmfs") { - //$dialogAddPool.find("#add_pool_server_container").show(); - $form.find('.form-item[rel=server]').css('display', 'inline-block'); - //$dialogAddPool.find("#add_pool_nfs_server").val(""); + } else if (protocol == "vmfs") { + $form.find('.form-item[rel=server]').css('display', 'inline-block'); $form.find('.form-item[rel=server]').find(".value").find("input").val(""); - - //$('li[input_group="nfs"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=path]').hide(); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + $form.find('.form-item[rel=iqn]').hide(); $form.find('.form-item[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=volumegroup]').hide(); - - //$('li[input_group="vmfs"]', $dialogAddPool).show(); + $form.find('.form-item[rel=vCenterDataCenter]').css('display', 'inline-block'); $form.find('.form-item[rel=vCenterDataStore]').css('display', 'inline-block'); @@ -13770,25 +13785,23 @@ $form.find('.form-item[rel=rbdpool]').hide(); $form.find('.form-item[rel=rbdid]').hide(); $form.find('.form-item[rel=rbdsecret]').hide(); - } else if (protocol == "SharedMountPoint") { //"SharedMountPoint" show the same fields as "nfs" does. - //$dialogAddPool.find("#add_pool_server_container").hide(); - $form.find('.form-item[rel=server]').hide(); - //$dialogAddPool.find("#add_pool_nfs_server").val("localhost"); + } else if (protocol == "SharedMountPoint") { //"SharedMountPoint" show the same fields as "nfs" does. + $form.find('.form-item[rel=server]').hide(); $form.find('.form-item[rel=server]').find(".value").find("input").val("localhost"); - - //$('li[input_group="nfs"]', $dialogAddPool).show(); + $form.find('.form-item[rel=path]').css('display', 'inline-block'); var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); $form.find('.form-item[rel=path]').find(".name").find("label").text("Path:").prepend($required); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + $form.find('.form-item[rel=iqn]').hide(); $form.find('.form-item[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=volumegroup]').hide(); - - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=vCenterDataCenter]').hide(); $form.find('.form-item[rel=vCenterDataStore]').hide(); @@ -13816,20 +13829,19 @@ $form.find('.form-item[rel=path]').hide(); $form.find('.form-item[rel=vCenterDataCenter]').hide(); $form.find('.form-item[rel=vCenterDataStore]').hide(); - } else { - //$dialogAddPool.find("#add_pool_server_container").show(); - $form.find('.form-item[rel=server]').css('display', 'inline-block'); - //$dialogAddPool.find("#add_pool_nfs_server").val(""); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + } else { + $form.find('.form-item[rel=server]').css('display', 'inline-block'); $form.find('.form-item[rel=server]').find(".value").find("input").val(""); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=iqn]').hide(); $form.find('.form-item[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=volumegroup]').hide(); - - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); + $form.find('.form-item[rel=vCenterDataCenter]').hide(); $form.find('.form-item[rel=vCenterDataStore]').hide(); @@ -13837,6 +13849,10 @@ $form.find('.form-item[rel=rbdpool]').hide(); $form.find('.form-item[rel=rbdid]').hide(); $form.find('.form-item[rel=rbdsecret]').hide(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); } }); @@ -13864,6 +13880,30 @@ isHidden: true }, + //SMB + smbUsername: { + label: 'SMB Username', + validation: { + required: true + }, + isHidden: true + }, + smbPassword: { + label: 'SMB Password', + isPassword: true, + validation: { + required: true + }, + isHidden: true + }, + smbDomain: { + label: 'SMB Domain', + validation: { + required: true + }, + isHidden: true + }, + //iscsi iqn: { label: 'label.target.iqn', @@ -13982,38 +14022,34 @@ var server = args.data.server; var url = null; - if (args.data.protocol == "nfs") { - //var path = trim($thisDialog.find("#add_pool_path").val()); + if (args.data.protocol == "nfs") { var path = args.data.path; - if (path.substring(0, 1) != "/") path = "/" + path; url = nfsURL(server, path); - } else if (args.data.protocol == "PreSetup") { - //var path = trim($thisDialog.find("#add_pool_path").val()); + + } else if (args.data.protocol == "SMB") { + var path = args.data.path; + if (path.substring(0, 1) != "/") + path = "/" + path; + url = smbURL(server, path, args.data.smbUsername, args.data.smbPassword, args.data.smbDomain); + } else if (args.data.protocol == "PreSetup") { var path = args.data.path; - if (path.substring(0, 1) != "/") path = "/" + path; url = presetupURL(server, path); - } else if (args.data.protocol == "ocfs2") { - //var path = trim($thisDialog.find("#add_pool_path").val()); + } else if (args.data.protocol == "ocfs2") { var path = args.data.path; - if (path.substring(0, 1) != "/") path = "/" + path; url = ocfs2URL(server, path); - } else if (args.data.protocol == "SharedMountPoint") { - //var path = trim($thisDialog.find("#add_pool_path").val()); + } else if (args.data.protocol == "SharedMountPoint") { var path = args.data.path; - if (path.substring(0, 1) != "/") path = "/" + path; url = SharedMountPointURL(server, path); - } else if (args.data.protocol == "clvm") { - //var vg = trim($thisDialog.find("#add_pool_clvm_vg").val()); + } else if (args.data.protocol == "clvm") { var vg = args.data.volumegroup; - if (vg.substring(0, 1) != "/") vg = "/" + vg; url = clvmURL(vg); @@ -14022,20 +14058,15 @@ var rbdpool = args.data.rbdpool; var rbdid = args.data.rbdid; var rbdsecret = args.data.rbdsecret; - url = rbdURL(rbdmonitor, rbdpool, rbdid, rbdsecret); - } else if (args.data.protocol == "vmfs") { - //var path = trim($thisDialog.find("#add_pool_vmfs_dc").val()); + } else if (args.data.protocol == "vmfs") { var path = args.data.vCenterDataCenter; - if (path.substring(0, 1) != "/") path = "/" + path; path += "/" + args.data.vCenterDataStore; url = vmfsURL("dummy", path); - } else { - //var iqn = trim($thisDialog.find("#add_pool_iqn").val()); + } else { var iqn = args.data.iqn; - if (iqn.substring(0, 1) != "/") iqn = "/" + iqn; var lun = args.data.lun; @@ -14051,7 +14082,6 @@ dataType: "json", success: function(json) { var item = json.createstoragepoolresponse.storagepool; - args.response.success({ data: item }); @@ -14957,12 +14987,9 @@ fields: { name: { label: 'label.name' - }, - url: { - label: 'label.url' - }, - providername: { - label: 'Provider' + }, + protocol: { + label: 'label.protocol' } }, @@ -15016,7 +15043,8 @@ }, success: function(json) { var objs = json.liststorageprovidersresponse.dataStoreProvider; - var items = []; + //var items = []; + var items = [{id: 'SMB', description: 'SMB/cifs'}]; //temporary, before Rajesh adds 'SMB' to listStorageProviders API response. if (objs != null) { for (var i = 0; i < objs.length; i++) { if (objs[i].name == 'NFS') @@ -15038,11 +15066,16 @@ args.$select.change(function() { var $form = $(this).closest('form'); if ($(this).val() == "NFS") { - //NFS + //NFS, SMB $form.find('.form-item[rel=zoneid]').css('display', 'inline-block'); $form.find('.form-item[rel=nfsServer]').css('display', 'inline-block'); - $form.find('.form-item[rel=path]').css('display', 'inline-block'); - + $form.find('.form-item[rel=path]').css('display', 'inline-block'); + + //SMB + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + //S3 $form.find('.form-item[rel=accesskey]').hide(); $form.find('.form-item[rel=secretkey]').hide(); @@ -15063,13 +15096,50 @@ $form.find('.form-item[rel=url]').hide(); $form.find('.form-item[rel=account]').hide(); $form.find('.form-item[rel=username]').hide(); - $form.find('.form-item[rel=key]').hide(); + $form.find('.form-item[rel=key]').hide(); + } else if ($(this).val() == "SMB") { + //NFS, SMB + $form.find('.form-item[rel=zoneid]').css('display', 'inline-block'); + $form.find('.form-item[rel=nfsServer]').css('display', 'inline-block'); + $form.find('.form-item[rel=path]').css('display', 'inline-block'); + + //SMB + $form.find('.form-item[rel=smbUsername]').css('display', 'inline-block'); + $form.find('.form-item[rel=smbPassword]').css('display', 'inline-block'); + $form.find('.form-item[rel=smbDomain]').css('display', 'inline-block'); + + //S3 + $form.find('.form-item[rel=accesskey]').hide(); + $form.find('.form-item[rel=secretkey]').hide(); + $form.find('.form-item[rel=bucket]').hide(); + $form.find('.form-item[rel=endpoint]').hide(); + $form.find('.form-item[rel=usehttps]').hide(); + $form.find('.form-item[rel=connectiontimeout]').hide(); + $form.find('.form-item[rel=maxerrorretry]').hide(); + $form.find('.form-item[rel=sockettimeout]').hide(); + + $form.find('.form-item[rel=createNfsCache]').find('input').removeAttr('checked'); + $form.find('.form-item[rel=createNfsCache]').hide(); + $form.find('.form-item[rel=nfsCacheZoneid]').hide(); + $form.find('.form-item[rel=nfsCacheNfsServer]').hide(); + $form.find('.form-item[rel=nfsCachePath]').hide(); + + //Swift + $form.find('.form-item[rel=url]').hide(); + $form.find('.form-item[rel=account]').hide(); + $form.find('.form-item[rel=username]').hide(); + $form.find('.form-item[rel=key]').hide(); } else if ($(this).val() == "S3") { - //NFS + //NFS, SMB $form.find('.form-item[rel=zoneid]').hide(); $form.find('.form-item[rel=nfsServer]').hide(); - $form.find('.form-item[rel=path]').hide(); - + $form.find('.form-item[rel=path]').hide(); + + //SMB + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + //S3 $form.find('.form-item[rel=accesskey]').css('display', 'inline-block'); $form.find('.form-item[rel=secretkey]').css('display', 'inline-block'); @@ -15094,11 +15164,16 @@ $form.find('.form-item[rel=username]').hide(); $form.find('.form-item[rel=key]').hide(); } else if ($(this).val() == "Swift") { - //NFS + //NFS, SMB $form.find('.form-item[rel=zoneid]').hide(); $form.find('.form-item[rel=nfsServer]').hide(); - $form.find('.form-item[rel=path]').hide(); - + $form.find('.form-item[rel=path]').hide(); + + //SMB + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + //S3 $form.find('.form-item[rel=accesskey]').hide(); $form.find('.form-item[rel=secretkey]').hide(); @@ -15130,7 +15205,7 @@ }, - //NFS (begin) + //NFS, SMB (begin) zoneid: { label: 'Zone', docID: 'helpSecondaryStorageZone', @@ -15177,8 +15252,31 @@ validation: { required: true } + }, + //NFS, SMB (end) + + + //SMB (begin) + smbUsername: { + label: 'SMB Username', + validation: { + required: true + } }, - //NFS (end) + smbPassword: { + label: 'SMB Password', + isPassword: true, + validation: { + required: true + } + }, + smbDomain: { + label: 'SMB Domain', + validation: { + required: true + } + }, + //SMB (end) //S3 (begin) @@ -15337,7 +15435,33 @@ var errorMsg = parseXMLHttpResponse(XMLHttpResponse); args.response.error(errorMsg); } + }); + } else if (args.data.provider == 'SMB') { + var zoneid = args.data.zoneid; + var nfs_server = args.data.nfsServer; + var path = args.data.path; + var url = smbURL(nfs_server, path, args.data.smbUsername, args.data.smbPassword, args.data.smbDomain); + + $.extend(data, { + provider: args.data.provider, + zoneid: zoneid, + url: url }); + + $.ajax({ + url: createURL('addImageStore'), + data: data, + success: function(json) { + var item = json.addimagestoreresponse.imagestore; + args.response.success({ + data: item + }); + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); } else if (args.data.provider == 'S3') { $.extend(data, { provider: args.data.provider, @@ -15546,6 +15670,9 @@ url: { label: 'label.url' }, + protocol: { + label: 'label.protocol' + }, providername: { label: 'Provider' }, @@ -15581,7 +15708,8 @@ dataType: "json", async: true, success: function(json) { - var item = json.listimagestoresresponse.imagestore[0]; + var item = json.listimagestoresresponse.imagestore[0]; + processPropertiesInImagestoreObject(item); args.response.success({ actionFilter: secondarystorageActionfilter, data: item @@ -16832,7 +16960,7 @@ var zoneActionfilter = function(args) { var jsonObj = args.context.item; var allowedActions = ['enableSwift']; - + if (jsonObj.vmwaredcId == null) allowedActions.push('addVmwareDc'); else diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js index 6bc49f59055..53cd971f605 100644 --- a/ui/scripts/ui/widgets/detailView.js +++ b/ui/scripts/ui/widgets/detailView.js @@ -462,7 +462,9 @@ $value.html(_s( $input.attr('value') )); - else if ($input.is('input[type=checkbox]')) { + else if ($input.is('input[type=password]')) { + $value.html(''); + } else if ($input.is('input[type=checkbox]')) { var val = $input.is(':checked'); $value.data('detail-view-boolean-value', _s(val)); @@ -628,6 +630,7 @@ var isBoolean = $value.data('detail-view-editable-boolean'); var data = !isBoolean ? cloudStack.sanitizeReverse($value.html()) : $value.data('detail-view-boolean-value'); var rules = $value.data('validation-rules') ? $value.data('validation-rules') : {}; + var isPassword = $value.data('detail-view-is-password'); $value.html(''); @@ -667,7 +670,7 @@ $value.append( $('').attr({ name: name, - type: 'text', + type: isPassword ? 'password' : 'text', value: data }).addClass('disallowSpecialCharacters').data('original-value', data) ); @@ -1004,6 +1007,8 @@ } else if (value.isBoolean) { $value.data('detail-view-editable-boolean', true); $value.data('detail-view-boolean-value', content == 'Yes' ? true : false); + } else { + $value.data('detail-view-is-password', value.isPassword); } return true; diff --git a/ui/scripts/zoneWizard.js b/ui/scripts/zoneWizard.js index 617c6e6580e..42fa799d422 100755 --- a/ui/scripts/zoneWizard.js +++ b/ui/scripts/zoneWizard.js @@ -79,6 +79,9 @@ case 'VMware': hypervisorAttr = 'vmwarenetworklabel'; break; + case 'Hyperv': + hypervisorAttr = 'hypervnetworklabel'; + break; case 'BareMetal': hypervisorAttr = 'baremetalnetworklabel'; break; @@ -1473,7 +1476,7 @@ items.push({ id: "nfs", description: "nfs" - }); + }); items.push({ id: "SharedMountPoint", description: "SharedMountPoint" @@ -1490,7 +1493,7 @@ items.push({ id: "nfs", description: "nfs" - }); + }); items.push({ id: "PreSetup", description: "PreSetup" @@ -1507,7 +1510,7 @@ items.push({ id: "nfs", description: "nfs" - }); + }); items.push({ id: "vmfs", description: "vmfs" @@ -1515,12 +1518,21 @@ args.response.success({ data: items }); + } else if (selectedClusterObj.hypervisortype == "Hyperv") { + var items = []; + items.push({ + id: "SMB", + description: "SMB/cifs" + }); + args.response.success({ + data: items + }); } else if (selectedClusterObj.hypervisortype == "Ovm") { var items = []; items.push({ id: "nfs", description: "nfs" - }); + }); items.push({ id: "ocfs2", description: "ocfs2" @@ -1533,7 +1545,7 @@ items.push({ id: "nfs", description: "nfs" - }); + }); items.push({ id: "SharedMountPoint", description: "SharedMountPoint" @@ -1557,160 +1569,156 @@ if (protocol == null) return; - if (protocol == "nfs") { - //$("#add_pool_server_container", $dialogAddPool).show(); - $form.find('[rel=server]').css('display', 'block'); - //$dialogAddPool.find("#add_pool_nfs_server").val(""); + if (protocol == "nfs") { + $form.find('[rel=server]').css('display', 'block'); $form.find('[rel=server]').find(".value").find("input").val(""); - - //$('li[input_group="nfs"]', $dialogAddPool).show(); - $form.find('[rel=path]').css('display', 'block'); - //$dialogAddPool.find("#add_pool_path_container").find("label").text(g_dictionary["label.path"]+":"); - //$form.find('[rel=path]').find(".name").find("label").text("Path:"); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); + + $form.find('[rel=path]').css('display', 'block'); + + $form.find('[rel=smbUsername]').hide(); + $form.find('[rel=smbPassword]').hide(); + $form.find('[rel=smbDomain]').hide(); + $form.find('[rel=iqn]').hide(); $form.find('[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); + $form.find('[rel=volumegroup]').hide(); - - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); + $form.find('[rel=vCenterDataCenter]').hide(); $form.find('[rel=vCenterDataStore]').hide(); - } else if (protocol == "ocfs2") { //ocfs2 is the same as nfs, except no server field. - //$dialogAddPool.find("#add_pool_server_container").hide(); - $form.find('[rel=server]').hide(); - //$dialogAddPool.find("#add_pool_nfs_server").val(""); + } else if (protocol == "SMB") { //"SMB" show almost the same fields as "nfs" does, except 3 more SMB-specific fields. + $form.find('[rel=server]').css('display', 'block'); $form.find('[rel=server]').find(".value").find("input").val(""); - - //$('li[input_group="nfs"]', $dialogAddPool).show(); - $form.find('[rel=path]').css('display', 'block'); - //$dialogAddPool.find("#add_pool_path_container").find("label").text(g_dictionary["label.path"]+":"); - //$form.find('[rel=path]').find(".name").find("label").text("Path:"); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); + + $form.find('[rel=path]').css('display', 'block'); + + $form.find('[rel=smbUsername]').css('display', 'block'); + $form.find('[rel=smbPassword]').css('display', 'block'); + $form.find('[rel=smbDomain]').css('display', 'block'); + $form.find('[rel=iqn]').hide(); $form.find('[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); + $form.find('[rel=volumegroup]').hide(); - - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); + $form.find('[rel=vCenterDataCenter]').hide(); $form.find('[rel=vCenterDataStore]').hide(); - } else if (protocol == "PreSetup") { - //$dialogAddPool.find("#add_pool_server_container").hide(); - $form.find('[rel=server]').hide(); - //$dialogAddPool.find("#add_pool_nfs_server").val("localhost"); + } else if (protocol == "ocfs2") { //ocfs2 is the same as nfs, except no server field. + $form.find('[rel=server]').hide(); + $form.find('[rel=server]').find(".value").find("input").val(""); + + $form.find('[rel=path]').css('display', 'block'); + + $form.find('[rel=smbUsername]').hide(); + $form.find('[rel=smbPassword]').hide(); + $form.find('[rel=smbDomain]').hide(); + + $form.find('[rel=iqn]').hide(); + $form.find('[rel=lun]').hide(); + + $form.find('[rel=volumegroup]').hide(); + + $form.find('[rel=vCenterDataCenter]').hide(); + $form.find('[rel=vCenterDataStore]').hide(); + } else if (protocol == "PreSetup") { + $form.find('[rel=server]').hide(); $form.find('[rel=server]').find(".value").find("input").val("localhost"); - - //$('li[input_group="nfs"]', $dialogAddPool).show(); - $form.find('[rel=path]').css('display', 'block'); - //$dialogAddPool.find("#add_pool_path_container").find("label").text(g_dictionary["label.SR.name"]+":"); + + $form.find('[rel=path]').css('display', 'block'); $form.find('[rel=path]').find(".name").find("label").html("*SR Name-Label:"); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); + + $form.find('[rel=smbUsername]').hide(); + $form.find('[rel=smbPassword]').hide(); + $form.find('[rel=smbDomain]').hide(); + $form.find('[rel=iqn]').hide(); $form.find('[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); + $form.find('[rel=volumegroup]').hide(); - - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); + $form.find('[rel=vCenterDataCenter]').hide(); $form.find('[rel=vCenterDataStore]').hide(); - } else if (protocol == "iscsi") { - //$dialogAddPool.find("#add_pool_server_container").show(); - $form.find('[rel=server]').css('display', 'block'); - //$dialogAddPool.find("#add_pool_nfs_server").val(""); + } else if (protocol == "iscsi") { + $form.find('[rel=server]').css('display', 'block'); $form.find('[rel=server]').find(".value").find("input").val(""); - - //$('li[input_group="nfs"]', $dialogAddPool).hide(); + $form.find('[rel=path]').hide(); - - //$('li[input_group="iscsi"]', $dialogAddPool).show(); + + $form.find('[rel=smbUsername]').hide(); + $form.find('[rel=smbPassword]').hide(); + $form.find('[rel=smbDomain]').hide(); + $form.find('[rel=iqn]').css('display', 'block'); $form.find('[rel=lun]').css('display', 'block'); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); + $form.find('[rel=volumegroup]').hide(); - - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); + $form.find('[rel=vCenterDataCenter]').hide(); $form.find('[rel=vCenterDataStore]').hide(); - } else if ($(this).val() == "clvm") { - //$("#add_pool_server_container", $dialogAddPool).hide(); - $form.find('[rel=server]').hide(); - //$dialogAddPool.find("#add_pool_nfs_server").val("localhost"); + } else if ($(this).val() == "clvm") { + $form.find('[rel=server]').hide(); $form.find('[rel=server]').find(".value").find("input").val("localhost"); - - //$('li[input_group="nfs"]', $dialogAddPool).hide(); + $form.find('[rel=path]').hide(); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); + + $form.find('[rel=smbUsername]').hide(); + $form.find('[rel=smbPassword]').hide(); + $form.find('[rel=smbDomain]').hide(); + $form.find('[rel=iqn]').hide(); $form.find('[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).show(); + $form.find('[rel=volumegroup]').css('display', 'inline-block'); - - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); + $form.find('[rel=vCenterDataCenter]').hide(); $form.find('[rel=vCenterDataStore]').hide(); - } else if (protocol == "vmfs") { - //$dialogAddPool.find("#add_pool_server_container").show(); - $form.find('[rel=server]').css('display', 'block'); - //$dialogAddPool.find("#add_pool_nfs_server").val(""); + } else if (protocol == "vmfs") { + $form.find('[rel=server]').css('display', 'block'); $form.find('[rel=server]').find(".value").find("input").val(""); - - //$('li[input_group="nfs"]', $dialogAddPool).hide(); + $form.find('[rel=path]').hide(); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); + + $form.find('[rel=smbUsername]').hide(); + $form.find('[rel=smbPassword]').hide(); + $form.find('[rel=smbDomain]').hide(); + $form.find('[rel=iqn]').hide(); $form.find('[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); + $form.find('[rel=volumegroup]').hide(); - - //$('li[input_group="vmfs"]', $dialogAddPool).show(); + $form.find('[rel=vCenterDataCenter]').css('display', 'block'); $form.find('[rel=vCenterDataStore]').css('display', 'block'); - } else if (protocol == "SharedMountPoint") { //"SharedMountPoint" show the same fields as "nfs" does. - //$dialogAddPool.find("#add_pool_server_container").hide(); - $form.find('[rel=server]').hide(); - //$dialogAddPool.find("#add_pool_nfs_server").val("localhost"); + } else if (protocol == "SharedMountPoint") { //"SharedMountPoint" show the same fields as "nfs" does. + $form.find('[rel=server]').hide(); $form.find('[rel=server]').find(".value").find("input").val("localhost"); - - //$('li[input_group="nfs"]', $dialogAddPool).show(); - $form.find('[rel=path]').css('display', 'block'); - //$form.find('[rel=path]').find(".name").find("label").text("Path:"); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); + + $form.find('[rel=path]').css('display', 'block'); + + $form.find('[rel=smbUsername]').hide(); + $form.find('[rel=smbPassword]').hide(); + $form.find('[rel=smbDomain]').hide(); + $form.find('[rel=iqn]').hide(); $form.find('[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); + $form.find('[rel=volumegroup]').hide(); - - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); + $form.find('[rel=vCenterDataCenter]').hide(); $form.find('[rel=vCenterDataStore]').hide(); - } else { - //$dialogAddPool.find("#add_pool_server_container").show(); - $form.find('[rel=server]').css('display', 'block'); - //$dialogAddPool.find("#add_pool_nfs_server").val(""); + } else { + $form.find('[rel=server]').css('display', 'block'); $form.find('[rel=server]').find(".value").find("input").val(""); - - //$('li[input_group="iscsi"]', $dialogAddPool).hide(); + + $form.find('[rel=smbUsername]').hide(); + $form.find('[rel=smbPassword]').hide(); + $form.find('[rel=smbDomain]').hide(); + $form.find('[rel=iqn]').hide(); $form.find('[rel=lun]').hide(); - - //$('li[input_group="clvm"]', $dialogAddPool).hide(); + $form.find('[rel=volumegroup]').hide(); - - //$('li[input_group="vmfs"]', $dialogAddPool).hide(); + $form.find('[rel=vCenterDataCenter]').hide(); $form.find('[rel=vCenterDataStore]').hide(); } @@ -1736,6 +1744,30 @@ isHidden: true }, + //SMB + smbUsername: { + label: 'SMB Username', + validation: { + required: true + }, + isHidden: true + }, + smbPassword: { + label: 'SMB Password', + isPassword: true, + validation: { + required: true + }, + isHidden: true + }, + smbDomain: { + label: 'SMB Domain', + validation: { + required: true + }, + isHidden: true + }, + //iscsi iqn: { label: 'label.target.iqn', @@ -1792,7 +1824,9 @@ provider: { label: 'Provider', select: function(args) { - var storageproviders = []; + var storageproviders = []; + storageproviders.push({ id: '', description: ''}); + $.ajax({ url: createURL('listImageStores'), data: { @@ -1802,7 +1836,7 @@ success: function(json) { var s3stores = json.listimagestoresresponse.imagestore; if(s3stores != null && s3stores.length > 0) { - storageproviders.push({ id: 'S3', description: 'S3'}); + storageproviders.push({ id: 'S3', description: 'S3'}); //if (region-wide) S3 store exists already, only "S3" option should be included here. Any other type of store is not allowed to be created since cloudstack doesn't support multiple types of store at this point. } else { $.ajax({ url: createURL('listStorageProviders'), @@ -1811,8 +1845,7 @@ }, async: false, success: function(json) { - var objs = json.liststorageprovidersresponse.dataStoreProvider; - storageproviders.push({ id: '', description: ''}); + var objs = json.liststorageprovidersresponse.dataStoreProvider; if (objs != null) { for (var i = 0; i < objs.length; i++) { storageproviders.push({ @@ -1823,6 +1856,7 @@ } } }); + storageproviders.push({ id: 'SMB', description: 'SMB/cifs'}); //temporary, before Rajesh adds 'SMB' to listStorageProviders API response. } args.response.success({ data: storageproviders @@ -1840,6 +1874,11 @@ $fields.filter('[rel=nfsServer]').hide(); $fields.filter('[rel=path]').hide(); + //SMB + $fields.filter('[rel=smbUsername]').hide(); + $fields.filter('[rel=smbPassword]').hide(); + $fields.filter('[rel=smbDomain]').hide(); + //S3 $fields.filter('[rel=accesskey]').hide(); $fields.filter('[rel=secretkey]').hide(); @@ -1868,6 +1907,44 @@ $fields.filter('[rel=nfsServer]').css('display', 'inline-block'); $fields.filter('[rel=path]').css('display', 'inline-block'); + //SMB + $fields.filter('[rel=smbUsername]').hide(); + $fields.filter('[rel=smbPassword]').hide(); + $fields.filter('[rel=smbDomain]').hide(); + + //S3 + $fields.filter('[rel=accesskey]').hide(); + $fields.filter('[rel=secretkey]').hide(); + $fields.filter('[rel=bucket]').hide(); + $fields.filter('[rel=endpoint]').hide(); + $fields.filter('[rel=usehttps]').hide(); + $fields.filter('[rel=connectiontimeout]').hide(); + $fields.filter('[rel=maxerrorretry]').hide(); + $fields.filter('[rel=sockettimeout]').hide(); + + $fields.filter('[rel=createNfsCache]').hide(); + $fields.filter('[rel=createNfsCache]').find('input').removeAttr('checked'); + $fields.filter('[rel=nfsCacheNfsServer]').hide(); + $fields.filter('[rel=nfsCachePath]').hide(); + + //Swift + $fields.filter('[rel=url]').hide(); + $fields.filter('[rel=account]').hide(); + $fields.filter('[rel=username]').hide(); + $fields.filter('[rel=key]').hide(); + } else if ($(this).val() == "SMB") { + $fields.filter('[rel=name]').css('display', 'inline-block'); + + //NFS + $fields.filter('[rel=zoneid]').css('display', 'inline-block'); + $fields.filter('[rel=nfsServer]').css('display', 'inline-block'); + $fields.filter('[rel=path]').css('display', 'inline-block'); + + //SMB + $fields.filter('[rel=smbUsername]').css('display', 'inline-block'); + $fields.filter('[rel=smbPassword]').css('display', 'inline-block'); + $fields.filter('[rel=smbDomain]').css('display', 'inline-block'); + //S3 $fields.filter('[rel=accesskey]').hide(); $fields.filter('[rel=secretkey]').hide(); @@ -1904,6 +1981,11 @@ $fields.filter('[rel=nfsServer]').hide(); $fields.filter('[rel=path]').hide(); + //SMB + $fields.filter('[rel=smbUsername]').hide(); + $fields.filter('[rel=smbPassword]').hide(); + $fields.filter('[rel=smbDomain]').hide(); + //S3 if(s3stores != null && s3stores.length > 0) { $fields.filter('[rel=accesskey]').hide(); @@ -1943,6 +2025,11 @@ $fields.filter('[rel=nfsServer]').hide(); $fields.filter('[rel=path]').hide(); + //SMB + $fields.filter('[rel=smbUsername]').hide(); + $fields.filter('[rel=smbPassword]').hide(); + $fields.filter('[rel=smbDomain]').hide(); + //S3 $fields.filter('[rel=accesskey]').hide(); $fields.filter('[rel=secretkey]').hide(); @@ -1976,7 +2063,7 @@ isHidden: true }, - //NFS (begin) + //NFS, SMB (begin) nfsServer: { label: 'label.nfs.server', validation: { @@ -1991,9 +2078,31 @@ }, isHidden: true }, - //NFS (end) + //NFS, SMB (end) + //SMB (begin) + smbUsername: { + label: 'SMB Username', + validation: { + required: true + } + }, + smbPassword: { + label: 'SMB Password', + isPassword: true, + validation: { + required: true + } + }, + smbDomain: { + label: 'SMB Domain', + validation: { + required: true + } + }, + //SMB (end) + //S3 (begin) accesskey: { label: 'label.s3.access_key', @@ -4020,53 +4129,44 @@ var server = args.data.primaryStorage.server; var url = null; - if (args.data.primaryStorage.protocol == "nfs") { - //var path = trim($thisDialog.find("#add_pool_path").val()); + if (args.data.primaryStorage.protocol == "nfs") { var path = args.data.primaryStorage.path; - if (path.substring(0, 1) != "/") path = "/" + path; url = nfsURL(server, path); - } else if (args.data.primaryStorage.protocol == "PreSetup") { - //var path = trim($thisDialog.find("#add_pool_path").val()); + } else if (args.data.primaryStorage.protocol == "SMB") { + var path = args.data.primaryStorage.path; + if (path.substring(0, 1) != "/") + path = "/" + path; + url = smbURL(server, path, args.data.primaryStorage.smbUsername, args.data.primaryStorage.smbPassword, args.data.primaryStorage.smbDomain); + } else if (args.data.primaryStorage.protocol == "PreSetup") { var path = args.data.primaryStorage.path; - if (path.substring(0, 1) != "/") path = "/" + path; url = presetupURL(server, path); - } else if (args.data.primaryStorage.protocol == "ocfs2") { - //var path = trim($thisDialog.find("#add_pool_path").val()); + } else if (args.data.primaryStorage.protocol == "ocfs2") { var path = args.data.primaryStorage.path; - if (path.substring(0, 1) != "/") path = "/" + path; url = ocfs2URL(server, path); - } else if (args.data.primaryStorage.protocol == "SharedMountPoint") { - //var path = trim($thisDialog.find("#add_pool_path").val()); + } else if (args.data.primaryStorage.protocol == "SharedMountPoint") { var path = args.data.primaryStorage.path; - if (path.substring(0, 1) != "/") path = "/" + path; url = SharedMountPointURL(server, path); - } else if (args.data.primaryStorage.protocol == "clvm") { - //var vg = trim($thisDialog.find("#add_pool_clvm_vg").val()); + } else if (args.data.primaryStorage.protocol == "clvm") { var vg = args.data.primaryStorage.volumegroup; - if (vg.substring(0, 1) != "/") vg = "/" + vg; url = clvmURL(vg); - } else if (args.data.primaryStorage.protocol == "vmfs") { - //var path = trim($thisDialog.find("#add_pool_vmfs_dc").val()); + } else if (args.data.primaryStorage.protocol == "vmfs") { var path = args.data.primaryStorage.vCenterDataCenter; - if (path.substring(0, 1) != "/") path = "/" + path; path += "/" + args.data.primaryStorage.vCenterDataStore; url = vmfsURL("dummy", path); - } else { - //var iqn = trim($thisDialog.find("#add_pool_iqn").val()); + } else { var iqn = args.data.primaryStorage.iqn; - if (iqn.substring(0, 1) != "/") iqn = "/" + iqn; var lun = args.data.primaryStorage.lun; @@ -4121,7 +4221,36 @@ var url = nfsURL(nfs_server, path); $.extend(data, { - provider: 'NFS', + provider: args.data.secondaryStorage.provider, + zoneid: args.data.returnedZone.id, + url: url + }); + + $.ajax({ + url: createURL('addImageStore'), + data: data, + success: function(json) { + complete({ + data: $.extend(args.data, { + returnedSecondaryStorage: json.addimagestoreresponse.secondarystorage + }) + }); + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + error('addSecondaryStorage', errorMsg, { + fn: 'addSecondaryStorage', + args: args + }); + } + }); + } else if (args.data.secondaryStorage.provider == 'SMB') { + var nfs_server = args.data.secondaryStorage.nfsServer; + var path = args.data.secondaryStorage.path; + var url = smbURL(nfs_server, path, args.data.secondaryStorage.smbUsername, args.data.secondaryStorage.smbPassword, args.data.secondaryStorage.smbDomain); + + $.extend(data, { + provider: args.data.secondaryStorage.provider, zoneid: args.data.returnedZone.id, url: url }); diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HttpNfcLeaseMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HttpNfcLeaseMO.java index ca362809f3a..72424524074 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HttpNfcLeaseMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HttpNfcLeaseMO.java @@ -31,6 +31,7 @@ import com.cloud.hypervisor.vmware.util.VmwareContext; import com.vmware.vim25.HttpNfcLeaseInfo; import com.vmware.vim25.HttpNfcLeaseManifestEntry; import com.vmware.vim25.HttpNfcLeaseState; +import com.vmware.vim25.LocalizedMethodFault; import com.vmware.vim25.ManagedObjectReference; import com.vmware.vim25.ObjectSpec; import com.vmware.vim25.OvfCreateImportSpecResult; @@ -83,6 +84,10 @@ public class HttpNfcLeaseMO extends BaseMO { return (HttpNfcLeaseInfo)_context.getVimClient().getDynamicProperty(_mor, "info"); } + public LocalizedMethodFault getLeaseError() throws Exception { + return (LocalizedMethodFault)_context.getVimClient().getDynamicProperty(_mor, "error"); + } + public List getLeaseManifest() throws Exception { return _context.getService().httpNfcLeaseGetManifest(_mor); } diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java index cd2c3e8746c..0882e22b8c0 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java @@ -45,7 +45,9 @@ import com.vmware.vim25.HttpNfcLeaseDeviceUrl; import com.vmware.vim25.HttpNfcLeaseInfo; import com.vmware.vim25.HttpNfcLeaseState; import com.vmware.vim25.LongPolicy; +import com.vmware.vim25.LocalizedMethodFault; import com.vmware.vim25.ManagedObjectReference; +import com.vmware.vim25.MethodFault; import com.vmware.vim25.ObjectContent; import com.vmware.vim25.OvfCreateImportSpecParams; import com.vmware.vim25.OvfCreateImportSpecResult; @@ -1377,17 +1379,28 @@ public class HypervisorHostHelper { } } } catch (Exception e) { - s_logger.error("Failed to complete file upload task. " + e.getMessage()); - // Set flag to cleanup the stale template left due to failed import operation, if any - importSuccess = false; - throw e; + String erroMsg = "File upload task failed to complete due to: " + e.getMessage(); + s_logger.error(erroMsg); + importSuccess = false; // Set flag to cleanup the stale template left due to failed import operation, if any + throw new Exception(erroMsg); + } catch (Throwable th) { + String errorMsg = "throwable caught during file upload task: " + th.getMessage(); + s_logger.error(errorMsg); + importSuccess = false; // Set flag to cleanup the stale template left due to failed import operation, if any + throw new Exception(errorMsg, th); } finally { progressReporter.close(); } if (bytesAlreadyWritten == totalBytes) { leaseMo.updateLeaseProgress(100); } - } + } else if(state == HttpNfcLeaseState.ERROR) { + LocalizedMethodFault error = leaseMo.getLeaseError(); + MethodFault fault = error.getFault(); + String erroMsg = "Object creation on vCenter failed due to: Exception: " + fault.getClass().getName() + ", message: " + error.getLocalizedMessage(); + s_logger.error(erroMsg); + throw new Exception(erroMsg); + } } finally { if (!importSuccess) { s_logger.error("Aborting the lease on " + vmName + " after import operation failed."); diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index 784c0316e04..a9c7ec2fbab 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -29,14 +29,19 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import org.apache.log4j.Logger; import com.google.gson.Gson; import com.vmware.vim25.ArrayOfManagedObjectReference; +import com.vmware.vim25.ChoiceOption; import com.vmware.vim25.CustomFieldStringValue; import com.vmware.vim25.DistributedVirtualSwitchPortConnection; import com.vmware.vim25.DynamicProperty; +import com.vmware.vim25.ElementDescription; import com.vmware.vim25.GuestInfo; import com.vmware.vim25.GuestOsDescriptor; import com.vmware.vim25.HttpNfcLeaseDeviceUrl; @@ -80,8 +85,10 @@ import com.vmware.vim25.VirtualMachineConfigOption; import com.vmware.vim25.VirtualMachineConfigSpec; import com.vmware.vim25.VirtualMachineConfigSummary; import com.vmware.vim25.VirtualMachineFileInfo; +import com.vmware.vim25.VirtualMachineMessage; import com.vmware.vim25.VirtualMachineMovePriority; import com.vmware.vim25.VirtualMachinePowerState; +import com.vmware.vim25.VirtualMachineQuestionInfo; import com.vmware.vim25.VirtualMachineRelocateDiskMoveOptions; import com.vmware.vim25.VirtualMachineRelocateSpec; import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator; @@ -98,12 +105,14 @@ import com.cloud.hypervisor.vmware.util.VmwareHelper; import com.cloud.utils.ActionDelegate; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; +import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.script.Script; import java.util.Arrays; public class VirtualMachineMO extends BaseMO { private static final Logger s_logger = Logger.getLogger(VirtualMachineMO.class); + private static final ExecutorService _monitorServiceExecutor = Executors.newCachedThreadPool(new NamedThreadFactory("VM-Question-Monitor")); private ManagedObjectReference _vmEnvironmentBrowser = null; public VirtualMachineMO(VmwareContext context, ManagedObjectReference morVm) { @@ -170,6 +179,10 @@ public class VirtualMachineMO extends BaseMO { return (GuestInfo)getContext().getVimClient().getDynamicProperty(_mor, "guest"); } + public void answerVM(String questionId, String choice) throws Exception { + getContext().getService().answerVM(_mor, questionId, choice); + } + public boolean isVMwareToolsRunning() throws Exception { GuestInfo guestInfo = getVmGuestInfo(); if(guestInfo != null) { @@ -180,7 +193,7 @@ public class VirtualMachineMO extends BaseMO { } public boolean powerOn() throws Exception { - if(getPowerState() == VirtualMachinePowerState.POWERED_ON) + if(getResetSafePowerState() == VirtualMachinePowerState.POWERED_ON) return true; ManagedObjectReference morTask = _context.getService().powerOnVMTask(_mor, null); @@ -197,7 +210,7 @@ public class VirtualMachineMO extends BaseMO { } public boolean powerOff() throws Exception { - if(getPowerState() == VirtualMachinePowerState.POWERED_OFF) + if(getResetSafePowerState() == VirtualMachinePowerState.POWERED_OFF) return true; return powerOffNoCheck(); @@ -205,7 +218,7 @@ public class VirtualMachineMO extends BaseMO { public boolean safePowerOff(int shutdownWaitMs) throws Exception { - if(getPowerState() == VirtualMachinePowerState.POWERED_OFF) + if(getResetSafePowerState() == VirtualMachinePowerState.POWERED_OFF) return true; if(isVMwareToolsRunning()) { @@ -216,14 +229,14 @@ public class VirtualMachineMO extends BaseMO { shutdown(); long startTick = System.currentTimeMillis(); - while(getPowerState() != VirtualMachinePowerState.POWERED_OFF && System.currentTimeMillis() - startTick < shutdownWaitMs) { + while(getResetSafePowerState() != VirtualMachinePowerState.POWERED_OFF && System.currentTimeMillis() - startTick < shutdownWaitMs) { try { Thread.sleep(1000); } catch(InterruptedException e) { } } - if(getPowerState() != VirtualMachinePowerState.POWERED_OFF) { + if(getResetSafePowerState() != VirtualMachinePowerState.POWERED_OFF) { s_logger.info("can not gracefully shutdown VM within " + (shutdownWaitMs/1000) + " seconds, we will perform force power off on VM " + vmName); return powerOffNoCheck(); } @@ -248,7 +261,7 @@ public class VirtualMachineMO extends BaseMO { // wait up to 5 seconds to make sure to avoid race conditioning for immediate following on operations // that relies on a powered-off VM long startTick = System.currentTimeMillis(); - while(getPowerState() != VirtualMachinePowerState.POWERED_OFF && System.currentTimeMillis() - startTick < 5000) { + while(getResetSafePowerState() != VirtualMachinePowerState.POWERED_OFF && System.currentTimeMillis() - startTick < 5000) { try { Thread.sleep(1000); } catch(InterruptedException e) { @@ -256,7 +269,7 @@ public class VirtualMachineMO extends BaseMO { } return true; } else { - if(getPowerState() == VirtualMachinePowerState.POWERED_OFF) { + if(getResetSafePowerState() == VirtualMachinePowerState.POWERED_OFF) { // to help deal with possible race-condition s_logger.info("Current power-off task failed. However, VM has been switched to the state we are expecting for"); return true; @@ -268,7 +281,7 @@ public class VirtualMachineMO extends BaseMO { return false; } - public VirtualMachinePowerState getPowerState() throws Exception { + public VirtualMachinePowerState getResetSafePowerState() throws Exception { VirtualMachinePowerState powerState = VirtualMachinePowerState.POWERED_OFF; @@ -293,6 +306,10 @@ public class VirtualMachineMO extends BaseMO { return powerState; } + + public VirtualMachinePowerState getPowerState() throws Exception { + return (VirtualMachinePowerState)getContext().getVimClient().getDynamicProperty(_mor, "runtime.powerState"); + } public boolean reset() throws Exception { ManagedObjectReference morTask = _context.getService().resetVMTask(_mor); @@ -1157,7 +1174,7 @@ public class VirtualMachineMO extends BaseMO { boolean connect, boolean connectAtBoot) throws Exception { if(s_logger.isTraceEnabled()) - s_logger.trace("vCenter API trace - detachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + s_logger.trace("vCenter API trace - attachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath + ", datastore: " + morDs.getValue() + ", connect: " + connect + ", connectAtBoot: " + connectAtBoot); assert(isoDatastorePath != null); @@ -1240,18 +1257,90 @@ public class VirtualMachineMO extends BaseMO { //deviceConfigSpecArray[0] = deviceConfigSpec; reConfigSpec.getDeviceChange().add(deviceConfigSpec); - ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); - boolean result = _context.getVimClient().waitForTask(morTask); + ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); - if(!result) { - if(s_logger.isTraceEnabled()) - s_logger.trace("vCenter API trace - detachIso() done(failed)"); - throw new Exception("Failed to detachIso due to " + TaskMO.getTaskFailureInfo(_context, morTask)); + // Monitor VM questions + final Boolean[] flags = { false }; + final VirtualMachineMO vmMo = this; + Future future = _monitorServiceExecutor.submit(new Runnable() { + @Override + public void run() { + s_logger.info("VM Question monitor started..."); + + while(!flags[0]) { + try { + VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo(); + VirtualMachineQuestionInfo question = runtimeInfo.getQuestion(); + if(question != null) { + if(s_logger.isTraceEnabled()) { + s_logger.trace("Question id: " + question.getId()); + s_logger.trace("Question text: " + question.getText()); + } + if(question.getMessage() != null) { + for(VirtualMachineMessage msg : question.getMessage()) { + if(s_logger.isTraceEnabled()) { + s_logger.trace("msg id: " + msg.getId()); + s_logger.trace("msg text: " + msg.getText()); + } + if("msg.cdromdisconnect.locked".equalsIgnoreCase(msg.getId())) { + s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + msg.getId() + + ", for safe operation we will automatically decline it"); + vmMo.answerVM(question.getId(), "1"); + break; + } + } + } else if (question.getText() != null) { + String text = question.getText(); + String msgId; + String msgText; + if (s_logger.isDebugEnabled()) { + s_logger.debug("question text : " + text); + } + String[] tokens = text.split(":"); + msgId = tokens[0]; + msgText = tokens[1]; + if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msgId)) { + s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + question.getId() + + ". Message id : " + msgId + ". Message text : " + msgText + + ", for safe operation we will automatically decline it."); + vmMo.answerVM(question.getId(), "1"); + } + } + + ChoiceOption choice = question.getChoice(); + if(choice != null) { + for(ElementDescription info : choice.getChoiceInfo()) { + if(s_logger.isTraceEnabled()) { + s_logger.trace("Choice option key: " + info.getKey()); + s_logger.trace("Choice option label: " + info.getLabel()); + } + } + } + } + } catch(Throwable e) { + s_logger.error("Unexpected exception: ", e); + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + s_logger.info("VM Question monitor stopped"); + } + }); + try { + boolean result = _context.getVimClient().waitForTask(morTask); + if (!result) { + if(s_logger.isDebugEnabled()) + s_logger.trace("vCenter API trace - detachIso() done(failed)"); + throw new Exception("Failed to detachIso due to " + TaskMO.getTaskFailureInfo(_context, morTask)); + } + _context.waitForTaskProgressDone(morTask); + s_logger.trace("vCenter API trace - detachIso() done(successfully)"); + } finally { + flags[0] = true; + future.cancel(true); } - _context.waitForTaskProgressDone(morTask); - - if(s_logger.isTraceEnabled()) - s_logger.trace("vCenter API trace - detachIso() done(successfully)"); } public Pair getVmdkFileInfo(String vmdkDatastorePath) throws Exception { @@ -2041,7 +2130,7 @@ public class VirtualMachineMO extends BaseMO { } } - return detachedDiskFiles; + return detachedDiskFiles; } public List getAllDeviceList() throws Exception { @@ -2066,7 +2155,7 @@ public class VirtualMachineMO extends BaseMO { for(VirtualDevice device : allDevices ) { if(device instanceof VirtualDisk) { VirtualDisk disk = (VirtualDisk)device; - String diskBusName = getDeviceBusName(allDevices, (VirtualDevice)disk); + String diskBusName = getDeviceBusName(allDevices, disk); if(busName.equalsIgnoreCase(diskBusName)) return disk; } @@ -2294,8 +2383,87 @@ public class VirtualMachineMO extends BaseMO { } public void unmountToolsInstaller() throws Exception { - _context.getService().unmountToolsInstaller(_mor); - } + int i = 1; + // Monitor VM questions + final Boolean[] flags = {false}; + final VirtualMachineMO vmMo = this; + Future future = _monitorServiceExecutor.submit(new Runnable() { + @Override + public void run() { + s_logger.info("VM Question monitor started..."); + + while (!flags[0]) { + try { + VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo(); + VirtualMachineQuestionInfo question = runtimeInfo.getQuestion(); + if (question != null) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Question id: " + question.getId()); + s_logger.trace("Question text: " + question.getText()); + } + + if (question.getMessage() != null) { + for (VirtualMachineMessage msg : question.getMessage()) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("msg id: " + msg.getId()); + s_logger.trace("msg text: " + msg.getText()); + } + if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msg.getId())) { + s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + msg.getId() + + ", for safe operation we will automatically decline it"); + vmMo.answerVM(question.getId(), "1"); + break; + } + } + } else if (question.getText() != null) { + String text = question.getText(); + String msgId; + String msgText; + if (s_logger.isDebugEnabled()) { + s_logger.debug("question text : " + text); + } + String[] tokens = text.split(":"); + msgId = tokens[0]; + msgText = tokens[1]; + if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msgId)) { + s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + question.getId() + + ". Message id : " + msgId + ". Message text : " + msgText + + ", for safe operation we will automatically decline it."); + vmMo.answerVM(question.getId(), "1"); + } + } + + ChoiceOption choice = question.getChoice(); + if (choice != null) { + for (ElementDescription info : choice.getChoiceInfo()) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Choice option key: " + info.getKey()); + s_logger.trace("Choice option label: " + info.getLabel()); + } + } + } + } + } catch (Throwable e) { + s_logger.error("Unexpected exception: ", e); + } + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + + s_logger.info("VM Question monitor stopped"); + } + }); + + try { + _context.getService().unmountToolsInstaller(_mor); + } finally { + flags[0] = true; + future.cancel(true); + } + } public void redoRegistration(ManagedObjectReference morHost) throws Exception { String vmName = getVmName();