diff --git a/.gitignore b/.gitignore index 5efa7bbb5ca5..2af2d17ba74f 100644 --- a/.gitignore +++ b/.gitignore @@ -83,3 +83,6 @@ build-indep-stamp configure-stamp *_flymake.js engine/storage/integration-test/test-output +tools/apidoc/log/ +log/ +scripts/vm/hypervisor/xenserver/vhd-util diff --git a/CHANGES b/CHANGES index e3e316e9dc94..dad75619b3dc 100644 --- a/CHANGES +++ b/CHANGES @@ -5,13 +5,13 @@ Apache CloudStack CHANGES Full release notes for each release are located in the project's documentation website: http://cloudstack.apache.org/docs -Version 4.2.0 +Version 4.3.0 ------------------------ +Please refer to release notes for list of changes -In progress - - - +Version 4.2.0 +----------------------- +Released on October 1 2013. Please refer to Release Notes for list of changes Version 4.1.0 ------------------------ diff --git a/README.md b/README.md index c9f5733d5fa7..282a0c71bce8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Apache CloudStack Version 4.2.0 +Apache CloudStack Version 4.3.0 # About Apache CloudStack diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties index 5f5f3682afdc..8bd9756ef273 100644 --- a/agent/conf/agent.properties +++ b/agent/conf/agent.properties @@ -114,3 +114,7 @@ domr.scripts.dir=scripts/network/domr/kvm # for examples:"Conroe" "Penryn", "Nehalem", "Westmere", "pentiumpro" and so # on,run virsh capabilities for more details. # guest.cpu.model= +# +# vm.memballoon.disable=true +# Disable memory ballooning on vm guests for overcommit, by default overcommit +# feature enables balloon and sets currentMemory to a minimum value diff --git a/agent/pom.xml b/agent/pom.xml index c3ac308882ae..98f4b61b116f 100644 --- a/agent/pom.xml +++ b/agent/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack - 4.3.0-SNAPSHOT + 4.3.0 diff --git a/agent/src/com/cloud/agent/resource/DummyResource.java b/agent/src/com/cloud/agent/resource/DummyResource.java index 37a8b3d67e7c..4918207546c6 100755 --- a/agent/src/com/cloud/agent/resource/DummyResource.java +++ b/agent/src/com/cloud/agent/resource/DummyResource.java @@ -169,7 +169,7 @@ public StartupCommand[] initialize() { 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/pom.xml b/api/pom.xml index baedf01c0cb8..1c892f34ee6e 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack - 4.3.0-SNAPSHOT + 4.3.0 diff --git a/api/src/com/cloud/agent/api/HostVmStateReportEntry.java b/api/src/com/cloud/agent/api/HostVmStateReportEntry.java index 7bcb50f361a8..0b1a01e97e70 100644 --- a/api/src/com/cloud/agent/api/HostVmStateReportEntry.java +++ b/api/src/com/cloud/agent/api/HostVmStateReportEntry.java @@ -19,16 +19,29 @@ 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 PowerState getState() { public String getHost() { return host; } + + public String getHostToolsVersion() { + return hostToolsVersion; + } } diff --git a/api/src/com/cloud/agent/api/to/VirtualMachineTO.java b/api/src/com/cloud/agent/api/to/VirtualMachineTO.java index e6240ffda105..a5860d749798 100644 --- a/api/src/com/cloud/agent/api/to/VirtualMachineTO.java +++ b/api/src/com/cloud/agent/api/to/VirtualMachineTO.java @@ -60,6 +60,7 @@ public class VirtualMachineTO { DiskTO[] disks; NicTO[] nics; + Integer vcpuMaxLimit; public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type type, int cpus, Integer speed, long minRam, long maxRam, BootloaderType bootloader, String os, boolean enableHA, boolean limitCpuUse, String vncPassword) { this.id = id; @@ -263,5 +264,13 @@ public void setUuid(String uuid) { this.uuid = uuid; } + public Integer getVcpuMaxLimit() { + return vcpuMaxLimit; + } + + public void setVcpuMaxLimit(Integer vcpuMaxLimit) { + this.vcpuMaxLimit = vcpuMaxLimit; + } + } diff --git a/api/src/com/cloud/alert/Alert.java b/api/src/com/cloud/alert/Alert.java index 31768cf193d8..85ee43191de7 100644 --- a/api/src/com/cloud/alert/Alert.java +++ b/api/src/com/cloud/alert/Alert.java @@ -31,4 +31,5 @@ public interface Alert extends Identity, InternalIdentity { Date getLastSent(); Date getResolved(); boolean getArchived(); + String getName(); } diff --git a/api/src/com/cloud/deploy/DeployDestination.java b/api/src/com/cloud/deploy/DeployDestination.java index e00d3c6afd61..6b6e5e877cbd 100644 --- a/api/src/com/cloud/deploy/DeployDestination.java +++ b/api/src/com/cloud/deploy/DeployDestination.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.deploy; +import java.io.Serializable; import java.util.Map; import com.cloud.dc.DataCenter; @@ -26,7 +27,9 @@ import com.cloud.storage.Volume; import com.cloud.utils.NumbersUtil; -public class DeployDestination { +public class DeployDestination implements Serializable { + private static final long serialVersionUID = 7113840781939014695L; + DataCenter _dc; Pod _pod; Cluster _cluster; @@ -76,28 +79,28 @@ public int hashCode() { @Override public boolean equals(Object obj) { DeployDestination that = (DeployDestination) obj; - if (this._dc == null || that._dc == null) { + if (_dc == null || that._dc == null) { return false; } - if (this._dc.getId() != that._dc.getId()) { + if (_dc.getId() != that._dc.getId()) { return false; } - if (this._pod == null || that._pod == null) { + if (_pod == null || that._pod == null) { return false; } - if (this._pod.getId() != that._pod.getId()) { + if (_pod.getId() != that._pod.getId()) { return false; } - if (this._cluster == null || that._cluster == null) { + if (_cluster == null || that._cluster == null) { return false; } - if (this._cluster.getId() != that._cluster.getId()) { + if (_cluster.getId() != that._cluster.getId()) { return false; } - if (this._host == null || that._host == null) { + if (_host == null || that._host == null) { return false; } - return this._host.getId() == that._host.getId(); + return _host.getId() == that._host.getId(); } @Override diff --git a/api/src/com/cloud/deploy/DeploymentClusterPlanner.java b/api/src/com/cloud/deploy/DeploymentClusterPlanner.java index ca73267e732f..b4782239a35d 100644 --- a/api/src/com/cloud/deploy/DeploymentClusterPlanner.java +++ b/api/src/com/cloud/deploy/DeploymentClusterPlanner.java @@ -20,10 +20,20 @@ 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/deploy/DeploymentPlanner.java b/api/src/com/cloud/deploy/DeploymentPlanner.java index 88cfc74ca298..94cf2a992c49 100644 --- a/api/src/com/cloud/deploy/DeploymentPlanner.java +++ b/api/src/com/cloud/deploy/DeploymentPlanner.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.deploy; +import java.io.Serializable; import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -93,7 +94,9 @@ public enum PlannerResourceUsage { Shared, Dedicated; } - public static class ExcludeList { + public static class ExcludeList implements Serializable { + private static final long serialVersionUID = -482175549460148301L; + private Set _dcIds; private Set _podIds; private Set _clusterIds; @@ -177,6 +180,12 @@ public void addPool(long poolId) { _poolIds.add(poolId); } + public void removePool(long poolId) { + if (_poolIds != null) { + _poolIds.remove(poolId); + } + } + public void addDataCenter(long dataCenterId) { if (_dcIds == null) { _dcIds = new HashSet(); diff --git a/api/src/com/cloud/deploy/HAPlanner.java b/api/src/com/cloud/deploy/HAPlanner.java new file mode 100644 index 000000000000..aeb5083c5227 --- /dev/null +++ b/api/src/com/cloud/deploy/HAPlanner.java @@ -0,0 +1,21 @@ +// 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.deploy; + + +public interface HAPlanner extends DeploymentPlanner { +} \ No newline at end of file diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index a3e45fadce28..77d2fabdff1d 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -452,10 +452,17 @@ public class EventTypes { public static final String EVENT_CLEANUP_VM_RESERVATION = "VM.RESERVATION.CLEANUP"; public static final String EVENT_UCS_ASSOCIATED_PROFILE = "UCS.ASSOCIATEPROFILE"; + public static final String EVENT_UCS_INSTANTIATE_TEMPLATE_AND_ASSOCIATE = "UCS.TEMPLATEASSOCIATION"; + public static final String EVENT_UCS_DISASSOCIATED_PROFILE = "UCS.DISASSOCIATEPROFILE"; + public static final String EVENT_UCS_REFRESH_BLADES = "UCS.REFRESHBLADES"; // Object store migration public static final String EVENT_MIGRATE_PREPARE_SECONDARY_STORAGE = "MIGRATE.PREPARE.SS"; + //Alert generation + public static final String ALERT_GENERATE = "ALERT.GENERATE"; + + static { // TODO: need a way to force author adding event types to declare the entity details as well, with out braking diff --git a/api/src/com/cloud/exception/CloudException.java b/api/src/com/cloud/exception/CloudException.java index 0b71ce89a92e..06bda423405f 100644 --- a/api/src/com/cloud/exception/CloudException.java +++ b/api/src/com/cloud/exception/CloudException.java @@ -27,8 +27,9 @@ */ public class CloudException extends Exception { + private static final long serialVersionUID = 8784427323859682503L; - // This holds a list of uuids and their names. Add uuid:fieldname pairs + // This holds a list of uuids and their names. Add uuid:fieldname pairs protected ArrayList idList = new ArrayList(); protected Integer csErrorCode; @@ -43,8 +44,6 @@ public CloudException(String message, Throwable cause) { setCSErrorCode(CSExceptionErrorCode.getCSErrCode(this.getClass().getName())); } - - public CloudException() { super(); setCSErrorCode(CSExceptionErrorCode.getCSErrCode(this.getClass().getName())); @@ -60,10 +59,10 @@ public ArrayList getIdProxyList() { } public void setCSErrorCode(int cserrcode) { - this.csErrorCode = cserrcode; + csErrorCode = cserrcode; } public int getCSErrorCode() { - return this.csErrorCode; + return csErrorCode; } } diff --git a/api/src/com/cloud/exception/OperationTimedoutException.java b/api/src/com/cloud/exception/OperationTimedoutException.java index 2eeec3780aa5..c4a2b9ce2acb 100644 --- a/api/src/com/cloud/exception/OperationTimedoutException.java +++ b/api/src/com/cloud/exception/OperationTimedoutException.java @@ -24,13 +24,21 @@ */ public class OperationTimedoutException extends CloudException { private static final long serialVersionUID = SerialVersionUID.OperationTimedoutException; - + long _agentId; long _seqId; int _time; - Command[] _cmds; + + // TODO + // I did a reference search on usage of getCommands() and found none + // + // to prevent serialization problems across boundaries, I'm disabling serialization of _cmds here + // getCommands() will still be available within the same serialization boundary, but it will be lost + // when exception is propagated across job boundaries. + // + transient Command[] _cmds; boolean _isActive; - + public OperationTimedoutException(Command[] cmds, long agentId, long seqId, int time, boolean isActive) { super("Commands " + seqId + " to Host " + agentId + " timed out after " + time); _agentId = agentId; @@ -39,23 +47,23 @@ public OperationTimedoutException(Command[] cmds, long agentId, long seqId, int _cmds = cmds; _isActive = isActive; } - + public long getAgentId() { return _agentId; } - + public long getSequenceId() { return _seqId; } - + public int getWaitTime() { return _time; } - + public Command[] getCommands() { return _cmds; } - + public boolean isActive() { return _isActive; } diff --git a/api/src/com/cloud/host/Host.java b/api/src/com/cloud/host/Host.java index 581bd47c5f41..9a20f6287e54 100755 --- a/api/src/com/cloud/host/Host.java +++ b/api/src/com/cloud/host/Host.java @@ -91,6 +91,11 @@ public static String[] toStrings(Host.Type... types) { */ String getPrivateIpAddress(); + /** + * @return the ip address of the host. + */ + String getStorageUrl(); + /** * @return the ip address of the host attached to the storage network. */ diff --git a/api/src/com/cloud/hypervisor/HypervisorGuru.java b/api/src/com/cloud/hypervisor/HypervisorGuru.java index cc2768082014..6f354d3bb6c6 100644 --- a/api/src/com/cloud/hypervisor/HypervisorGuru.java +++ b/api/src/com/cloud/hypervisor/HypervisorGuru.java @@ -75,4 +75,6 @@ public interface HypervisorGuru extends Adapter { * */ List finalizeExpungeNics(VirtualMachine vm, List nics); + + List finalizeExpungeVolumes(VirtualMachine vm); } diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 4eadd61aa255..b5e8173c99b8 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.network; +import java.io.Serializable; import java.net.URI; import java.util.ArrayList; import java.util.List; @@ -33,7 +34,7 @@ /** * owned by an account. */ -public interface Network extends ControlledEntity, StateObject, InternalIdentity, Identity { +public interface Network extends ControlledEntity, StateObject, InternalIdentity, Identity, Serializable { public enum GuestType { Shared, @@ -114,7 +115,7 @@ public static class Provider { private static List supportedProviders = new ArrayList(); public static final Provider VirtualRouter = new Provider("VirtualRouter", false); - public static final Provider JuniperContrail = new Provider("JuniperContrail", false); + public static final Provider JuniperContrailRouter = new Provider("JuniperContrailRouter", false); public static final Provider JuniperSRX = new Provider("JuniperSRX", true); public static final Provider PaloAlto = new Provider("PaloAlto", true); public static final Provider F5BigIp = new Provider("F5BigIp", true); @@ -129,6 +130,7 @@ public static class Provider { public static final Provider NiciraNvp = new Provider("NiciraNvp", false); public static final Provider InternalLbVm = new Provider("InternalLbVm", false); public static final Provider CiscoVnmc = new Provider("CiscoVnmc", true); + public static final Provider Ovs = new Provider("Ovs", false); private final String name; private final boolean isExternal; @@ -230,7 +232,7 @@ public enum State { s_fsm.addTransition(State.Implementing, Event.OperationFailed, State.Shutdown); s_fsm.addTransition(State.Implemented, Event.DestroyNetwork, State.Shutdown); s_fsm.addTransition(State.Shutdown, Event.OperationSucceeded, State.Allocated); - s_fsm.addTransition(State.Shutdown, Event.OperationFailed, State.Implemented); + s_fsm.addTransition(State.Shutdown, Event.OperationFailed, State.Shutdown); s_fsm.addTransition(State.Setup, Event.DestroyNetwork, State.Destroy); s_fsm.addTransition(State.Allocated, Event.DestroyNetwork, State.Destroy); } @@ -248,7 +250,7 @@ private State(String description) { public class IpAddresses { private String ip4Address; private String ip6Address; - + public IpAddresses(String ip4Address, String ip6Address) { setIp4Address(ip4Address); setIp6Address(ip6Address); @@ -270,7 +272,7 @@ public void setIp6Address(String ip6Address) { this.ip6Address = ip6Address; } } - + String getName(); Mode getMode(); diff --git a/api/src/com/cloud/network/NetworkModel.java b/api/src/com/cloud/network/NetworkModel.java index f067787b9d69..bf6ac9a591eb 100644 --- a/api/src/com/cloud/network/NetworkModel.java +++ b/api/src/com/cloud/network/NetworkModel.java @@ -61,6 +61,8 @@ public interface NetworkModel { */ List listPublicIpsAssignedToGuestNtwk(long accountId, long associatedNetworkId, Boolean sourceNat); + List listPublicIpsAssignedToGuestNtwk(long associatedNetworkId, Boolean sourceNat); + List getSystemAccountNetworkOfferings(String... offeringNames); List getNics(long vmId); @@ -199,10 +201,10 @@ Map> getIpToServices(List getPhysicalNtwksSupportingTrafficType(long zoneId, TrafficType trafficType); /** - * @param guestNic + * @param ntwkId * @return */ - boolean isPrivateGateway(Nic guestNic); + boolean isPrivateGateway(long ntwkId); Map> getNetworkCapabilities(long networkId); @@ -271,4 +273,6 @@ Map> getIpToServices(List searchForNetworks(ListNetworksCmd cmd); + Pair, Integer> searchForNetworks(ListNetworksCmd cmd); - boolean deleteNetwork(long networkId); + boolean deleteNetwork(long networkId, boolean forced); boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; @@ -115,7 +115,7 @@ Pair, Integer> listNetworkService long findPhysicalNetworkId(long zoneId, String tag, TrafficType trafficType); - PhysicalNetworkTrafficType addTrafficTypeToPhysicalNetwork(Long physicalNetworkId, String trafficType, + PhysicalNetworkTrafficType addTrafficTypeToPhysicalNetwork(Long physicalNetworkId, String trafficType, String isolationMethod, String xenLabel, String kvmLabel, String vmwareLabel, String simulatorLabel, String vlan, String hypervLabel); PhysicalNetworkTrafficType getPhysicalNetworkTrafficType(Long id); diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java index 0412bf459827..3159f6ee32bf 100755 --- a/api/src/com/cloud/network/Networks.java +++ b/api/src/com/cloud/network/Networks.java @@ -108,7 +108,20 @@ public String getValueFrom(URI uri) { }, Mido("mido", String.class), Pvlan("pvlan", String.class), - Vxlan("vxlan", Long.class), + Vxlan("vxlan", Long.class) { + @Override + public URI toUri(T value) { + try { + if (value.toString().contains("://")) + return new URI(value.toString()); + else + return new URI("vxlan://" + value.toString()); + } catch (URISyntaxException e) { + throw new CloudRuntimeException( + "Unable to convert to broadcast URI: " + value); + } + } + }, UnDecided(null, null); private final String scheme; diff --git a/api/src/com/cloud/network/PhysicalNetwork.java b/api/src/com/cloud/network/PhysicalNetwork.java index 55b18e67ba99..5d38b5003058 100644 --- a/api/src/com/cloud/network/PhysicalNetwork.java +++ b/api/src/com/cloud/network/PhysicalNetwork.java @@ -40,7 +40,8 @@ public enum IsolationMethod { VNS, MIDO, SSP, - VXLAN; + VXLAN, + L3VPN; } public enum BroadcastDomainRange { diff --git a/api/src/com/cloud/network/VirtualNetworkApplianceService.java b/api/src/com/cloud/network/VirtualNetworkApplianceService.java index fb5d12aed999..cf93f649ff24 100644 --- a/api/src/com/cloud/network/VirtualNetworkApplianceService.java +++ b/api/src/com/cloud/network/VirtualNetworkApplianceService.java @@ -71,5 +71,5 @@ VirtualRouter rebootRouter(long routerId, boolean reprogramNetwork) throws Concu List upgradeRouterTemplate(UpgradeRouterTemplateCmd cmd); - public static final String _minVRVersion = "4.2.0"; + public static final String _minVRVersion = "4.3.0"; } diff --git a/api/src/com/cloud/network/VpcVirtualNetworkApplianceService.java b/api/src/com/cloud/network/VpcVirtualNetworkApplianceService.java index 6e8fd38ba667..661ac64cb4c6 100644 --- a/api/src/com/cloud/network/VpcVirtualNetworkApplianceService.java +++ b/api/src/com/cloud/network/VpcVirtualNetworkApplianceService.java @@ -16,10 +16,13 @@ // under the License. package com.cloud.network; +import java.util.Map; + import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.router.VirtualRouter; +import com.cloud.vm.VirtualMachineProfile; public interface VpcVirtualNetworkApplianceService extends VirtualNetworkApplianceService{ @@ -27,12 +30,13 @@ public interface VpcVirtualNetworkApplianceService extends VirtualNetworkApplian * @param router * @param network * @param isRedundant + * @param params TODO * @return * @throws ConcurrentOperationException * @throws ResourceUnavailableException * @throws InsufficientCapacityException */ - boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant) + boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant, Map params) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; /** diff --git a/api/src/com/cloud/network/lb/LoadBalancingRule.java b/api/src/com/cloud/network/lb/LoadBalancingRule.java index 39c969c70014..36f3a44e59f2 100644 --- a/api/src/com/cloud/network/lb/LoadBalancingRule.java +++ b/api/src/com/cloud/network/lb/LoadBalancingRule.java @@ -439,16 +439,17 @@ public String getCurrentState() { public static class LbSslCert { private String cert; private String key; - private String password=null; - private String chain=null; + private String password = null; + private String chain = null; + private String fingerprint = null; private boolean revoked; - - public LbSslCert(String cert, String key, String password, String chain, boolean revoked) { + public LbSslCert(String cert, String key, String password, String chain, String fingerprint, boolean revoked) { this.cert = cert; this.key = key; this.password = password; this.chain = chain; + this.fingerprint = fingerprint; this.revoked = revoked; } @@ -469,7 +470,11 @@ public String getChain() { return chain; } - public boolean isRevoked(){ + public String getFingerprint() { + return fingerprint; + } + + public boolean isRevoked() { return revoked; } } diff --git a/api/src/com/cloud/network/rules/FirewallRule.java b/api/src/com/cloud/network/rules/FirewallRule.java index 042665cdcf95..0c74d02e224b 100644 --- a/api/src/com/cloud/network/rules/FirewallRule.java +++ b/api/src/com/cloud/network/rules/FirewallRule.java @@ -41,7 +41,8 @@ enum State { Staged, // Rule been created but has never got through network rule conflict detection. Rules in this state can not be sent to network elements. Add, // Add means the rule has been created and has gone through network rule conflict detection. Active, // Rule has been sent to the network elements and reported to be active. - Revoke // Revoke means this rule has been revoked. If this rule has been sent to the network elements, the rule will be deleted from database. + Revoke, // Revoke means this rule has been revoked. If this rule has been sent to the network elements, the rule will be deleted from database. + Deleting // rule has been revoked and is scheduled for deletion } enum TrafficType { diff --git a/api/src/com/cloud/network/rules/LoadBalancer.java b/api/src/com/cloud/network/rules/LoadBalancer.java index e6dadcaee971..c260b81c3924 100644 --- a/api/src/com/cloud/network/rules/LoadBalancer.java +++ b/api/src/com/cloud/network/rules/LoadBalancer.java @@ -25,4 +25,5 @@ public interface LoadBalancer extends FirewallRule, LoadBalancerContainer { int getDefaultPortEnd(); + } diff --git a/api/src/com/cloud/network/rules/LoadBalancerContainer.java b/api/src/com/cloud/network/rules/LoadBalancerContainer.java index 9d5ea595c9da..c75d0cc22eb7 100644 --- a/api/src/com/cloud/network/rules/LoadBalancerContainer.java +++ b/api/src/com/cloud/network/rules/LoadBalancerContainer.java @@ -27,6 +27,8 @@ public enum Scheme { String getDescription(); String getAlgorithm(); + + String getLbProtocol(); Scheme getScheme(); diff --git a/api/src/com/cloud/network/vpc/NetworkACLService.java b/api/src/com/cloud/network/vpc/NetworkACLService.java index ec53c26a4cec..d2ff287da798 100644 --- a/api/src/com/cloud/network/vpc/NetworkACLService.java +++ b/api/src/com/cloud/network/vpc/NetworkACLService.java @@ -20,6 +20,7 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.utils.Pair; import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd; +import org.apache.cloudstack.api.command.user.network.ListNetworkACLListsCmd; import org.apache.cloudstack.api.command.user.network.ListNetworkACLsCmd; import java.util.List; @@ -43,13 +44,10 @@ public interface NetworkACLService { /** * List NetworkACLs by Id/Name/Network or Vpc it belongs to - * @param id - * @param name - * @param networkId - * @param vpcId + * @param cmd * @return */ - Pair,Integer> listNetworkACLs(Long id, String name, Long networkId, Long vpcId); + Pair,Integer> listNetworkACLs(ListNetworkACLListsCmd cmd); /** * Delete specified network ACL. Deletion fails if the list is not empty diff --git a/api/src/com/cloud/network/vpc/StaticRoute.java b/api/src/com/cloud/network/vpc/StaticRoute.java index ccdbec899b8f..5707ca140246 100644 --- a/api/src/com/cloud/network/vpc/StaticRoute.java +++ b/api/src/com/cloud/network/vpc/StaticRoute.java @@ -25,7 +25,8 @@ enum State { Staged, // route been created but has never got through network rule conflict detection. Routes in this state can not be sent to VPC virtual router. Add, // Add means the route has been created and has gone through network rule conflict detection. Active, // Route has been sent to the VPC router and reported to be active. - Revoke // Revoke means this route has been revoked. If this route has been sent to the VPC router, the route will be deleted from database. + Revoke, // Revoke means this route has been revoked. If this route has been sent to the VPC router, the route will be deleted from database. + Deleting // rule has been revoked and is scheduled for deletion } /** diff --git a/api/src/com/cloud/region/ha/GlobalLoadBalancerRule.java b/api/src/com/cloud/region/ha/GlobalLoadBalancerRule.java index 597304fa860d..7a824127b447 100644 --- a/api/src/com/cloud/region/ha/GlobalLoadBalancerRule.java +++ b/api/src/com/cloud/region/ha/GlobalLoadBalancerRule.java @@ -53,10 +53,11 @@ public static boolean isValidPersistence(String persistence) { } enum ServiceType { - tcp, - udp; - public static boolean isValidServiceType(String serviceType) { - if (tcp.name().equalsIgnoreCase(serviceType) || udp.name().equalsIgnoreCase(serviceType)) { + tcp, udp, http; + public static boolean isValidServiceType(String serviceType) { + if (tcp.name().equalsIgnoreCase(serviceType) || + udp.name().equalsIgnoreCase(serviceType) || + http.name().equalsIgnoreCase(serviceType)) { return true; } return false; diff --git a/api/src/com/cloud/server/ManagementService.java b/api/src/com/cloud/server/ManagementService.java index ed465899a746..45e1da6db354 100755 --- a/api/src/com/cloud/server/ManagementService.java +++ b/api/src/com/cloud/server/ManagementService.java @@ -365,7 +365,6 @@ Ternary, Integer>, List, Map securityGroupIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, - HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, - IpAddresses defaultIp, Boolean displayVm, String keyboard, List affinityGroupIdList, Integer cpuSpeed, Integer memory, Integer cpuNumber, Long rootdisksize) - throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; + UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList, + Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, + String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard, + List affinityGroupIdList, Map customParameter) throws InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** * Creates a User VM in Advanced Zone (Security Group feature is enabled) in @@ -282,10 +282,11 @@ UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering s * available. * @throws InsufficientResourcesException */ - UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, List securityGroupIdList, - Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair, - Map requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List affinityGroupIdList, Integer cpuSpeed, Integer memory, Integer cpuNumber, Long rootdisksize) - throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; + UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, + List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, + HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, + List affinityGroupIdList, Map customParameters) throws InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** * Creates a User VM in Advanced Zone (Security Group feature is disabled) @@ -357,10 +358,10 @@ UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOfferin * available. * @throws InsufficientResourcesException */ - UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, - HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, - IpAddresses defaultIps, Boolean displayVm, String keyboard, List affinityGroupIdList, Integer cpuSpeed, Integer memory, Integer cpuNumber, Long rootdkisksize) + UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, + String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, + String sshKeyPair, Map requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List affinityGroupIdList, + Map customParameters) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index 9a8d88330c7a..b88df22719a4 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -29,7 +29,7 @@ /** * VirtualMachine describes the properties held by a virtual machine - * + * */ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, InternalIdentity, StateObject { @@ -117,7 +117,7 @@ public static StateMachine2 getStat s_fsm.addTransition(State.Expunging, VirtualMachine.Event.ExpungeOperation, State.Expunging); s_fsm.addTransition(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging); s_fsm.addTransition(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging); - + s_fsm.addTransition(State.Stopping, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running); s_fsm.addTransition(State.Stopped, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running); s_fsm.addTransition(State.Running, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running); @@ -126,8 +126,9 @@ public static StateMachine2 getStat s_fsm.addTransition(State.Stopping, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); s_fsm.addTransition(State.Running, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); s_fsm.addTransition(State.Migrating, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); + s_fsm.addTransition(State.Stopped, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); } - + public static boolean isVmStarted(State oldState, Event e, State newState) { if (oldState == State.Starting && newState == State.Running) { return true; @@ -194,10 +195,10 @@ public enum Event { AgentReportMigrated, RevertRequested, SnapshotRequested, - + // added for new VMSync logic FollowAgentPowerOnReport, - FollowAgentPowerOffReport, + FollowAgentPowerOffReport, }; public enum Type { @@ -213,7 +214,12 @@ public enum Type { * UserBareMetal is only used for selecting VirtualMachineGuru, there is no * VM with this type. UserBareMetal should treat exactly as User. */ - UserBareMetal(false); + UserBareMetal(false), + + /* + * General VM type for queuing VM orchestration work + */ + Instance(false); boolean _isUsedBySystem; @@ -269,7 +275,7 @@ public boolean isUsedBySystem() { /** * returns the guest OS ID - * + * * @return guestOSId */ long getGuestOSId(); @@ -308,7 +314,7 @@ public boolean isUsedBySystem() { Date getCreated(); long getServiceOfferingId(); - + Long getDiskOfferingId(); Type getType(); diff --git a/api/src/com/cloud/vm/VirtualMachineName.java b/api/src/com/cloud/vm/VirtualMachineName.java index 1279fd6910e9..49cb40bda391 100755 --- a/api/src/com/cloud/vm/VirtualMachineName.java +++ b/api/src/com/cloud/vm/VirtualMachineName.java @@ -25,6 +25,19 @@ */ public class VirtualMachineName { public static final String SEPARATOR = "-"; + + public static boolean isValidCloudStackVmName(String name, String instance) { + String[] parts = name.split(SEPARATOR); + if (parts.length <= 1) { + return false; + } + + if (!parts[parts.length - 1].equals(instance)) { + return false; + } + + return true; + } public static String getVnetName(long vnetId) { StringBuilder vnet = new StringBuilder(); diff --git a/api/src/org/apache/cloudstack/alert/AlertService.java b/api/src/org/apache/cloudstack/alert/AlertService.java new file mode 100644 index 000000000000..ad3d31988ec7 --- /dev/null +++ b/api/src/org/apache/cloudstack/alert/AlertService.java @@ -0,0 +1,103 @@ +// 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.alert; + +import java.util.HashSet; +import java.util.Set; + +import com.cloud.capacity.Capacity; +import com.cloud.exception.InvalidParameterValueException; + +public interface AlertService { + public static class AlertType { + private static Set defaultAlertTypes = new HashSet(); + private final String name; + private final short type; + + private AlertType(short type, String name, boolean isDefault) { + this.name = name; + this.type = type; + if (isDefault) { + defaultAlertTypes.add(this); + } + } + + public static final AlertType ALERT_TYPE_MEMORY = new AlertType(Capacity.CAPACITY_TYPE_MEMORY, "ALERT.MEMORY", true); + public static final AlertType ALERT_TYPE_CPU = new AlertType(Capacity.CAPACITY_TYPE_CPU, "ALERT.CPU", true); + public static final AlertType ALERT_TYPE_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_STORAGE, "ALERT.STORAGE", true); + public static final AlertType ALERT_TYPE_STORAGE_ALLOCATED = new AlertType(Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, "ALERT.STORAGE.ALLOCATED", true); + public static final AlertType ALERT_TYPE_VIRTUAL_NETWORK_PUBLIC_IP = new AlertType(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_PUBLIC_IP, "ALERT.NETWORK.PUBLICIP", true); + public static final AlertType ALERT_TYPE_PRIVATE_IP = new AlertType(Capacity.CAPACITY_TYPE_PRIVATE_IP, "ALERT.NETWORK.PRIVATEIP", true); + public static final AlertType ALERT_TYPE_SECONDARY_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_SECONDARY_STORAGE, "ALERT.STORAGE.SECONDARY", true); + public static final AlertType ALERT_TYPE_HOST = new AlertType((short)7, "ALERT.COMPUTE.HOST", true); + public static final AlertType ALERT_TYPE_USERVM = new AlertType((short)8, "ALERT.USERVM", true); + public static final AlertType ALERT_TYPE_DOMAIN_ROUTER = new AlertType((short)9, "ALERT.SERVICE.DOMAINROUTER", true); + public static final AlertType ALERT_TYPE_CONSOLE_PROXY = new AlertType((short)10, "ALERT.SERVICE.CONSOLEPROXY", true); + public static final AlertType ALERT_TYPE_ROUTING = new AlertType((short)11, "ALERT.NETWORK.ROUTING", true); + public static final AlertType ALERT_TYPE_STORAGE_MISC = new AlertType((short)12, "ALERT.STORAGE.MISC", true); + public static final AlertType ALERT_TYPE_USAGE_SERVER = new AlertType((short)13, "ALERT.USAGE", true); + public static final AlertType ALERT_TYPE_MANAGMENT_NODE = new AlertType((short)14, "ALERT.MANAGEMENT", true); + public static final AlertType ALERT_TYPE_DOMAIN_ROUTER_MIGRATE = new AlertType((short)15, "ALERT.NETWORK.DOMAINROUTERMIGRATE", true); + public static final AlertType ALERT_TYPE_CONSOLE_PROXY_MIGRATE = new AlertType((short)16, "ALERT.SERVICE.CONSOLEPROXYMIGRATE", true); + public static final AlertType ALERT_TYPE_USERVM_MIGRATE = new AlertType((short)17, "ALERT.USERVM.MIGRATE", true); + public static final AlertType ALERT_TYPE_VLAN = new AlertType((short)18, "ALERT.NETWORK.VLAN", true); + public static final AlertType ALERT_TYPE_SSVM = new AlertType((short)19, "ALERT.SERVICE.SSVM", true); + public static final AlertType ALERT_TYPE_USAGE_SERVER_RESULT = new AlertType((short)20, "ALERT.USAGE.RESULT", true); + public static final AlertType ALERT_TYPE_STORAGE_DELETE = new AlertType((short)21, "ALERT.STORAGE.DELETE", true); + public static final AlertType ALERT_TYPE_UPDATE_RESOURCE_COUNT = new AlertType((short)22, "ALERT.RESOURCE.COUNT", true); + public static final AlertType ALERT_TYPE_USAGE_SANITY_RESULT = new AlertType((short)23, "ALERT.USAGE.SANITY", true); + public static final AlertType ALERT_TYPE_DIRECT_ATTACHED_PUBLIC_IP = new AlertType((short)24, "ALERT.NETWORK.DIRECTPUBLICIP", true); + public static final AlertType ALERT_TYPE_LOCAL_STORAGE = new AlertType((short)25, "ALERT.STORAGE.LOCAL", true); + public static final AlertType ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED = new AlertType((short)26, "ALERT.RESOURCE.EXCEED", true); + public static final AlertType ALERT_TYPE_SYNC = new AlertType((short)27, "ALERT.TYPE.SYNC", true); + + public short getType() { + return type; + } + + public String getName() { + return name; + } + + + private static AlertType getAlertType(short type) { + for (AlertType alertType : defaultAlertTypes) { + if (alertType.getType() == type) { + return alertType; + } + } + return null; + } + + @Override + public String toString() { + return String.valueOf(this.getType()); + } + + public static AlertType generateAlert(short type, String name) { + AlertType defaultAlert = getAlertType(type); + if (defaultAlert != null && !defaultAlert.getName().equalsIgnoreCase(name)) { + throw new InvalidParameterValueException("There is a default alert having type " + type + " and name " + defaultAlert.getName()); + } else { + return new AlertType(type, name, false); + } + } + } + + boolean generateAlert(AlertType alertType, long dataCenterId, Long podId, String msg); + +} diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 82b2af69759e..68abf8d4f49b 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -16,7 +16,6 @@ // under the License. package org.apache.cloudstack.api; - public class ApiConstants { public static final String ACCOUNT = "account"; public static final String ACCOUNTS = "accounts"; @@ -209,6 +208,7 @@ public class ApiConstants { public static final String SENT_BYTES = "sentbytes"; public static final String SERVICE_OFFERING_ID = "serviceofferingid"; public static final String SHOW_CAPACITIES = "showcapacities"; + public static final String SHOW_REMOVED = "showremoved"; public static final String SIZE = "size"; public static final String SNAPSHOT_ID = "snapshotid"; public static final String SNAPSHOT_POLICY_ID = "snapshotpolicyid"; @@ -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"; @@ -247,7 +248,7 @@ public class ApiConstants { public static final String VIRTUAL_MACHINE_IDS = "virtualmachineids"; public static final String VLAN = "vlan"; public static final String VLAN_RANGE = "vlanrange"; - public static final String REMOVE_VLAN="removevlan"; + public static final String REMOVE_VLAN = "removevlan"; public static final String VLAN_ID = "vlanid"; public static final String ISOLATED_PVLAN = "isolatedpvlan"; public static final String VM_AVAILABLE = "vmavailable"; @@ -342,6 +343,7 @@ public class ApiConstants { public static final String CAPACITY_IOPS = "capacityiops"; public static final String NETWORK_SPEED = "networkspeed"; public static final String BROADCAST_DOMAIN_RANGE = "broadcastdomainrange"; + public static final String ISOLATION_METHOD = "isolationmethod"; public static final String ISOLATION_METHODS = "isolationmethods"; public static final String PHYSICAL_NETWORK_ID = "physicalnetworkid"; public static final String DEST_PHYSICAL_NETWORK_ID = "destinationphysicalnetworkid"; @@ -410,7 +412,8 @@ public class ApiConstants { public static final String EXTERNAL_SWITCH_MGMT_DEVICE_ID = "vsmdeviceid"; public static final String EXTERNAL_SWITCH_MGMT_DEVICE_NAME = "vsmdevicename"; public static final String EXTERNAL_SWITCH_MGMT_DEVICE_STATE = "vsmdevicestate"; - // Would we need to have a capacity field for Cisco N1KV VSM? Max hosts managed by it perhaps? May remove this later. + // Would we need to have a capacity field for Cisco N1KV VSM? Max hosts managed by it perhaps? May remove this +// later. public static final String EXTERNAL_SWITCH_MGMT_DEVICE_CAPACITY = "vsmdevicecapacity"; public static final String CISCO_NEXUS_VSM_NAME = "vsmname"; public static final String VSM_USERNAME = "vsmusername"; @@ -490,6 +493,7 @@ public class ApiConstants { public static final String BAREMETAL_DISCOVER_NAME = "baremetaldiscovername"; public static final String UCS_DN = "ucsdn"; public static final String GSLB_PROVIDER = "gslbprovider"; + public static final String EXCLUSIVE_GSLB_PROVIDER = "isexclusivegslbprovider"; public static final String GSLB_PROVIDER_PUBLIC_IP = "gslbproviderpublicip"; public static final String GSLB_PROVIDER_PRIVATE_IP = "gslbproviderprivateip"; public static final String VM_SNAPSHOT_DESCRIPTION = "description"; @@ -504,8 +508,11 @@ public class ApiConstants { public static final String RESERVED_IP_RANGE = "reservediprange"; public static final String UCS_MANAGER_ID = "ucsmanagerid"; public static final String UCS_PROFILE_DN = "profiledn"; + public static final String UCS_TEMPLATE_DN = "templatedn"; public static final String UCS_BLADE_DN = "bladedn"; public static final String UCS_BLADE_ID = "bladeid"; + public static final String UCS_PROFILE_NAME = "profilename"; + public static final String UCS_DELETE_PROFILE = "deleteprofile"; public static final String VM_GUEST_IP = "vmguestip"; public static final String HEALTHCHECK_RESPONSE_TIMEOUT = "responsetimeout"; public static final String HEALTHCHECK_INTERVAL_TIME = "intervaltime"; @@ -534,6 +541,7 @@ public class ApiConstants { public static final String FOR_DISPLAY = "fordisplay"; public static final String PASSIVE = "passive"; public static final String VERSION = "version"; + public static final String START = "start"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index 01d9b53fee17..acc15685a992 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -27,15 +27,12 @@ import javax.inject.Inject; import org.apache.cloudstack.affinity.AffinityGroupService; - -import com.cloud.server.ResourceMetaDataService; - +import org.apache.cloudstack.alert.AlertService; import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService; import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService; import org.apache.cloudstack.query.QueryService; import org.apache.cloudstack.usage.UsageService; - import org.apache.log4j.Logger; import com.cloud.configuration.ConfigurationService; @@ -54,10 +51,10 @@ import com.cloud.network.VpcVirtualNetworkApplianceService; import com.cloud.network.as.AutoScaleService; import com.cloud.network.firewall.FirewallService; -import com.cloud.network.vpc.NetworkACLService; import com.cloud.network.lb.LoadBalancingRulesService; import com.cloud.network.rules.RulesService; import com.cloud.network.security.SecurityGroupService; +import com.cloud.network.vpc.NetworkACLService; import com.cloud.network.vpc.VpcProvisioningService; import com.cloud.network.vpc.VpcService; import com.cloud.network.vpn.RemoteAccessVpnService; @@ -66,6 +63,7 @@ import com.cloud.projects.ProjectService; import com.cloud.resource.ResourceService; import com.cloud.server.ManagementService; +import com.cloud.server.ResourceMetaDataService; import com.cloud.server.TaggedResourceService; import com.cloud.storage.DataStoreProviderApiService; import com.cloud.storage.StorageService; @@ -151,6 +149,7 @@ public enum HTTPMethod { @Inject public InternalLoadBalancerElementService _internalLbElementSvc; @Inject public InternalLoadBalancerVMService _internalLbSvc; @Inject public NetworkModel _ntwkModel; + @Inject public AlertService _alertSvc; public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException; diff --git a/api/src/org/apache/cloudstack/api/InternalIdentity.java b/api/src/org/apache/cloudstack/api/InternalIdentity.java index 1dfeb8c90912..4149dd1c8465 100644 --- a/api/src/org/apache/cloudstack/api/InternalIdentity.java +++ b/api/src/org/apache/cloudstack/api/InternalIdentity.java @@ -16,11 +16,13 @@ // under the License. package org.apache.cloudstack.api; +import java.io.Serializable; + // This interface is a contract that getId() will give the internal // ID of an entity which extends this interface // Any class having an internal ID in db table/schema should extend this // For example, all ControlledEntity, OwnedBy would have an internal ID -public interface InternalIdentity { +public interface InternalIdentity extends Serializable { long getId(); } diff --git a/api/src/org/apache/cloudstack/api/ServerApiException.java b/api/src/org/apache/cloudstack/api/ServerApiException.java index 1a740d56c90e..c202eb38431e 100644 --- a/api/src/org/apache/cloudstack/api/ServerApiException.java +++ b/api/src/org/apache/cloudstack/api/ServerApiException.java @@ -81,4 +81,8 @@ public void setDescription(String description) { _description = description; } + @Override + public String getMessage() { + return _description; + } } diff --git a/api/src/org/apache/cloudstack/api/command/admin/alert/GenerateAlertCmd.java b/api/src/org/apache/cloudstack/api/command/admin/alert/GenerateAlertCmd.java new file mode 100644 index 000000000000..b23a3be9dea5 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/alert/GenerateAlertCmd.java @@ -0,0 +1,123 @@ +// 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.api.command.admin.alert; + +import org.apache.cloudstack.alert.AlertService; +import org.apache.cloudstack.alert.AlertService.AlertType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.PodResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; + +@APICommand(name = "generateAlert", description = "Generates an alert", responseObject = SuccessResponse.class, since="4.3") +public class GenerateAlertCmd extends BaseAsyncCmd { + + public static final Logger s_logger = Logger.getLogger(GenerateAlertCmd.class.getName()); + + private static final String s_name = "generatealertresponse"; + + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.TYPE, type = CommandType.SHORT, description = "Type of the alert", required=true) + private Short type; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "Name of the alert", required=true) + private String name; + + @Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "Alert description", required=true) + private String description; + + @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType=ZoneResponse.class, description="Zone id for which alert is generated") + private Long zoneId; + + @Parameter(name=ApiConstants.POD_ID, type=CommandType.UUID, entityType=PodResponse.class, description="Pod id for which alert is generated") + private Long podId; + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + @Override + public String getCommandName() { + return s_name; + } + + public Short getType() { + return type; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public long getZoneId() { + if (zoneId == null) { + return 0L; + } + return zoneId; + } + + public Long getPodId() { + return podId; + } + + + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + + + @Override + public void execute() { + AlertType alertType = AlertService.AlertType.generateAlert(getType(), getName()); + if (_alertSvc.generateAlert(alertType, getZoneId(), getPodId(), getDescription())) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate an alert"); + } + } + + @Override + public String getEventType() { + return EventTypes.ALERT_GENERATE; + } + + @Override + public String getEventDescription() { + return "Generating alert of type " + type + "; name " + name; + } + + @Override + public long getEntityOwnerId() { + return 0; + } +} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/api/command/admin/host/AddSecondaryStorageCmd.java b/api/src/org/apache/cloudstack/api/command/admin/host/AddSecondaryStorageCmd.java index 69a4a493ba3a..02e53a901bf9 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/host/AddSecondaryStorageCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/host/AddSecondaryStorageCmd.java @@ -16,16 +16,16 @@ // under the License. package org.apache.cloudstack.api.command.admin.host; +import org.apache.log4j.Logger; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd; import org.apache.cloudstack.api.response.ImageStoreResponse; import org.apache.cloudstack.api.response.ZoneResponse; -import org.apache.log4j.Logger; import com.cloud.exception.DiscoveryException; import com.cloud.storage.ImageStore; @@ -78,19 +78,14 @@ public long getEntityOwnerId() { @Override public void execute(){ - AddImageStoreCmd cmd = new AddImageStoreCmd(); - cmd.setUrl(this.getUrl()); - cmd.setZoneId(this.getZoneId()); - cmd.setProviderName("NFS"); - try{ - ImageStore result = _storageService.discoverImageStore(cmd); + ImageStore result = _storageService.discoverImageStore(null, getUrl(), "NFS", getZoneId(), null); ImageStoreResponse storeResponse = null; if (result != null ) { storeResponse = _responseGenerator.createImageStoreResponse(result); storeResponse.setResponseName(getCommandName()); storeResponse.setObjectName("secondarystorage"); - this.setResponseObject(storeResponse); + setResponseObject(storeResponse); } else { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add secondary storage"); } diff --git a/api/src/org/apache/cloudstack/api/command/admin/resource/ListAlertsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/resource/ListAlertsCmd.java index 015d82bcccb6..724ae111a7f9 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/resource/ListAlertsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/resource/ListAlertsCmd.java @@ -47,6 +47,9 @@ public class ListAlertsCmd extends BaseListCmd { @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "list by alert type") private String type; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "list by alert name", since="4.3") + private String name; // /////////////////////////////////////////////////// // ///////////////// Accessors /////////////////////// @@ -59,6 +62,10 @@ public Long getId() { public String getType() { return type; } + + public String getName() { + return name; + } // /////////////////////////////////////////////////// // ///////////// API Implementation/////////////////// @@ -80,6 +87,7 @@ public void execute() { alertResponse.setAlertType(alert.getType()); alertResponse.setDescription(alert.getSubject()); alertResponse.setLastSent(alert.getLastSent()); + alertResponse.setName(alert.getName()); alertResponse.setObjectName("alert"); alertResponseList.add(alertResponse); diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java index 2752a13b176d..528d1a9b2935 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java @@ -21,6 +21,7 @@ import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd; import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ClusterResponse; import org.apache.cloudstack.api.response.DomainRouterResponse; import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.ListResponse; @@ -65,6 +66,10 @@ public class ListRoutersCmd extends BaseListProjectAndAccountResourcesCmd { description="the Zone ID of the router") private Long zoneId; + @Parameter(name=ApiConstants.CLUSTER_ID, type=CommandType.UUID, entityType=ClusterResponse.class, + description="the cluster ID of the router") + private Long clusterId; + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType=NetworkResponse.class, description="list by network id") private Long networkId; @@ -107,6 +112,10 @@ public Long getZoneId() { return zoneId; } + public Long getClusterId() { + return clusterId; + } + public Long getNetworkId() { return networkId; } diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/UpgradeRouterTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/UpgradeRouterTemplateCmd.java index 1db22bc0842d..8cce2621d46c 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/router/UpgradeRouterTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/router/UpgradeRouterTemplateCmd.java @@ -69,9 +69,9 @@ public class UpgradeRouterTemplateCmd extends org.apache.cloudstack.api.BaseCmd description="upgrades all routers within the specified zone") private Long zoneId; - @Parameter(name=ApiConstants.ACCOUNT_ID, type=CommandType.UUID, entityType = AccountResponse.class, + @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="upgrades all routers owned by the specified account") - private Long accountId; + private String account; @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.UUID, entityType=DomainResponse.class, description="upgrades all routers owned by the specified domain") @@ -97,8 +97,8 @@ public Long getZoneId() { return zoneId; } - public Long getAccountId() { - return accountId; + public String getAccount() { + return account; } public Long getDomainId() { diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java index 1552e0520a8e..98c098844b7b 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java @@ -21,6 +21,8 @@ import java.util.Iterator; import java.util.Map; +import org.apache.log4j.Logger; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -29,7 +31,6 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.ImageStoreResponse; import org.apache.cloudstack.api.response.ZoneResponse; -import org.apache.log4j.Logger; import com.cloud.exception.DiscoveryException; import com.cloud.storage.ImageStore; @@ -98,7 +99,7 @@ public Map getDetails() { } public String getProviderName() { - return this.providerName; + return providerName; } public void setUrl(String url) { @@ -136,13 +137,13 @@ public long getEntityOwnerId() { @Override public void execute(){ try{ - ImageStore result = _storageService.discoverImageStore(this); + ImageStore result = _storageService.discoverImageStore(getName(), getUrl(), getProviderName(), getZoneId(), getDetails()); ImageStoreResponse storeResponse = null; if (result != null ) { storeResponse = _responseGenerator.createImageStoreResponse(result); storeResponse.setResponseName(getCommandName()); storeResponse.setObjectName("imagestore"); - this.setResponseObject(storeResponse); + setResponseObject(storeResponse); } else { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add secondary storage"); } diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/AddS3Cmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/AddS3Cmd.java index 0af1a85051ff..035a85c7833d 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/storage/AddS3Cmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/storage/AddS3Cmd.java @@ -34,6 +34,8 @@ import java.util.HashMap; import java.util.Map; +import org.apache.log4j.Logger; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -41,7 +43,6 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.ImageStoreResponse; -import org.apache.log4j.Logger; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.DiscoveryException; @@ -94,39 +95,32 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { - AddImageStoreCmd cmd = new AddImageStoreCmd() { - @Override - public Map getDetails() { - Map dm = new HashMap(); - dm.put(ApiConstants.S3_ACCESS_KEY, getAccessKey()); - dm.put(ApiConstants.S3_SECRET_KEY, getSecretKey()); - dm.put(ApiConstants.S3_END_POINT, getEndPoint()); - dm.put(ApiConstants.S3_BUCKET_NAME, getBucketName()); - if (getHttpsFlag() != null) { - dm.put(ApiConstants.S3_HTTPS_FLAG, getHttpsFlag().toString()); - } - if (getConnectionTimeout() != null) { - dm.put(ApiConstants.S3_CONNECTION_TIMEOUT, getConnectionTimeout().toString()); - } - if (getMaxErrorRetry() != null) { - dm.put(ApiConstants.S3_MAX_ERROR_RETRY, getMaxErrorRetry().toString()); - } - if (getSocketTimeout() != null) { - dm.put(ApiConstants.S3_SOCKET_TIMEOUT, getSocketTimeout().toString()); - } - return dm; - } - }; - cmd.setProviderName("S3"); + Map dm = new HashMap(); + dm.put(ApiConstants.S3_ACCESS_KEY, getAccessKey()); + dm.put(ApiConstants.S3_SECRET_KEY, getSecretKey()); + dm.put(ApiConstants.S3_END_POINT, getEndPoint()); + dm.put(ApiConstants.S3_BUCKET_NAME, getBucketName()); + if (getHttpsFlag() != null) { + dm.put(ApiConstants.S3_HTTPS_FLAG, getHttpsFlag().toString()); + } + if (getConnectionTimeout() != null) { + dm.put(ApiConstants.S3_CONNECTION_TIMEOUT, getConnectionTimeout().toString()); + } + if (getMaxErrorRetry() != null) { + dm.put(ApiConstants.S3_MAX_ERROR_RETRY, getMaxErrorRetry().toString()); + } + if (getSocketTimeout() != null) { + dm.put(ApiConstants.S3_SOCKET_TIMEOUT, getSocketTimeout().toString()); + } try{ - ImageStore result = _storageService.discoverImageStore(cmd); + ImageStore result = _storageService.discoverImageStore(null, null, "S3", null, dm); ImageStoreResponse storeResponse = null; if (result != null ) { storeResponse = _responseGenerator.createImageStoreResponse(result); storeResponse.setResponseName(getCommandName()); storeResponse.setObjectName("secondarystorage"); - this.setResponseObject(storeResponse); + setResponseObject(storeResponse); } else { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add S3 secondary storage"); } @@ -149,35 +143,35 @@ public boolean equals(final Object thatObject) { final AddS3Cmd thatAddS3Cmd = (AddS3Cmd) thatObject; - if (this.httpsFlag != null ? !this.httpsFlag.equals(thatAddS3Cmd.httpsFlag) : thatAddS3Cmd.httpsFlag != null) { + if (httpsFlag != null ? !httpsFlag.equals(thatAddS3Cmd.httpsFlag) : thatAddS3Cmd.httpsFlag != null) { return false; } - if (this.accessKey != null ? !this.accessKey.equals(thatAddS3Cmd.accessKey) : thatAddS3Cmd.accessKey != null) { + if (accessKey != null ? !accessKey.equals(thatAddS3Cmd.accessKey) : thatAddS3Cmd.accessKey != null) { return false; } - if (this.connectionTimeout != null ? !this.connectionTimeout.equals(thatAddS3Cmd.connectionTimeout) : thatAddS3Cmd.connectionTimeout != null) { + if (connectionTimeout != null ? !connectionTimeout.equals(thatAddS3Cmd.connectionTimeout) : thatAddS3Cmd.connectionTimeout != null) { return false; } - if (this.endPoint != null ? !this.endPoint.equals(thatAddS3Cmd.endPoint) : thatAddS3Cmd.endPoint != null) { + if (endPoint != null ? !endPoint.equals(thatAddS3Cmd.endPoint) : thatAddS3Cmd.endPoint != null) { return false; } - if (this.maxErrorRetry != null ? !this.maxErrorRetry.equals(thatAddS3Cmd.maxErrorRetry) : thatAddS3Cmd.maxErrorRetry != null) { + if (maxErrorRetry != null ? !maxErrorRetry.equals(thatAddS3Cmd.maxErrorRetry) : thatAddS3Cmd.maxErrorRetry != null) { return false; } - if (this.secretKey != null ? !this.secretKey.equals(thatAddS3Cmd.secretKey) : thatAddS3Cmd.secretKey != null) { + if (secretKey != null ? !secretKey.equals(thatAddS3Cmd.secretKey) : thatAddS3Cmd.secretKey != null) { return false; } - if (this.socketTimeout != null ? !this.socketTimeout.equals(thatAddS3Cmd.socketTimeout) : thatAddS3Cmd.socketTimeout != null) { + if (socketTimeout != null ? !socketTimeout.equals(thatAddS3Cmd.socketTimeout) : thatAddS3Cmd.socketTimeout != null) { return false; } - if (this.bucketName != null ? !this.bucketName.equals(thatAddS3Cmd.bucketName) : thatAddS3Cmd.bucketName != null) { + if (bucketName != null ? !bucketName.equals(thatAddS3Cmd.bucketName) : thatAddS3Cmd.bucketName != null) { return false; } @@ -188,14 +182,14 @@ public boolean equals(final Object thatObject) { @Override public int hashCode() { - int result = this.accessKey != null ? this.accessKey.hashCode() : 0; - result = 31 * result + (this.secretKey != null ? this.secretKey.hashCode() : 0); - result = 31 * result + (this.endPoint != null ? this.endPoint.hashCode() : 0); - result = 31 * result + (this.bucketName != null ? this.bucketName.hashCode() : 0); - result = 31 * result + (this.httpsFlag != null && this.httpsFlag == true ? 1 : 0); - result = 31 * result + (this.connectionTimeout != null ? this.connectionTimeout.hashCode() : 0); - result = 31 * result + (this.maxErrorRetry != null ? this.maxErrorRetry.hashCode() : 0); - result = 31 * result + (this.socketTimeout != null ? this.socketTimeout.hashCode() : 0); + int result = accessKey != null ? accessKey.hashCode() : 0; + result = 31 * result + (secretKey != null ? secretKey.hashCode() : 0); + result = 31 * result + (endPoint != null ? endPoint.hashCode() : 0); + result = 31 * result + (bucketName != null ? bucketName.hashCode() : 0); + result = 31 * result + (httpsFlag != null && httpsFlag == true ? 1 : 0); + result = 31 * result + (connectionTimeout != null ? connectionTimeout.hashCode() : 0); + result = 31 * result + (maxErrorRetry != null ? maxErrorRetry.hashCode() : 0); + result = 31 * result + (socketTimeout != null ? socketTimeout.hashCode() : 0); return result; @@ -212,35 +206,35 @@ public long getEntityOwnerId() { } public String getAccessKey() { - return this.accessKey; + return accessKey; } public String getSecretKey() { - return this.secretKey; + return secretKey; } public String getEndPoint() { - return this.endPoint; + return endPoint; } public String getBucketName() { - return this.bucketName; + return bucketName; } public Boolean getHttpsFlag() { - return this.httpsFlag; + return httpsFlag; } public Integer getConnectionTimeout() { - return this.connectionTimeout; + return connectionTimeout; } public Integer getMaxErrorRetry() { - return this.maxErrorRetry; + return maxErrorRetry; } public Integer getSocketTimeout() { - return this.socketTimeout; + return socketTimeout; } } diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/PrepareSecondaryStorageForMigrationCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/PrepareSecondaryStorageForMigrationCmd.java deleted file mode 100644 index d0c995a64f1a..000000000000 --- a/api/src/org/apache/cloudstack/api/command/admin/storage/PrepareSecondaryStorageForMigrationCmd.java +++ /dev/null @@ -1,109 +0,0 @@ -// 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.api.command.admin.storage; - -import org.apache.log4j.Logger; - -import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.ApiCommandJobType; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseAsyncCmd; -import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.response.ImageStoreResponse; -import org.apache.cloudstack.context.CallContext; - -import com.cloud.event.EventTypes; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.storage.ImageStore; -import com.cloud.user.Account; - -@APICommand(name = "prepareSecondaryStorageForMigration", description = "Prepare a NFS secondary storage to migrate to use object store like S3", responseObject = ImageStoreResponse.class) -public class PrepareSecondaryStorageForMigrationCmd extends BaseAsyncCmd { - public static final Logger s_logger = Logger.getLogger(PrepareSecondaryStorageForMigrationCmd.class.getName()); - private static final String s_name = "preparesecondarystorageformigrationresponse"; - - ///////////////////////////////////////////////////// - //////////////// API parameters ///////////////////// - ///////////////////////////////////////////////////// - - @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = ImageStoreResponse.class, - required = true, description = "Secondary image store ID") - private Long id; - - ///////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// - - public Long getId() { - return id; - } - - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// - - @Override - public String getCommandName() { - return s_name; - } - - @Override - public ApiCommandJobType getInstanceType() { - return ApiCommandJobType.ImageStore; - } - - @Override - public Long getInstanceId() { - return getId(); - } - - @Override - public long getEntityOwnerId() { - Account account = CallContext.current().getCallingAccount(); - if (account != null) { - return account.getId(); - } - - return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked - } - - @Override - public String getEventType() { - return EventTypes.EVENT_MIGRATE_PREPARE_SECONDARY_STORAGE; - } - - @Override - public String getEventDescription() { - return "preparing secondary storage: " + getId() + " for object store migration"; - } - - @Override - public void execute() throws ResourceUnavailableException, InsufficientCapacityException{ - ImageStore result = _storageService.prepareSecondaryStorageForObjectStoreMigration(getId()); - if (result != null){ - ImageStoreResponse response = _responseGenerator.createImageStoreResponse(result); - response.setResponseName(getCommandName()); - response.setResponseName("secondarystorage"); - setResponseObject(response); - } else { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to prepare secondary storage for object store migration"); - } - } -} diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/UpdateCloudToUseObjectStoreCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/UpdateCloudToUseObjectStoreCmd.java new file mode 100644 index 000000000000..983a01c7fbe1 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/storage/UpdateCloudToUseObjectStoreCmd.java @@ -0,0 +1,142 @@ +// 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.api.command.admin.storage; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ImageStoreResponse; + +import com.cloud.exception.DiscoveryException; +import com.cloud.storage.ImageStore; +import com.cloud.user.Account; + +@APICommand(name = "updateCloudToUseObjectStore", description = "Migrate current NFS secondary storages to use object store.", responseObject = ImageStoreResponse.class, since = "4.3.0") +public class UpdateCloudToUseObjectStoreCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(UpdateCloudToUseObjectStoreCmd.class.getName()); + private static final String s_name = "updatecloudtouseobjectstoreresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, description="the name for the image store") + private String name; + + @Parameter(name=ApiConstants.URL, type=CommandType.STRING, description="the URL for the image store") + private String url; + + @Parameter(name=ApiConstants.PROVIDER, type=CommandType.STRING, + required=true, description="the image store provider name") + private String providerName; + + @Parameter(name=ApiConstants.DETAILS, type=CommandType.MAP, description="the details for the image store. Example: details[0].key=accesskey&details[0].value=s389ddssaa&details[1].key=secretkey&details[1].value=8dshfsss") + private Map details; + + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public String getUrl() { + return url; + } + + public String getName() { + return name; + } + + public Map getDetails() { + Map detailsMap = null; + if (details != null && !details.isEmpty()) { + detailsMap = new HashMap(); + Collection props = details.values(); + Iterator iter = props.iterator(); + while (iter.hasNext()) { + HashMap detail = (HashMap) iter.next(); + String key = detail.get("key"); + String value = detail.get("value"); + detailsMap.put(key, value); + } + } + return detailsMap; + } + + public String getProviderName() { + return providerName; + } + + public void setUrl(String url) { + this.url = url; + } + + + public void setProviderName(String providerName) { + this.providerName = providerName; + } + + public void setDetails(Map details) { + this.details = details; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute(){ + try{ + ImageStore result = _storageService.migrateToObjectStore(getName(), getUrl(), getProviderName(), getDetails()); + ImageStoreResponse storeResponse = null; + if (result != null ) { + storeResponse = _responseGenerator.createImageStoreResponse(result); + storeResponse.setResponseName(getCommandName()); + storeResponse.setObjectName("imagestore"); + setResponseObject(storeResponse); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add secondary storage"); + } + } catch (DiscoveryException ex) { + s_logger.warn("Exception: ", ex); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); + } + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/swift/AddSwiftCmd.java b/api/src/org/apache/cloudstack/api/command/admin/swift/AddSwiftCmd.java index ea22429f0935..ec6e88cc19e4 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/swift/AddSwiftCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/swift/AddSwiftCmd.java @@ -19,15 +19,15 @@ import java.util.HashMap; import java.util.Map; +import org.apache.log4j.Logger; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd; import org.apache.cloudstack.api.response.ImageStoreResponse; -import org.apache.log4j.Logger; import com.cloud.exception.DiscoveryException; import com.cloud.storage.ImageStore; @@ -89,28 +89,20 @@ public long getEntityOwnerId() { } @Override - public void execute(){ - AddImageStoreCmd cmd = new AddImageStoreCmd() { - @Override - public Map getDetails() { - Map dm = new HashMap(); - dm.put(ApiConstants.ACCOUNT, getAccount()); - dm.put(ApiConstants.USERNAME, getUsername()); - dm.put(ApiConstants.KEY, getKey()); - return dm; - } - }; - cmd.setProviderName("Swift"); - cmd.setUrl(this.getUrl()); + public void execute() { + Map dm = new HashMap(); + dm.put(ApiConstants.ACCOUNT, getAccount()); + dm.put(ApiConstants.USERNAME, getUsername()); + dm.put(ApiConstants.KEY, getKey()); try{ - ImageStore result = _storageService.discoverImageStore(cmd); + ImageStore result = _storageService.discoverImageStore(null, getUrl(), "Swift", null, dm); ImageStoreResponse storeResponse = null; if (result != null ) { storeResponse = _responseGenerator.createImageStoreResponse(result); storeResponse.setResponseName(getCommandName()); storeResponse.setObjectName("secondarystorage"); - this.setResponseObject(storeResponse); + setResponseObject(storeResponse); } else { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Swift secondary storage"); } diff --git a/api/src/org/apache/cloudstack/api/command/admin/systemvm/ScaleSystemVMCmd.java b/api/src/org/apache/cloudstack/api/command/admin/systemvm/ScaleSystemVMCmd.java index 212f129aca4e..9d2f06bd5d5e 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/systemvm/ScaleSystemVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/systemvm/ScaleSystemVMCmd.java @@ -39,6 +39,11 @@ import com.cloud.user.Account; import com.cloud.vm.VirtualMachine; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + @APICommand(name = "scaleSystemVm", responseObject=SystemVmResponse.class, description="Scale the service offering for a system vm (console proxy or secondary storage). " + "The system vm must be in a \"Stopped\" state for " + "this command to take effect.") @@ -58,6 +63,9 @@ public class ScaleSystemVMCmd extends BaseAsyncCmd { required=true, description="the service offering ID to apply to the system vm") private Long serviceOfferingId; + @Parameter(name=ApiConstants.DETAILS, type = CommandType.MAP, description = "name value pairs of custom parameters for cpu, memory and cpunumber. example details[i].name=value") + private Map details; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -70,6 +78,21 @@ public Long getServiceOfferingId() { return serviceOfferingId; } + public Map getDetails() { + Map customparameterMap = new HashMap(); + if (details != null && details.size() !=0){ + Collection parameterCollection = details.values(); + Iterator iter = parameterCollection.iterator(); + while (iter.hasNext()) { + HashMap value = (HashMap) iter.next(); + for (String key : value.keySet()) { + customparameterMap.put(key, value.get(key)); + } + } + } + return customparameterMap; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/admin/systemvm/UpgradeSystemVMCmd.java b/api/src/org/apache/cloudstack/api/command/admin/systemvm/UpgradeSystemVMCmd.java index 738b15dff1eb..f44abd80c8a2 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/systemvm/UpgradeSystemVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/systemvm/UpgradeSystemVMCmd.java @@ -34,6 +34,11 @@ import com.cloud.user.Account; import com.cloud.vm.VirtualMachine; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + @APICommand(name = "changeServiceForSystemVm", responseObject=SystemVmResponse.class, description="Changes the service offering for a system vm (console proxy or secondary storage). " + "The system vm must be in a \"Stopped\" state for " + "this command to take effect.") @@ -53,6 +58,9 @@ public class UpgradeSystemVMCmd extends BaseCmd { required=true, description="the service offering ID to apply to the system vm") private Long serviceOfferingId; + @Parameter(name=ApiConstants.DETAILS, type = CommandType.MAP, description = "name value pairs of custom parameters for cpu, memory and cpunumber. example details[i].name=value") + private Map details; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -65,6 +73,21 @@ public Long getServiceOfferingId() { return serviceOfferingId; } + public Map getDetails() { + Map customparameterMap = new HashMap(); + if (details != null && details.size() !=0){ + Collection parameterCollection = details.values(); + Iterator iter = parameterCollection.iterator(); + while (iter.hasNext()) { + HashMap value = (HashMap) iter.next(); + for (String key : value.keySet()) { + customparameterMap.put(key, value.get(key)); + } + } + } + return customparameterMap; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/admin/usage/AddTrafficTypeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/usage/AddTrafficTypeCmd.java index f6e4319fdee4..9cb713bc121d 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/usage/AddTrafficTypeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/usage/AddTrafficTypeCmd.java @@ -66,6 +66,9 @@ public class AddTrafficTypeCmd extends BaseAsyncCreateCmd { @Parameter(name=ApiConstants.VLAN, type=CommandType.STRING, description="The VLAN id to be used for Management traffic by VMware host") private String vlan; + @Parameter(name=ApiConstants.ISOLATION_METHOD, type=CommandType.STRING, description="Used if physical network has multiple isolation types and traffic type is public. Choose which isolation method. Valid options currently 'vlan' or 'vxlan', defaults to 'vlan'.") + private String isolationMethod; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -108,6 +111,14 @@ public String getVlan() { return vlan; } + public String getIsolationMethod() { + if (isolationMethod != null && !isolationMethod.isEmpty()) { + return isolationMethod; + } else { + return "vlan"; + } + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -137,7 +148,7 @@ public void execute(){ @Override public void create() throws ResourceAllocationException { - PhysicalNetworkTrafficType result = _networkService.addTrafficTypeToPhysicalNetwork(getPhysicalNetworkId(), getTrafficType(), getXenLabel(), getKvmLabel(), getVmwareLabel(), getSimulatorLabel(), getVlan(), getHypervLabel()); + PhysicalNetworkTrafficType result = _networkService.addTrafficTypeToPhysicalNetwork(getPhysicalNetworkId(), getTrafficType(), getIsolationMethod(), getXenLabel(), getKvmLabel(), getVmwareLabel(), getSimulatorLabel(), getVlan(), getHypervLabel()); if (result != null) { setEntityId(result.getId()); setEntityUuid(result.getUuid()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java index 541da1ece502..82f594a87ca3 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java @@ -144,6 +144,9 @@ public String getStartIp() { } public String getVlan() { + if (vlan == null || vlan.isEmpty()) { + vlan = "untagged"; + } return vlan; } diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java index 40ba715bb4e0..fb78f335d01f 100644 --- a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java @@ -78,7 +78,7 @@ public void execute(){ ListResponse response = _queryService.listAffinityGroups(id, affinityGroupName, affinityGroupType, virtualMachineId, this.getAccountName(), this.getDomainId(), this.isRecursive(), - this.listAll(), this.getStartIndex(), this.getPageSizeVal()); + this.listAll(), this.getStartIndex(), this.getPageSizeVal(), this.getKeyword()); response.setResponseName(getCommandName()); this.setResponseObject(response); diff --git a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java index 90e0d416de08..2176bc023323 100644 --- a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java @@ -54,6 +54,7 @@ public void execute(){ response.setAllowUsersCreateProjects((Boolean)capabilities.get("allowusercreateprojects")); response.setDiskOffMaxSize((Long)capabilities.get("customDiskOffMaxSize")); response.setRegionSecondaryEnabled((Boolean)capabilities.get("regionSecondaryEnabled")); + response.setKVMSnapshotEnabled((Boolean)capabilities.get("KVMSnapshotEnabled")); if (capabilities.containsKey("apiLimitInterval")) { response.setApiLimitInterval((Integer) capabilities.get("apiLimitInterval")); } diff --git a/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java index ff63d088e963..2e8f662ec76a 100644 --- a/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java @@ -18,6 +18,7 @@ import java.util.List; +import com.cloud.utils.net.NetUtils; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandJobType; import org.apache.cloudstack.api.ApiConstants; @@ -317,7 +318,7 @@ public void create() { Ip privateIp = getVmSecondaryIp(); if (privateIp != null) { - if ( !privateIp.isIp4()) { + if (!NetUtils.isValidIp(privateIp.toString())) { throw new InvalidParameterValueException("Invalid vm ip address"); } } 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 c2aee55f51ef..ae1a2dd69a21 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.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 FirewallRule.TrafficType getTrafficType () { 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 9fd4e450ea69..7e96e0b2fab2 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.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 Long getIpAddressId() { public Long getId() { return id; } + + public Long getNetworkId() { + return networkId; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java b/api/src/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java index c3f558bd2493..9b4b414cf531 100644 --- a/api/src/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java @@ -79,6 +79,9 @@ public class ListIsosCmd extends BaseListTaggedResourcesCmd { description="the ID of the zone") private Long zoneId; + @Parameter(name=ApiConstants.SHOW_REMOVED, type=CommandType.BOOLEAN, description="show removed ISOs as well") + private Boolean showRemoved; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -116,6 +119,10 @@ public Long getZoneId() { return zoneId; } + public Boolean getShowRemoved() { + return (showRemoved != null ? showRemoved : false); + } + public boolean listInReadyState() { Account account = CallContext.current().getCallingAccount(); // It is account specific if account is admin type and domainId and accountName are not null diff --git a/api/src/org/apache/cloudstack/api/command/user/network/DeleteNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/DeleteNetworkCmd.java index 6e1b380448b4..4a749a49f239 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/DeleteNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/DeleteNetworkCmd.java @@ -46,6 +46,9 @@ public class DeleteNetworkCmd extends BaseAsyncCmd{ required=true, description="the ID of the network") private Long id; + @Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, required = false, description = "Force delete a network." + + " Network will be marked as 'Destroy' even when commands to shutdown and cleanup to the backend fails.") + private Boolean forced; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -55,6 +58,9 @@ public Long getId() { return id; } + public boolean isForced() { + return (forced != null) ? forced : false; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -68,7 +74,7 @@ public String getCommandName() { @Override public void execute(){ CallContext.current().setEventDetails("Network Id: " + id); - boolean result = _networkService.deleteNetwork(id); + boolean result = _networkService.deleteNetwork(id, isForced()); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/org/apache/cloudstack/api/command/user/network/ListNetworkACLListsCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/ListNetworkACLListsCmd.java index bb825d9f9f97..abd614368a0f 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/ListNetworkACLListsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/ListNetworkACLListsCmd.java @@ -21,6 +21,7 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.NetworkACLResponse; @@ -32,7 +33,7 @@ import java.util.List; @APICommand(name = "listNetworkACLLists", description="Lists all network ACLs", responseObject=NetworkACLResponse.class) -public class ListNetworkACLListsCmd extends BaseListCmd { +public class ListNetworkACLListsCmd extends BaseListProjectAndAccountResourcesCmd { public static final Logger s_logger = Logger.getLogger(ListNetworkACLListsCmd.class.getName()); private static final String s_name = "listnetworkacllistsresponse"; @@ -87,7 +88,7 @@ public String getCommandName() { @Override public void execute(){ - Pair,Integer> result = _networkACLService.listNetworkACLs(getId(), getName(), getNetworkId(), getVpcId()); + Pair,Integer> result = _networkACLService.listNetworkACLs(this); ListResponse response = new ListResponse(); List aclResponses = new ArrayList(); diff --git a/api/src/org/apache/cloudstack/api/command/user/network/ListNetworkACLsCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/ListNetworkACLsCmd.java index df21a722408c..b93bf62b11fa 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/ListNetworkACLsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/ListNetworkACLsCmd.java @@ -39,7 +39,7 @@ public class ListNetworkACLsCmd extends BaseListTaggedResourcesCmd { ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = FirewallRuleResponse.class, + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = NetworkACLItemResponse.class, description="Lists network ACL Item with the specified ID") private Long id; diff --git a/api/src/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java index afce0926e4d1..97cfbae0b4ba 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java @@ -31,8 +31,9 @@ import org.apache.log4j.Logger; import com.cloud.network.Network; +import com.cloud.utils.Pair; -@APICommand(name = "listNetworks", description="Lists all available networks.", responseObject=NetworkResponse.class) +@APICommand(name = "listNetworks", description = "Lists all available networks.", responseObject = NetworkResponse.class) public class ListNetworksCmd extends BaseListTaggedResourcesCmd { public static final Logger s_logger = Logger.getLogger(ListNetworksCmd.class.getName()); private static final String _name = "listnetworksresponse"; @@ -40,48 +41,43 @@ public class ListNetworksCmd extends BaseListTaggedResourcesCmd { ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = NetworkResponse.class, - description="list networks by id") + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = NetworkResponse.class, description = "list networks by id") private Long id; - @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class, - description="the Zone ID of the network") + @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, description = "the Zone ID of the network") private Long zoneId; - @Parameter(name=ApiConstants.TYPE, type=CommandType.STRING, description="the type of the network. Supported values are: Isolated and Shared") + @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "the type of the network. Supported values are: Isolated and Shared") private String guestIpType; - @Parameter(name=ApiConstants.IS_SYSTEM, type=CommandType.BOOLEAN, description="true if network is system, false otherwise") + @Parameter(name = ApiConstants.IS_SYSTEM, type = CommandType.BOOLEAN, description = "true if network is system, false otherwise") private Boolean isSystem; - @Parameter(name=ApiConstants.ACL_TYPE, type=CommandType.STRING, description="list networks by ACL (access control list) type. Supported values are Account and Domain") + @Parameter(name = ApiConstants.ACL_TYPE, type = CommandType.STRING, description = "list networks by ACL (access control list) type. Supported values are Account and Domain") private String aclType; - @Parameter(name=ApiConstants.TRAFFIC_TYPE, type=CommandType.STRING, description="type of the traffic") + @Parameter(name = ApiConstants.TRAFFIC_TYPE, type = CommandType.STRING, description = "type of the traffic") private String trafficType; - @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType = PhysicalNetworkResponse.class, - description="list networks by physical network id") + @Parameter(name = ApiConstants.PHYSICAL_NETWORK_ID, type = CommandType.UUID, entityType = PhysicalNetworkResponse.class, description = "list networks by physical network id") private Long physicalNetworkId; - @Parameter(name=ApiConstants.SUPPORTED_SERVICES, type=CommandType.LIST, collectionType=CommandType.STRING, description="list networks supporting certain services") + @Parameter(name = ApiConstants.SUPPORTED_SERVICES, type = CommandType.LIST, collectionType = CommandType.STRING, description = "list networks supporting certain services") private List supportedServices; - @Parameter(name=ApiConstants.RESTART_REQUIRED, type=CommandType.BOOLEAN, description="list networks by restartRequired") - + @Parameter(name = ApiConstants.RESTART_REQUIRED, type = CommandType.BOOLEAN, description = "list networks by restartRequired") private Boolean restartRequired; - @Parameter(name=ApiConstants.SPECIFY_IP_RANGES, type=CommandType.BOOLEAN, description="true if need to list only networks which support specifying ip ranges") + @Parameter(name = ApiConstants.SPECIFY_IP_RANGES, type = CommandType.BOOLEAN, description = "true if need to list only networks which support specifying ip ranges") private Boolean specifyIpRanges; - @Parameter(name=ApiConstants.VPC_ID, type=CommandType.UUID, entityType = VpcResponse.class, - description="List networks by VPC") + @Parameter(name = ApiConstants.VPC_ID, type = CommandType.UUID, entityType = VpcResponse.class, description = "List networks by VPC") private Long vpcId; - @Parameter(name=ApiConstants.CAN_USE_FOR_DEPLOY, type=CommandType.BOOLEAN, description="list networks available for vm deployment") + @Parameter(name = ApiConstants.CAN_USE_FOR_DEPLOY, type = CommandType.BOOLEAN, description = "list networks available for vm deployment") private Boolean canUseForDeploy; - @Parameter(name=ApiConstants.FOR_VPC, type=CommandType.BOOLEAN, description="the network belongs to vpc") + @Parameter(name = ApiConstants.FOR_VPC, type = CommandType.BOOLEAN, description = "the network belongs to vpc") private Boolean forVpc; ///////////////////////////////////////////////////// @@ -149,16 +145,16 @@ public String getCommandName() { } @Override - public void execute(){ - List networks = _networkService.searchForNetworks(this); + public void execute() { + Pair, Integer> networks = _networkService.searchForNetworks(this); ListResponse response = new ListResponse(); List networkResponses = new ArrayList(); - for (Network network : networks) { + for (Network network : networks.first()) { NetworkResponse networkResponse = _responseGenerator.createNetworkResponse(network); networkResponses.add(networkResponse); } - response.setResponses(networkResponses); + response.setResponses(networkResponses, networks.second()); response.setResponseName(getCommandName()); this.setResponseObject(response); } diff --git a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java index 57b227deef4c..fcc83e496e7a 100644 --- a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java @@ -70,7 +70,7 @@ public class CreateGlobalLoadBalancerRuleCmd extends BaseAsyncCreateCmd { @Parameter(name=ApiConstants.GSLB_SERVICE_DOMAIN_NAME, type = CommandType.STRING, required = true, description = "domain name for the GSLB service.") private String serviceDomainName; - @Parameter(name=ApiConstants.GSLB_SERVICE_TYPE, type = CommandType.STRING, required = true, description = "GSLB service type (tcp, udp)") + @Parameter(name = ApiConstants.GSLB_SERVICE_TYPE, type = CommandType.STRING, required = true, description = "GSLB service type (tcp, udp, http)") private String serviceType; ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/template/CopyTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/CopyTemplateCmd.java index a25bd65f9c2b..10c62643fe71 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/CopyTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/CopyTemplateCmd.java @@ -18,6 +18,8 @@ import java.util.List; +import org.apache.log4j.Logger; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandJobType; import org.apache.cloudstack.api.ApiConstants; @@ -26,12 +28,9 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.TemplateResponse; -import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.context.CallContext; -import org.apache.log4j.Logger; - import com.cloud.event.EventTypes; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.StorageUnavailableException; @@ -56,7 +55,7 @@ public class CopyTemplateCmd extends BaseAsyncCmd { private Long id; @Parameter(name=ApiConstants.SOURCE_ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class, - required=true, description="ID of the zone the template is currently hosted on.") + description = "ID of the zone the template is currently hosted on. If not specified and template is cross-zone, then we will sync this template to region wide image store") private Long sourceZoneId; @@ -110,10 +109,12 @@ public String getEventDescription() { return "copying template: " + getId() + " from zone: " + getSourceZoneId() + " to zone: " + getDestinationZoneId(); } + @Override public ApiCommandJobType getInstanceType() { return ApiCommandJobType.Template; } + @Override public Long getInstanceId() { return getId(); } @@ -132,7 +133,7 @@ public void execute() throws ResourceAllocationException{ } response.setResponseName(getCommandName()); - this.setResponseObject(response); + setResponseObject(response); } else { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to copy template"); } diff --git a/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java index 4b3490921254..b055bf243aba 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java @@ -70,6 +70,9 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd { @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class, description="list templates by zoneId") private Long zoneId; + + @Parameter(name=ApiConstants.SHOW_REMOVED, type=CommandType.BOOLEAN, description="show removed templates as well") + private Boolean showRemoved; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -94,6 +97,10 @@ public Long getZoneId() { return zoneId; } + public Boolean getShowRemoved() { + return (showRemoved != null ? showRemoved : false); + } + public boolean listInReadyState() { Account account = CallContext.current().getCallingAccount(); diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index 3643f91de6c8..c9f017218e83 100755 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -188,17 +188,11 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { @Parameter(name=ApiConstants.DISPLAY_VM, type=CommandType.BOOLEAN, since="4.2", description="an optional field, whether to the display the vm to the end user or not.") private Boolean displayVm; - @Parameter(name=ApiConstants.CPU_SPEED, type = CommandType.INTEGER, since="4.3", description = "optional field to specify the cpu speed when using dynamic compute offering.") - private Integer cpuSpeed; - - @Parameter(name=ApiConstants.MEMORY, type = CommandType.INTEGER, since="4.3", description = "optional field to specify the memory when using dynamic compute offering") - private Integer memory; - - @Parameter(name=ApiConstants.CPU_NUMBER, type=CommandType.INTEGER, since="4.3", description = "optional field to specify the number of cpu cores when using dynamic offering.") - private Integer cpuNumber; - - @Parameter(name=ApiConstants.ROOT_DISK_SIZE, type=CommandType.LONG, since="4.3", description = "optional field to specify the number of cpu cores when using dynamic offering.") - private Long rootdisksize; + @Parameter(name = ApiConstants.DETAILS, + type = CommandType.MAP, + since= "4.3", + description = "used to specify the custom parameters.") + private Map details; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -227,6 +221,21 @@ public Long getDomainId() { return domainId; } + public Map getDetails() { + Map customparameterMap = new HashMap(); + if (details != null && details.size() !=0){ + Collection parameterCollection = details.values(); + Iterator iter = parameterCollection.iterator(); + while (iter.hasNext()) { + HashMap value = (HashMap) iter.next(); + for (String key : value.keySet()) { + customparameterMap.put(key, value.get(key)); + } + } + } + return customparameterMap; + } + public String getGroup() { return group; } @@ -239,21 +248,6 @@ public Boolean getDisplayVm() { return displayVm; } - public Integer getMemory() { - return memory; - } - - public Integer getCpuSpeed() { - return cpuSpeed; - } - - public Integer getCpuNumber() { - return cpuNumber; - } - - public Long getRootdisksize() { - return rootdisksize; - } public List getSecurityGroupIdList() { if (securityGroupNameList != null && securityGroupIdList != null) { @@ -522,20 +516,26 @@ public void create() throws ResourceAllocationException{ if (getNetworkIds() != null) { throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); } else { - vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(), owner, name, - displayName, diskOfferingId, size, group, getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, getAffinityGroupIdList(), cpuSpeed, memory, cpuNumber, rootdisksize); + vm = + _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(), owner, name, displayName, + diskOfferingId, size, group, getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, + getAffinityGroupIdList(), getDetails()); } } else { - if (zone.isSecurityGroupEnabled()) { - vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(), - owner, name, displayName, diskOfferingId, size, group, getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, getAffinityGroupIdList(), cpuSpeed, memory, cpuNumber, rootdisksize ); + if (zone.isSecurityGroupEnabled()) { + vm = + _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(), owner, name, + displayName, diskOfferingId, size, group, getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, + keyboard, getAffinityGroupIdList(), getDetails()); } else { if (getSecurityGroupIdList() != null && !getSecurityGroupIdList().isEmpty()) { throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone"); } - vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName, - diskOfferingId, size, group, getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, getAffinityGroupIdList(), cpuSpeed, memory, cpuNumber, rootdisksize); + vm = + _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName, diskOfferingId, size, + group, getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, getAffinityGroupIdList(), + getDetails()); } } diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java index 408f69f39994..199cf2e772c5 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java @@ -39,7 +39,7 @@ import com.cloud.vm.Nic; import com.cloud.vm.NicSecondaryIp; -@APICommand(name = "removeIpFromNic", description="Assigns secondary IP to NIC.", responseObject=SuccessResponse.class) +@APICommand(name = "removeIpFromNic", description="Removes secondary IP from the NIC.", responseObject=SuccessResponse.class) public class RemoveIpFromVmNicCmd extends BaseAsyncCmd { public static final Logger s_logger = Logger.getLogger(RemoveIpFromVmNicCmd.class.getName()); private static final String s_name = "removeipfromnicresponse"; diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java index 44f55753545b..a9cdd1425fbf 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java @@ -25,11 +25,14 @@ import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.cloudstack.api.response.UserVmResponse; -import org.apache.cloudstack.context.CallContext; import org.apache.log4j.Logger; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; @APICommand(name = "scaleVirtualMachine", description="Scales the virtual machine to a new service offering.", responseObject=SuccessResponse.class) @@ -51,6 +54,9 @@ public class ScaleVMCmd extends BaseAsyncCmd { required=true, description="the ID of the service offering for the virtual machine") private Long serviceOfferingId; + @Parameter(name=ApiConstants.DETAILS,type = BaseCmd.CommandType.MAP, description = "name value pairs of custom parameters for cpu,memory and cpunumber. example details[i].name=value") + private Map details; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -63,6 +69,24 @@ public Long getServiceOfferingId() { return serviceOfferingId; } + //instead of reading a map directly we are using collections. + //it is because details.values() cannot be cast to a map. + //it gives a exception + public Map getDetails() { + Map customparameterMap = new HashMap(); + if (details != null && details.size() !=0){ + Collection parameterCollection = details.values(); + Iterator iter = parameterCollection.iterator(); + while (iter.hasNext()) { + HashMap value = (HashMap) iter.next(); + for (String key : value.keySet()) { + customparameterMap.put(key, value.get(key)); + } + } + } + return customparameterMap; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/UpgradeVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/UpgradeVMCmd.java index 161131b39558..6b875809f58c 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/UpgradeVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/UpgradeVMCmd.java @@ -34,6 +34,11 @@ import com.cloud.user.Account; import com.cloud.uservm.UserVm; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + @APICommand(name = "changeServiceForVirtualMachine", responseObject=UserVmResponse.class, description="Changes the service offering for a virtual machine. " + "The virtual machine must be in a \"Stopped\" state for " + "this command to take effect.") @@ -53,6 +58,9 @@ public class UpgradeVMCmd extends BaseCmd { required=true, description="the service offering ID to apply to the virtual machine") private Long serviceOfferingId; + @Parameter(name=ApiConstants.DETAILS, type = CommandType.MAP, description = "name value pairs of custom parameters for cpu, memory and cpunumber. example details[i].name=value") + private Map details; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -65,6 +73,21 @@ public Long getServiceOfferingId() { return serviceOfferingId; } + public Map getDetails() { + Map customparameterMap = new HashMap(); + if (details != null && details.size() !=0){ + Collection parameterCollection = details.values(); + Iterator iter = parameterCollection.iterator(); + while (iter.hasNext()) { + HashMap value = (HashMap) iter.next(); + for (String key : value.keySet()) { + customparameterMap.put(key, value.get(key)); + } + } + } + return customparameterMap; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java index e5c7a51b8d2b..5dd14ac917a4 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java @@ -20,19 +20,18 @@ import org.apache.cloudstack.api.ApiCommandJobType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseAsyncCreateCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ProjectResponse; import org.apache.cloudstack.api.response.SnapshotResponse; +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.log4j.Logger; - +import org.apache.cloudstack.api.BaseAsyncCreateCmd; import com.cloud.event.EventTypes; import com.cloud.exception.ResourceAllocationException; import com.cloud.storage.Snapshot; @@ -86,6 +85,9 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd { @Parameter(name=ApiConstants.DISPLAY_VOLUME, type=CommandType.BOOLEAN, description="an optional field, whether to display the volume to the end user or not.") private Boolean displayVolume; + @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, entityType = UserVmResponse.class, description = "the ID of the virtual machine; to be used with snapshot Id, VM to which the volume gets attached after creation") + private Long virtualMachineId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -135,6 +137,10 @@ public Boolean getDisplayVolume() { return displayVolume; } + public Long getVirtualMachineId() { + return virtualMachineId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java index 6e86ba086d66..ebed1ca9d045 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java @@ -16,8 +16,6 @@ // under the License. package org.apache.cloudstack.api.command.user.vpc; -import org.apache.log4j.Logger; - import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -30,6 +28,7 @@ import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; @@ -38,54 +37,59 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.vpc.Vpc; -@APICommand(name = "createVPC", description="Creates a VPC", responseObject=VpcResponse.class) -public class CreateVPCCmd extends BaseAsyncCreateCmd{ +@APICommand(name = "createVPC", description = "Creates a VPC", responseObject = VpcResponse.class) +public class CreateVPCCmd extends BaseAsyncCreateCmd { public static final Logger s_logger = Logger.getLogger(CreateVPCCmd.class.getName()); private static final String s_name = "createvpcresponse"; - ///////////////////////////////////////////////////// - //////////////// API parameters ///////////////////// - ///////////////////////////////////////////////////// + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// - @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="the account associated with the VPC. " + + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "the account associated with the VPC. " + "Must be used with the domainId parameter.") private String accountName; - @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.UUID, entityType=DomainResponse.class, - description="the domain ID associated with the VPC. " + - "If used with the account parameter returns the VPC associated with the account for the specified domain.") + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, + description = "the domain ID associated with the VPC. " + + "If used with the account parameter returns the VPC associated with the account for the specified domain.") private Long domainId; - @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.UUID, entityType=ProjectResponse.class, - description="create VPC for the project") + @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, + description = "create VPC for the project") private Long projectId; - @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType=ZoneResponse.class, - required=true, description="the ID of the availability zone") + @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, + required = true, description = "the ID of the availability zone") private Long zoneId; - @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, required=true, description="the name of the VPC") + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "the name of the VPC") private String vpcName; - @Parameter(name=ApiConstants.DISPLAY_TEXT, type=CommandType.STRING, required=true, description="the display text of " + + @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, required = true, description = "the display text of " + "the VPC") private String displayText; - @Parameter(name=ApiConstants.CIDR, type=CommandType.STRING, required=true, description="the cidr of the VPC. All VPC " + + @Parameter(name = ApiConstants.CIDR, type = CommandType.STRING, required = true, description = "the cidr of the VPC. All VPC " + "guest networks' cidrs should be within this CIDR") private String cidr; - @Parameter(name=ApiConstants.VPC_OFF_ID, type=CommandType.UUID, entityType=VpcOfferingResponse.class, - required=true, description="the ID of the VPC offering") + @Parameter(name = ApiConstants.VPC_OFF_ID, type = CommandType.UUID, entityType = VpcOfferingResponse.class, + required = true, description = "the ID of the VPC offering") private Long vpcOffering; - @Parameter(name=ApiConstants.NETWORK_DOMAIN, type=CommandType.STRING, - description="VPC network domain. All networks inside the VPC will belong to this domain") + @Parameter(name = ApiConstants.NETWORK_DOMAIN, type = CommandType.STRING, + description = "VPC network domain. All networks inside the VPC will belong to this domain") private String networkDomain; - ///////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// + @Parameter(name = ApiConstants.START, type = CommandType.BOOLEAN, + description = "If set to false, the VPC won't start (VPC VR will not get allocated) until its first network gets implemented. " + + "True by default.", since = "4.3") + private Boolean start; + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// public String getAccountName() { return accountName; @@ -119,6 +123,13 @@ public String getNetworkDomain() { return networkDomain; } + public boolean isStart() { + if (start != null) { + return start; + } + return true; + } + @Override public void create() throws ResourceAllocationException { Vpc vpc = _vpcService.createVpc(getZoneId(), getVpcOffering(), getEntityOwnerId(), getVpcName(), getDisplayText(), @@ -134,10 +145,14 @@ public void create() throws ResourceAllocationException { @Override public void execute() { Vpc vpc = null; + boolean success = true; try { - if (_vpcService.startVpc(getEntityId(), true)) { - vpc = _entityMgr.findById(Vpc.class, getEntityId()); - } + if (isStart()) { + success = _vpcService.startVpc(getEntityId(), true); + } else { + s_logger.debug("Not starting VPC as " + ApiConstants.START + "=false was passed to the API"); + } + vpc = _entityMgr.findById(Vpc.class, getEntityId()); } catch (ResourceUnavailableException ex) { s_logger.warn("Exception: ", ex); throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage()); @@ -150,7 +165,7 @@ public void execute() { throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage()); } - if (vpc != null) { + if (vpc != null && success) { VpcResponse response = _responseGenerator.createVpcResponse(vpc); response.setResponseName(getCommandName()); setResponseObject(response); @@ -159,16 +174,14 @@ public void execute() { } } - @Override public String getEventType() { return EventTypes.EVENT_VPC_CREATE; } - @Override public String getEventDescription() { - return "creating VPC. Id: " + getEntityId(); + return "creating VPC. Id: " + getEntityId(); } @Override 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 12ee95ba5f4f..3b4d6cdb2a0c 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.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/AlertResponse.java b/api/src/org/apache/cloudstack/api/response/AlertResponse.java index f3755e58d46d..89de605fcf3f 100644 --- a/api/src/org/apache/cloudstack/api/response/AlertResponse.java +++ b/api/src/org/apache/cloudstack/api/response/AlertResponse.java @@ -41,6 +41,9 @@ public class AlertResponse extends BaseResponse { "DOMAIN_ROUTER_MIGRATE = 14, CONSOLE_PROXY_MIGRATE = 15, USERVM_MIGRATE = 16, VLAN = 17, SSVM = 18, " + "USAGE_SERVER_RESULT = 19") private Short alertType; + + @SerializedName(ApiConstants.NAME) @Param(description="the name of the alert", since="4.3") + private String alertName; @SerializedName(ApiConstants.DESCRIPTION) @Param(description="description of the alert") private String description; @@ -63,4 +66,8 @@ public void setDescription(String description) { public void setLastSent(Date lastSent) { this.lastSent = lastSent; } + + public void setName(String name) { + this.alertName = name; + } } diff --git a/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java b/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java index 2189ae0a3ec1..3ce31b55cf07 100644 --- a/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java +++ b/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java @@ -46,10 +46,12 @@ public class CapabilitiesResponse extends BaseResponse { @SerializedName(ApiConstants.CUSTOM_DISK_OFF_MAX_SIZE) @Param(description="maximum size that can be specified when " + "create disk from disk offering with custom size") private Long diskOffMaxSize; - @SerializedName("regionsecondaryenabled") @Param(description = "true if region wide secondary is enabled, false otherwise") private boolean regionSecondaryEnabled; + @SerializedName("kvmsnapshotenabled") @Param(description = "true if snapshot is supported for KVM host, false otherwise") + private boolean KVMSnapshotEnabled; + @SerializedName("apilimitinterval") @Param(description="time interval (in seconds) to reset api count") private Integer apiLimitInterval; @@ -89,6 +91,10 @@ public void setRegionSecondaryEnabled(boolean regionSecondaryEnabled){ this.regionSecondaryEnabled = regionSecondaryEnabled; } + public void setKVMSnapshotEnabled(boolean KVMSnapshotEnabled) { + this.KVMSnapshotEnabled = KVMSnapshotEnabled; + } + public void setApiLimitInterval(Integer apiLimitInterval) { this.apiLimitInterval = apiLimitInterval; } diff --git a/api/src/org/apache/cloudstack/api/response/FirewallRuleResponse.java b/api/src/org/apache/cloudstack/api/response/FirewallRuleResponse.java index 787410a24c5f..20ea407e2b7e 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 void setCidrList(String cidrs) { 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/LoadBalancerResponse.java b/api/src/org/apache/cloudstack/api/response/LoadBalancerResponse.java index 0f180970fc7c..39650d3feaac 100644 --- a/api/src/org/apache/cloudstack/api/response/LoadBalancerResponse.java +++ b/api/src/org/apache/cloudstack/api/response/LoadBalancerResponse.java @@ -91,6 +91,11 @@ public class LoadBalancerResponse extends BaseResponse implements ControlledEnti @Param(description = "the id of the zone the rule belongs to") private String zoneId; + @SerializedName(ApiConstants.PROTOCOL) + @Param(description = "the protocol of the loadbalanacer rule") + private String lbProtocol; + + @SerializedName(ApiConstants.TAGS) @Param(description="the list of resource tags associated with load balancer", responseObject = ResourceTagResponse.class) private List tags; @@ -170,4 +175,7 @@ public void setNetworkId(String networkId) { this.networkId = networkId; } + public void setLbProtocol(String lbProtocol) { + this.lbProtocol = lbProtocol; + } } diff --git a/api/src/org/apache/cloudstack/api/response/ResourceTagResponse.java b/api/src/org/apache/cloudstack/api/response/ResourceTagResponse.java index 47b06250a2c4..00db1b5f5fd4 100644 --- a/api/src/org/apache/cloudstack/api/response/ResourceTagResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ResourceTagResponse.java @@ -101,4 +101,35 @@ public void setProjectName(String projectName) { public void setCustomer(String customer) { this.customer = customer; } + + public String getKey() { + return this.key; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + String key = this.getKey(); + result = prime * result + ((key == null) ? 0 : key.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ResourceTagResponse other = (ResourceTagResponse) obj; + String key = this.getKey(); + if (key == null) { + if (other.getKey() != null) + return false; + } else if (!key.equals(other.getKey())) + return false; + return true; + } } diff --git a/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java b/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java index e305ee95e702..1e12a670e4fa 100644 --- a/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java @@ -39,13 +39,13 @@ public class ServiceOfferingResponse extends BaseResponse { private String displayText; @SerializedName("cpunumber") @Param(description="the number of CPU") - private int cpuNumber; + private Integer cpuNumber; @SerializedName("cpuspeed") @Param(description="the clock rate CPU speed in Mhz") - private int cpuSpeed; + private Integer cpuSpeed; @SerializedName("memory") @Param(description="the memory in MB") - private int memory; + private Integer memory; @SerializedName("created") @Param(description="the date this service offering was created") private Date created; @@ -104,6 +104,10 @@ public class ServiceOfferingResponse extends BaseResponse { @SerializedName(ApiConstants.SERVICE_OFFERING_DETAILS) @Param(description = "additional key/value details tied with this service offering", since = "4.2.0") private Map details; + + @SerializedName("iscustomized") + @Param(description = "is true if the offering is customized", since = "4.3.0") + private Boolean isCustomized; public ServiceOfferingResponse(){ @@ -164,7 +168,7 @@ public int getCpuNumber() { return cpuNumber; } - public void setCpuNumber(int cpuNumber) { + public void setCpuNumber(Integer cpuNumber) { this.cpuNumber = cpuNumber; } @@ -172,7 +176,7 @@ public int getCpuSpeed() { return cpuSpeed; } - public void setCpuSpeed(int cpuSpeed) { + public void setCpuSpeed(Integer cpuSpeed) { this.cpuSpeed = cpuSpeed; } @@ -180,7 +184,7 @@ public int getMemory() { return memory; } - public void setMemory(int memory) { + public void setMemory(Integer memory) { this.memory = memory; } @@ -288,4 +292,9 @@ public void setDetails(Map details) { this.details = details; } + public void setIscutomized(boolean iscutomized) { + this.isCustomized = iscutomized; + + } + } diff --git a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java index 7321d98b4769..1c943774e415 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.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/api/src/org/apache/cloudstack/api/response/VolumeResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java index 56c007f2d69d..ec33ff88f963 100644 --- a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java +++ b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java @@ -193,6 +193,10 @@ public class VolumeResponse extends BaseResponse implements ControlledViewEntity @Param(description = "id of the primary storage hosting the disk volume; returned to admin user only", since="4.3") private String storagePoolId; + @SerializedName(ApiConstants.SNAPSHOT_QUIESCEVM) + @Param(description = "need quiesce vm or not when taking snapshot", since="4.3") + private boolean needQuiescevm; + public String getPath() { return path; } @@ -408,4 +412,17 @@ public void setDisplayVm(Boolean displayVm) { public void setStoragePoolId(String storagePoolId) { this.storagePoolId = storagePoolId; } + + public String getStoragePoolId() { + return storagePoolId; + } + + public void setNeedQuiescevm(boolean quiescevm) { + this.needQuiescevm = quiescevm; + } + + public boolean isNeedQuiescevm() { + return this.needQuiescevm; + } + } diff --git a/api/src/org/apache/cloudstack/context/CallContext.java b/api/src/org/apache/cloudstack/context/CallContext.java index 5439aee70623..3cdccc526fe8 100644 --- a/api/src/org/apache/cloudstack/context/CallContext.java +++ b/api/src/org/apache/cloudstack/context/CallContext.java @@ -197,6 +197,18 @@ public static CallContext register(long callingUserId, long callingAccountId) th } return register(user, account); } + + public static CallContext register(long callingUserId, long callingAccountId, String contextId) throws CloudAuthenticationException { + Account account = s_entityMgr.findById(Account.class, callingAccountId); + if (account == null) { + throw new CloudAuthenticationException("The account is no longer current.").add(Account.class, Long.toString(callingAccountId)); + } + User user = s_entityMgr.findById(User.class, callingUserId); + if (user == null) { + throw new CloudAuthenticationException("The user is no longer current.").add(User.class, Long.toString(callingUserId)); + } + return register(user, account, contextId); + } public static void unregisterAll() { while ( unregister() != null ) { diff --git a/api/src/org/apache/cloudstack/query/QueryService.java b/api/src/org/apache/cloudstack/query/QueryService.java index 4a9e21840797..81c0157fc772 100644 --- a/api/src/org/apache/cloudstack/query/QueryService.java +++ b/api/src/org/apache/cloudstack/query/QueryService.java @@ -98,7 +98,7 @@ public interface QueryService { public ListResponse listIsos(ListIsosCmd cmd); public ListResponse listAffinityGroups(Long affinityGroupId, String affinityGroupName, String affinityGroupType, Long vmId, String accountName, Long domainId, boolean isRecursive, - boolean listAll, Long startIndex, Long pageSize); + boolean listAll, Long startIndex, Long pageSize, String keyword); public List listResourceDetails(ListResourceDetailsCmd cmd); diff --git a/api/test/com/cloud/network/NetworksTest.java b/api/test/com/cloud/network/NetworksTest.java index 87f69d62192d..860cff571cf7 100644 --- a/api/test/com/cloud/network/NetworksTest.java +++ b/api/test/com/cloud/network/NetworksTest.java @@ -23,6 +23,7 @@ import org.junit.Before; import org.junit.Test; +import com.cloud.dc.Vlan; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.IsolationType; import com.cloud.utils.exception.CloudRuntimeException; @@ -59,6 +60,20 @@ public void vlanBroadcastDomainTypeTest() throws URISyntaxException { Assert.assertEquals("id2 should be \"2\"", "2", id2); } + @Test + public void vlanValueTest() throws URISyntaxException { + String uri1 = "vlan://1"; + String uri2 = "1"; + String vtag = BroadcastDomainType.Vlan.getValueFrom(BroadcastDomainType.fromString(uri1)); + Assert.assertEquals("vtag should be \"1\"", "1", vtag); + BroadcastDomainType tiep1 = BroadcastDomainType.getTypeOf(uri1); + Assert.assertEquals("the type of uri1 should be 'Vlan'", BroadcastDomainType.Vlan, tiep1); + BroadcastDomainType tiep2 = BroadcastDomainType.getTypeOf(uri2); + Assert.assertEquals("the type of uri1 should be 'Undecided'", BroadcastDomainType.UnDecided, tiep2); + BroadcastDomainType tiep3 = BroadcastDomainType.getTypeOf(Vlan.UNTAGGED); + Assert.assertEquals("the type of uri1 should be 'vlan'", BroadcastDomainType.Native, tiep3); + } + @Test public void vlanIsolationTypeTest() throws URISyntaxException { String uri1 = "vlan://1"; diff --git a/api/test/org/apache/cloudstack/api/command/test/AddSecondaryStorageCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/AddSecondaryStorageCmdTest.java index c221ace62cc5..552a3c79f65c 100644 --- a/api/test/org/apache/cloudstack/api/command/test/AddSecondaryStorageCmdTest.java +++ b/api/test/org/apache/cloudstack/api/command/test/AddSecondaryStorageCmdTest.java @@ -16,20 +16,26 @@ // under the License. package org.apache.cloudstack.api.command.test; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.anyString; + +import java.util.Map; + import junit.framework.Assert; import junit.framework.TestCase; -import org.apache.cloudstack.api.ResponseGenerator; -import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd; -import org.apache.cloudstack.api.response.HostResponse; -import org.apache.cloudstack.api.response.ImageStoreResponse; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.Mockito; +import org.apache.cloudstack.api.ResponseGenerator; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd; +import org.apache.cloudstack.api.response.ImageStoreResponse; + import com.cloud.storage.ImageStore; import com.cloud.storage.StorageService; @@ -56,7 +62,7 @@ public void testExecuteForResult() throws Exception { ImageStore store = Mockito.mock(ImageStore.class); - Mockito.when(resourceService.discoverImageStore(addImageStoreCmd)) + Mockito.when(resourceService.discoverImageStore(anyString(), anyString(), anyString(), anyLong(), (Map)anyObject())) .thenReturn(store); ResponseGenerator responseGenerator = Mockito @@ -88,7 +94,7 @@ public void testExecuteForNullResult() throws Exception { StorageService resourceService = Mockito.mock(StorageService.class); addImageStoreCmd._storageService = resourceService; - Mockito.when(resourceService.discoverImageStore(addImageStoreCmd)) + Mockito.when(resourceService.discoverImageStore(anyString(), anyString(), anyString(), anyLong(), (Map)anyObject())) .thenReturn(null); try { diff --git a/awsapi/pom.xml b/awsapi/pom.xml index b1afd2d696ef..437ffbcbd7a3 100644 --- a/awsapi/pom.xml +++ b/awsapi/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack - 4.3.0-SNAPSHOT + 4.3.0 @@ -126,94 +126,6 @@ CAStorSDK 1.3.1-CS40 - - org.apache.rampart - rahas - ${cs.rampart.version} - mar - - - bouncycastle - bcprov-jdk14 - - - org.apache.xalan - xalan - - - org.opensaml - opensaml - - - - - org.apache.rampart - rampart - ${cs.rampart.version} - mar - - - bouncycastle - bcprov-jdk14 - - - org.apache.xalan - xalan - - - org.opensaml - opensaml - - - - - org.apache.rampart - rampart-core - ${cs.rampart.version} - runtime - - - org.apache.xalan - xalan - - - org.opensaml - opensaml - - - - - org.apache.rampart - rampart-policy - ${cs.rampart.version} - runtime - - - org.apache.xalan - xalan - - - org.opensaml - opensaml - - - - - org.apache.rampart - rampart-trust - ${cs.rampart.version} - runtime - - - org.apache.xalan - xalan - - - org.opensaml - opensaml - - - org.slf4j slf4j-jdk14 diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index 5885bd00c110..bccf71d2b251 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -14,6 +14,21 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +label.port=Port +label.remove.ldap=Remove LDAP +message.remove.ldap=Are you sure you want to delete the LDAP configuration? +label.configure.ldap=Configure LDAP +message.configure.ldap=Please confirm you would like to configure LDAP. +label.ldap.configuration=LDAP Configuration +label.ldap.port=LDAP port +label.create.nfs.secondary.staging.store=Create NFS secondary staging store +label.volatile=Volatile +label.planner.mode=Planner mode +label.deployment.planner=Deployment planner +label.quiesce.vm=Quiesce VM +label.smb.username=SMB Username +label.smb.password=SMB Password +label.smb.domain=SMB Domain label.hypervisors=Hypervisors label.home=Home label.sockets=Sockets @@ -691,6 +706,7 @@ label.lang.arabic=Arabic label.lang.brportugese=Brazilian Portugese label.lang.catalan=Catalan label.lang.chinese=Chinese (Simplified) +label.lang.dutch=Dutch (Netherlands) label.lang.english=English label.lang.french=French label.lang.german=German @@ -698,6 +714,7 @@ label.lang.italian=Italian label.lang.japanese=Japanese label.lang.korean=Korean label.lang.norwegian=Norwegian +label.lang.polish=Polish label.lang.russian=Russian label.lang.spanish=Spanish label.last.disconnected=Last Disconnected @@ -1250,6 +1267,7 @@ label.zoneWizard.trafficType.guest=Guest\: Traffic between end-user virtual mach label.zoneWizard.trafficType.management=Management\: Traffic between CloudStack\\\\'s internal resources, including any components that communicate with the Management Server, such as hosts and CloudStack system VMs label.zoneWizard.trafficType.public=Public\: Traffic between the internet and virtual machines in the cloud. label.zoneWizard.trafficType.storage=Storage\: Traffic between primary and secondary storage servers, such as VM templates and snapshots +label.ldap.group.name=LDAP Group managed.state=Managed State message.acquire.new.ip.vpc=Please confirm that you would like to acquire a new IP for this VPC. message.acquire.new.ip=Please confirm that you would like to acquire a new IP for this network. @@ -1549,7 +1567,7 @@ message.tooltip.reserved.system.netmask=The network prefix that defines the pod message.tooltip.zone.name=A name for the zone. message.update.os.preference=Please choose a OS preference for this host. All virtual instances with similar preferences will be first allocated to this host before choosing another. message.update.resource.count=Please confirm that you want to update resource counts for this account. -message.update.ssl=Please submit a new X.509 compliant SSL certificate to be updated to each console proxy virtual instance\: +message.update.ssl=Please submit a new X.509 compliant SSL certificate to be updated to each console proxy and secondary storage virtual instance\: message.validate.instance.name=Instance name can not be longer than 63 characters. Only ASCII letters a~z, A~Z, digits 0~9, hyphen are allowed. Must start with a letter and end with a letter or a digit. message.virtual.network.desc=A dedicated virtualized network for your account. The broadcast domain is contained within a VLAN and all public network access is routed out by a virtual router. message.vm.create.template.confirm=Create Template will reboot the VM automatically. diff --git a/client/WEB-INF/classes/resources/messages_de_DE.properties b/client/WEB-INF/classes/resources/messages_de_DE.properties index 2f164609d00c..ee3bab649378 100644 --- a/client/WEB-INF/classes/resources/messages_de_DE.properties +++ b/client/WEB-INF/classes/resources/messages_de_DE.properties @@ -224,8 +224,8 @@ label.add.system.service.offering=System-Service-Angebot hinzuf\u00fcgen label.add.template=Vorlage hinzuf\u00fcgen label.add.user=Benutzer hinzuf\u00fcgen label.add.vlan=VLAN hinzuf\u00fcgen -label.add.vxlan=VXLAN hinzuf\u00fcgen label.add.volume=Volume hinzuf\u00fcgen +label.add.vxlan=VXLAN hinzuf\u00fcgen label.add.zone=Zone hinzuf\u00fcgen label.admin.accounts=Administrator-Konten label.admin=Administrator @@ -622,9 +622,6 @@ label.virtual.network=Virtuelles Netzwerk label.vlan.id=VLAN ID label.vlan.range=VLAN Reichweite label.vlan=VLAN -label.vxlan.id=VXLAN ID -label.vxlan.range=VXLAN Reichweite -label.vxlan=VXLAN label.vm.add=Instanz hinzuf\u00fcgen label.vm.destroy=Zerst\u00f6ren label.VMFS.datastore=VMFS Datenspeicher @@ -634,11 +631,16 @@ label.vmsnapshot.type=Typ label.vm.start=Start label.vm.stop=Stopp label.vms=VMs +label.vnet.id=VLAN ID +label.vnet=VLAN label.volume.limits=Volume Grenzen label.volume.name=Volume Name label.volumes=Volumes label.volume=Volume label.vpn=VPN +label.vxlan.id=VXLAN ID +label.vxlan.range=VXLAN Reichweite +label.vxlan=VXLAN label.waiting=Warten label.warn=Warnen label.wednesday=Mittwoch diff --git a/client/WEB-INF/classes/resources/messages_es.properties b/client/WEB-INF/classes/resources/messages_es.properties index 3620047a2757..b7b1ec917ce1 100644 --- a/client/WEB-INF/classes/resources/messages_es.properties +++ b/client/WEB-INF/classes/resources/messages_es.properties @@ -15,41 +15,43 @@ # specific language governing permissions and limitations # under the License. -error.installWizard.message=Algo salio mal, debes ir para atr\u00e1s y corregir los error. -error.login=Su nombre de usuario / contrase\u00c3\u00b1a no coincide con nuestros registros. +error.installWizard.message=Algo salio mal, debes ir para atr\u00e1s y corregir los errores. +error.login=Su nombre de usuario / contrase\u00f1a no coinciden con nuestros registros. error.mgmt.server.inaccessible=El Servidor de Gesti\u00c3\u00b3n es inaccesible. Por favor, int\u00c3\u00a9ntelo de nuevo m\u00c3\u00a1s tarde. error.session.expired=Su sesi\u00c3\u00b3n ha caducado. error.unresolved.internet.name=El nombre de Internet no se puede resolver. extractable=extra\u00c3\u00adble force.delete.domain.warning=Advertencia\: Si elige esta opci\u00c3\u00b3n, la supresi\u00c3\u00b3n de todos los dominios secundarios y todas las cuentas asociadas y sus recursos. -force.delete=Fuerza Borrar -force.remove=Fuerza Retire -force.remove.host.warning=Advertencia\: Si elige esta opci\u00c3\u00b3n, CloudStack para detener la fuerza todas las m\u00c3\u00a1quinas virtuales en ejecuci\u00c3\u00b3n antes de retirar este host del cl\u00c3\u00baster. -force.stop=Grupo de Alto -force.stop.instance.warning=Advertencia\: Obligar a una parada en este caso deber\u00c3\u00ada ser su \u00c3\u00baltima opci\u00c3\u00b3n. Puede conducir a la p\u00c3\u00a9rdida de datos, as\u00c3\u00ad como un comportamiento incoherente del Estado de la m\u00c3\u00a1quina virtual. -ICMP.code=ICMP C\u00c3\u00b3digo +force.delete=Forzar el borrado +force.remove=Forzar el retiro +force.remove.host.warning=Advertencia\: Si elige esta opci\u00f3n, CloudStack para detener la fuerza todas las m\u00e1quinas virtuales en ejecuci\u00f3n antes de retirar este host del cl\u00faster. +force.stop=Forzar la detenci\u00f3n +force.stop.instance.warning=Advertencia\: Forzar la dertenci\u00f3n de esta instancia deber\u00ed\u00ada ser su \u00faltima opci\u00f3n. Puede conducir a la p\u00e9rdida de datos, as\u00ed\u00ad como un comportamiento incoherente del Estado de la m\u00e1quina virtual. +ICMP.code=C\u00f3digo ICMP ICMP.type=Tipo ICMP -image.directory=Directorio de la imagen -inline=en l\u00c3\u00adnea +image.directory=Directorio de im\u00e1genes +inline=alineado +label.about=Acerca de +label.about.app=Acerca de CloudStack label.account=Cuenta label.account.id=ID de la cuenta -label.account.name=Nombre de la cuenta +label.account.name=Nombre de cuenta label.accounts=Cuentas label.account.specific=espec\u00c3\u00adficas de la cuenta -label.acquire.new.ip=adquirir nuevas IP +label.acquire.new.ip=Adquirir nueva IP label.action.attach.disk=Conecte el disco -label.action.attach.disk.processing=disco Fijaci\u00c3\u00b3n .... -label.action.attach.iso=Adjuntar ISO -label.action.attach.iso.processing=Colocaci\u00c3\u00b3n de la norma ISO .... -label.action.cancel.maintenance.mode=Cancelar modo de mantenimiento -label.action.cancel.maintenance.mode.processing=Cancelaci\u00c3\u00b3n del modo de mantenimiento .... -label.action.change.password=Cambiar contrase\u00c3\u00b1a -label.action.change.service=Cambio de Servicio -label.action.change.service.processing=Cambio de servicio .... -label.action.copy.ISO=Copia de la ISO -label.action.copy.ISO.processing=hacer frente ISO .... -label.action.copy.template=Copia de plantilla -label.action.copy.template.processing=hacer frente plantilla .... +label.action.attach.disk.processing=Conectando el disco.... +label.action.attach.iso=Conectar ISO +label.action.attach.iso.processing=Conectando el ISO.... +label.action.cancel.maintenance.mode=Cancelar el modo de mantenimiento +label.action.cancel.maintenance.mode.processing=Cancelando el modo de mantenimiento.... +label.action.change.password=Cambiar la contrase\u00f1a +label.action.change.service=Cambiar el Servicio +label.action.change.service.processing=Cambiando el servicio.... +label.action.copy.ISO=Copiar ISO +label.action.copy.ISO.processing=Copiando ISO .... +label.action.copy.template=Copiear la plantilla +label.action.copy.template.processing=Copiando la plantilla .... label.action.create.template=Crear plantilla label.action.create.template.from.vm=Crear plantilla de VM label.action.create.template.from.volume=Crear plantilla de volumen @@ -238,8 +240,8 @@ label.add.template=A\u00c3\u00b1adir plantilla label.add.to.group=Agregar al grupo label.add.user=Agregar usuario label.add.vlan=A\u00c3\u00b1adir VLAN -label.add.vxlan=A\u00c3\u00b1adir VXLAN label.add.volume=A\u00c3\u00b1adir volumen +label.add.vxlan=A\u00c3\u00b1adir VXLAN label.add.zone=A\u00c3\u00b1adir Zona label.admin.accounts=Administrador de Cuentas label.admin=Admin @@ -250,6 +252,9 @@ label.alert=Alerta label.algorithm=Algoritmo label.allocated=Asignados label.api.key=clave de API +label.app.name=CloudStack +label.archive.alerts=Archivar alertas +label.archive.events=Archivar sucesos label.assign=Asignar label.assign.to.load.balancer=instancia de Asignaci\u00c3\u00b3n de equilibrador de carga label.associated.network.id=ID de red asociados @@ -263,9 +268,13 @@ label.basic.mode=Modo b\u00c3\u00a1sico label.bootable=arranque label.broadcast.domain.type=Tipo de dominio de difusi\u00c3\u00b3n label.by.account=Por Cuenta +label.by.alert.type=Por tipo de alerta label.by.availability=Por Disponibilidad +label.by.date.end=Por fecha (finalizaci\u00f3n) +label.by.date.start=Por fecha (inicio) label.by.domain=Por dominio label.by.end.date=Por Fecha de finalizaci\u00c3\u00b3n +label.by.event.type=Por tipo de suceso label.by.level=por Nivel label.by.pod=Por Pod label.by.role=por funci\u00c3\u00b3n @@ -300,6 +309,7 @@ label.cpu=CPU label.cpu.utilized=CPU Utilizado label.created=creaci\u00c3\u00b3n label.cross.zones=Cruz Zonas +label.custom.disk.iops=IOPS personalizadas label.custom.disk.size=Personal Disk Size label.daily=diario label.data.disk.offering=Datos Disco Offering @@ -307,7 +317,9 @@ label.date=Fecha label.day.of.month=D\u00c3\u00ada del mes label.day.of.week=d\u00c3\u00ada de la semana label.default.use=Usar por defecto +label.delete.alerts=Eliminar alertas label.delete=Eliminar +label.delete.events=Eliminar sucesos label.deleting.failed=No se pudo eliminar label.deleting.processing=Eliminar .... label.description=Descripci\u00c3\u00b3n @@ -319,6 +331,9 @@ label.DHCP.server.type=Tipo de servidor DHCP label.disabled=personas de movilidad reducida label.disabling.vpn.access=Desactivaci\u00c3\u00b3n de VPN de acceso label.disk.allocated=disco asignado +label.disk.iops.max=IOPS m\u00e1ximas +label.disk.iops.min=IOPS m\u00ednimas +label.disk.iops.total=Total de IOPS label.disk.offering=disco Ofrenda label.disk.size.gb=tama\u00c3\u00b1o de disco (en GB) label.disk.size=tama\u00c3\u00b1o de disco @@ -335,6 +350,7 @@ label.domain.suffix=DNS sufijo de dominio (es decir, xyz.com) label.double.quotes.are.not.allowed=comillas dobles no se permite label.download.progress=Progreso de la descarga label.edit=Editar +label.egress.default.policy=Directiva de salida predeterminada label.email=correo electr\u00c3\u00b3nico label.enabling.vpn.access=Habilitaci\u00c3\u00b3n de Acceso VPN label.enabling.vpn=Habilitaci\u00c3\u00b3n VPN @@ -374,6 +390,8 @@ label.host.name=nombre de host label.hosts=Ej\u00c3\u00a9rcitos label.hourly=por hora label.hypervisor=Hypervisor +label.hypervisors=Hipervisores +label.hypervisor.snapshot.reserve=Reserva de instant\u00e1neas de hipervisores label.hypervisor.type=Tipo Hypervisor label.id=ID label.info=Informaci\u00c3\u00b3n @@ -576,7 +594,10 @@ label.resource=Recursos label.resources=Recursos label.role=Papel label.root.disk.offering=Root Disco Offering +label.routing=Enrutamiento label.running.vms=Ejecuci\u00c3\u00b3n de m\u00c3\u00a1quinas virtuales +label.s3.nfs.path=Ruta NFS S3 +label.s3.nfs.server=Servidor NFS S3 label.s3.secret_key=clave secreta label.saturday=s\u00c3\u00a1bado label.save=Guardar @@ -594,6 +615,7 @@ label.select.a.zone=Seleccione una zona. label.sent=Enviados label.server=Servidor label.service.offering=Oferta de Servicio +label.service.state=Estado del servicio label.session.expired=Session Caducado label.shared=compartidas label.SharedMountPoint=SharedMountPoint @@ -605,6 +627,7 @@ label.snapshot.name=Nombre de instant\u00c3\u00a1neas label.snapshot.schedule=Lista de instant\u00c3\u00a1neas label.snapshot.s=Instant\u00c3\u00a1nea (s) label.snapshots=instant\u00c3\u00a1neas +label.sockets=Sockets label.source.nat=NAT Fuente label.specify.vlan=Especifique VLAN label.specify.vxlan=Especifique VXLAN @@ -636,6 +659,7 @@ label.submit=Enviar label.submitted.by=[Enviado por\: ] label.succeeded=Sucesor label.sunday=domingo +label.switch.type=Cambiar el tipo label.system.capacity=Capacidad de todo el sistema label.system.vm=Sistema de VM label.system.vms=Sistema de m\u00c3\u00a1quinas virtuales @@ -680,6 +704,7 @@ label.vcenter.host=vCenter anfitri\u00c3\u00b3n label.vcenter.password=vCenter Contrase\u00c3\u00b1a label.vcenter.username=vCenter Nombre de usuario label.version=Versi\u00c3\u00b3n +label.view.secondary.ips=Ver las IP secundarias label.virtual.appliances=Virtual Appliances label.virtual.appliance=Virtual Appliance label.virtual.machines=Maquinas virtuales @@ -687,9 +712,6 @@ label.virtual.network=Red Virtual label.vlan.id=ID de VLAN label.vlan.range=VLAN Gama label.vlan=VLAN -label.vxlan.id=ID de VXLAN -label.vxlan.range=VXLAN Gama -label.vxlan=VXLAN label.vm.add=A\u00c3\u00b1adir Instancia label.vm.destroy=Destroy label.VMFS.datastore=VMFS de datos tienda @@ -699,6 +721,8 @@ label.vmsnapshot.type=Tipo label.vm.start=Inicio label.vm.stop=Detener label.vms=VM +label.vnet.id=ID de VLAN +label.vnet=VLAN label.volgroup=Volume Group label.volume.limits=l\u00c3\u00admites de volumen label.volume.name=Nombre de Volumen @@ -706,6 +730,9 @@ label.volumes=Vol\u00c3\u00bamenes label.volume=Volumen label.vpn=VPN label.vsphere.managed=Gestionado \= vSphere +label.vxlan.id=ID de VXLAN +label.vxlan.range=VXLAN Gama +label.vxlan=VXLAN label.waiting=Esperando label.warn=Advertir label.wednesday=mi\u00c3\u00a9rcoles @@ -854,6 +881,7 @@ message.step.4.continue=Por favor seleccione al menos una red social para contin message.step.4.desc=Por favor, seleccione la red primaria que la instancia virtual estar\u00c3\u00a1 conectado. message.update.os.preference=Por favor seleccione un sistema operativo de preferencia para este equipo. Todas las instancias virtuales con preferencias similares ser\u00c3\u00a1n los primeros asignados a este equipo antes de elegir otro. message.update.ssl=Por favor, env\u00c3\u00ade una nueva X.509 compatible con certificado SSL que se actualizar\u00c3\u00a1 a cada instancia virtual de la consola del servidor proxy\: +message.validate.invalid.characters=Se han hallado caracteres no v\u00e1lidos. Por favor, corr\u00edjalos. message.virtual.network.desc=Una red dedicada virtualizados para su cuenta. El dominio de difusi\u00c3\u00b3n est\u00c3\u00a1 contenida dentro de una VLAN y todos los acceso a la red p\u00c3\u00bablica se encamina a cabo por un router virtual. message.vm.create.template.confirm=Crear plantilla de la m\u00c3\u00a1quina virtual se reiniciar\u00c3\u00a1 autom\u00c3\u00a1ticamente. message.volume.create.template.confirm=Por favor, confirme que desea crear una plantilla para este volumen de disco. Creaci\u00c3\u00b3n de la plantilla puede oscilar entre varios minutos m\u00c3\u00a1s, dependiendo del tama\u00c3\u00b1o del volumen. diff --git a/client/WEB-INF/classes/resources/messages_fr_FR.properties b/client/WEB-INF/classes/resources/messages_fr_FR.properties index db624221ddf7..e8c7b01475ab 100644 --- a/client/WEB-INF/classes/resources/messages_fr_FR.properties +++ b/client/WEB-INF/classes/resources/messages_fr_FR.properties @@ -18,6 +18,7 @@ changed.item.properties=Propri\u00e9t\u00e9s de l\\'\u00e9l\u00e9ment modifi\u00e9es confirm.enable.s3=Remplir les informations suivantes pour activer le support de stockage secondaire S3 confirm.enable.swift=Remplir les informations suivantes pour activer Swift +error.could.not.change.your.password.because.ldap.is.enabled=Erreur\: impossible de changer votre mot de passe car le mode LDAP est activ\u00e9. error.could.not.enable.zone=Impossible d\\'activer la zone error.installWizard.message=Une erreur s\\'est produite ; vous pouvez retourner en arri\u00e8re et corriger les erreurs error.invalid.username.password=Utilisateur ou mot de passe invalide @@ -42,6 +43,8 @@ ICMP.type=Type ICMP image.directory=R\u00e9pertoire d\\'images inline=Align\u00e9 instances.actions.reboot.label=Red\u00e9marrer l\\'instance +label.about.app=A propose de CloudStack +label.about=A propos de label.accept.project.invitation=Accepter l\\'invitation au projet label.account.and.security.group=Compte, groupe de s\u00e9curit\u00e9 label.account=Compte @@ -175,6 +178,8 @@ label.action.enable.user=Activer l\\'utilisateur label.action.enable.user.processing=Activation de l\\'utilisateur... label.action.enable.zone=Activer la zone label.action.enable.zone.processing=Activation de la zone... +label.action.expunge.instance.processing=Purge de l\\'Instance... +label.action.expunge.instance=Purger Instance label.action.force.reconnect=Forcer la reconnexion label.action.force.reconnect.processing=Reconnexion en cours... label.action.generate.keys=G\u00e9n\u00e9rer les cl\u00e9s @@ -210,6 +215,8 @@ label.action.resize.volume=Redimensionner Volume label.action.resource.limits=Limites de ressources label.action.restore.instance.processing=Restauration de l\\'instance... label.action.restore.instance=Restaurer l\\'instance +label.action.revert.snapshot.processing=Retour \u00e0 l\\'instantan\u00e9... +label.action.revert.snapshot=R\u00e9tablir Instantan\u00e9 label.actions=Actions label.action.start.instance=D\u00e9marrer l\\'instance label.action.start.instance.processing=D\u00e9marrage de l\\'instance... @@ -233,7 +240,7 @@ label.action.update.resource.count=Mettre \u00e0 jour le compteur des ressources label.action.update.resource.count.processing=Mise \u00e0 jour du compteur... label.action.vmsnapshot.create=Prendre un instantan\u00e9 VM label.action.vmsnapshot.delete=Supprimer l\\'instantan\u00e9 VM -label.action.vmsnapshot.revert=Revenir \u00e0 un instantan\u00e9 VM +label.action.vmsnapshot.revert=R\u00e9tablir Instantan\u00e9 VM label.activate.project=Activer projet label.active.sessions=Sessions actives label.add.account=Ajouter un compte @@ -278,9 +285,11 @@ label.add.network.offering=Ajouter une offre r\u00e9seau label.add.new.F5=Ajouter un F5 label.add.new.gateway=Ajouter une nouvelle passerelle label.add.new.NetScaler=Ajouter un Netscaler +label.add.new.PA=Ajouter nouveau Palo Alto label.add.new.SRX=Ajouter un SRX label.add.new.tier=Ajouter un nouveau tiers label.add.NiciraNvp.device=Ajouter un contr\u00f4leur Nvp +label.add.PA.device=Ajouter p\u00e9riph\u00e9rique Palo Alto label.add.physical.network=Ajouter un r\u00e9seau physique label.add.pod=Ajouter un pod label.add.port.forwarding.rule=Ajouter une r\u00e8gle de transfert de port @@ -300,7 +309,6 @@ label.add.template=Ajouter un mod\u00e8le label.add.to.group=Ajouter au groupe label.add.user=Ajouter un utilisateur label.add.vlan=Ajouter un VLAN -label.add.vxlan=Ajouter un VXLAN label.add.vm=Ajouter VM label.add.vms=Ajouter VMs label.add.vms.to.lb=Ajouter une/des VM(s) \u00e0 la r\u00e8gle de r\u00e9partition de charge @@ -310,6 +318,7 @@ label.add.vpc=Ajouter un VPC label.add.vpn.customer.gateway=Ajouter une passerelle VPN cliente label.add.VPN.gateway=Ajouter une passerelle VPN label.add.vpn.user=Ajouter un utilisateur VPN +label.add.vxlan=Ajouter un VXLAN label.add.zone=Ajouter une zone label.admin.accounts=Comptes Administrateur label.admin=Administrateur @@ -331,6 +340,9 @@ label.anti.affinity.group=Groupe d\\'Anti-affinit\u00e9 label.anti.affinity.groups=Groupes d\\'Anti-affinit\u00e9 label.api.key=Cl\u00e9 d\\'API label.apply=Appliquer +label.app.name=CloudStack +label.archive.alerts=Archiver alertes +label.archive.events=Archiver \u00e9v\u00e9nements label.assign=Assigner label.assign.to.load.balancer=Assigner l\\'instance au r\u00e9partiteur de charge label.associated.network.id=ID du r\u00e9seau associ\u00e9 @@ -352,9 +364,13 @@ label.broadcast.domain.range=Plage du domaine multi-diffusion label.broadcast.domain.type=Type de domaine de multi-diffusion label.broadcast.uri=URI multi-diffusion label.by.account=Par compte +label.by.alert.type=Par type d\\'alerte label.by.availability=Par disponibilit\u00e9 +label.by.date.end=par date (fin) +label.by.date.start=Par date (d\u00e9but) label.by.domain=Par domaine label.by.end.date=Par date de fin +label.by.event.type=Par type d\\'\u00e9v\u00e9nement label.by.level=Par niveau label.by.pod=Par Pod label.by.role=Par r\u00f4le @@ -392,9 +408,11 @@ label.code=Code label.community=Communaut\u00e9 label.compute.and.storage=Calcul et Stockage label.compute.offering=Offre de calcul +label.compute.offerings=Offres de Calcul label.compute=Processeur label.configuration=Configuration label.configure=Configurer +label.configure.ldap=Configurer LDAP label.configure.network.ACLs=Configurer les r\u00e8gles d\\'acc\u00e8s r\u00e9seau ACL label.configure.vpc=Configurer le VPC label.confirmation=Confirmation @@ -414,10 +432,12 @@ label.cpu.mhz=CPU (en MHz) label.cpu.utilized=CPU utilis\u00e9e label.created.by.system=Cr\u00e9\u00e9 par le syst\u00e8me label.created=Cr\u00e9\u00e9 +label.create.nfs.secondary.staging.store=Cr\u00e9er le magasin de transit du NFS secondaire label.create.project=Cr\u00e9er un projet label.create.template=Cr\u00e9er un mod\u00e8le label.create.VPN.connection=Cr\u00e9er une connexion VPN label.cross.zones=Multi Zones +label.custom.disk.iops=IOPS personnalis\u00e9s label.custom.disk.size=Taille de disque personnalis\u00e9e label.daily=Quotidien label.data.disk.offering=Offre de disque de donn\u00e9es @@ -431,11 +451,14 @@ label.default=Par d\u00e9faut label.default.use=Utilisation par d\u00e9faut label.default.view=Vue par d\u00e9faut label.delete.affinity.group=Supprimer le groupe d\\'affinit\u00e9 +label.delete.alerts=Supprimer alertes label.delete.BigSwitchVns=Supprimer contr\u00f4leur BigSwitch Vns +label.delete.events=Supprimer \u00e9v\u00e9nements label.delete.F5=Supprimer F5 label.delete.gateway=Supprimer la passerelle label.delete.NetScaler=Supprimer Netscaler label.delete.NiciraNvp=Supprimer un contr\u00f4leur Nvp +label.delete.PA=Supprimer Palo Alto label.delete.project=Supprimer projet label.delete.SRX=Supprimer SRX label.delete=Supprimer @@ -445,6 +468,7 @@ label.delete.VPN.gateway=Supprimer la passerelle VPN label.delete.vpn.user=Supprimer l\\'utilisateur VPN label.deleting.failed=Suppression \u00e9chou\u00e9e label.deleting.processing=Suppression... +label.deployment.planner=Planning d\u00e9ploiement label.description=Description label.destination.physical.network.id=Identifiant du r\u00e9seau physique de destination label.destination.zone=Zone de destination @@ -462,6 +486,13 @@ label.disable.provider=D\u00e9sactiver ce fournisseur label.disable.vpn=D\u00e9sactiver le VPN label.disabling.vpn.access=D\u00e9sactiver l\\'acc\u00e8s VPN label.disk.allocated=Disque Allou\u00e9 +label.disk.bytes.read.rate=D\u00e9bit lecture disque (BPS) +label.disk.bytes.write.rate=D\u00e9bit \u00e9criture disque (BPS) +label.disk.iops.max=IOPS maximum +label.disk.iops.min=IOPS minimum +label.disk.iops.read.rate=D\u00e9bit lecture disque (IOPS) +label.disk.iops.total=IOPS Total +label.disk.iops.write.rate=D\u00e9bit \u00e9criture disque (IOPS) label.disk.offering=Offre de Disque label.disk.read.bytes=Lecture Disque (Octets) label.disk.read.io=Lecture Disque (IO) @@ -495,6 +526,7 @@ label.edit.project.details=Modifier les d\u00e9tails du projet label.edit.tags=Modifier les balises label.edit.traffic.type=Modifier le type de trafic label.edit.vpc=Modifier le VPC +label.egress.default.policy=Politique par d\u00e9faut Egress label.egress.rule=R\u00e8gle sortante label.egress.rules=R\u00e8gles de sortie label.elastic.IP=IP extensible @@ -523,6 +555,7 @@ label.ESP.lifetime=Dur\u00e9e de vie ESP (secondes) label.ESP.policy=Mode ESP label.esx.host=H\u00f4te ESX/ESXi label.example=Exemple +label.expunge=Purger label.external.link=Lien externe label.f5=F5 label.failed=\u00c9chou\u00e9 @@ -559,6 +592,7 @@ label.ha.enabled=Haute disponibilit\u00e9 activ\u00e9e label.help=Aide label.hide.ingress.rule=Cacher la r\u00e8gle d\\'entr\u00e9e label.hints=Astuces +label.home=Accueil label.host.alerts=Alertes des h\u00f4tes label.host=H\u00f4te label.host.MAC=Adresse MAC h\u00f4te @@ -568,6 +602,8 @@ label.host.tags=\u00c9tiquettes d\\'h\u00f4te label.hourly=Chaque heure label.hypervisor.capabilities=Fonctions hyperviseur label.hypervisor=Hyperviseur +label.hypervisors=Hyperviseurs +label.hypervisor.snapshot.reserve=R\u00e9serve d\\'instantan\u00e9e de l\\'Hyperviseur label.hypervisor.type=Type d\\'hyperviseur label.hypervisor.version=Version hyperviseur label.id=ID @@ -641,6 +677,7 @@ label.lang.arabic=Arabe label.lang.brportugese=Portuguais Br\u00e9sil label.lang.catalan=Catalan label.lang.chinese=Chinois (simplifi\u00e9) +label.lang.dutch=N\u00e9erlandais label.lang.english=Anglais label.lang.french=Fran\u00e7ais label.lang.german=Allemand @@ -648,6 +685,7 @@ label.lang.italian=Italien label.lang.japanese=Japonais label.lang.korean=Cor\u00e9en label.lang.norwegian=Norv\u00e9gien +label.lang.polish=Polonais label.lang.russian=Russe label.lang.spanish=Espagnol label.last.disconnected=Derni\u00e8re D\u00e9connexion @@ -657,8 +695,12 @@ label.launch=D\u00e9marrer label.launch.vm=D\u00e9marrer VM label.launch.zone=D\u00e9marrer la zone label.LB.isolation=R\u00e9partition de charge isol\u00e9e +label.ldap.configuration=Configuration LDAP +label.ldap.group.name=Groupe LDAP +label.ldap.port=Port LDAP label.least.connections=Le moins de connexions label.level=Niveau +label.linklocal.ip=Adresse IP de lien local label.load.balancer=R\u00e9partiteur de charge label.load.balancing.policies=R\u00e8gles de r\u00e9partition de charge label.load.balancing=R\u00e9partition de charge @@ -771,6 +813,7 @@ label.network.domain.text=Domaine r\u00e9seau label.network.id=ID r\u00e9seau label.networking.and.security=R\u00e9seau et s\u00e9curit\u00e9 label.network.label.display.for.blank.value=Utiliser la passerelle par d\u00e9faut +label.network.limits=Limites r\u00e9seau label.network.name=Nom du r\u00e9seau label.network.offering.display.text=Texte affich\u00e9 d\\'Offre de R\u00e9seau label.network.offering.id=ID de l\\'Offre de Service R\u00e9seau @@ -828,10 +871,13 @@ label.os.type=Type du OS label.owned.public.ips=Adresses IP Publiques d\u00e9tenues label.owner.account=Propri\u00e9taire label.owner.domain=Propri\u00e9taire +label.PA.log.profile=Profil Journal Palo Alto +label.PA=Palo Alto label.parent.domain=Parent du Domaine label.password.enabled=Mot de passe activ\u00e9 label.password=Mot de passe label.path=Chemin +label.PA.threat.profile=Profil menace Palo Alto label.perfect.forward.secrecy=Confidentialit\u00e9 persistante label.physical.network.ID=Identifiant du r\u00e9seau physique label.physical.network=R\u00e9seau physique @@ -839,6 +885,7 @@ label.PING.CIFS.password=Mot de passe CIFS PING label.PING.CIFS.username=Identifiant CIFS PING label.PING.dir=R\u00e9pertoire PING label.PING.storage.IP=IP stockage PING +label.planner.mode=Mode planification label.please.specify.netscaler.info=Renseigner les informations sur le Netscaler label.please.wait=Patientez s\\'il vous plait label.plugin.details=D\u00e9tails extension @@ -848,6 +895,7 @@ label.pod=Pod label.pods=Pods label.port.forwarding.policies=R\u00e8gles de transfert de port label.port.forwarding=Redirection de port +label.port=Port label.port.range=Plage de ports label.PreSetup=PreSetup label.previous=Retour @@ -886,7 +934,14 @@ label.public.traffic=Trafic public label.public.zone=Zone publique label.purpose=R\u00f4le label.Pxe.server.type=Serveur PXE +label.qos.type=Type de QoS label.quickview=Aper\u00e7u +label.quiesce.vm=Mettre en veille VM +label.rbd.id=Utilisateur Cephx +label.rbd.monitor=Superviseur Ceph +label.rbd.pool=Pool Ceph +label.rbd=RBD +label.rbd.secret=Secret Cephx label.reboot=Red\u00e9marrer label.recent.errors=Erreurs r\u00e9centes label.redundant.router.capability=Router redondant @@ -901,6 +956,7 @@ label.remove.egress.rule=Supprimer la r\u00e8gle sortante label.remove.from.load.balancer=Supprimer l\\'instance du r\u00e9partiteur de charge label.remove.ingress.rule=Supprimer la r\u00e8gle entrante label.remove.ip.range=Supprimer la plage IP +label.remove.ldap=Supprimer LDAP label.remove.pf=Supprimer la r\u00e8gle de transfert de port label.remove.project.account=Supprimer le compte projet label.remove.region=Supprimer r\u00e9gion @@ -933,7 +989,9 @@ label.revoke.project.invite=R\u00e9voquer l\\'invitation label.role=R\u00f4le label.root.disk.controller=Contr\u00f4leur de disque principal label.root.disk.offering=Offre de disque racine +label.root.disk.size=Taille disque principal label.round.robin=Al\u00e9atoire +label.routing=Routage label.rules=R\u00e8gles label.running.vms=VMs actives label.s3.access_key=Cl\u00e9 d\\'Acc\u00e8s @@ -941,6 +999,8 @@ label.s3.bucket=Seau label.s3.connection_timeout=D\u00e9lai d\\'expiration de connexion label.s3.endpoint=Terminaison label.s3.max_error_retry=Nombre d\\'essai en erreur max. +label.s3.nfs.path=S3 Chemin NFS +label.s3.nfs.server=S3 Serveur NFS label.s3.secret_key=Cl\u00e9 Priv\u00e9e label.s3.socket_timeout=D\u00e9lai d\\'expiration de la socket label.s3.use_https=Utiliser HTTPS @@ -975,6 +1035,7 @@ label.sent=Envoy\u00e9 label.server=Serveur label.service.capabilities=Fonctions disponibles label.service.offering=Offre de Service +label.service.state=\u00c9tat du service label.session.expired=Session expir\u00e9e label.setup=Configuration label.setup.network=Configurer le r\u00e9seau @@ -987,12 +1048,16 @@ label.shutdown.provider=\u00c9teindre ce fournisseur label.site.to.site.VPN=VPN Site-\u00e0-Site label.size=Taille label.skip.guide=J\\'ai d\u00e9j\u00e0 utilis\u00e9 CloudStack avant, passer ce tutoriel +label.smb.domain=Domaine SMB +label.smb.password=Mot de passe SMB +label.smb.username=Identifiant SMB label.snapshot=Instantan\u00e9 label.snapshot.limits=Limites d\\'instantan\u00e9s label.snapshot.name=Nom Instantan\u00e9 label.snapshot.schedule=Configurer un instantan\u00e9 r\u00e9current label.snapshot.s=Instantan\u00e9(s) label.snapshots=Instantan\u00e9s +label.sockets=Sockets label.source.nat=NAT Source label.source=Origine label.specify.IP.ranges=Sp\u00e9cifier des plages IP @@ -1050,6 +1115,7 @@ label.super.cidr.for.guest.networks=Super CIDR pour les r\u00e9seaux invit\u00e9 label.supported.services=Services support\u00e9s label.supported.source.NAT.type=Type de NAT support\u00e9 label.suspend.project=Suspendre projet +label.switch.type=Type commutateur label.system.capacity=Capacit\u00e9 syst\u00e8me label.system.offering=Offre de syst\u00e8me label.system.service.offering=Offre de Service Syst\u00e8me @@ -1131,9 +1197,6 @@ label.virtual.routers=Routeurs virtuels label.vlan.id=ID du VLAN label.vlan.range=Plage du VLAN label.vlan=VLAN -label.vxlan.id=VXLAN ID -label.vxlan.range=Plage du VXLAN -label.vxlan=VXLAN label.vm.add=Ajouter une instance label.vm.destroy=D\u00e9truire label.vm.display.name=Nom commun VM @@ -1152,6 +1215,9 @@ label.vm.state=\u00c9tat VM label.vm.stop=Arr\u00eater label.vms=VMs label.vmware.traffic.label=Libell\u00e9 pour le trafic VMware +label.vnet.id=ID VLAN/VNI +label.vnet=VLAN/VNI +label.volatile=Volatile label.volgroup=Groupe de Volume label.volume.limits=Limites des volumes label.volume.name=Nom du volume @@ -1169,6 +1235,9 @@ label.vsmctrlvlanid=\ ID VLAN Contr\u00f4le label.vsmpktvlanid=ID VLAN Paquet label.vsmstoragevlanid=VLAN ID Stockage label.vsphere.managed=G\u00e9r\u00e9e par vSphere +label.vxlan.id=VXLAN ID +label.vxlan.range=Plage du VXLAN +label.vxlan=VXLAN label.waiting=En attente label.warn=Avertissement label.wednesday=Mercredi @@ -1241,6 +1310,7 @@ message.action.enable.nexusVswitch=Confirmer l\\'activation de ce Nexus 1000v message.action.enable.physical.network=Confirmer l\\'activation de ce r\u00e9seau physique. message.action.enable.pod=\u00cates-vous s\u00fbr que vous souhaitez activer ce Pod message.action.enable.zone=\u00cates-vous s\u00fbr que vous souhaitez activer cette zone +message.action.expunge.instance=Confirmez que vous souhaitez oruger cette instance. message.action.force.reconnect=Votre h\u00f4te a \u00e9t\u00e9 forc\u00e9e \u00e0 se reconnecter avec succ\u00e8s. Ce processus peut prendre jusqu\\'\u00e0 plusieurs minutes. message.action.host.enable.maintenance.mode=Activer le mode maintenance va causer la migration \u00e0 chaud de l\\'ensemble des instances de cet h\u00f4te sur les autres h\u00f4tes disponibles. message.action.instance.reset.password=Confirmer le changement du mot de passe ROOT pour cette machine virtuelle. @@ -1254,6 +1324,7 @@ message.action.remove.host=\u00cates-vous s\u00fbr que vous voulez supprimer cet message.action.reset.password.off=Votre instance ne supporte pas pour le moment cette fonctionnalit\u00e9. message.action.reset.password.warning=Votre instance doit \u00eatre arr\u00eat\u00e9e avant d\\'essayer de changer son mot de passe. message.action.restore.instance=\u00cates-vous s\u00fbr que vous souhaitez restaurer cette instance. +message.action.revert.snapshot=Confirmez que vous souhaitez r\u00e9tablir ce volume pour cet instantan\u00e9 message.action.start.instance=\u00cates-vous s\u00fbr que vous souhaitez d\u00e9marrer cette instance. message.action.start.router=\u00cates-vous s\u00fbr que vous souhaitez d\u00e9marrer ce routeur. message.action.start.systemvm=\u00cates-vous s\u00fbr que vous souhaitez red\u00e9marrer cette VM syst\u00e8me. @@ -1263,7 +1334,7 @@ message.action.stop.systemvm=\u00cates-vous s\u00fbr que vous souhaitez arr\u00e message.action.take.snapshot=Confirmer la prise d\\'un instantan\u00e9 pour ce volume. message.action.unmanage.cluster=Confirmez que vous ne voulez plus g\u00e9rer le cluster message.action.vmsnapshot.delete=Confirmez que vous souhaitez supprimer cet instantan\u00e9 VM. -message.action.vmsnapshot.revert=Revenir \u00e0 un instantan\u00e9 VM +message.action.vmsnapshot.revert=R\u00e9tablir l\\'instantan\u00e9 VM message.activate.project=\u00cates-vous s\u00fbr de vouloir activer ce projet ? message.add.cluster=Ajouter un cluster d\\'hyperviseurs g\u00e9r\u00e9 pour cette zone , pod message.add.cluster.zone=Ajouter un cluster d\\'hyperviseurs g\u00e9r\u00e9 pour cette zone @@ -1308,6 +1379,7 @@ message.basic.mode.desc=Choisissez ce mod\u00e8le de r\u00e9seau si vous *
Fournir au moins une plage d\\'adresses IP pour le trafic Internet. message.public.traffic.in.basic.zone=Le trafic public est g\u00e9n\u00e9r\u00e9 lorsque les machines virtuelles dans le nuage acc\u00e8dent \u00e0 Internet ou fournissent des services \u00e0 des utilisateurs sur Internet. Des adresses IP publiquement accessibles doivent \u00eatre pr\u00e9vus \u00e0 cet effet. Quand une instance est cr\u00e9\u00e9e, une adresse IP publique depuis un ensemble d\\'adresses IP publiques sera allou\u00e9e \u00e0 l\\'instance, en plus de l\\'adresse IP de l\\'invit\u00e9. La translation d\\'adresses statique NAT 1-1 sera mises en place automatiquement entre l\\'adresse IP publique et l\\'adresse IP de l\\'invit\u00e9. Les utilisateurs peuvent \u00e9galement utiliser l\\'interface d\\'administration CloudStack pour acqu\u00e9rir des adresses IP suppl\u00e9mentaires pour ajouter une translation d\\'adresse statique NAT entre leurs instances et le r\u00e9seau d\\'adresses IP publiques. message.redirecting.region=Redirection vers r\u00e9gion... +message.remove.ldap=\u00cates-vous s\u00fbr de vouloir supprimer la configuration LDAP ? message.remove.region=Confirmer que vous souhaitez supprimer cette r\u00e9gion depuis ce serveur d\\'administration ? message.remove.vpc=Confirmer la suppression du VPC message.remove.vpn.access=\u00cates-vous s\u00fbr que vous souhaitez supprimer l\\'acc\u00e8s VPN \u00e0 l\\'utilisateur suivant. @@ -1494,6 +1569,7 @@ message.update.os.preference=Choisissez votre OS pr\u00e9f\u00e9r\u00e9 pour cet message.update.resource.count=Confirmer la mise \u00e0 jour des ressources pour ce compte. message.update.ssl=Soumettez un nouveau certificat SSL compatible X.509 qui sera mis \u00e0 jour sur l\\'ensemble de instance de proxy console. message.validate.instance.name=Le nom de l\\'instance ne peut d\u00e9passer 63 caract\u00e8res. Seuls les lettres de a \u00e0 z, les chiffres de 0 \u00e0 9 et les tirets sont accept\u00e9s. Le nom doit commencer par une lettre et se terminer par une lettre ou un chiffre. +message.validate.invalid.characters=Caract\u00e8res invalides trouv\u00e9s ; veuillez corriger. message.virtual.network.desc=Un r\u00e9seau virtuel d\u00e9di\u00e9 pour votre compte. Ce domaine de multi-diffusion est contenu dans un VLAN et l\\'ensemble des r\u00e9seaux d\\'acc\u00e8s publique sont rout\u00e9s par un routeur virtuel. message.vm.create.template.confirm=Cr\u00e9er un mod\u00e8le va red\u00e9marrer la VM automatiquement message.vm.review.launch=Merci de v\u00e9rifier les informations suivantes et de confirmer que votre instance virtuelle est correcte avant de la d\u00e9marrer. diff --git a/client/WEB-INF/classes/resources/messages_it_IT.properties b/client/WEB-INF/classes/resources/messages_it_IT.properties index eab29b9b995f..a8301f66fe9d 100644 --- a/client/WEB-INF/classes/resources/messages_it_IT.properties +++ b/client/WEB-INF/classes/resources/messages_it_IT.properties @@ -606,6 +606,7 @@ label.VMs.in.tier=VM nei livelli label.vm.state=Stato VM label.vm.stop=Stop label.vmware.traffic.label=Etichetta del traffico via VMware +label.vnet=VLAN label.vpc.id=ID del VPC label.VPC.router.details=Dettagli del router VPC label.vpc=VPC diff --git a/client/WEB-INF/classes/resources/messages_ja.properties b/client/WEB-INF/classes/resources/messages_ja_JP.properties similarity index 97% rename from client/WEB-INF/classes/resources/messages_ja.properties rename to client/WEB-INF/classes/resources/messages_ja_JP.properties index d01efe88ff1c..8e9988674935 100644 --- a/client/WEB-INF/classes/resources/messages_ja.properties +++ b/client/WEB-INF/classes/resources/messages_ja_JP.properties @@ -1,4 +1,4 @@ -a# Licensed to the Apache Software Foundation (ASF) under one +# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file @@ -14,35 +14,11 @@ a# Licensed to the Apache Software Foundation (ASF) under one # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -label.delete.events=\u30a4\u30d9\u30f3\u30c8\u306e\u524a\u9664 -label.delete.alerts=\u30a2\u30e9\u30fc\u30c8\u306e\u524a\u9664 -label.archive.alerts=\u30a2\u30e9\u30fc\u30c8\u306e\u30a2\u30fc\u30ab\u30a4\u30d6 -label.archive.events=\u30a4\u30d9\u30f3\u30c8\u306e\u30a2\u30fc\u30ab\u30a4\u30d6 -label.by.alert.type=\u30a2\u30e9\u30fc\u30c8\u306e\u7a2e\u985e -label.by.event.type=\u30a4\u30d9\u30f3\u30c8\u306e\u7a2e\u985e -label.by.date.start=\u65e5\u4ed8 (\u958b\u59cb) -label.by.date.end=\u65e5\u4ed8 (\u7d42\u4e86) -label.switch.type=\u30b9\u30a4\u30c3\u30c1\u306e\u7a2e\u985e -label.service.state=\u30b5\u30fc\u30d3\u30b9\u306e\u72b6\u614b -label.egress.default.policy=\u9001\u4fe1\u306e\u30c7\u30d5\u30a9\u30eb\u30c8 \u30dd\u30ea\u30b7\u30fc -label.routing=\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0 -label.about=\u30d0\u30fc\u30b8\u30e7\u30f3\u60c5\u5831 -label.app.name=CloudStack -label.about.app=CloudStack \u306b\u3064\u3044\u3066 -label.custom.disk.iops=\u30ab\u30b9\u30bf\u30e0 IOPS -label.disk.iops.min=\u6700\u5c0f IOPS -label.disk.iops.max=\u6700\u5927 IOPS -label.disk.iops.total=IOPS \u5408\u8a08 -label.view.secondary.ips=\u30bb\u30ab\u30f3\u30c0\u30ea IP \u30a2\u30c9\u30ec\u30b9\u306e\u8868\u793a -message.validate.invalid.characters=\u7121\u52b9\u306a\u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f\u3002\u4fee\u6574\u3057\u3066\u304f\u3060\u3055\u3044\u3002 -message.acquire.ip.nic=\u3053\u306e NIC \u306e\u305f\u3081\u306b\u65b0\u3057\u3044\u30bb\u30ab\u30f3\u30c0\u30ea IP \u30a2\u30c9\u30ec\u30b9\u3092\u53d6\u5f97\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b?
\u6ce8: \u65b0\u3057\u304f\u53d6\u5f97\u3057\u305f\u30bb\u30ab\u30f3\u30c0\u30ea IP \u30a2\u30c9\u30ec\u30b9\u306f\u4eee\u60f3\u30de\u30b7\u30f3\u5185\u3067\u624b\u52d5\u3067\u69cb\u6210\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 -message.select.affinity.groups=\u3053\u306e VM \u3092\u8ffd\u52a0\u3059\u308b\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 -message.no.affinity.groups=\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u304c\u3042\u308a\u307e\u305b\u3093\u3002\u6b21\u306e\u624b\u9806\u306b\u9032\u3093\u3067\u304f\u3060\u3055\u3044\u3002 -label.action.delete.nic=NIC \u306e\u524a\u9664 -message.action.delete.nic=\u3053\u306e NIC \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? \u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3082 VM \u304b\u3089\u524a\u9664\u3055\u308c\u307e\u3059\u3002 + changed.item.properties=\u9805\u76ee\u306e\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u5909\u66f4 confirm.enable.s3=S3 \u30d9\u30fc\u30b9\u306e\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306e\u30b5\u30dd\u30fc\u30c8\u3092\u6709\u52b9\u306b\u3059\u308b\u306b\u306f\u3001\u6b21\u306e\u60c5\u5831\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 confirm.enable.swift=Swift \u306e\u30b5\u30dd\u30fc\u30c8\u3092\u6709\u52b9\u306b\u3059\u308b\u306b\u306f\u3001\u6b21\u306e\u60c5\u5831\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +error.could.not.change.your.password.because.ldap.is.enabled=LDAP \u304c\u6709\u52b9\u306a\u305f\u3081\u3001\u30a8\u30e9\u30fc\u306b\u3088\u3063\u3066\u30d1\u30b9\u30ef\u30fc\u30c9\u306f\u5909\u66f4\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f\u3002 error.could.not.enable.zone=\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f error.installWizard.message=\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u623b\u3063\u3066\u30a8\u30e9\u30fc\u3092\u4fee\u6b63\u3067\u304d\u307e\u3059\u3002 error.invalid.username.password=\u7121\u52b9\u306a\u30e6\u30fc\u30b6\u30fc\u540d\u307e\u305f\u306f\u30d1\u30b9\u30ef\u30fc\u30c9\u3067\u3059\u3002 @@ -67,25 +43,28 @@ ICMP.type=ICMP \u306e\u7a2e\u985e image.directory=\u753b\u50cf\u30c7\u30a3\u30ec\u30af\u30c8\u30ea inline=\u76f4\u5217 instances.actions.reboot.label=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u518d\u8d77\u52d5 +label.about.app=CloudStack \u306b\u3064\u3044\u3066 +label.about=\u30d0\u30fc\u30b8\u30e7\u30f3\u60c5\u5831 label.accept.project.invitation=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3078\u306e\u62db\u5f85\u306e\u627f\u8afe label.account.and.security.group=\u30a2\u30ab\u30a6\u30f3\u30c8\u3001\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 label.account.id=\u30a2\u30ab\u30a6\u30f3\u30c8 ID label.account.name=\u30a2\u30ab\u30a6\u30f3\u30c8\u540d label.account.specific=\u30a2\u30ab\u30a6\u30f3\u30c8\u56fa\u6709 -label.account=\u30a2\u30ab\u30a6\u30f3\u30c8 label.accounts=\u30a2\u30ab\u30a6\u30f3\u30c8 +label.account=\u30a2\u30ab\u30a6\u30f3\u30c8 label.acquire.new.ip=\u65b0\u3057\u3044 IP \u30a2\u30c9\u30ec\u30b9\u306e\u53d6\u5f97 +label.acquire.new.secondary.ip=\u30bb\u30ab\u30f3\u30c0\u30ea IP \u30a2\u30c9\u30ec\u30b9\u306e\u53d6\u5f97 label.action.attach.disk.processing=\u30c7\u30a3\u30b9\u30af\u3092\u30a2\u30bf\u30c3\u30c1\u3057\u3066\u3044\u307e\u3059... label.action.attach.disk=\u30c7\u30a3\u30b9\u30af\u306e\u30a2\u30bf\u30c3\u30c1 -label.action.attach.iso.processing=ISO \u3092\u30a2\u30bf\u30c3\u30c1\u3057\u3066\u3044\u307e\u3059... label.action.attach.iso=ISO \u306e\u30a2\u30bf\u30c3\u30c1 +label.action.attach.iso.processing=ISO \u3092\u30a2\u30bf\u30c3\u30c1\u3057\u3066\u3044\u307e\u3059... label.action.cancel.maintenance.mode.processing=\u4fdd\u5b88\u30e2\u30fc\u30c9\u3092\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u3066\u3044\u307e\u3059... label.action.cancel.maintenance.mode=\u4fdd\u5b88\u30e2\u30fc\u30c9\u306e\u30ad\u30e3\u30f3\u30bb\u30eb label.action.change.password=\u30d1\u30b9\u30ef\u30fc\u30c9\u306e\u5909\u66f4 label.action.change.service.processing=\u30b5\u30fc\u30d3\u30b9\u3092\u5909\u66f4\u3057\u3066\u3044\u307e\u3059... label.action.change.service=\u30b5\u30fc\u30d3\u30b9\u306e\u5909\u66f4 -label.action.copy.ISO.processing=ISO \u3092\u30b3\u30d4\u30fc\u3057\u3066\u3044\u307e\u3059... label.action.copy.ISO=ISO \u306e\u30b3\u30d4\u30fc +label.action.copy.ISO.processing=ISO \u3092\u30b3\u30d4\u30fc\u3057\u3066\u3044\u307e\u3059... label.action.copy.template.processing=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u30b3\u30d4\u30fc\u3057\u3066\u3044\u307e\u3059... label.action.copy.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u30b3\u30d4\u30fc label.action.create.template.from.vm=VM \u304b\u3089\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u4f5c\u6210 @@ -108,15 +87,16 @@ label.action.delete.firewall.processing=\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30 label.action.delete.firewall=\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u898f\u5247\u306e\u524a\u9664 label.action.delete.ingress.rule.processing=\u53d7\u4fe1\u898f\u5247\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... label.action.delete.ingress.rule=\u53d7\u4fe1\u898f\u5247\u306e\u524a\u9664 -label.action.delete.IP.range.processing=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... label.action.delete.IP.range=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u306e\u524a\u9664 -label.action.delete.ISO.processing=ISO \u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.IP.range.processing=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... label.action.delete.ISO=ISO \u306e\u524a\u9664 +label.action.delete.ISO.processing=ISO \u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... label.action.delete.load.balancer.processing=\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... label.action.delete.load.balancer=\u8ca0\u8377\u5206\u6563\u898f\u5247\u306e\u524a\u9664 label.action.delete.network.processing=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... label.action.delete.network=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u524a\u9664 label.action.delete.nexusVswitch=Nexus 1000V \u306e\u524a\u9664 +label.action.delete.nic=NIC \u306e\u524a\u9664 label.action.delete.physical.network=\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u524a\u9664 label.action.delete.pod.processing=\u30dd\u30c3\u30c9\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... label.action.delete.pod=\u30dd\u30c3\u30c9\u306e\u524a\u9664 @@ -145,8 +125,8 @@ label.action.destroy.systemvm.processing=\u30b7\u30b9\u30c6\u30e0 VM \u3092\u783 label.action.destroy.systemvm=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u7834\u68c4 label.action.detach.disk.processing=\u30c7\u30a3\u30b9\u30af\u3092\u30c7\u30bf\u30c3\u30c1\u3057\u3066\u3044\u307e\u3059... label.action.detach.disk=\u30c7\u30a3\u30b9\u30af\u306e\u30c7\u30bf\u30c3\u30c1 -label.action.detach.iso.processing=ISO \u3092\u30c7\u30bf\u30c3\u30c1\u3057\u3066\u3044\u307e\u3059... label.action.detach.iso=ISO \u306e\u30c7\u30bf\u30c3\u30c1 +label.action.detach.iso.processing=ISO \u3092\u30c7\u30bf\u30c3\u30c1\u3057\u3066\u3044\u307e\u3059... label.action.disable.account.processing=\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... label.action.disable.account=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u7121\u52b9\u5316 label.action.disable.cluster.processing=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... @@ -198,6 +178,8 @@ label.action.enable.user.processing=\u30e6\u30fc\u30b6\u30fc\u3092\u6709\u52b9\u label.action.enable.user=\u30e6\u30fc\u30b6\u30fc\u306e\u6709\u52b9\u5316 label.action.enable.zone.processing=\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... label.action.enable.zone=\u30be\u30fc\u30f3\u306e\u6709\u52b9\u5316 +label.action.expunge.instance.processing=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u62b9\u6d88\u3057\u3066\u3044\u307e\u3059... +label.action.expunge.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u62b9\u6d88 label.action.force.reconnect.processing=\u518d\u63a5\u7d9a\u3057\u3066\u3044\u307e\u3059... label.action.force.reconnect=\u5f37\u5236\u518d\u63a5\u7d9a label.action.generate.keys.processing=\u30ad\u30fc\u3092\u751f\u6210\u3057\u3066\u3044\u307e\u3059... @@ -222,8 +204,8 @@ label.action.reboot.systemvm=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u518d\u8d77\u52d label.action.recurring.snapshot=\u5b9a\u671f\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 label.action.register.iso=ISO \u306e\u767b\u9332 label.action.register.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u767b\u9332 -label.action.release.ip.processing=IP \u30a2\u30c9\u30ec\u30b9\u3092\u89e3\u653e\u3057\u3066\u3044\u307e\u3059... label.action.release.ip=IP \u30a2\u30c9\u30ec\u30b9\u306e\u89e3\u653e +label.action.release.ip.processing=IP \u30a2\u30c9\u30ec\u30b9\u3092\u89e3\u653e\u3057\u3066\u3044\u307e\u3059... label.action.remove.host.processing=\u30db\u30b9\u30c8\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... label.action.remove.host=\u30db\u30b9\u30c8\u306e\u524a\u9664 label.action.reset.password.processing=\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u30ea\u30bb\u30c3\u30c8\u3057\u3066\u3044\u307e\u3059... @@ -233,6 +215,8 @@ label.action.resize.volume=\u30dc\u30ea\u30e5\u30fc\u30e0 \u30b5\u30a4\u30ba\u30 label.action.resource.limits=\u30ea\u30bd\u30fc\u30b9\u5236\u9650 label.action.restore.instance.processing=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5fa9\u5143\u3057\u3066\u3044\u307e\u3059... label.action.restore.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u5fa9\u5143 +label.action.revert.snapshot.processing=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306b\u623b\u3057\u3066\u3044\u307e\u3059... +label.action.revert.snapshot=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306b\u623b\u3059 label.action.start.instance.processing=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u8d77\u52d5\u3057\u3066\u3044\u307e\u3059... label.action.start.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u8d77\u52d5 label.action.start.router.processing=\u30eb\u30fc\u30bf\u30fc\u3092\u8d77\u52d5\u3057\u3066\u3044\u307e\u3059... @@ -245,24 +229,24 @@ label.action.stop.router.processing=\u30eb\u30fc\u30bf\u30fc\u3092\u505c\u6b62\u label.action.stop.router=\u30eb\u30fc\u30bf\u30fc\u306e\u505c\u6b62 label.action.stop.systemvm.processing=\u30b7\u30b9\u30c6\u30e0 VM \u3092\u505c\u6b62\u3057\u3066\u3044\u307e\u3059... label.action.stop.systemvm=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u505c\u6b62 +label.actions=\u64cd\u4f5c label.action.take.snapshot.processing=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059.... label.action.take.snapshot=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306e\u4f5c\u6210 label.action.unmanage.cluster.processing=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u975e\u7ba1\u7406\u5bfe\u8c61\u306b\u3057\u3066\u3044\u307e\u3059... label.action.unmanage.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u306e\u975e\u7ba1\u7406\u5bfe\u8c61\u5316 -label.action.update.OS.preference.processing=OS \u57fa\u672c\u8a2d\u5b9a\u3092\u66f4\u65b0\u3057\u3066\u3044\u307e\u3059... label.action.update.OS.preference=OS \u57fa\u672c\u8a2d\u5b9a\u306e\u66f4\u65b0 +label.action.update.OS.preference.processing=OS \u57fa\u672c\u8a2d\u5b9a\u3092\u66f4\u65b0\u3057\u3066\u3044\u307e\u3059... label.action.update.resource.count.processing=\u30ea\u30bd\u30fc\u30b9\u6570\u3092\u66f4\u65b0\u3057\u3066\u3044\u307e\u3059... label.action.update.resource.count=\u30ea\u30bd\u30fc\u30b9\u6570\u306e\u66f4\u65b0 label.action.vmsnapshot.create=VM \u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306e\u4f5c\u6210 label.action.vmsnapshot.delete=VM \u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306e\u524a\u9664 -label.action.vmsnapshot.revert=VM \u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u5143\u306b\u623b\u3059 -label.actions=\u64cd\u4f5c +label.action.vmsnapshot.revert=VM \u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306b\u623b\u3059 label.activate.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u30a2\u30af\u30c6\u30a3\u30d6\u5316 label.active.sessions=\u30a2\u30af\u30c6\u30a3\u30d6\u306a\u30bb\u30c3\u30b7\u30e7\u30f3 -label.add.account.to.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3078\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u8ffd\u52a0 -label.add.account=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u8ffd\u52a0 label.add.accounts.to=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u8ffd\u52a0\u5148: label.add.accounts=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u8ffd\u52a0 +label.add.account.to.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3078\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u8ffd\u52a0 +label.add.account=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u8ffd\u52a0 label.add.ACL=ACL \u306e\u8ffd\u52a0 label.add.affinity.group=\u65b0\u3057\u3044\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u306e\u8ffd\u52a0 label.add.BigSwitchVns.device=Big Switch VNS \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u306e\u8ffd\u52a0 @@ -279,8 +263,17 @@ label.add.F5.device=F5 \u30c7\u30d0\u30a4\u30b9\u306e\u8ffd\u52a0 label.add.firewall=\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u898f\u5247\u306e\u8ffd\u52a0 label.add.guest.network=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8ffd\u52a0 label.add.host=\u30db\u30b9\u30c8\u306e\u8ffd\u52a0 +label.adding.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +label.adding.failed=\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f +label.adding.pod=\u30dd\u30c3\u30c9\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +label.adding.processing=\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059... label.add.ingress.rule=\u53d7\u4fe1\u898f\u5247\u306e\u8ffd\u52a0 +label.adding.succeeded=\u8ffd\u52a0\u3057\u307e\u3057\u305f +label.adding=\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +label.adding.user=\u30e6\u30fc\u30b6\u30fc\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +label.adding.zone=\u30be\u30fc\u30f3\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 label.add.ip.range=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u306e\u8ffd\u52a0 +label.additional.networks=\u8ffd\u52a0\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af label.add.load.balancer=\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u306e\u8ffd\u52a0 label.add.more=\u305d\u306e\u307b\u304b\u306e\u9805\u76ee\u306e\u8ffd\u52a0 label.add.netScaler.device=Netscaler \u30c7\u30d0\u30a4\u30b9\u306e\u8ffd\u52a0 @@ -291,9 +284,11 @@ label.add.network=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8ffd\u52a0 label.add.new.F5=\u65b0\u3057\u3044 F5 \u306e\u8ffd\u52a0 label.add.new.gateway=\u65b0\u3057\u3044\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u306e\u8ffd\u52a0 label.add.new.NetScaler=\u65b0\u3057\u3044 NetScaler \u306e\u8ffd\u52a0 +label.add.new.PA=\u65b0\u3057\u3044 Palo Alto \u306e\u8ffd\u52a0 label.add.new.SRX=\u65b0\u3057\u3044 SRX \u306e\u8ffd\u52a0 label.add.new.tier=\u65b0\u3057\u3044\u968e\u5c64\u306e\u8ffd\u52a0 label.add.NiciraNvp.device=NVP \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u306e\u8ffd\u52a0 +label.add.PA.device=Palo Alto \u30c7\u30d0\u30a4\u30b9\u306e\u8ffd\u52a0 label.add.physical.network=\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8ffd\u52a0 label.add.pod=\u30dd\u30c3\u30c9\u306e\u8ffd\u52a0 label.add.port.forwarding.rule=\u30dd\u30fc\u30c8\u8ee2\u9001\u898f\u5247\u306e\u8ffd\u52a0 @@ -311,36 +306,27 @@ label.add.static.route=\u9759\u7684\u30eb\u30fc\u30c8\u306e\u8ffd\u52a0 label.add.system.service.offering=\u30b7\u30b9\u30c6\u30e0 \u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u8ffd\u52a0 label.add.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u8ffd\u52a0 label.add.to.group=\u8ffd\u52a0\u5148\u30b0\u30eb\u30fc\u30d7 +label.add=\u8ffd\u52a0 label.add.user=\u30e6\u30fc\u30b6\u30fc\u306e\u8ffd\u52a0 label.add.vlan=VLAN \u306e\u8ffd\u52a0 -label.add.vxlan=VXLAN \u306e\u8ffd\u52a0 -label.add.VM.to.tier=\u968e\u5c64\u3078\u306e VM \u306e\u8ffd\u52a0 -label.add.vm=VM \u306e\u8ffd\u52a0 label.add.vms.to.lb=\u8ca0\u8377\u5206\u6563\u898f\u5247\u3078\u306e VM \u306e\u8ffd\u52a0 label.add.vms=VM \u306e\u8ffd\u52a0 +label.add.VM.to.tier=\u968e\u5c64\u3078\u306e VM \u306e\u8ffd\u52a0 +label.add.vm=VM \u306e\u8ffd\u52a0 label.add.volume=\u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u8ffd\u52a0 label.add.vpc=VPC \u306e\u8ffd\u52a0 label.add.vpn.customer.gateway=VPN \u30ab\u30b9\u30bf\u30de\u30fc \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u306e\u8ffd\u52a0 label.add.VPN.gateway=VPN \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u306e\u8ffd\u52a0 label.add.vpn.user=VPN \u30e6\u30fc\u30b6\u30fc\u306e\u8ffd\u52a0 +label.add.vxlan=VXLAN \u306e\u8ffd\u52a0 label.add.zone=\u30be\u30fc\u30f3\u306e\u8ffd\u52a0 -label.add=\u8ffd\u52a0 -label.adding.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 -label.adding.failed=\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f -label.adding.pod=\u30dd\u30c3\u30c9\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 -label.adding.processing=\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059... -label.adding.succeeded=\u8ffd\u52a0\u3057\u307e\u3057\u305f -label.adding.user=\u30e6\u30fc\u30b6\u30fc\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 -label.adding.zone=\u30be\u30fc\u30f3\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 -label.adding=\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 -label.additional.networks=\u8ffd\u52a0\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af label.admin.accounts=\u7ba1\u7406\u8005\u30a2\u30ab\u30a6\u30f3\u30c8 label.admin=\u7ba1\u7406\u8005 label.advanced.mode=\u62e1\u5f35\u30e2\u30fc\u30c9 label.advanced.search=\u9ad8\u5ea6\u306a\u691c\u7d22 label.advanced=\u62e1\u5f35 -label.affinity.group=\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 label.affinity.groups=\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 +label.affinity.group=\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 label.affinity=\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 label.agent.password=\u30a8\u30fc\u30b8\u30a7\u30f3\u30c8 \u30d1\u30b9\u30ef\u30fc\u30c9 label.agent.username=\u30a8\u30fc\u30b8\u30a7\u30f3\u30c8 \u30e6\u30fc\u30b6\u30fc\u540d @@ -349,11 +335,14 @@ label.alert=\u30a2\u30e9\u30fc\u30c8 label.algorithm=\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0 label.allocated=\u5272\u308a\u5f53\u3066\u6e08\u307f label.allocation.state=\u5272\u308a\u5f53\u3066\u72b6\u614b -label.anti.affinity.group=\u30a2\u30f3\u30c1\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 label.anti.affinity.groups=\u30a2\u30f3\u30c1\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 +label.anti.affinity.group=\u30a2\u30f3\u30c1\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 label.anti.affinity=\u30a2\u30f3\u30c1\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 label.api.key=API \u30ad\u30fc label.apply=\u9069\u7528 +label.app.name=CloudStack +label.archive.alerts=\u30a2\u30e9\u30fc\u30c8\u306e\u30a2\u30fc\u30ab\u30a4\u30d6 +label.archive.events=\u30a4\u30d9\u30f3\u30c8\u306e\u30a2\u30fc\u30ab\u30a4\u30d6 label.assign.to.load.balancer=\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u306b\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5272\u308a\u5f53\u3066\u3066\u3044\u307e\u3059 label.assign=\u5272\u308a\u5f53\u3066 label.associated.network.id=\u95a2\u9023\u3065\u3051\u3089\u308c\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ID @@ -361,33 +350,39 @@ label.associated.network=\u95a2\u9023\u3065\u3051\u3089\u308c\u305f\u30cd\u30c3\ label.attached.iso=\u30a2\u30bf\u30c3\u30c1\u3055\u308c\u305f ISO label.author.email=\u4f5c\u6210\u8005\u306e\u96fb\u5b50\u30e1\u30fc\u30eb label.author.name=\u4f5c\u6210\u8005\u306e\u540d\u524d -label.availability.zone=\u5229\u7528\u53ef\u80fd\u30be\u30fc\u30f3 label.availability=\u53ef\u7528\u6027 +label.availability.zone=\u5229\u7528\u53ef\u80fd\u30be\u30fc\u30f3 label.available.public.ips=\u4f7f\u7528\u3067\u304d\u308b\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9 label.available=\u4f7f\u7528\u53ef\u80fd label.back=\u623b\u308b label.bandwidth=\u5e2f\u57df\u5e45 label.basic.mode=\u57fa\u672c\u30e2\u30fc\u30c9 label.basic=\u57fa\u672c +label.bigswitch.controller.address=Big Switch VNS \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u306e\u30a2\u30c9\u30ec\u30b9 label.bootable=\u8d77\u52d5\u53ef\u80fd label.broadcast.domain.range=\u30d6\u30ed\u30fc\u30c9\u30ad\u30e3\u30b9\u30c8 \u30c9\u30e1\u30a4\u30f3\u306e\u7bc4\u56f2 label.broadcast.domain.type=\u30d6\u30ed\u30fc\u30c9\u30ad\u30e3\u30b9\u30c8 \u30c9\u30e1\u30a4\u30f3\u306e\u7a2e\u985e label.broadcast.uri=\u30d6\u30ed\u30fc\u30c9\u30ad\u30e3\u30b9\u30c8 URI label.by.account=\u30a2\u30ab\u30a6\u30f3\u30c8 +label.by.alert.type=\u30a2\u30e9\u30fc\u30c8\u306e\u7a2e\u985e label.by.availability=\u53ef\u7528\u6027 +label.by.date.end=\u65e5\u4ed8 (\u7d42\u4e86) +label.by.date.start=\u65e5\u4ed8 (\u958b\u59cb) label.by.domain=\u30c9\u30e1\u30a4\u30f3 label.by.end.date=\u7d42\u4e86\u65e5 +label.by.event.type=\u30a4\u30d9\u30f3\u30c8\u306e\u7a2e\u985e label.by.level=\u30ec\u30d9\u30eb label.by.pod=\u30dd\u30c3\u30c9 label.by.role=\u5f79\u5272 label.by.start.date=\u958b\u59cb\u65e5 label.by.state=\u72b6\u614b +label.bytes.received=\u53d7\u4fe1\u30d0\u30a4\u30c8 +label.bytes.sent=\u9001\u4fe1\u30d0\u30a4\u30c8 label.by.traffic.type=\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e label.by.type.id=\u7a2e\u985e ID label.by.type=\u7a2e\u985e label.by.zone=\u30be\u30fc\u30f3 -label.bytes.received=\u53d7\u4fe1\u30d0\u30a4\u30c8 -label.bytes.sent=\u9001\u4fe1\u30d0\u30a4\u30c8 +label.cache.mode=\u66f8\u304d\u8fbc\u307f\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u7a2e\u985e label.cancel=\u30ad\u30e3\u30f3\u30bb\u30eb label.capacity=\u51e6\u7406\u80fd\u529b label.certificate=\u8a3c\u660e\u66f8 @@ -396,32 +391,32 @@ label.change.value=\u5024\u306e\u5909\u66f4 label.character=\u6587\u5b57 label.checksum=MD5 \u30c1\u30a7\u30c3\u30af\u30b5\u30e0 label.cidr.account=CIDR \u307e\u305f\u306f\u30a2\u30ab\u30a6\u30f3\u30c8/\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 +label.cidr=CIDR label.CIDR.list=CIDR \u4e00\u89a7 label.cidr.list=\u9001\u4fe1\u5143 CIDR label.CIDR.of.destination.network=\u5b9b\u5148\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e CIDR -label.cidr=CIDR label.clean.up=\u30af\u30ea\u30fc\u30f3 \u30a2\u30c3\u30d7\u3059\u308b label.clear.list=\u4e00\u89a7\u306e\u6d88\u53bb label.close=\u9589\u3058\u308b label.cloud.console=\u30af\u30e9\u30a6\u30c9\u7ba1\u7406\u30b3\u30f3\u30bd\u30fc\u30eb label.cloud.managed=Cloud.com \u306b\u3088\u308b\u7ba1\u7406 label.cluster.name=\u30af\u30e9\u30b9\u30bf\u30fc\u540d +label.clusters=\u30af\u30e9\u30b9\u30bf\u30fc label.cluster.type=\u30af\u30e9\u30b9\u30bf\u30fc\u306e\u7a2e\u985e label.cluster=\u30af\u30e9\u30b9\u30bf\u30fc -label.clusters=\u30af\u30e9\u30b9\u30bf\u30fc label.clvm=CLVM label.code=\u30b3\u30fc\u30c9 label.community=\u30b3\u30df\u30e5\u30cb\u30c6\u30a3 label.compute.and.storage=\u30b3\u30f3\u30d4\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0\u3068\u30b9\u30c8\u30ec\u30fc\u30b8 -label.compute.offering=\u30b3\u30f3\u30d4\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 label.compute.offerings=\u30b3\u30f3\u30d4\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.compute.offering=\u30b3\u30f3\u30d4\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 label.compute=\u30b3\u30f3\u30d4\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0 label.configuration=\u69cb\u6210 label.configure.network.ACLs=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ACL \u306e\u69cb\u6210 -label.configure.vpc=VPC \u306e\u69cb\u6210 label.configure=\u69cb\u6210 -label.confirm.password=\u30d1\u30b9\u30ef\u30fc\u30c9\u306e\u78ba\u8a8d\u5165\u529b +label.configure.vpc=VPC \u306e\u69cb\u6210 label.confirmation=\u78ba\u8a8d +label.confirm.password=\u30d1\u30b9\u30ef\u30fc\u30c9\u306e\u78ba\u8a8d\u5165\u529b label.congratulations=\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u306f\u3053\u308c\u3067\u5b8c\u4e86\u3067\u3059\u3002 label.conserve.mode=\u7bc0\u7d04\u30e2\u30fc\u30c9 label.console.proxy=\u30b3\u30f3\u30bd\u30fc\u30eb \u30d7\u30ed\u30ad\u30b7 @@ -431,16 +426,17 @@ label.corrections.saved=\u63a5\u7d9a\u304c\u4fdd\u5b58\u3055\u308c\u307e\u3057\u label.cpu.allocated.for.VMs=VM \u306b\u5272\u308a\u5f53\u3066\u6e08\u307f\u306e CPU label.cpu.allocated=\u5272\u308a\u5f53\u3066\u6e08\u307f\u306e CPU label.CPU.cap=CPU \u4e0a\u9650 +label.cpu=CPU label.cpu.limits=CPU \u5236\u9650 label.cpu.mhz=CPU (MHz) label.cpu.utilized=CPU \u4f7f\u7528\u7387 -label.cpu=CPU +label.created.by.system=\u30b7\u30b9\u30c6\u30e0\u4f5c\u6210 +label.created=\u4f5c\u6210\u65e5\u6642 label.create.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u4f5c\u6210 label.create.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u4f5c\u6210 label.create.VPN.connection=VPN \u63a5\u7d9a\u306e\u4f5c\u6210 -label.created.by.system=\u30b7\u30b9\u30c6\u30e0\u4f5c\u6210 -label.created=\u4f5c\u6210\u65e5\u6642 label.cross.zones=\u30af\u30ed\u30b9 \u30be\u30fc\u30f3 +label.custom.disk.iops=\u30ab\u30b9\u30bf\u30e0 IOPS label.custom.disk.size=\u30ab\u30b9\u30bf\u30e0 \u30c7\u30a3\u30b9\u30af \u30b5\u30a4\u30ba label.daily=\u6bce\u65e5 label.data.disk.offering=\u30c7\u30fc\u30bf \u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 @@ -450,22 +446,25 @@ label.day.of.week=\u6bce\u9031\u6307\u5b9a\u65e5 label.dead.peer.detection=\u505c\u6b62\u30d4\u30a2\u3092\u691c\u51fa\u3059\u308b label.decline.invitation=\u62db\u5f85\u306e\u8f9e\u9000 label.dedicated=\u5c02\u7528 +label.default=\u30c7\u30d5\u30a9\u30eb\u30c8 label.default.use=\u30c7\u30d5\u30a9\u30eb\u30c8\u4f7f\u7528 label.default.view=\u30c7\u30d5\u30a9\u30eb\u30c8 \u30d3\u30e5\u30fc -label.default=\u30c7\u30d5\u30a9\u30eb\u30c8 label.delete.affinity.group=\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u306e\u524a\u9664 +label.delete.alerts=\u30a2\u30e9\u30fc\u30c8\u306e\u524a\u9664 label.delete.BigSwitchVns=Big Switch VNS \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u306e\u524a\u9664 +label.delete.events=\u30a4\u30d9\u30f3\u30c8\u306e\u524a\u9664 label.delete.F5=F5 \u306e\u524a\u9664 label.delete.gateway=\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u306e\u524a\u9664 label.delete.NetScaler=NetScaler \u306e\u524a\u9664 label.delete.NiciraNvp=NVP \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u306e\u524a\u9664 +label.delete.PA=Palo Alto \u306e\u524a\u9664 label.delete.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u524a\u9664 label.delete.SRX=SRX \u306e\u524a\u9664 +label.delete=\u524a\u9664 label.delete.VPN.connection=VPN \u63a5\u7d9a\u306e\u524a\u9664 label.delete.VPN.customer.gateway=VPN \u30ab\u30b9\u30bf\u30de\u30fc \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u306e\u524a\u9664 label.delete.VPN.gateway=VPN \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u306e\u524a\u9664 label.delete.vpn.user=VPN \u30e6\u30fc\u30b6\u30fc\u306e\u524a\u9664 -label.delete=\u524a\u9664 label.deleting.failed=\u524a\u9664\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f label.deleting.processing=\u524a\u9664\u3057\u3066\u3044\u307e\u3059... label.description=\u8aac\u660e @@ -477,18 +476,25 @@ label.detaching.disk=\u30c7\u30a3\u30b9\u30af\u3092\u30c7\u30bf\u30c3\u30c1\u305 label.details=\u8a73\u7d30 label.device.id=\u30c7\u30d0\u30a4\u30b9 ID label.devices=\u30c7\u30d0\u30a4\u30b9 -label.DHCP.server.type=DHCP \u30b5\u30fc\u30d0\u30fc\u306e\u7a2e\u985e label.dhcp=DHCP +label.DHCP.server.type=DHCP \u30b5\u30fc\u30d0\u30fc\u306e\u7a2e\u985e label.direct.ips=\u5171\u6709\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e IP \u30a2\u30c9\u30ec\u30b9 +label.disabled=\u7121\u52b9 label.disable.provider=\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u306e\u7121\u52b9\u5316 label.disable.vpn=VPN \u306e\u7121\u52b9\u5316 -label.disabled=\u7121\u52b9 label.disabling.vpn.access=VPN \u30a2\u30af\u30bb\u30b9\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u307e\u3059 label.disk.allocated=\u5272\u308a\u5f53\u3066\u6e08\u307f\u306e\u30c7\u30a3\u30b9\u30af +label.disk.bytes.read.rate=\u30c7\u30a3\u30b9\u30af\u8aad\u307f\u53d6\u308a\u901f\u5ea6 (BPS) +label.disk.bytes.write.rate=\u30c7\u30a3\u30b9\u30af\u66f8\u304d\u8fbc\u307f\u901f\u5ea6 (BPS) +label.disk.iops.max=\u6700\u5927 IOPS +label.disk.iops.min=\u6700\u5c0f IOPS +label.disk.iops.read.rate=\u30c7\u30a3\u30b9\u30af\u8aad\u307f\u53d6\u308a\u901f\u5ea6 (IOPS) +label.disk.iops.total=IOPS \u5408\u8a08 +label.disk.iops.write.rate=\u30c7\u30a3\u30b9\u30af\u66f8\u304d\u8fbc\u307f\u901f\u5ea6 (IOPS) label.disk.offering=\u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 label.disk.read.bytes=\u30c7\u30a3\u30b9\u30af\u8aad\u307f\u53d6\u308a (\u30d0\u30a4\u30c8) label.disk.read.io=\u30c7\u30a3\u30b9\u30af\u8aad\u307f\u53d6\u308a (IO) -label.disk.size.gb=\u30c7\u30a3\u30b9\u30af \u30b5\u30a4\u30ba (GB \u5358\u4f4d) +label.disk.size.gb=\u30c7\u30a3\u30b9\u30af \u30b5\u30a4\u30ba (GB) label.disk.size=\u30c7\u30a3\u30b9\u30af \u30b5\u30a4\u30ba label.disk.total=\u30c7\u30a3\u30b9\u30af\u5408\u8a08 label.disk.volume=\u30c7\u30a3\u30b9\u30af \u30dc\u30ea\u30e5\u30fc\u30e0 @@ -498,8 +504,8 @@ label.display.name=\u8868\u793a\u540d label.display.text=\u8868\u793a\u30c6\u30ad\u30b9\u30c8 label.dns.1=DNS 1 label.dns.2=DNS 2 -label.DNS.domain.for.guest.networks=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e DNS \u30c9\u30e1\u30a4\u30f3 label.dns=DNS +label.DNS.domain.for.guest.networks=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e DNS \u30c9\u30e1\u30a4\u30f3 label.domain.admin=\u30c9\u30e1\u30a4\u30f3\u7ba1\u7406\u8005 label.domain.id=\u30c9\u30e1\u30a4\u30f3 ID label.domain.name=\u30c9\u30e1\u30a4\u30f3\u540d @@ -510,15 +516,17 @@ label.done=\u5b8c\u4e86 label.double.quotes.are.not.allowed=\u4e8c\u91cd\u5f15\u7528\u7b26\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 label.download.progress=\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u306e\u9032\u6357\u72b6\u6cc1 label.drag.new.position=\u65b0\u3057\u3044\u4f4d\u7f6e\u306b\u30c9\u30e9\u30c3\u30b0 +label.edit.affinity.group=\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u306e\u7de8\u96c6 label.edit.lb.rule=\u8ca0\u8377\u5206\u6563\u898f\u5247\u306e\u7de8\u96c6 label.edit.network.details=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8a73\u7d30\u306e\u7de8\u96c6 label.edit.project.details=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u8a73\u7d30\u306e\u7de8\u96c6 label.edit.tags=\u30bf\u30b0\u306e\u7de8\u96c6 label.edit.traffic.type=\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e\u306e\u7de8\u96c6 -label.edit.vpc=VPC \u306e\u7de8\u96c6 label.edit=\u7de8\u96c6 -label.egress.rule=\u9001\u4fe1\u898f\u5247 +label.edit.vpc=VPC \u306e\u7de8\u96c6 +label.egress.default.policy=\u9001\u4fe1\u306e\u30c7\u30d5\u30a9\u30eb\u30c8 \u30dd\u30ea\u30b7\u30fc label.egress.rules=\u9001\u4fe1\u898f\u5247 +label.egress.rule=\u9001\u4fe1\u898f\u5247 label.elastic.IP=\u30a8\u30e9\u30b9\u30c6\u30a3\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9 label.elastic.LB=\u30a8\u30e9\u30b9\u30c6\u30a3\u30c3\u30af\u8ca0\u8377\u5206\u6563 label.elastic=\u30a8\u30e9\u30b9\u30c6\u30a3\u30c3\u30af @@ -530,20 +538,23 @@ label.enable.vpn=VPN \u306e\u6709\u52b9\u5316 label.enabling.vpn.access=VPN \u30a2\u30af\u30bb\u30b9\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059 label.enabling.vpn=VPN \u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059 label.end.IP=\u7d42\u4e86 IP \u30a2\u30c9\u30ec\u30b9 +label.endpoint.or.operation=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u307e\u305f\u306f\u64cd\u4f5c +label.endpoint=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 label.end.port=\u7d42\u4e86\u30dd\u30fc\u30c8 label.end.reserved.system.IP=\u4e88\u7d04\u6e08\u307f\u7d42\u4e86\u30b7\u30b9\u30c6\u30e0 IP \u30a2\u30c9\u30ec\u30b9 label.end.vlan=\u7d42\u4e86 VLAN label.end.vxlan=\u7d42\u4e86 VXLAN -label.endpoint.or.operation=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u307e\u305f\u306f\u64cd\u4f5c -label.endpoint=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 label.enter.token=\u30c8\u30fc\u30af\u30f3\u306e\u5165\u529b label.error.code=\u30a8\u30e9\u30fc \u30b3\u30fc\u30c9 label.error=\u30a8\u30e9\u30fc label.ESP.encryption=ESP \u6697\u53f7\u5316 label.ESP.hash=ESP \u30cf\u30c3\u30b7\u30e5 +label.ESP.lifetime=ESP \u6709\u52b9\u671f\u9593 (\u79d2) label.ESP.policy=ESP \u30dd\u30ea\u30b7\u30fc label.esx.host=ESX/ESXi \u30db\u30b9\u30c8 label.example=\u4f8b +label.expunge=\u62b9\u6d88 +label.external.link=\u5916\u90e8\u30ea\u30f3\u30af label.f5=F5 label.failed=\u5931\u6557 label.featured=\u304a\u3059\u3059\u3081 @@ -579,17 +590,20 @@ label.ha.enabled=\u9ad8\u53ef\u7528\u6027\u6709\u52b9 label.help=\u30d8\u30eb\u30d7 label.hide.ingress.rule=\u53d7\u4fe1\u898f\u5247\u3092\u96a0\u3059 label.hints=\u30d2\u30f3\u30c8 +label.home=\u30db\u30fc\u30e0 label.host.alerts=\u30db\u30b9\u30c8 \u30a2\u30e9\u30fc\u30c8 label.host.MAC=\u30db\u30b9\u30c8\u306e MAC label.host.name=\u30db\u30b9\u30c8\u540d +label.hosts=\u30db\u30b9\u30c8 label.host.tags=\u30db\u30b9\u30c8 \u30bf\u30b0 label.host=\u30db\u30b9\u30c8 -label.hosts=\u30db\u30b9\u30c8 label.hourly=\u6bce\u6642 label.hypervisor.capabilities=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u306e\u6a5f\u80fd +label.hypervisor.snapshot.reserve=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc \u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u4e88\u7d04 +label.hypervisors=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc label.hypervisor.type=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u306e\u7a2e\u985e -label.hypervisor.version=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u306e\u30d0\u30fc\u30b8\u30e7\u30f3 label.hypervisor=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc +label.hypervisor.version=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u306e\u30d0\u30fc\u30b8\u30e7\u30f3 label.id=ID label.IKE.DH=IKE DH label.IKE.encryption=IKE \u6697\u53f7\u5316 @@ -609,16 +623,16 @@ label.installWizard.addPrimaryStorageIntro.subtitle=\u30d7\u30e9\u30a4\u30de\u30 label.installWizard.addPrimaryStorageIntro.title=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u8ffd\u52a0\u3057\u307e\u3057\u3087\u3046 label.installWizard.addSecondaryStorageIntro.subtitle=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306b\u3064\u3044\u3066 label.installWizard.addSecondaryStorageIntro.title=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u8ffd\u52a0\u3057\u307e\u3057\u3087\u3046 -label.installWizard.addZone.title=\u30be\u30fc\u30f3\u306e\u8ffd\u52a0 label.installWizard.addZoneIntro.subtitle=\u30be\u30fc\u30f3\u306b\u3064\u3044\u3066 label.installWizard.addZoneIntro.title=\u30be\u30fc\u30f3\u3092\u8ffd\u52a0\u3057\u307e\u3057\u3087\u3046 +label.installWizard.addZone.title=\u30be\u30fc\u30f3\u306e\u8ffd\u52a0 label.installWizard.click.launch=[\u8d77\u52d5] \u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u304f\u3060\u3055\u3044\u3002 label.installWizard.subtitle=\u3053\u306e\u30ac\u30a4\u30c9 \u30c4\u30a2\u30fc\u306f CloudStack&\#8482; \u74b0\u5883\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u306b\u5f79\u7acb\u3061\u307e\u3059 -label.installWizard.title=CloudStack&\#8482 \u3078\u3088\u3046\u3053\u305d +label.installWizard.title=CloudStack&\#8482; \u3078\u3088\u3046\u3053\u305d label.instance.limits=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5236\u9650 label.instance.name=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u540d -label.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9 label.instances=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9 +label.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9 label.internal.dns.1=\u5185\u90e8 DNS 1 label.internal.dns.2=\u5185\u90e8 DNS 2 label.internal.name=\u5185\u90e8\u540d @@ -627,34 +641,34 @@ label.introduction.to.cloudstack=CloudStack&\#8482; \u306e\u7d39\u4ecb label.invalid.integer=\u7121\u52b9\u306a\u6574\u6570 label.invalid.number=\u7121\u52b9\u306a\u6570 label.invitations=\u62db\u5f85\u72b6 +label.invited.accounts=\u62db\u5f85\u6e08\u307f\u30a2\u30ab\u30a6\u30f3\u30c8 label.invite.to=\u62db\u5f85\u3059\u308b\u30d7\u30ed\u30b8\u30a7\u30af\u30c8: label.invite=\u62db\u5f85 -label.invited.accounts=\u62db\u5f85\u6e08\u307f\u30a2\u30ab\u30a6\u30f3\u30c8 label.ip.address=IP \u30a2\u30c9\u30ec\u30b9 +label.ipaddress=IP \u30a2\u30c9\u30ec\u30b9 label.ip.allocations=IP \u30a2\u30c9\u30ec\u30b9\u306e\u5272\u308a\u5f53\u3066 +label.ip=IP label.ip.limits=\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9\u306e\u5236\u9650 label.ip.or.fqdn=IP \u30a2\u30c9\u30ec\u30b9\u307e\u305f\u306f FQDN label.ip.range=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2 label.ip.ranges=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2 -label.ip=IP -label.ipaddress=IP \u30a2\u30c9\u30ec\u30b9 -label.ips=IP \u30a2\u30c9\u30ec\u30b9 label.IPsec.preshared.key=IPsec \u4e8b\u524d\u5171\u6709\u30ad\u30fc -label.is.default=\u30c7\u30d5\u30a9\u30eb\u30c8 -label.is.redundant.router=\u5197\u9577 -label.is.shared=\u5171\u6709 -label.is.system=\u30b7\u30b9\u30c6\u30e0 +label.ips=IP \u30a2\u30c9\u30ec\u30b9 label.iscsi=iSCSI +label.is.default=\u30c7\u30d5\u30a9\u30eb\u30c8 label.iso.boot=ISO \u8d77\u52d5 label.iso=ISO label.isolated.networks=\u5206\u96e2\u3055\u308c\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af label.isolation.method=\u5206\u96e2\u65b9\u6cd5 label.isolation.mode=\u5206\u96e2\u30e2\u30fc\u30c9 label.isolation.uri=\u5206\u96e2 URI +label.is.redundant.router=\u5197\u9577 +label.is.shared=\u5171\u6709 +label.is.system=\u30b7\u30b9\u30c6\u30e0 label.item.listing=\u9805\u76ee\u4e00\u89a7 label.keep=\u7dad\u6301 -label.key=\u30ad\u30fc label.keyboard.type=\u30ad\u30fc\u30dc\u30fc\u30c9\u306e\u7a2e\u985e +label.key=\u30ad\u30fc label.kvm.traffic.label=KVM \u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af \u30e9\u30d9\u30eb label.label=\u30e9\u30d9\u30eb label.lang.arabic=\u30a2\u30e9\u30d3\u30a2\u8a9e @@ -673,12 +687,14 @@ label.lang.spanish=\u30b9\u30da\u30a4\u30f3\u8a9e label.last.disconnected=\u6700\u7d42\u5207\u65ad\u65e5\u6642 label.last.name=\u59d3 label.latest.events=\u6700\u65b0\u30a4\u30d9\u30f3\u30c8 +label.launch=\u8d77\u52d5 label.launch.vm=VM \u306e\u8d77\u52d5 label.launch.zone=\u30be\u30fc\u30f3\u306e\u8d77\u52d5 -label.launch=\u8d77\u52d5 label.LB.isolation=\u8ca0\u8377\u5206\u6563\u5206\u96e2 +label.ldap.group.name=LDAP \u30b0\u30eb\u30fc\u30d7 label.least.connections=\u6700\u5c0f\u63a5\u7d9a label.level=\u30ec\u30d9\u30eb +label.linklocal.ip=\u30ea\u30f3\u30af \u30ed\u30fc\u30ab\u30eb IP \u30a2\u30c9\u30ec\u30b9 label.load.balancer=\u8ca0\u8377\u5206\u6563\u88c5\u7f6e label.load.balancing.policies=\u8ca0\u8377\u5206\u6563\u30dd\u30ea\u30b7\u30fc label.load.balancing=\u8ca0\u8377\u5206\u6563 @@ -688,30 +704,33 @@ label.local.storage=\u30ed\u30fc\u30ab\u30eb \u30b9\u30c8\u30ec\u30fc\u30b8 label.local=\u30ed\u30fc\u30ab\u30eb label.login=\u30ed\u30b0\u30aa\u30f3 label.logout=\u30ed\u30b0\u30aa\u30d5 -label.LUN.number=LUN \u756a\u53f7 label.lun=LUN +label.LUN.number=LUN \u756a\u53f7 label.make.project.owner=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u6240\u6709\u8005\u5316 -label.manage.resources=\u30ea\u30bd\u30fc\u30b9\u306e\u7ba1\u7406 -label.manage=\u7ba1\u7406 label.management.ips=\u7ba1\u7406 IP \u30a2\u30c9\u30ec\u30b9 label.management=\u7ba1\u7406 +label.manage.resources=\u30ea\u30bd\u30fc\u30b9\u306e\u7ba1\u7406 +label.manage=\u7ba1\u7406 label.max.cpus=\u6700\u5927 CPU \u30b3\u30a2\u6570 label.max.guest.limit=\u6700\u5927\u30b2\u30b9\u30c8\u5236\u9650 +label.maximum=\u6700\u5927 label.max.memory=\u6700\u5927\u30e1\u30e2\u30ea (MiB) label.max.networks=\u6700\u5927\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u6570 +label.max.primary.storage=\u6700\u5927\u30d7\u30e9\u30a4\u30de\u30ea (GiB) label.max.public.ips=\u6700\u5927\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9\u6570 +label.max.secondary.storage=\u6700\u5927\u30bb\u30ab\u30f3\u30c0\u30ea (GiB) label.max.snapshots=\u6700\u5927\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u6570 label.max.templates=\u6700\u5927\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u6570 label.max.vms=\u6700\u5927\u30e6\u30fc\u30b6\u30fc VM \u6570 label.max.volumes=\u6700\u5927\u30dc\u30ea\u30e5\u30fc\u30e0\u6570 label.max.vpcs=\u6700\u5927 VPC \u6570 -label.maximum=\u6700\u5927 label.may.continue=\u7d9a\u884c\u3067\u304d\u307e\u3059\u3002 label.memory.allocated=\u5272\u308a\u5f53\u3066\u6e08\u307f\u306e\u30e1\u30e2\u30ea +label.memory.limits=\u30e1\u30e2\u30ea\u5236\u9650 (MiB) label.memory.mb=\u30e1\u30e2\u30ea (MB) label.memory.total=\u30e1\u30e2\u30ea\u5408\u8a08 -label.memory.used=\u30e1\u30e2\u30ea\u4f7f\u7528\u91cf label.memory=\u30e1\u30e2\u30ea +label.memory.used=\u30e1\u30e2\u30ea\u4f7f\u7528\u91cf label.menu.accounts=\u30a2\u30ab\u30a6\u30f3\u30c8 label.menu.alerts=\u30a2\u30e9\u30fc\u30c8 label.menu.all.accounts=\u3059\u3079\u3066\u306e\u30a2\u30ab\u30a6\u30f3\u30c8 @@ -746,8 +765,8 @@ label.menu.snapshots=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 label.menu.stopped.instances=\u505c\u6b62\u3055\u308c\u305f\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9 label.menu.storage=\u30b9\u30c8\u30ec\u30fc\u30b8 label.menu.system.service.offerings=\u30b7\u30b9\u30c6\u30e0 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 -label.menu.system.vms=\u30b7\u30b9\u30c6\u30e0 VM label.menu.system=\u30b7\u30b9\u30c6\u30e0 +label.menu.system.vms=\u30b7\u30b9\u30c6\u30e0 VM label.menu.templates=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8 label.menu.virtual.appliances=\u4eee\u60f3\u30a2\u30d7\u30e9\u30a4\u30a2\u30f3\u30b9 label.menu.virtual.resources=\u4eee\u60f3\u30ea\u30bd\u30fc\u30b9 @@ -777,16 +796,18 @@ label.name=\u540d\u524d label.nat.port.range=NAT \u30dd\u30fc\u30c8\u306e\u7bc4\u56f2 label.netmask=\u30cd\u30c3\u30c8\u30de\u30b9\u30af label.netScaler=NetScaler +label.network.ACLs=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ACL label.network.ACL.total=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ACL \u5408\u8a08 label.network.ACL=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ACL -label.network.ACLs=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ACL label.network.desc=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8aac\u660e label.network.device.type=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30c7\u30d0\u30a4\u30b9\u306e\u7a2e\u985e label.network.device=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30c7\u30d0\u30a4\u30b9 label.network.domain.text=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30c9\u30e1\u30a4\u30f3 label.network.domain=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30c9\u30e1\u30a4\u30f3 label.network.id=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ID +label.networking.and.security=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3068\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 label.network.label.display.for.blank.value=\u30c7\u30d5\u30a9\u30eb\u30c8 \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u3092\u4f7f\u7528 +label.network.limits=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5236\u9650 label.network.name=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u540d label.network.offering.display.text=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u8868\u793a\u30c6\u30ad\u30b9\u30c8 label.network.offering.id=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 ID @@ -796,20 +817,19 @@ label.network.rate.megabytes=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u901f\u5ea6 (M label.network.rate=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u901f\u5ea6 (MB/\u79d2) label.network.read=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u8aad\u307f\u53d6\u308a label.network.service.providers=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30b5\u30fc\u30d3\u30b9 \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc +label.networks=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af label.network.type=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u7a2e\u985e -label.network.write=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u66f8\u304d\u8fbc\u307f label.network=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af -label.networking.and.security=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3068\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 -label.networks=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.network.write=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u66f8\u304d\u8fbc\u307f label.new.password=\u65b0\u3057\u3044\u30d1\u30b9\u30ef\u30fc\u30c9 label.new.project=\u65b0\u3057\u3044\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 -label.new.vm=\u65b0\u3057\u3044 VM label.new=\u65b0\u898f +label.new.vm=\u65b0\u3057\u3044 VM label.next=\u6b21\u3078 label.nexusVswitch=Nexus 1000V +label.nfs=NFS label.nfs.server=NFS \u30b5\u30fc\u30d0\u30fc label.nfs.storage=NFS \u30b9\u30c8\u30ec\u30fc\u30b8 -label.nfs=NFS label.nic.adapter.type=NIC \u30a2\u30c0\u30d7\u30bf\u30fc\u306e\u7a2e\u985e label.nicira.controller.address=\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc \u30a2\u30c9\u30ec\u30b9 label.nicira.l3gatewayserviceuuid=L3 \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 \u30b5\u30fc\u30d3\u30b9\u306e UUID @@ -821,19 +841,19 @@ label.no.data=\u8868\u793a\u3059\u308b\u30c7\u30fc\u30bf\u304c\u3042\u308a\u307e label.no.errors=\u6700\u8fd1\u306e\u30a8\u30e9\u30fc\u306f\u3042\u308a\u307e\u305b\u3093 label.no.isos=\u4f7f\u7528\u3067\u304d\u308b ISO \u306f\u3042\u308a\u307e\u305b\u3093 label.no.items=\u4f7f\u7528\u3067\u304d\u308b\u9805\u76ee\u306f\u3042\u308a\u307e\u305b\u3093 -label.no.security.groups=\u4f7f\u7528\u3067\u304d\u308b\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u306f\u3042\u308a\u307e\u305b\u3093 -label.no.thanks=\u8a2d\u5b9a\u3057\u306a\u3044 -label.no=\u3044\u3044\u3048 label.none=\u306a\u3057 +label.no.security.groups=\u4f7f\u7528\u3067\u304d\u308b\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u306f\u3042\u308a\u307e\u305b\u3093 label.not.found=\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +label.no.thanks=\u8a2d\u5b9a\u3057\u306a\u3044 label.notifications=\u901a\u77e5 -label.num.cpu.cores=CPU \u30b3\u30a2\u6570 +label.no=\u3044\u3044\u3048 label.number.of.clusters=\u30af\u30e9\u30b9\u30bf\u30fc\u6570 label.number.of.hosts=\u30db\u30b9\u30c8\u6570 label.number.of.pods=\u30dd\u30c3\u30c9\u6570 label.number.of.system.vms=\u30b7\u30b9\u30c6\u30e0 VM \u6570 label.number.of.virtual.routers=\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc\u6570 label.number.of.zones=\u30be\u30fc\u30f3\u6570 +label.num.cpu.cores=CPU \u30b3\u30a2\u6570 label.numretries=\u518d\u8a66\u884c\u56de\u6570 label.ocfs2=OCFS2 label.offer.ha=\u9ad8\u53ef\u7528\u6027\u3092\u63d0\u4f9b\u3059\u308b @@ -845,12 +865,16 @@ label.os.type=OS \u306e\u7a2e\u985e label.owned.public.ips=\u6240\u6709\u3059\u308b\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9 label.owner.account=\u6240\u6709\u8005\u30a2\u30ab\u30a6\u30f3\u30c8 label.owner.domain=\u6240\u6709\u8005\u30c9\u30e1\u30a4\u30f3 +label.PA.log.profile=Palo Alto \u30ed\u30b0 \u30d7\u30ed\u30d5\u30a1\u30a4\u30eb +label.PA=Palo Alto label.parent.domain=\u89aa\u30c9\u30e1\u30a4\u30f3 label.password.enabled=\u30d1\u30b9\u30ef\u30fc\u30c9\u7ba1\u7406\u6709\u52b9 label.password=\u30d1\u30b9\u30ef\u30fc\u30c9 +label.PA.threat.profile=Palo Alto \u8105\u5a01\u30d7\u30ed\u30d5\u30a1\u30a4\u30eb label.path=\u30d1\u30b9 label.perfect.forward.secrecy=Perfect Forward Secrecy label.physical.network.ID=\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ID +label.physical.network=\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af label.PING.CIFS.password=PING CIFS \u30d1\u30b9\u30ef\u30fc\u30c9 label.PING.CIFS.username=PING CIFS \u30e6\u30fc\u30b6\u30fc\u540d label.PING.dir=PING \u30c7\u30a3\u30ec\u30af\u30c8\u30ea @@ -860,48 +884,55 @@ label.please.wait=\u304a\u5f85\u3061\u304f\u3060\u3055\u3044 label.plugin.details=\u30d7\u30e9\u30b0\u30a4\u30f3\u306e\u8a73\u7d30 label.plugins=\u30d7\u30e9\u30b0\u30a4\u30f3 label.pod.name=\u30dd\u30c3\u30c9\u540d -label.pod=\u30dd\u30c3\u30c9 label.pods=\u30dd\u30c3\u30c9 +label.pod=\u30dd\u30c3\u30c9 label.port.forwarding.policies=\u30dd\u30fc\u30c8\u8ee2\u9001\u30dd\u30ea\u30b7\u30fc label.port.forwarding=\u30dd\u30fc\u30c8\u8ee2\u9001 label.port.range=\u30dd\u30fc\u30c8\u306e\u7bc4\u56f2 label.PreSetup=PreSetup -label.prev=\u623b\u308b label.previous=\u623b\u308b +label.prev=\u623b\u308b label.primary.allocated=\u5272\u308a\u5f53\u3066\u6e08\u307f\u306e\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 label.primary.network=\u30d7\u30e9\u30a4\u30de\u30ea \u30cd\u30c3\u30c8\u30ef\u30fc\u30af label.primary.storage.count=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 \u30d7\u30fc\u30eb +label.primary.storage.limits=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u5236\u9650 (GiB) label.primary.storage=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 label.primary.used=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u4f7f\u7528\u91cf label.private.Gateway=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 label.private.interface=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30a4\u30b9 label.private.ip.range=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2 -label.private.ip=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 IP \u30a2\u30c9\u30ec\u30b9 label.private.ips=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 IP \u30a2\u30c9\u30ec\u30b9 +label.private.ip=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 IP \u30a2\u30c9\u30ec\u30b9 +label.privatekey=PKCS\#8 \u79d8\u5bc6\u30ad\u30fc label.private.network=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af label.private.port=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30dd\u30fc\u30c8 label.private.zone=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30be\u30fc\u30f3 -label.privatekey=PKCS\#8 \u79d8\u5bc6\u30ad\u30fc label.project.dashboard=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 \u30c0\u30c3\u30b7\u30e5\u30dc\u30fc\u30c9 label.project.id=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 ID label.project.invite=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3078\u306e\u62db\u5f85 label.project.name=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u540d -label.project.view=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 \u30d3\u30e5\u30fc -label.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 label.projects=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 +label.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 +label.project.view=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 \u30d3\u30e5\u30fc label.protocol=\u30d7\u30ed\u30c8\u30b3\u30eb label.providers=\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc label.public.interface=\u30d1\u30d6\u30ea\u30c3\u30af \u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30a4\u30b9 -label.public.ip=\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9 label.public.ips=\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9 +label.public.ip=\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9 label.public.network=\u30d1\u30d6\u30ea\u30c3\u30af \u30cd\u30c3\u30c8\u30ef\u30fc\u30af label.public.port=\u30d1\u30d6\u30ea\u30c3\u30af \u30dd\u30fc\u30c8 label.public.traffic=\u30d1\u30d6\u30ea\u30c3\u30af \u30c8\u30e9\u30d5\u30a3\u30c3\u30af -label.public.zone=\u30d1\u30d6\u30ea\u30c3\u30af \u30be\u30fc\u30f3 label.public=\u30d1\u30d6\u30ea\u30c3\u30af +label.public.zone=\u30d1\u30d6\u30ea\u30c3\u30af \u30be\u30fc\u30f3 label.purpose=\u76ee\u7684 label.Pxe.server.type=PXE \u30b5\u30fc\u30d0\u30fc\u306e\u7a2e\u985e +label.qos.type=QoS \u306e\u7a2e\u985e label.quickview=\u30af\u30a4\u30c3\u30af\u30d3\u30e5\u30fc +label.rbd.id=Cephx \u30e6\u30fc\u30b6\u30fc +label.rbd.monitor=Ceph \u30e2\u30cb\u30bf\u30fc +label.rbd.pool=Ceph \u30d7\u30fc\u30eb +label.rbd=RBD +label.rbd.secret=Cephx \u30b7\u30fc\u30af\u30ec\u30c3\u30c8 label.reboot=\u518d\u8d77\u52d5 label.recent.errors=\u6700\u8fd1\u306e\u30a8\u30e9\u30fc label.redundant.router.capability=\u5197\u9577\u30eb\u30fc\u30bf\u30fc\u6a5f\u80fd @@ -925,17 +956,20 @@ label.remove.static.route=\u9759\u7684\u30eb\u30fc\u30c8\u306e\u524a\u9664 label.remove.tier=\u968e\u5c64\u306e\u524a\u9664 label.remove.vm.from.lb=\u8ca0\u8377\u5206\u6563\u898f\u5247\u304b\u3089\u306e VM \u306e\u524a\u9664 label.remove.vpc=VPC \u306e\u524a\u9664 -label.removing.user=\u30e6\u30fc\u30b6\u30fc\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059 label.removing=\u524a\u9664\u3057\u3066\u3044\u307e\u3059 +label.removing.user=\u30e6\u30fc\u30b6\u30fc\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059 label.required=\u5fc5\u9808\u3067\u3059 label.reserved.system.gateway=\u4e88\u7d04\u6e08\u307f\u30b7\u30b9\u30c6\u30e0 \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 label.reserved.system.ip=\u4e88\u7d04\u6e08\u307f\u30b7\u30b9\u30c6\u30e0 IP \u30a2\u30c9\u30ec\u30b9 label.reserved.system.netmask=\u4e88\u7d04\u6e08\u307f\u30b7\u30b9\u30c6\u30e0 \u30cd\u30c3\u30c8\u30de\u30b9\u30af label.reset.VPN.connection=VPN \u63a5\u7d9a\u306e\u30ea\u30bb\u30c3\u30c8 +label.resize.new.offering.id=\u65b0\u3057\u3044\u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.resize.new.size=\u65b0\u3057\u3044\u30b5\u30a4\u30ba (GB) +label.resize.shrink.ok=\u7e2e\u5c0f\u53ef\u80fd\u306b\u3059\u308b label.resource.limits=\u30ea\u30bd\u30fc\u30b9\u5236\u9650 label.resource.state=\u30ea\u30bd\u30fc\u30b9\u306e\u72b6\u614b -label.resource=\u30ea\u30bd\u30fc\u30b9 label.resources=\u30ea\u30bd\u30fc\u30b9 +label.resource=\u30ea\u30bd\u30fc\u30b9 label.restart.network=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u518d\u8d77\u52d5 label.restart.required=\u518d\u8d77\u52d5\u304c\u5fc5\u8981 label.restart.vpc=VPC \u306e\u518d\u8d77\u52d5 @@ -945,7 +979,9 @@ label.revoke.project.invite=\u62db\u5f85\u306e\u53d6\u308a\u6d88\u3057 label.role=\u5f79\u5272 label.root.disk.controller=\u30eb\u30fc\u30c8 \u30c7\u30a3\u30b9\u30af \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc label.root.disk.offering=\u30eb\u30fc\u30c8 \u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.root.disk.size=\u30eb\u30fc\u30c8 \u30c7\u30a3\u30b9\u30af \u30b5\u30a4\u30ba label.round.robin=\u30e9\u30a6\u30f3\u30c9\u30ed\u30d3\u30f3 +label.routing=\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0 label.rules=\u898f\u5247 label.running.vms=\u5b9f\u884c\u4e2d\u306e VM label.s3.access_key=\u30a2\u30af\u30bb\u30b9 \u30ad\u30fc @@ -953,6 +989,8 @@ label.s3.bucket=\u30d0\u30b1\u30c3\u30c8 label.s3.connection_timeout=\u63a5\u7d9a\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8 label.s3.endpoint=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 label.s3.max_error_retry=\u6700\u5927\u30a8\u30e9\u30fc\u518d\u8a66\u884c\u6570 +label.s3.nfs.path=S3 NFS \u30d1\u30b9 +label.s3.nfs.server=S3 NFS \u30b5\u30fc\u30d0\u30fc label.s3.secret_key=\u79d8\u5bc6\u30ad\u30fc label.s3.socket_timeout=\u30bd\u30b1\u30c3\u30c8 \u30bf\u30a4\u30e0\u30a2\u30a6\u30c8 label.s3.use_https=HTTPS \u3092\u4f7f\u7528 @@ -964,15 +1002,14 @@ label.scope=\u30b9\u30b3\u30fc\u30d7 label.search=\u691c\u7d22 label.secondary.storage.count=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 \u30d7\u30fc\u30eb label.secondary.storage.limits=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u5236\u9650 (GiB) -label.secondary.storage.vm=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 VM label.secondary.storage=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 +label.secondary.storage.vm=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 VM label.secondary.used=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u4f7f\u7528\u91cf label.secret.key=\u79d8\u5bc6\u30ad\u30fc label.security.group.name=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u540d -label.security.group=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 label.security.groups.enabled=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u6709\u52b9 label.security.groups=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 -label.select-view=\u30d3\u30e5\u30fc\u306e\u9078\u629e +label.security.group=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 label.select.a.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u9078\u629e label.select.a.zone=\u30be\u30fc\u30f3\u306e\u9078\u629e label.select.instance.to.attach.volume.to=\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u30a2\u30bf\u30c3\u30c1\u3059\u308b\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044 @@ -981,19 +1018,21 @@ label.select.iso.or.template=ISO \u307e\u305f\u306f\u30c6\u30f3\u30d7\u30ec\u30f label.select.offering=\u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u9078\u629e label.select.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u9078\u629e label.select.tier=\u968e\u5c64\u306e\u9078\u629e -label.select.vm.for.static.nat=\u9759\u7684 NAT \u7528 VM \u306e\u9078\u629e label.select=\u9078\u629e +label.select-view=\u30d3\u30e5\u30fc\u306e\u9078\u629e +label.select.vm.for.static.nat=\u9759\u7684 NAT \u7528 VM \u306e\u9078\u629e label.sent=\u9001\u4fe1\u6e08\u307f label.server=\u30b5\u30fc\u30d0\u30fc label.service.capabilities=\u30b5\u30fc\u30d3\u30b9\u306e\u6a5f\u80fd label.service.offering=\u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.service.state=\u30b5\u30fc\u30d3\u30b9\u306e\u72b6\u614b label.session.expired=\u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u6709\u52b9\u671f\u9650\u304c\u5207\u308c\u307e\u3057\u305f -label.set.up.zone.type=\u30be\u30fc\u30f3\u306e\u7a2e\u985e\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7 label.setup.network=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7 -label.setup.zone=\u30be\u30fc\u30f3\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7 label.setup=\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7 -label.shared=\u5171\u6709 +label.set.up.zone.type=\u30be\u30fc\u30f3\u306e\u7a2e\u985e\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7 +label.setup.zone=\u30be\u30fc\u30f3\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7 label.SharedMountPoint=SharedMountPoint +label.shared=\u5171\u6709 label.show.ingress.rule=\u53d7\u4fe1\u898f\u5247\u306e\u8868\u793a label.shutdown.provider=\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u306e\u30b7\u30e3\u30c3\u30c8\u30c0\u30a6\u30f3 label.site.to.site.VPN=\u30b5\u30a4\u30c8\u9593 VPN @@ -1001,10 +1040,11 @@ label.size=\u30b5\u30a4\u30ba label.skip.guide=CloudStack \u3092\u4f7f\u7528\u3057\u305f\u3053\u3068\u304c\u3042\u308b\u306e\u3067\u3001\u3053\u306e\u30ac\u30a4\u30c9\u3092\u30b9\u30ad\u30c3\u30d7\u3059\u308b label.snapshot.limits=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u5236\u9650 label.snapshot.name=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u540d -label.snapshot.s=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 label.snapshot.schedule=\u5b9a\u671f\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7 -label.snapshot=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 +label.snapshot.s=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 label.snapshots=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 +label.snapshot=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 +label.sockets=\u30bd\u30b1\u30c3\u30c8 label.source.nat=\u9001\u4fe1\u5143 NAT label.source=\u9001\u4fe1\u5143 label.specify.IP.ranges=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u306e\u6307\u5b9a @@ -1020,8 +1060,8 @@ label.start.vxlan=\u958b\u59cb VXLAN label.state=\u72b6\u614b label.static.nat.enabled=\u9759\u7684 NAT \u6709\u52b9 label.static.nat.to=\u9759\u7684 NAT \u306e\u8a2d\u5b9a\u5148: -label.static.nat.vm.details=\u9759\u7684 NAT VM \u306e\u8a73\u7d30 label.static.nat=\u9759\u7684 NAT +label.static.nat.vm.details=\u9759\u7684 NAT VM \u306e\u8a73\u7d30 label.statistics=\u7d71\u8a08 label.status=\u72b6\u6cc1 label.step.1.title=\u624b\u9806 1\: \u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u9078\u629e @@ -1047,28 +1087,28 @@ label.sticky.postonly=\u30dd\u30b9\u30c8\u306e\u307f label.sticky.prefix=\u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9 label.sticky.request-learn=\u30e9\u30fc\u30cb\u30f3\u30b0\u306e\u8981\u6c42 label.sticky.tablesize=\u30c6\u30fc\u30d6\u30eb \u30b5\u30a4\u30ba -label.stop=\u505c\u6b62 label.stopped.vms=\u505c\u6b62\u4e2d\u306e VM +label.stop=\u505c\u6b62 label.storage.tags=\u30b9\u30c8\u30ec\u30fc\u30b8 \u30bf\u30b0 label.storage.traffic=\u30b9\u30c8\u30ec\u30fc\u30b8 \u30c8\u30e9\u30d5\u30a3\u30c3\u30af label.storage.type=\u30b9\u30c8\u30ec\u30fc\u30b8\u306e\u7a2e\u985e -label.qos.type=QoS \u306e\u7a2e\u985e label.storage=\u30b9\u30c8\u30ec\u30fc\u30b8 label.subdomain.access=\u30b5\u30d6\u30c9\u30e1\u30a4\u30f3 \u30a2\u30af\u30bb\u30b9 -label.submit=\u9001\u4fe1 label.submitted.by=[\u9001\u4fe1\u30e6\u30fc\u30b6\u30fc\: ] +label.submit=\u9001\u4fe1 label.succeeded=\u6210\u529f label.sunday=\u65e5\u66dc\u65e5 label.super.cidr.for.guest.networks=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u30b9\u30fc\u30d1\u30fc CIDR label.supported.services=\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u308b\u30b5\u30fc\u30d3\u30b9 label.supported.source.NAT.type=\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u308b\u9001\u4fe1\u5143 NAT \u306e\u7a2e\u985e label.suspend.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u4e00\u6642\u505c\u6b62 +label.switch.type=\u30b9\u30a4\u30c3\u30c1\u306e\u7a2e\u985e label.system.capacity=\u30b7\u30b9\u30c6\u30e0\u306e\u51e6\u7406\u80fd\u529b label.system.offering=\u30b7\u30b9\u30c6\u30e0 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 label.system.service.offering=\u30b7\u30b9\u30c6\u30e0 \u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.system.vms=\u30b7\u30b9\u30c6\u30e0 VM label.system.vm.type=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u7a2e\u985e label.system.vm=\u30b7\u30b9\u30c6\u30e0 VM -label.system.vms=\u30b7\u30b9\u30c6\u30e0 VM label.system.wide.capacity=\u30b7\u30b9\u30c6\u30e0\u5168\u4f53\u306e\u51e6\u7406\u80fd\u529b label.tagged=\u30bf\u30b0\u3042\u308a label.tags=\u30bf\u30b0 @@ -1083,14 +1123,14 @@ label.theme.lightblue=\u30ab\u30b9\u30bf\u30e0 - \u30e9\u30a4\u30c8 \u30d6\u30eb label.thursday=\u6728\u66dc\u65e5 label.tier.details=\u968e\u5c64\u306e\u8a73\u7d30 label.tier=\u968e\u5c64 -label.time.zone=\u30bf\u30a4\u30e0\u30be\u30fc\u30f3 -label.time=\u6642\u523b label.timeout.in.second = \u30bf\u30a4\u30e0\u30a2\u30a6\u30c8 (\u79d2) label.timeout=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8 +label.time=\u6642\u523b +label.time.zone=\u30bf\u30a4\u30e0\u30be\u30fc\u30f3 label.timezone=\u30bf\u30a4\u30e0\u30be\u30fc\u30f3 label.token=\u30c8\u30fc\u30af\u30f3 -label.total.CPU=CPU \u5408\u8a08 label.total.cpu=CPU \u5408\u8a08 +label.total.CPU=CPU \u5408\u8a08 label.total.hosts=\u30db\u30b9\u30c8\u5408\u8a08 label.total.memory=\u30e1\u30e2\u30ea\u5408\u8a08 label.total.of.ip=IP \u30a2\u30c9\u30ec\u30b9\u5408\u8a08 @@ -1098,8 +1138,8 @@ label.total.of.vm=VM \u5408\u8a08 label.total.storage=\u30b9\u30c8\u30ec\u30fc\u30b8\u5408\u8a08 label.total.vms=VM \u5408\u8a08 label.traffic.label=\u30c8\u30e9\u30d5\u30a3\u30c3\u30af \u30e9\u30d9\u30eb -label.traffic.type=\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e label.traffic.types=\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e +label.traffic.type=\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e label.tuesday=\u706b\u66dc\u65e5 label.type.id=\u7a2e\u985e ID label.type=\u7a2e\u985e @@ -1110,15 +1150,15 @@ label.update.project.resources=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 \u30ea\u30bd label.update.ssl.cert= SSL \u8a3c\u660e\u66f8 label.update.ssl= SSL \u8a3c\u660e\u66f8 label.updating=\u66f4\u65b0\u3057\u3066\u3044\u307e\u3059 -label.upload.volume=\u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 label.upload=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 +label.upload.volume=\u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 label.url=URL label.usage.interface=\u4f7f\u7528\u72b6\u6cc1\u6e2c\u5b9a\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30a4\u30b9 -label.use.vm.ip=\u6b21\u306e VM IP \u30a2\u30c9\u30ec\u30b9\u3092\u4f7f\u7528\: label.used=\u4f7f\u7528\u4e2d -label.user=\u30e6\u30fc\u30b6\u30fc label.username=\u30e6\u30fc\u30b6\u30fc\u540d label.users=\u30e6\u30fc\u30b6\u30fc +label.user=\u30e6\u30fc\u30b6\u30fc +label.use.vm.ip=\u6b21\u306e VM IP \u30a2\u30c9\u30ec\u30b9\u3092\u4f7f\u7528\: label.value=\u5024 label.vcdcname=vCenter DC \u540d label.vcenter.cluster=vCenter \u30af\u30e9\u30b9\u30bf\u30fc @@ -1131,56 +1171,59 @@ label.vcipaddress=vCenter IP \u30a2\u30c9\u30ec\u30b9 label.version=\u30d0\u30fc\u30b8\u30e7\u30f3 label.view.all=\u3059\u3079\u3066\u8868\u793a label.view.console=\u30b3\u30f3\u30bd\u30fc\u30eb\u306e\u8868\u793a +label.viewing=\u8868\u793a\u9805\u76ee: label.view.more=\u8a73\u7d30\u8868\u793a +label.view.secondary.ips=\u30bb\u30ab\u30f3\u30c0\u30ea IP \u30a2\u30c9\u30ec\u30b9\u306e\u8868\u793a label.view=\u8868\u793a - -label.viewing=\u8868\u793a\u9805\u76ee: -label.virtual.appliance=\u4eee\u60f3\u30a2\u30d7\u30e9\u30a4\u30a2\u30f3\u30b9 label.virtual.appliances=\u4eee\u60f3\u30a2\u30d7\u30e9\u30a4\u30a2\u30f3\u30b9 +label.virtual.appliance=\u4eee\u60f3\u30a2\u30d7\u30e9\u30a4\u30a2\u30f3\u30b9 label.virtual.machines=\u4eee\u60f3\u30de\u30b7\u30f3 label.virtual.network=\u4eee\u60f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af -label.virtual.router=\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc label.virtual.routers=\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc -label.vlan.id=VLAN ID -label.vlan.range=VLAN \u306e\u7bc4\u56f2 -label.vlan=VLAN -label.vxlan.id=VXLAN ID -label.vxlan.range=VXLAN \u306e\u7bc4\u56f2 -label.vxlan=VXLAN +label.virtual.router=\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc +label.vlan.id=VLAN/VNI ID +label.vlan.range=VLAN/VNI \u306e\u7bc4\u56f2 +label.vlan=VLAN/VNI label.vm.add=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u8ffd\u52a0 label.vm.destroy=\u7834\u68c4 label.vm.display.name=VM \u8868\u793a\u540d -label.vm.name=VM \u540d -label.vm.reboot=\u518d\u8d77\u52d5 -label.vm.start=\u8d77\u52d5 -label.vm.state=VM \u306e\u72b6\u614b -label.vm.stop=\u505c\u6b62 label.VMFS.datastore=VMFS \u30c7\u30fc\u30bf\u30b9\u30c8\u30a2 label.vmfs=VMFS +label.vm.name=VM \u540d +label.vm.reboot=\u518d\u8d77\u52d5 label.VMs.in.tier=\u968e\u5c64\u5185\u306e VM -label.vms=VM label.vmsnapshot.current=\u4f7f\u7528\u4e2d label.vmsnapshot.memory=\u30e1\u30e2\u30ea\u3082\u542b\u3081\u308b label.vmsnapshot.parentname=\u89aa label.vmsnapshot.type=\u7a2e\u985e label.vmsnapshot=VM \u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 +label.vm.start=\u8d77\u52d5 +label.vm.state=VM \u306e\u72b6\u614b +label.vm.stop=\u505c\u6b62 +label.vms=VM label.vmware.traffic.label=VMware \u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af \u30e9\u30d9\u30eb +label.vnet.id=VLAN/VNI ID +label.vnet=VLAN/VNI label.volgroup=\u30dc\u30ea\u30e5\u30fc\u30e0 \u30b0\u30eb\u30fc\u30d7 label.volume.limits=\u30dc\u30ea\u30e5\u30fc\u30e0\u5236\u9650 label.volume.name=\u30dc\u30ea\u30e5\u30fc\u30e0\u540d -label.volume=\u30dc\u30ea\u30e5\u30fc\u30e0 label.volumes=\u30dc\u30ea\u30e5\u30fc\u30e0 +label.volume=\u30dc\u30ea\u30e5\u30fc\u30e0 label.vpc.id=VPC ID label.VPC.router.details=VPC \u30eb\u30fc\u30bf\u30fc\u306e\u8a73\u7d30 label.vpc=VPC label.VPN.connection=VPN \u63a5\u7d9a -label.VPN.customer.gateway=VPN \u30ab\u30b9\u30bf\u30de\u30fc \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 label.vpn.customer.gateway=VPN \u30ab\u30b9\u30bf\u30de\u30fc \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 +label.VPN.customer.gateway=VPN \u30ab\u30b9\u30bf\u30de\u30fc \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 label.VPN.gateway=VPN \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 label.vpn=VPN label.vsmctrlvlanid=\u30b3\u30f3\u30c8\u30ed\u30fc\u30eb VLAN ID label.vsmpktvlanid=\u30d1\u30b1\u30c3\u30c8 VLAN ID label.vsmstoragevlanid=\u30b9\u30c8\u30ec\u30fc\u30b8 VLAN ID label.vsphere.managed=vSphere \u306b\u3088\u308b\u7ba1\u7406 +label.vxlan.id=VXLAN ID +label.vxlan.range=VXLAN \u306e\u7bc4\u56f2 +label.vxlan=VXLAN label.waiting=\u5f85\u6a5f\u3057\u3066\u3044\u307e\u3059 label.warn=\u8b66\u544a label.wednesday=\u6c34\u66dc\u65e5 @@ -1197,17 +1240,18 @@ label.zone.step.1.title=\u624b\u9806 1\: \u30cd\u30c3\u30c8\u30ef\u30fc\ label.zone.step.2.title=\u624b\u9806 2\: \u30be\u30fc\u30f3\u306e\u8ffd\u52a0 label.zone.step.3.title=\u624b\u9806 3\: \u30dd\u30c3\u30c9\u306e\u8ffd\u52a0 label.zone.step.4.title=\u624b\u9806 4\: IP \u30a2\u30c9\u30ec\u30b9\u7bc4\u56f2\u306e\u8ffd\u52a0 +label.zones=\u30be\u30fc\u30f3 label.zone.type=\u30be\u30fc\u30f3\u306e\u7a2e\u985e -label.zone.wide=\u30be\u30fc\u30f3\u5168\u4f53 label.zone=\u30be\u30fc\u30f3 -label.zones=\u30be\u30fc\u30f3 +label.zone.wide=\u30be\u30fc\u30f3\u5168\u4f53 label.zoneWizard.trafficType.guest=\u30b2\u30b9\u30c8\: \u30a8\u30f3\u30c9 \u30e6\u30fc\u30b6\u30fc\u306e\u4eee\u60f3\u30de\u30b7\u30f3\u306e\u9593\u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3067\u3059\u3002 label.zoneWizard.trafficType.management=\u7ba1\u7406\: \u30db\u30b9\u30c8\u3084 CloudStack \u30b7\u30b9\u30c6\u30e0 VM \u306a\u3069\u3001\u7ba1\u7406\u30b5\u30fc\u30d0\u30fc\u3068\u901a\u4fe1\u3059\u308b CloudStack \u306e\u5185\u90e8\u30ea\u30bd\u30fc\u30b9\u9593\u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3067\u3059\u3002 label.zoneWizard.trafficType.public=\u30d1\u30d6\u30ea\u30c3\u30af\: \u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u3068\u30af\u30e9\u30a6\u30c9\u5185\u306e\u4eee\u60f3\u30de\u30b7\u30f3\u306e\u9593\u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3067\u3059\u3002 label.zoneWizard.trafficType.storage=\u30b9\u30c8\u30ec\u30fc\u30b8\: VM \u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3084\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306a\u3069\u3001\u30d7\u30e9\u30a4\u30de\u30ea\u304a\u3088\u3073\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 \u30b5\u30fc\u30d0\u30fc\u9593\u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3067\u3059\u3002 managed.state=\u7ba1\u7406\u5bfe\u8c61\u72b6\u614b -message.acquire.new.ip.vpc=\u3053\u306e VPC \u306e\u65b0\u3057\u3044 IP \u30a2\u30c9\u30ec\u30b9\u3092\u53d6\u5f97\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.acquire.ip.nic=\u3053\u306e NIC \u306e\u305f\u3081\u306b\u65b0\u3057\u3044\u30bb\u30ab\u30f3\u30c0\u30ea IP \u30a2\u30c9\u30ec\u30b9\u3092\u53d6\u5f97\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b?
\u6ce8: \u65b0\u3057\u304f\u53d6\u5f97\u3057\u305f\u30bb\u30ab\u30f3\u30c0\u30ea IP \u30a2\u30c9\u30ec\u30b9\u306f\u4eee\u60f3\u30de\u30b7\u30f3\u5185\u3067\u624b\u52d5\u3067\u69cb\u6210\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 message.acquire.new.ip=\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u65b0\u3057\u3044 IP \u30a2\u30c9\u30ec\u30b9\u3092\u53d6\u5f97\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.acquire.new.ip.vpc=\u3053\u306e VPC \u306e\u65b0\u3057\u3044 IP \u30a2\u30c9\u30ec\u30b9\u3092\u53d6\u5f97\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.acquire.public.ip=\u65b0\u3057\u3044 IP \u30a2\u30c9\u30ec\u30b9\u3092\u53d6\u5f97\u3059\u308b\u30be\u30fc\u30f3\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.action.cancel.maintenance.mode=\u3053\u306e\u4fdd\u5b88\u3092\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.cancel.maintenance=\u30db\u30b9\u30c8\u306e\u4fdd\u5b88\u306f\u6b63\u5e38\u306b\u30ad\u30e3\u30f3\u30bb\u30eb\u3055\u308c\u307e\u3057\u305f\u3002\u3053\u306e\u51e6\u7406\u306b\u306f\u6570\u5206\u304b\u304b\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002 @@ -1223,6 +1267,7 @@ message.action.delete.ISO.for.all.zones=\u305d\u306e ISO \u306f\u3059\u3079\u306 message.action.delete.ISO=\u3053\u306e ISO \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.delete.network=\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.delete.nexusVswitch=\u3053\u306e Nexus 1000V \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.nic=\u3053\u306e NIC \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? \u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3082 VM \u304b\u3089\u524a\u9664\u3055\u308c\u307e\u3059\u3002 message.action.delete.physical.network=\u3053\u306e\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.delete.pod=\u3053\u306e\u30dd\u30c3\u30c9\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.delete.primary.storage=\u3053\u306e\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? @@ -1251,6 +1296,7 @@ message.action.enable.nexusVswitch=\u3053\u306e Nexus 1000V \u3092\u6709\u52b9\u message.action.enable.physical.network=\u3053\u306e\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.enable.pod=\u3053\u306e\u30dd\u30c3\u30c9\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.enable.zone=\u3053\u306e\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.expunge.instance=\u3053\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u62b9\u6d88\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.force.reconnect=\u30db\u30b9\u30c8\u306f\u5f37\u5236\u7684\u306b\u518d\u63a5\u7d9a\u3057\u307e\u3057\u305f\u3002\u3053\u306e\u51e6\u7406\u306b\u306f\u6570\u5206\u304b\u304b\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002 message.action.host.enable.maintenance.mode=\u4fdd\u5b88\u30e2\u30fc\u30c9\u3092\u6709\u52b9\u306b\u3059\u308b\u3068\u3001\u3053\u306e\u30db\u30b9\u30c8\u3067\u5b9f\u884c\u4e2d\u306e\u3059\u3079\u3066\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u304c\u307b\u304b\u306e\u4f7f\u7528\u3067\u304d\u308b\u30db\u30b9\u30c8\u306b\u30e9\u30a4\u30d6 \u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u3055\u308c\u307e\u3059\u3002 message.action.instance.reset.password=\u3053\u306e\u4eee\u60f3\u30de\u30b7\u30f3\u306e\u30eb\u30fc\u30c8 \u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u5909\u66f4\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? @@ -1264,6 +1310,7 @@ message.action.remove.host=\u3053\u306e\u30db\u30b9\u30c8\u3092\u524a\u9664\u305 message.action.reset.password.off=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306f\u73fe\u5728\u3053\u306e\u6a5f\u80fd\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u305b\u3093\u3002 message.action.reset.password.warning=\u73fe\u5728\u306e\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u5909\u66f4\u3059\u308b\u524d\u306b\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u505c\u6b62\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 message.action.restore.instance=\u3053\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5fa9\u5143\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.revert.snapshot=\u6240\u6709\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u3053\u306e\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306b\u623b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.start.instance=\u3053\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.start.router=\u3053\u306e\u30eb\u30fc\u30bf\u30fc\u3092\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.start.systemvm=\u3053\u306e\u30b7\u30b9\u30c6\u30e0 VM \u3092\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? @@ -1272,19 +1319,25 @@ message.action.stop.router=\u3053\u306e\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc\u306 message.action.stop.systemvm=\u3053\u306e\u30b7\u30b9\u30c6\u30e0 VM \u3092\u505c\u6b62\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.take.snapshot=\u3053\u306e\u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u4f5c\u6210\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.unmanage.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u975e\u7ba1\u7406\u5bfe\u8c61\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.vmsnapshot.delete=\u3053\u306e VM \u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.vmsnapshot.revert=VM \u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u5143\u306b\u623b\u3059 message.activate.project=\u3053\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3092\u30a2\u30af\u30c6\u30a3\u30d6\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? -message.add.cluster.zone=\u30be\u30fc\u30f3 \u306b\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u3067\u7ba1\u7406\u3055\u308c\u308b\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u8ffd\u52a0\u3057\u307e\u3059 message.add.cluster=\u30be\u30fc\u30f3 \u306e\u30dd\u30c3\u30c9 \u306b\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u3067\u7ba1\u7406\u3055\u308c\u308b\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u8ffd\u52a0\u3057\u307e\u3059 +message.add.cluster.zone=\u30be\u30fc\u30f3 \u306b\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u3067\u7ba1\u7406\u3055\u308c\u308b\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u8ffd\u52a0\u3057\u307e\u3059 message.add.disk.offering=\u65b0\u3057\u3044\u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u30d1\u30e9\u30e1\u30fc\u30bf\u30fc\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.add.domain=\u3053\u306e\u30c9\u30e1\u30a4\u30f3\u306b\u4f5c\u6210\u3059\u308b\u30b5\u30d6\u30c9\u30e1\u30a4\u30f3\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.add.firewall=\u30be\u30fc\u30f3\u306b\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u3092\u8ffd\u52a0\u3057\u307e\u3059 message.add.guest.network=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u8ffd\u52a0\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.add.host=\u65b0\u3057\u3044\u30db\u30b9\u30c8\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u30d1\u30e9\u30e1\u30fc\u30bf\u30fc\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.adding.host=\u30db\u30b9\u30c8\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +message.adding.Netscaler.device=Netscaler \u30c7\u30d0\u30a4\u30b9\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +message.adding.Netscaler.provider=Netscaler \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 message.add.ip.range.direct.network=\u30be\u30fc\u30f3 \u306e\u76f4\u63a5\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u306b IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3092\u8ffd\u52a0\u3057\u307e\u3059 message.add.ip.range.to.pod=

\u30dd\u30c3\u30c9 \u306b IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3092\u8ffd\u52a0\u3057\u307e\u3059

message.add.ip.range=\u30be\u30fc\u30f3\u306e\u30d1\u30d6\u30ea\u30c3\u30af \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306b IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3092\u8ffd\u52a0\u3057\u307e\u3059 -message.add.load.balancer.under.ip=\u8ca0\u8377\u5206\u6563\u898f\u5247\u304c\u6b21\u306e IP \u30a2\u30c9\u30ec\u30b9\u306b\u5bfe\u3057\u3066\u8ffd\u52a0\u3055\u308c\u307e\u3057\u305f\: +message.additional.networks.desc=\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u304c\u63a5\u7d9a\u3059\u308b\u8ffd\u52a0\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.add.load.balancer=\u30be\u30fc\u30f3\u306b\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u3092\u8ffd\u52a0\u3057\u307e\u3059 +message.add.load.balancer.under.ip=\u8ca0\u8377\u5206\u6563\u898f\u5247\u304c\u6b21\u306e IP \u30a2\u30c9\u30ec\u30b9\u306b\u5bfe\u3057\u3066\u8ffd\u52a0\u3055\u308c\u307e\u3057\u305f\: message.add.network=\u30be\u30fc\u30f3 \u306b\u65b0\u3057\u3044\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u8ffd\u52a0\u3057\u307e\u3059 message.add.new.gateway.to.vpc=\u3053\u306e VPC \u306b\u65b0\u3057\u3044\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3081\u306e\u60c5\u5831\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.add.pod.during.zone.creation=\u5404\u30be\u30fc\u30f3\u306b\u306f 1 \u3064\u4ee5\u4e0a\u306e\u30dd\u30c3\u30c9\u304c\u5fc5\u8981\u3067\u3059\u3002\u4eca\u3053\u3053\u3067\u6700\u521d\u306e\u30dd\u30c3\u30c9\u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002\u30dd\u30c3\u30c9\u306f\u30db\u30b9\u30c8\u3068\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 \u30b5\u30fc\u30d0\u30fc\u304b\u3089\u69cb\u6210\u3055\u308c\u307e\u3059\u304c\u3001\u3053\u308c\u3089\u306f\u5f8c\u306e\u624b\u9806\u3067\u8ffd\u52a0\u3057\u307e\u3059\u3002\u6700\u521d\u306b\u3001CloudStack \u306e\u5185\u90e8\u7ba1\u7406\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u305f\u3081\u306b IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3092\u4e88\u7d04\u3057\u307e\u3059\u3002IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u306f\u3001\u30af\u30e9\u30a6\u30c9\u5185\u306e\u5404\u30be\u30fc\u30f3\u3067\u91cd\u8907\u3057\u306a\u3044\u3088\u3046\u306b\u4e88\u7d04\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 @@ -1298,10 +1351,6 @@ message.add.system.service.offering=\u65b0\u3057\u3044\u30b7\u30b9\u30c6\u30e0 \ message.add.template=\u65b0\u3057\u3044\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f5c\u6210\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u30c7\u30fc\u30bf\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.add.volume=\u65b0\u3057\u3044\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u30c7\u30fc\u30bf\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.add.VPN.gateway=VPN \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u3092\u8ffd\u52a0\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? -message.adding.host=\u30db\u30b9\u30c8\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 -message.adding.Netscaler.device=Netscaler \u30c7\u30d0\u30a4\u30b9\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 -message.adding.Netscaler.provider=Netscaler \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 -message.additional.networks.desc=\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u304c\u63a5\u7d9a\u3059\u308b\u8ffd\u52a0\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.advanced.mode.desc=VLAN \u30b5\u30dd\u30fc\u30c8\u3092\u6709\u52b9\u306b\u3059\u308b\u5834\u5408\u306f\u3001\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30e2\u30c7\u30eb\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u3053\u306e\u30e2\u30c7\u30eb\u3067\u306f\u6700\u3082\u67d4\u8edf\u306b\u30ab\u30b9\u30bf\u30e0 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u63d0\u4f9b\u3067\u304d\u3001\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u3001VPN\u3001\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u306e\u30b5\u30dd\u30fc\u30c8\u306e\u307b\u304b\u306b\u3001\u76f4\u63a5\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3068\u4eee\u60f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3082\u6709\u52b9\u306b\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002 message.advanced.security.group=\u30b2\u30b9\u30c8 VM \u3092\u5206\u96e2\u3059\u308b\u305f\u3081\u306b\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u3092\u4f7f\u7528\u3059\u308b\u5834\u5408\u306f\u3001\u3053\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.advanced.virtual=\u30b2\u30b9\u30c8 VM \u3092\u5206\u96e2\u3059\u308b\u305f\u3081\u306b\u30be\u30fc\u30f3\u5168\u4f53\u306e VLAN \u3092\u4f7f\u7528\u3059\u308b\u5834\u5408\u306f\u3001\u3053\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 @@ -1323,6 +1372,7 @@ message.configuring.storage.traffic=\u30b9\u30c8\u30ec\u30fc\u30b8 \u30c8\u30e9\ message.confirm.action.force.reconnect=\u3053\u306e\u30db\u30b9\u30c8\u3092\u5f37\u5236\u518d\u63a5\u7d9a\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.confirm.delete.F5=F5 \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.confirm.delete.NetScaler=NetScaler \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.delete.PA=Palo Alto \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.confirm.delete.SRX=SRX \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.confirm.destroy.router=\u3053\u306e\u30eb\u30fc\u30bf\u30fc\u3092\u7834\u68c4\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.confirm.disable.provider=\u3053\u306e\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3092\u7121\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? @@ -1332,9 +1382,9 @@ message.confirm.remove.IP.range=\u3053\u306e IP \u30a2\u30c9\u30ec\u30b9\u306e\u message.confirm.shutdown.provider=\u3053\u306e\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3092\u30b7\u30e3\u30c3\u30c8\u30c0\u30a6\u30f3\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.copy.iso.confirm=ISO \u3092\u6b21\u306e\u5834\u6240\u306b\u30b3\u30d4\u30fc\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.copy.template=\u30be\u30fc\u30f3 \u304b\u3089\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8 XXX \u3092\u6b21\u306e\u5834\u6240\u306b\u30b3\u30d4\u30fc\u3057\u307e\u3059\: +message.create.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f5c\u6210\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.create.template.vm=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8 \u304b\u3089 VM \u3092\u4f5c\u6210\u3057\u307e\u3059 message.create.template.volume=\u30c7\u30a3\u30b9\u30af \u30dc\u30ea\u30e5\u30fc\u30e0 \u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f5c\u6210\u3059\u308b\u524d\u306b\u3001\u6b21\u306e\u60c5\u5831\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u30dc\u30ea\u30e5\u30fc\u30e0 \u30b5\u30a4\u30ba\u306b\u3088\u3063\u3066\u306f\u3001\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u4f5c\u6210\u306b\u306f\u6570\u5206\u4ee5\u4e0a\u304b\u304b\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002 -message.create.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f5c\u6210\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.creating.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059 message.creating.guest.network=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059 message.creating.physical.networks=\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059 @@ -1375,11 +1425,11 @@ message.edit.confirm=[\u4fdd\u5b58] \u3092\u30af\u30ea\u30c3\u30af\u3059\u308b\u message.edit.limits=\u6b21\u306e\u30ea\u30bd\u30fc\u30b9\u306b\u5236\u9650\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u300c-1\u300d\u306f\u3001\u30ea\u30bd\u30fc\u30b9\u4f5c\u6210\u306b\u5236\u9650\u304c\u306a\u3044\u3053\u3068\u3092\u793a\u3057\u307e\u3059\u3002 message.edit.traffic.type=\u3053\u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e\u306b\u95a2\u9023\u4ed8\u3051\u308b\u30c8\u30e9\u30d5\u30a3\u30c3\u30af \u30e9\u30d9\u30eb\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.enable.account=\u3053\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.enabled.vpn.ip.sec=IPSec \u4e8b\u524d\u5171\u6709\u30ad\u30fc: +message.enabled.vpn=\u73fe\u5728\u3001VPN \u30a2\u30af\u30bb\u30b9\u304c\u6709\u52b9\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u3002\u6b21\u306e IP \u30a2\u30c9\u30ec\u30b9\u7d4c\u7531\u3067\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u3059\u3002 message.enable.user=\u3053\u306e\u30e6\u30fc\u30b6\u30fc\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.enable.vpn.access=\u73fe\u5728\u3053\u306e IP \u30a2\u30c9\u30ec\u30b9\u306b\u5bfe\u3059\u308b VPN \u306f\u7121\u52b9\u3067\u3059\u3002VPN \u30a2\u30af\u30bb\u30b9\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.enable.vpn=\u3053\u306e IP \u30a2\u30c9\u30ec\u30b9\u306b\u5bfe\u3059\u308b VPN \u30a2\u30af\u30bb\u30b9\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? -message.enabled.vpn.ip.sec=IPSec \u4e8b\u524d\u5171\u6709\u30ad\u30fc: -message.enabled.vpn=\u73fe\u5728\u3001VPN \u30a2\u30af\u30bb\u30b9\u304c\u6709\u52b9\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u3002\u6b21\u306e IP \u30a2\u30c9\u30ec\u30b9\u7d4c\u7531\u3067\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u3059\u3002 message.enabling.security.group.provider=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059 message.enabling.zone=\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059 message.enter.token=\u96fb\u5b50\u30e1\u30fc\u30eb\u306e\u62db\u5f85\u72b6\u306b\u8a18\u8f09\u3055\u308c\u3066\u3044\u308b\u30c8\u30fc\u30af\u30f3\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 @@ -1434,6 +1484,7 @@ message.migrate.router.confirm=\u30eb\u30fc\u30bf\u30fc\u306e\u79fb\u884c\u5148\ message.migrate.systemvm.confirm=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u79fb\u884c\u5148\u306f\u6b21\u306e\u30db\u30b9\u30c8\u3067\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.migrate.volume=\u5225\u306e\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306b\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u79fb\u884c\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.new.user=\u30a2\u30ab\u30a6\u30f3\u30c8\u306b\u65b0\u3057\u3044\u30e6\u30fc\u30b6\u30fc\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u60c5\u5831\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.no.affinity.groups=\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u304c\u3042\u308a\u307e\u305b\u3093\u3002\u6b21\u306e\u624b\u9806\u306b\u9032\u3093\u3067\u304f\u3060\u3055\u3044\u3002 message.no.network.support.configuration.not.true=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u304c\u6709\u52b9\u306a\u30be\u30fc\u30f3\u304c\u7121\u3044\u305f\u3081\u3001\u8ffd\u52a0\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u6a5f\u80fd\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u624b\u9806 5. \u306b\u9032\u3093\u3067\u304f\u3060\u3055\u3044\u3002 message.no.network.support=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u3068\u3057\u3066 vSphere \u3092\u9078\u629e\u3057\u307e\u3057\u305f\u304c\u3001\u3053\u306e\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u306b\u8ffd\u52a0\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u6a5f\u80fd\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u624b\u9806 5. \u306b\u9032\u3093\u3067\u304f\u3060\u3055\u3044\u3002 message.no.projects.adminOnly=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u304c\u3042\u308a\u307e\u305b\u3093\u3002
\u7ba1\u7406\u8005\u306b\u65b0\u3057\u3044\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u4f5c\u6210\u3092\u4f9d\u983c\u3057\u3066\u304f\u3060\u3055\u3044\u3002 @@ -1466,6 +1517,7 @@ message.restart.mgmt.usage.server=\u65b0\u3057\u3044\u8a2d\u5b9a\u3092\u6709\u52 message.restart.network=\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3067\u63d0\u4f9b\u3059\u308b\u3059\u3079\u3066\u306e\u30b5\u30fc\u30d3\u30b9\u304c\u4e2d\u65ad\u3055\u308c\u307e\u3059\u3002\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u518d\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.restart.vpc=VPC \u3092\u518d\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.security.group.usage=(\u8a72\u5f53\u3059\u308b\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u3092\u3059\u3079\u3066\u9078\u629e\u3059\u308b\u306b\u306f\u3001Ctrl \u30ad\u30fc\u3092\u62bc\u3057\u306a\u304c\u3089\u30af\u30ea\u30c3\u30af\u3057\u3066\u304f\u3060\u3055\u3044) +message.select.affinity.groups=\u3053\u306e VM \u3092\u8ffd\u52a0\u3059\u308b\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.select.a.zone=\u30be\u30fc\u30f3\u306f\u901a\u5e38\u3001\u5358\u4e00\u306e\u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u306b\u76f8\u5f53\u3057\u307e\u3059\u3002\u8907\u6570\u306e\u30be\u30fc\u30f3\u3092\u8a2d\u5b9a\u3057\u3001\u7269\u7406\u7684\u306b\u5206\u96e2\u3057\u3066\u5197\u9577\u6027\u3092\u6301\u305f\u305b\u308b\u3053\u3068\u306b\u3088\u308a\u3001\u30af\u30e9\u30a6\u30c9\u306e\u4fe1\u983c\u6027\u3092\u9ad8\u3081\u307e\u3059\u3002 message.select.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.select.iso=\u65b0\u3057\u3044\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e ISO \u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 @@ -1501,13 +1553,14 @@ message.update.os.preference=\u3053\u306e\u30db\u30b9\u30c8\u306e OS \u57fa\u672 message.update.resource.count=\u3053\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u30ea\u30bd\u30fc\u30b9\u6570\u3092\u66f4\u65b0\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.update.ssl=\u5404\u30b3\u30f3\u30bd\u30fc\u30eb \u30d7\u30ed\u30ad\u30b7\u306e\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3067\u66f4\u65b0\u3059\u308b\u3001X.509 \u6e96\u62e0\u306e\u65b0\u3057\u3044 SSL \u8a3c\u660e\u66f8\u3092\u9001\u4fe1\u3057\u3066\u304f\u3060\u3055\u3044\: message.validate.instance.name=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u540d\u306f 63 \u6587\u5b57\u4ee5\u5185\u3067\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002ASCII \u6587\u5b57\u306e a\uff5ez\u3001A\uff5eZ\u3001\u6570\u5b57\u306e 0\uff5e9\u3001\u304a\u3088\u3073\u30cf\u30a4\u30d5\u30f3\u306e\u307f\u3092\u4f7f\u7528\u3067\u304d\u307e\u3059\u3002\u6587\u5b57\u3067\u59cb\u307e\u308a\u3001\u6587\u5b57\u307e\u305f\u306f\u6570\u5b57\u3067\u7d42\u308f\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.validate.invalid.characters=\u7121\u52b9\u306a\u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f\u3002\u4fee\u6574\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.virtual.network.desc=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u5c02\u7528\u4eee\u60f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3067\u3059\u3002\u30d6\u30ed\u30fc\u30c9\u30ad\u30e3\u30b9\u30c8 \u30c9\u30e1\u30a4\u30f3\u306f VLAN \u5185\u306b\u914d\u7f6e\u3055\u308c\u3001\u30d1\u30d6\u30ea\u30c3\u30af \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3078\u306e\u30a2\u30af\u30bb\u30b9\u306f\u3059\u3079\u3066\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc\u306b\u3088\u3063\u3066\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u3055\u308c\u307e\u3059\u3002 message.vm.create.template.confirm=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f5c\u6210\u3059\u308b\u3068 VM \u304c\u81ea\u52d5\u7684\u306b\u518d\u8d77\u52d5\u3055\u308c\u307e\u3059\u3002 message.vm.review.launch=\u6b21\u306e\u60c5\u5831\u3092\u53c2\u7167\u3057\u3066\u3001\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u6b63\u3057\u304f\u8a2d\u5b9a\u3057\u305f\u3053\u3068\u3092\u78ba\u8a8d\u3057\u3066\u304b\u3089\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.volume.create.template.confirm=\u3053\u306e\u30c7\u30a3\u30b9\u30af \u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f5c\u6210\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? \u30dc\u30ea\u30e5\u30fc\u30e0 \u30b5\u30a4\u30ba\u306b\u3088\u3063\u3066\u306f\u3001\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u4f5c\u6210\u306b\u306f\u6570\u5206\u4ee5\u4e0a\u304b\u304b\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002 message.you.must.have.at.least.one.physical.network=\u5c11\u306a\u304f\u3068\u3082 1 \u3064\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u304c\u5fc5\u8981\u3067\u3059 -message.zone.creation.complete.would.you.like.to.enable.this.zone=\u30be\u30fc\u30f3\u304c\u4f5c\u6210\u3055\u308c\u307e\u3057\u305f\u3002\u3053\u306e\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.Zone.creation.complete=\u30be\u30fc\u30f3\u304c\u4f5c\u6210\u3055\u308c\u307e\u3057\u305f +message.zone.creation.complete.would.you.like.to.enable.this.zone=\u30be\u30fc\u30f3\u304c\u4f5c\u6210\u3055\u308c\u307e\u3057\u305f\u3002\u3053\u306e\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.zone.no.network.selection=\u9078\u629e\u3057\u305f\u30be\u30fc\u30f3\u3067\u306f\u3001\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u9078\u629e\u3067\u304d\u307e\u305b\u3093\u3002 message.zone.step.1.desc=\u30be\u30fc\u30f3\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30e2\u30c7\u30eb\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.zone.step.2.desc=\u65b0\u3057\u3044\u30be\u30fc\u30f3\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u60c5\u5831\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 @@ -1530,14 +1583,14 @@ state.Creating=\u4f5c\u6210\u4e2d state.Declined=\u8f9e\u9000 state.Destroyed=\u7834\u68c4\u6e08\u307f state.Disabled=\u7121\u52b9 -state.Enabled=\u6709\u52b9 state.enabled=\u6709\u52b9 +state.Enabled=\u6709\u52b9 state.Error=\u30a8\u30e9\u30fc state.Expunging=\u62b9\u6d88\u4e2d state.Migrating=\u79fb\u884c\u4e2d state.Pending=\u4fdd\u7559 -state.Ready=\u6e96\u5099\u5b8c\u4e86 state.ready=\u6e96\u5099\u5b8c\u4e86 +state.Ready=\u6e96\u5099\u5b8c\u4e86 state.Running=\u5b9f\u884c\u4e2d state.Starting=\u958b\u59cb\u4e2d state.Stopped=\u505c\u6b62\u6e08\u307f diff --git a/client/WEB-INF/classes/resources/messages_ko_KR.properties b/client/WEB-INF/classes/resources/messages_ko_KR.properties index b755072d6137..e299c3e9046f 100644 --- a/client/WEB-INF/classes/resources/messages_ko_KR.properties +++ b/client/WEB-INF/classes/resources/messages_ko_KR.properties @@ -16,6 +16,7 @@ # under the License. changed.item.properties=\ud56d\ubaa9 \uc18d\uc131 \ubcc0\uacbd +confirm.enable.s3=S3 \uae30\ubc18 2\ucc28 \uc800\uc7a5\uc18c \uc9c0\uc6d0\uc744 \ud558\ub824\uba74 \uc544\ub798 \uc815\ubcf4\ub97c \uc785\ub825\ud574 \uc8fc\uc2ed\uc2dc\uc624. confirm.enable.swift=Swift \uae30\uc220 \uc9c0\uc6d0\ub97c \uc0ac\uc6a9 \ud558\ub824\uba74 \ub2e4\uc74c \uc815\ubcf4\ub97c \uc785\ub825\ud574 \uc8fc\uc2ed\uc2dc\uc624. error.could.not.enable.zone=Zone\uc744 \uc0ac\uc6a9 \ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. error.installWizard.message=\ubb38\uc81c\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc624\ub958\ub97c \uc218\uc815\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. @@ -28,6 +29,7 @@ error.please.specify.physical.network.tags=\ud604\uc7ac \ubb3c\ub9ac \ub124\ud2b error.session.expired=\uc138\uc158 \uc720\ud6a8\uae30\uac04\uc774 \ub04a\uc5b4\uc84c\uc2b5\ub2c8\ub2e4. error.something.went.wrong.please.correct.the.following=\ubb38\uc81c\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4. \ub2e4\uc74c \ub0b4\uc6a9\uc744 \uc218\uc815\ud574 \uc8fc\uc2ed\uc2dc\uc624 error.unable.to.reach.management.server=\uad00\ub9ac \uc11c\ubc84\uc640 \ud1b5\uc2e0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +error.unresolved.internet.name=\uc778\ud130\ub137 \uc8fc\uc18c\ub97c \uc54c\uc218 \uc5c6\uc2b5\ub2c8\ub2e4. extractable=\ucd94\ucd9c \uac00\ub2a5 force.delete.domain.warning=\uacbd\uace0\:\uc774 \uc635\uc158\uc744 \uc120\ud0dd\ud558\uba74, \ubaa8\ub4e0 \ub0b4\ubd80 \ub3c4\uba54\uc778 \ubc0f \uad00\ub828\ud558\ub294 \ubaa8\ub4e0 \uacc4\uc815 \uc815\ubcf4\uc640 \uadf8 \uc790\uc6d0\uc774 \uc0ad\uc81c\ub429\ub2c8\ub2e4. force.delete=\uac15\uc81c \uc0ad\uc81c @@ -40,6 +42,8 @@ ICMP.type=ICMP \uc885\ub958 image.directory=\uc774\ubbf8\uc9c0 \ub514\ub809\ud1a0\ub9ac inline=\uc9c1\ub82c instances.actions.reboot.label=\uc778\uc2a4\ud134\uc2a4 \uc7ac\uc2dc\uc791 +label.about.app=CloudStack \uc18c\uac1c +label.about=\uc18c\uac1c label.accept.project.invitation=\ud504\ub85c\uc81d\ud2b8 \ucd08\ub300 \uc2b9\uc778 label.account.and.security.group=\uacc4\uc815 \uc815\ubcf4, \ubcf4\uc548 \uadf8\ub8f9 label.account.id=\uacc4\uc815 \uc815\ubcf4 ID @@ -227,6 +231,9 @@ label.action.update.OS.preference=OS \uae30\ubcf8 \uc124\uc815 \uc5c5\ub370\uc77 label.action.update.OS.preference.processing=OS \uae30\ubcf8 \uc124\uc815\uc744 \uc5c5\ub370\uc774\ud2b8\ud558\ub294 \uc911... label.action.update.resource.count.processing=\uc790\uc6d0 \uc218\ub97c \uc5c5\ub370\uc774\ud2b8\ud558\ub294 \uc911... label.action.update.resource.count=\uc790\uc6d0 \uc218 \uc5c5\ub370\uc774\ud2b8 +label.action.vmsnapshot.create=VM \uc2a4 +label.action.vmsnapshot.delete=VM +label.action.vmsnapshot.revert=VM \uc2a4\ub0c5\uc0f7 label.activate.project=\ud504\ub85c\uc81d\ud2b8 \ud65c\uc131\ud654 label.active.sessions=\ud65c\uc131 \uc138\uc158 label.add.accounts.to=\uacc4\uc815 \uc815\ubcf4 \ucd94\uac00\: @@ -234,6 +241,7 @@ label.add.accounts=\uacc4\uc815 \uc815\ubcf4 \ucd94\uac00 label.add.account.to.project=\uacc4\uc815 \uc815\ubcf4 \ud504\ub85c\uc81d\ud2b8\uc5d0 \ucd94\uac00 label.add.account=\uacc4\uc815 \uc815\ubcf4 \ucd94\uac00 label.add.ACL=\uad8c\ud55c \uad00\ub9ac(ACL) \ucd94\uac00 +label.add.BigSwitchVns.device=BigSwitch Vns \ucf58\ud2b8\ub864\ub7ec label.add.by.cidr=CIDR \ub85c \ucd94\uac00 label.add.by.group=\uadf8\ub8f9\uc5d0\uc11c \ucd94\uac00 label.add.by=\ucd94\uac00 \ub2e8\uc704 @@ -270,10 +278,12 @@ label.add.new.gateway=\uc0c8 \uac8c\uc774\ud2b8\uc6e8\uc774 \ucd94\uac00\ud558\u label.add.new.NetScaler=\uc0c8\ub85c\uc6b4 NetScaler \ucd94\uac00 label.add.new.SRX=\uc0c8\ub85c\uc6b4 SRX \ucd94\uac00 label.add.new.tier=\uc0c8 \uacc4\uce35 \ucd94\uac00 +label.add.NiciraNvp.device=Nvp \ucf58\ud2b8\ub864\ub7ec label.add.physical.network=\ubb3c\ub9ac \ub124\ud2b8\uc6cc\ud06c \ucd94\uac00 label.add.pod=Pod \ucd94\uac00 label.add.port.forwarding.rule=\ud3ec\ud1a0 \uc804\uc1a1 \uaddc\uce59\uc758 \ucd94\uac00 label.add.primary.storage=\uae30\ubcf8 \uc2a4\ud1a0\ub9ac\uc9c0 \ucd94\uac00 +label.add.region=\uc9c0\uc5ed label.add.resources=\uc790\uc6d0 \ucd94\uac00 label.add.route=\ub77c\uc6b0\ud2b8 \ucd94\uac00 label.add.rule=\uaddc\uce59 \ucd94\uac00 @@ -289,7 +299,6 @@ label.add.to.group=\uadf8\ub8f9\uc5d0 \ucd94\uac00 label.add=\ucd94\uac00 label.add.user=\uc0ac\uc6a9\uc790 \ucd94\uac00 label.add.vlan=VLAN \ucd94\uac00 -label.add.vxlan=VXLAN \ucd94\uac00 label.add.vms.to.lb=\ub124\ud2b8\uc6cc\ud06c \ub85c\ub4dc \uacf5\uc720 \uaddc\uce59\uc5d0 VM \ucd94\uac00 label.add.vms=VM \ucd94\uac00 label.add.VM.to.tier=\uacc4\uce35\uc5d0 VM \ucd94\uac00 @@ -299,6 +308,7 @@ label.add.vpc=VPC \ucd94\uac00 label.add.vpn.customer.gateway=VPN \uace0\uac1d \uac8c\uc774\ud2b8\uc6e8\uc774 \ucd94\uac00 label.add.VPN.gateway=VPN \uac8c\uc774\ud2b8\uc6e8\uc774 \ucd94\uac00 label.add.vpn.user=VPN \uc0ac\uc6a9\uc790 \ucd94\uac00 +label.add.vxlan=VXLAN \ucd94\uac00 label.add.zone=Zone \ucd94\uac00 label.admin.accounts=\uad00\ub9ac\uc790 \uacc4\uc815 \uc815\ubcf4 label.admin=\uad00\ub9ac\uc790 @@ -314,11 +324,15 @@ label.allocated=\ud560\ub2f9 \uc644\ub8cc \uc0c1\ud0dc label.allocation.state=\ud560\ub2f9 \uc0c1\ud0dc label.api.key=API \ud0a4 label.apply=\uc801\uc6a9 +label.app.name=CloudStack +label.archive.alerts=\uc54c\ub9bc +label.archive.events=\uc774\ubca4\ud2b8 label.assign.to.load.balancer=\ub124\ud2b8\uc6cc\ud06c \ub85c\ub4dc \uacf5\uc720 \uc7a5\uce58\uc5d0 \uc778\uc2a4\ud134\uc2a4\ub97c \ud560\ub2f9 label.assign=\ud560\ub2f9 label.associated.network.id=\uad00\ub828 \ub124\ud2b8\uc6cc\ud06c ID label.associated.network=\uad00\ub828 \ub124\ud2b8\uc6cc\ud06c label.attached.iso=\uc5f0\uacb0 ISO +label.author.email=\uc81c\uc791\uc790 label.availability=\uac00\uc6a9\uc131 label.availability.zone=\uc774\uc6a9 \uac00\ub2a5 Zone label.available.public.ips=\uc0ac\uc6a9 \uac00\ub2a5 \uacf5\uac1c IP \uc8fc\uc18c @@ -331,9 +345,13 @@ label.bootable=\ubd80\ud305 \uac00\ub2a5 label.broadcast.domain.range=\ube0c\ub85c\ub4dc\uce90\uc2a4\ud2b8 \ub3c4\uba54\uc778 \ubc94\uc704 label.broadcast.domain.type=\ube0c\ub85c\ub4dc\uce90\uc2a4\ud2b8 \ub3c4\uba54\uc778 \uc885\ub958 label.by.account=\uacc4\uc815 \uc815\ubcf4 +label.by.alert.type=\uc54c\ub9bc label.by.availability=\uac00\uc6a9\uc131 +label.by.date.end=\ub0a0\uc9dc(\uc885\ub8cc\uc77c) +label.by.date.start=\ub0a0\uc9dc(\uc2dc\uc791\uc77c) label.by.domain=\ub3c4\uba54\uc778 label.by.end.date=\uc885\ub8cc\uc77c +label.by.event.type=\uc774\ubca4\ud2b8 label.by.level=\ub808\ubca8 label.by.pod=Pod label.by.role=\uc5ed\ud560 @@ -408,6 +426,8 @@ label.dedicated=\uc804\uc6a9 label.default=\uae30\ubcf8 label.default.use=\uae30\ubcf8 \uc0ac\uc6a9 label.default.view=\uae30\ubcf8 \ubcf4\uae30 +label.delete.alerts=\uc54c\ub9bc +label.delete.events=\uc774\ubca4\ud2b8 label.delete.F5=F5 \uc0ad\uc81c label.delete.gateway=\uac8c\uc774\ud2b8\uc6e8\uc774 \uc0ad\uc81c label.delete.NetScaler=NetScaler \uc0ad\uc81c @@ -465,6 +485,7 @@ label.edit.tags=\ud0dc\uadf8 \ud3b8\uc9d1 label.edit.traffic.type=\ud2b8\ub798\ud53d \uc885\ub958 \ud3b8\uc9d1 label.edit=\ud3b8\uc9d1 label.edit.vpc=VPC \ud3b8\uc9d1 +label.egress.default.policy=Egress \uae30\ubcf8 label.egress.rule=\uc804\uc1a1 \uaddc\uce59 label.elastic.IP=\ud0c4\ub825\uc801 IP \uc8fc\uc18c label.elastic.LB=\ud0c4\ub825\uc801 \ub124\ud2b8\uc6cc\ud06c \ub85c\ub4dc \uacf5\uc720 @@ -533,6 +554,7 @@ label.host.tags=\ud638\uc2a4\ud2b8 \ud0dc\uadf8 label.host=\ud638\uc2a4\ud2b8 label.hourly=\ub9e4\uc2dc\uac04 label.hypervisor.capabilities=\ud558\uc774\ud37c \ubc14\uc774\uc800 \uae30\ub2a5 +label.hypervisors=\ud558\uc774\ud37c\ubc14\uc774\uc800 label.hypervisor.type=\ud558\uc774\ud37c \ubc14\uc774\uc800 \uc885\ub958 label.hypervisor=\ud558\uc774\ud37c \ubc14\uc774\uc800 label.hypervisor.version=\ud558\uc774\ud37c \ubc14\uc774\uc800 \ubc84\uc804 @@ -871,9 +893,13 @@ label.revoke.project.invite=\ucd08\ub300 \ucde8\uc18c label.role=\uc5ed\ud560 label.root.disk.controller=\ub8e8\ud2b8 \ub514\uc2a4\ud06c \ucf58\ud2b8\ub864\ub7ec label.root.disk.offering=\ub8e8\ud2b8 \ub514\uc2a4\ud06c\uc81c\uacf5 +label.root.disk.size=\ub8e8\ud2b8 \ub514\uc2a4\ud06c label.round.robin=\ub77c\uc6b4\ub4dc \ub85c\ube48 +label.routing=\ub77c\uc6b0\ud305 label.rules=\uaddc\uce59 label.running.vms=\uc2e4\ud589\uc911 VM +label.s3.nfs.path=S3 NFS +label.s3.nfs.server=S3 NFS label.s3.secret_key=\ube44\ubc00 \ud0a4 label.saturday=\ud1a0\uc694\uc77c label.save.and.continue=\uc800\uc7a5\ud558\uae30 @@ -905,6 +931,7 @@ label.sent=\uc804\uc1a1\ub41c \uc0c1\ud0dc label.server=\uc11c\ubc84 label.service.capabilities=\uc11c\ube44\uc2a4 \uae30\ub2a5 label.service.offering=\uc11c\ube44\uc2a4\uc81c\uacf5 +label.service.state=\uc11c\ube44\uc2a4 label.session.expired=\uc138\uc158 \uc720\ud6a8\uae30\uac04\uc774 \ub04a\uc5b4\uc9d0 label.setup.network=\ub124\ud2b8\uc6cc\ud06c \uc124\uc815 label.setup=\uc124\uc815 @@ -980,6 +1007,7 @@ label.super.cidr.for.guest.networks=\uc190\ub2d8 \ub124\ud2b8\uc6cc\ud06c \uc288 label.supported.services=\uae30\uc220 \uc9c0\uc6d0\ub418\ub294 \uc11c\ube44\uc2a4 label.supported.source.NAT.type=\uae30\uc220 \uc9c0\uc6d0\ub418\ub294 \uc804\uc1a1 NAT \uc885\ub958 label.suspend.project=\ud504\ub85c\uc81d\ud2b8 \uc77c\uc2dc\uc815\uc9c0 +label.switch.type=\ud615\uc2dd label.system.capacity=\uc2dc\uc2a4\ud15c \ucc98\ub9ac \ub2a5\ub825 label.system.offering=\uc2dc\uc2a4\ud15c \uc81c\uacf5 label.system.service.offering=\uc2dc\uc2a4\ud15c \uc11c\ube44\uc2a4 \uc81c\uacf5 @@ -1059,9 +1087,6 @@ label.virtual.router=\uac00\uc0c1 \ub77c\uc6b0\ud130 label.vlan.id=VLAN ID label.vlan.range=VLAN \ubc94\uc704 label.vlan=\uac00\uc0c1 \ub124\ud2b8\uc6cc\ud06c(VLAN) -label.vxlan.id=VXLAN ID -label.vxlan.range=VXLAN \ubc94\uc704 -label.vxlan=VXLAN label.vm.add=\uc778\uc2a4\ud134\uc2a4 \ucd94\uac00 label.vm.destroy=\ud30c\uae30 label.vm.display.name=VM \ud45c\uc2dc\uba85 @@ -1076,6 +1101,8 @@ label.vm.state=VM \uc0c1\ud0dc label.vm.stop=\uc815\uc9c0 label.vms=VM label.vmware.traffic.label=VMware \ud2b8\ub798\ud53d \ub77c\ubca8 +label.vnet.id=VLAN ID +label.vnet=\uac00\uc0c1 \ub124\ud2b8\uc6cc\ud06c(VLAN) label.volgroup=\ubcfc\ub968 \uadf8\ub8f9 label.volume.limits=\ubcfc\ub968 \uc81c\ud55c label.volume.name=\ubcfc\ub968\uba85 @@ -1093,6 +1120,9 @@ label.vsmctrlvlanid=\uc81c\uc5b4 VLAN ID label.vsmpktvlanid=\ud328\ud0b7 VLAN ID label.vsmstoragevlanid=\uc2a4\ud1a0\ub9ac\uc9c0 VLAN ID label.vsphere.managed=vSphere \uad00\ub9ac +label.vxlan.id=VXLAN ID +label.vxlan.range=VXLAN \ubc94\uc704 +label.vxlan=VXLAN label.waiting=\ub300\uae30\ud558\ub294 \uc911 label.warn=\uacbd\uace0 label.wednesday=\uc218\uc694\uc77c diff --git a/client/WEB-INF/classes/resources/messages_nb_NO.properties b/client/WEB-INF/classes/resources/messages_nb_NO.properties index be4124493984..f6294d3594bb 100644 --- a/client/WEB-INF/classes/resources/messages_nb_NO.properties +++ b/client/WEB-INF/classes/resources/messages_nb_NO.properties @@ -16,103 +16,465 @@ # under the License. changed.item.properties=Endrede egenskaper +confirm.enable.swift=Vennligst fyll inn f\u00f8lgende informasjon for \u00e5 aktivere st\u00f8tte for Swift +error.could.not.change.your.password.because.ldap.is.enabled=Feil kunne ikke bytte ditt passord fordi LDAP er aktivert. error.could.not.enable.zone=Kunne ikke aktivere sonen error.installWizard.message=Noe gikk galt. G\u00e5 tilbake og korriger feilene. +error.invalid.username.password=Ugyldig brukernavn eller passord +error.mgmt.server.inaccessible=Administrasjonsserver er utilgjengelig. Vennligst pr\u00f8v igjen senere. error.password.not.match=Passordfeltene sammensvarer ikke +error.session.expired=Din sesjon har utl\u00f8pt. error.something.went.wrong.please.correct.the.following=Noe gikk galt. Vennligst korrig\u00e9r f\u00f8lgende +error.unable.to.reach.management.server=Kan ikke oppn\u00e5 kontakt med administrasjonsserveren +extractable=Utpakkbar force.delete=Tving sletting force.remove=Tving fjerning force.stop=Tving stopp +ICMP.code=ICMP-kode +ICMP.type=ICMP-type +image.directory=Bilde-katalog instances.actions.reboot.label=Omstart av instans +label.about.app=Om CloudStack +label.about=Om label.accept.project.invitation=Aksepter prosjektinvitasjon +label.account.and.security.group=Konto, Sikkerhetsgruppe +label.account.id=Konto ID +label.account=Konto +label.account.name=Kontonavn +label.accounts=Kontoer +label.action.attach.disk.processing=Tilknytter Disk.... +label.action.attach.disk=Tilknytt Disk +label.action.attach.iso.processing=Tilknytter ISO.... +label.action.attach.iso=Tilknytt ISO +label.action.change.password=Endre passord +label.action.change.service=Endre Tjeneste +label.action.change.service.processing=Endrer Tjeneste.... +label.action.copy.ISO=Kopier ISO +label.action.copy.ISO.processing=Kopierer ISO.... +label.action.copy.template=Kopier mal +label.action.copy.template.processing=Kopier mal.... +label.action.create.template.from.vm=Lag Mal fra VM +label.action.create.template.from.volume=Lag Mal fra Volum +label.action.create.template=Opprett mal +label.action.create.template.processing=Oppretter mal.... +label.action.create.vm=Opprett VM +label.action.create.vm.processing=Oppretter VM.... +label.action.create.volume=Opprett volum +label.action.create.volume.processing=Oppretter volum.... +label.action.delete.account.processing=Sletter konto.... +label.action.delete.account=Slett konto +label.action.delete.cluster.processing=Sletter klynge.... +label.action.delete.cluster=Slett klynge +label.action.delete.disk.offering.processing=Sletter disktilbud.... +label.action.delete.disk.offering=Slett disktilbud +label.action.delete.domain.processing=Sletter domene.... +label.action.delete.domain=Slett domene +label.action.delete.firewall.processing=Sletter brannmur.... +label.action.delete.firewall=Slett brannmurregel +label.action.delete.ingress.rule.processing=Sletter inng\u00e5ende regel.... +label.action.delete.ingress.rule=Slett inng\u00e5ende regel +label.action.delete.IP.range.processing=Sletter IP-rekke.... +label.action.delete.IP.range=Slett IP-rekke +label.action.delete.ISO.processing=Sletter ISO.... +label.action.delete.ISO=Slett ISO +label.action.delete.load.balancer.processing=Sletter Lastbalanserer +label.action.delete.load.balancer=Slett lastbalanseringsregel +label.action.delete.network.processing=Sletter nettverk.... +label.action.delete.network=Slett nettverk +label.action.delete.nexusVswitch=Slett Nexus 1000v +label.action.delete.nic=Fjern NIC +label.action.delete.physical.network=Slett fysisk nettverk +label.action.delete.pod.processing=Sletter pod.... +label.action.delete.pod=Slett pod +label.action.delete.primary.storage.processing=Sletter prim\u00e6rlagring.... +label.action.delete.primary.storage=Slett prim\u00e6rlagring +label.action.delete.secondary.storage.processing=Sletter sekund\u00e6rlagring.... +label.action.delete.secondary.storage=Slett sekund\u00e6rlagring +label.action.delete.security.group.processing=Slett Sikkerhetsgruppe.... +label.action.delete.security.group=Slett Sikkerhetsgruppe +label.action.delete.service.offering.processing=Sletter tjenestetilbud.... +label.action.delete.service.offering=Slett tjenestetilbud +label.action.delete.system.service.offering=Slett system-tjenestetilbud +label.action.delete.template.processing=Sletter mal.... +label.action.delete.template=Slett mal +label.action.delete.user.processing=Sletter bruker.... +label.action.delete.user=Slett bruker +label.action.delete.volume.processing=Sletter volum.... +label.action.delete.volume=Slett volum +label.action.delete.zone.processing=Sletter sone.... +label.action.delete.zone=Slett sone +label.action.destroy.instance.processing=\u00d8delegge instans.... +label.action.destroy.instance=\u00d8delegg Instans +label.action.destroy.systemvm.processing=Sletter system VM.... +label.action.destroy.systemvm=Slett system VM +label.action.disable.account=Deaktiver konto +label.action.disable.account.processing=Deaktiverer konto.... label.action.disable.cluster=Deaktiver klyngen label.action.disable.cluster.processing=Deaktiverer klyngen... +label.action.disable.nexusVswitch=Deaktiver Nexus 1000v +label.action.disable.physical.network=Deaktiver fysisk nettverk label.action.disable.pod=Deaktiver pod label.action.disable.pod.processing=Deaktiverer pod... +label.action.disable.static.NAT=Deaktiver statisk NAT +label.action.disable.static.NAT.processing=Deaktiverer statisk NAT.... +label.action.disable.user=Deaktivert bruker +label.action.disable.user.processing=Deaktiverer bruker.... label.action.disable.zone=Deaktiver sonen label.action.disable.zone.processing=Deaktiverer sonen... +label.action.download.ISO=Last ned ISO +label.action.download.template=Laster ned mal +label.action.download.volume=Last ned volum +label.action.download.volume.processing=Laster ned volum.... +label.action.edit.account=Rediger konto +label.action.edit.disk.offering=Editer disktilbud +label.action.edit.domain=Editer domene +label.action.edit.global.setting=Editer global innstilling +label.action.edit.host=Editer vert +label.action.edit.instance=Rediger instans +label.action.edit.ISO=Rediger ISO +label.action.edit.network=Editer Nettverk +label.action.edit.network.processing=Editerer Nettverk.... +label.action.edit.pod=Editer Pod +label.action.edit.primary.storage=Editer Prim\u00e6rlagring +label.action.edit.service.offering=Editer tjenestetilbud +label.action.edit.template=Editer mal +label.action.edit.user=Rediger bruker +label.action.edit.zone=Rediger Sone +label.action.enable.account=Aktiver konto +label.action.enable.account.processing=Aktiverer konto.... label.action.enable.cluster=Aktiver klynge label.action.enable.cluster.processing=Aktiverer klyngen... +label.action.enable.nexusVswitch=Aktiver Nexus 1000v +label.action.enable.physical.network=Aktiver fysisk nettverk label.action.enable.pod=Aktiver pod label.action.enable.pod.processing=Aktiverer pod... +label.action.enable.static.NAT=Aktiver statisk NAT +label.action.enable.static.NAT.processing=Aktiverer statisk NAT.... +label.action.enable.user=Aktiver Bruker +label.action.enable.user.processing=Aktiverer Bruker.... label.action.enable.zone=Aktiver sone label.action.enable.zone.processing=Aktiverer sone... +label.action.generate.keys=Generer n\u00f8kler +label.action.generate.keys.processing=Genererer n\u00f8kler.... +label.action.list.nexusVswitch=Liste Nexus 1000v +label.action.lock.account=L\u00e5s konto +label.action.lock.account.processing=L\u00e5ser konto.... +label.action.manage.cluster=Administrer klynge +label.action.manage.cluster.processing=Administrerer klynge.... +label.action.migrate.instance=Migrer Instans +label.action.migrate.instance.processing=Migrerer Instans.... +label.action.migrate.router=Migrer ruter +label.action.migrate.router.processing=Migrerer Ruter.... +label.action.migrate.systemvm=Migrer System VM +label.action.migrate.systemvm.processing=Migrerer System VM.... +label.action.reboot.instance=Omstart Instans +label.action.reboot.instance.processing=Starter om Instans.... +label.action.reboot.router=Omstart Ruter +label.action.reboot.router.processing=Omstaer Instans.... +label.action.reboot.systemvm=Omstart System VM +label.action.reboot.systemvm.processing=Omstarter System VM +label.action.register.iso=Registrer ISO +label.action.register.template=Registrer mal +label.action.remove.host=Fjern Vert +label.action.remove.host.processing=Fjerner Vest.... +label.action.reset.password.processing=Tilbakestiller passord.... +label.action.reset.password=Tilbakestill passord +label.action.resize.volume=Endre st\u00f8rrelse p\u00e5 volum +label.action.resize.volume.processing=Endrer st\u00f8rrelse p\u00e5 volum.... +label.action.resource.limits=Ressursbegrensninger +label.action.restore.instance=Gjenopprett Instans +label.action.restore.instance.processing=Gjenoppretter Instans.... +label.actions=Handlinger +label.action.start.instance.processing=Starter instans.... +label.action.start.instance=Start instans +label.action.start.router.processing=Stopper ruter +label.action.start.router=Start ruter +label.action.start.systemvm.processing=Starter System VM.... +label.action.start.systemvm=Start System VM +label.action.stop.instance.processing=Stopper instans.... +label.action.stop.instance=Stopp instans +label.action.stop.router.processing=Stopper ruter.... +label.action.stop.router=Stopp ruter +label.action.stop.systemvm.processing=Stopper System VM.... +label.action.stop.systemvm=Stopp System VM label.action.unmanage.cluster.processing=Fjerner administrasjon av klynge... label.activate.project=Aktiver prosjekt +label.active.sessions=Aktive sesjoner +label.add.account=Legg til konto label.add.accounts=Legg til kontoer label.add.accounts.to=Legg kontoer til label.add.account.to.project=Legg kontoen til prosjektet +label.add.ACL=Legg til ACL label.add.by=Legg til ved +label.add.cluster=Legg til klynge +label.add.compute.offering=Legg til systemtilbud +label.add.domain=Legg til domene +label.add.F5.device=Legg til F5 enhet +label.add.firewall=Legg til brannmurregel label.add.guest.network=Legg til gjestenettverk +label.add.host=Legg til vert +label.adding.cluster=Legger til klynge +label.adding.failed=Tillegging feilet +label.adding.pod=Legger til pod +label.adding.processing=Legger til +label.adding.succeeded=Tillegging vellykket +label.adding=Tillegger +label.adding.user=Legger til bruker +label.adding.zone=Legger til sone +label.add.ip.range=Legg til IP-rekke +label.add=Legg til +label.add.load.balancer=Legg til lastbalanserer +label.add.more=Legg til mer +label.add.netScaler.device=Legg til Netscaler enhet +label.add.network.ACL=Legg til nettverk ACL label.add.network.device=Legg til nettverksenhet +label.add.network=Legg til nettverk +label.add.network.offering=Legg til nettverkstilbud label.add.new.F5=Legg til ny F5 +label.add.new.gateway=Legg til ny gateway label.add.new.NetScaler=Legg til ny NetScaler +label.add.new.PA=Legg til ny Palo Alto label.add.new.SRX=Legg til ny SRX +label.add.PA.device=Legg til Palo Alto enhet label.add.physical.network=Legg til fysisk nettverk +label.add.pod=Legg til pod +label.add.port.forwarding.rule=Legg til portvideresendingsregel +label.add.primary.storage=Legg til prim\u00e6rlagring +label.add.region=Legg til region label.add.resources=Legg til ressurser +label.add.route=Legg til rute +label.add.rule=Legg til regel +label.add.secondary.storage=Legg til sekund\u00e6rlagring +label.add.security.group=Legg til sikkerhetsgruppe +label.add.service.offering=Legg til tjenestetilbud +label.add.SRX.device=Legg til SRX enhet +label.add.static.nat.rule=Legg til statisk NAT-regel +label.add.static.route=Legg til statisk rute label.add.system.service.offering=Legg til et systemtilbud +label.add.template=Legg til mal label.add.to.group=Legg til gruppe +label.add.user=Legg til bruker +label.add.vlan=Legg til VLAN +label.add.vm=Legg til VM label.add.vms=Legg til VMer +label.add.vms.to.lb=Legg til VM(er) til lastbalanseringsregel +label.add.volume=Legg til volum +label.add.vpc=Legg til VPC +label.add.VPN.gateway=Legg til VPN Gateway +label.add.vpn.user=Legg til VPN-bruker +label.add.vxlan=Legg til VXLAN +label.add.zone=Legg til sone +label.admin.accounts=Adminkontoer +label.admin=Admin label.advanced=Avansert +label.advanced.mode=Avansermodus +label.advanced.search=Avansert s\u00f8k +label.agent.password=Agentpassord label.agree=Godtar +label.alert=Varsel label.allocated=Allokert label.allocation.state=Allokeringsstatus +label.api.key=API-n\u00f8kkel label.apply=Bruk +label.app.name=CloudStack +label.archive.alerts=Arkiver varsler +label.archive.events=Arkiver hendelser +label.assign=Tildel +label.attached.iso=Tilknyttet ISO +label.author.email=Forfatter e-post +label.author.name=Forfatternavn +label.availability=Tilgjengelighet +label.availability.zone=Tilgjengelighetssone +label.available.public.ips=Tilgjengelig offentlige IP-adresser +label.available=Tilgjengelig +label.back=Tilbake label.bandwidth=B\u00e5ndbredde label.basic=Basis +label.basic.mode=Basismodus +label.by.account=Etter Konto +label.by.alert.type=Etter varseltype +label.by.availability=Etter Tilgjengelighet +label.by.date.end=Etter dato (slutt) +label.by.date.start=Etter dato (start) +label.by.domain=Etter Domene +label.by.event.type=Etter hendelsestype +label.by.pod=Etter Pod +label.by.role=Etter Rolle +label.by.start.date=Etter Startdato +label.by.traffic.type=Etter Trafikktype +label.by.type=Etter Type +label.by.type.id=Etter Type ID +label.by.zone=Etter Sone +label.cancel=Avbryt label.capacity=Kapasitet +label.certificate=Sertifikat label.change.service.offering=Endre tjenestetilbud label.change.value=Endre verdi +label.character=Karakter +label.checksum=MD5 sjekksum label.cidr=CIDR +label.CIDR.list=CIDR liste label.cidr.list=Kilde-CIDR label.clean.up=Rydd opp +label.clear.list=T\u00f8m liste +label.close=Lukk +label.cloud.console=Cloud +label.cluster=Klynge +label.cluster.name=Klyngenavn +label.clusters=Klynger +label.cluster.type=Klyngetype label.clvm=CLVM label.compute.and.storage=Regnekraft og lagring label.compute=Beregne +label.compute.offering=Regnekraftstilbud +label.compute.offerings=Regnekraftstilbud +label.configuration=Konfigurering label.configure=Konfigurer +label.configure.vpc=Konfigurer VPC +label.confirmation=Bekreftelse label.confirm.password=Bekreft passord label.congratulations=Gratulerer\! +label.conserve.mode=Konserveringsmodus +label.console.proxy=Konsollproxy label.continue.basic.install=Fortsett med enkelt oppsett label.continue=Fortsett label.corrections.saved=Endringer lagret +label.cpu.allocated=CPU allokert +label.cpu.allocated.for.VMs=CPU Allokert for VMer label.CPU.cap=CPU begrensning +label.cpu=CPU +label.cpu.limits=CPU-begrensninger +label.cpu.mhz=CPU (i MHz) +label.cpu.utilized=CPU-utnyttelse label.created.by.system=Opprettet av systemet +label.created=Opprettet label.create.project=Opprett prosjekt label.create.template=Opprett mal +label.create.VPN.connection=Opprett VPN-tilkobling +label.custom.disk.size=Tilpasset Diskst\u00f8rrelse +label.daily=Daglig +label.data.disk.offering=Datadisktilbud +label.date=Dato label.decline.invitation=Avvis invitasjon label.dedicated=Dedikert label.default=Standardverdi label.default.use=Standard bruk label.default.view=Standardvisning +label.delete.alerts=Slette varsler +label.delete.events=Slett hendelser +label.delete.F5=Slett F5 +label.delete.gateway=slett gateway +label.delete.NetScaler=Slett Netscaler +label.delete.PA=Slett Palo Alto label.delete.project=Slett prosjekt +label.delete=Slett +label.delete.SRX=Slett SRX +label.delete.VPN.connection=Slett VPN-tilkobling +label.delete.VPN.gateway=Slett VPN-gateway +label.delete.vpn.user=Slett VPN-bruker +label.deleting.failed=Sletting feilet +label.deleting.processing=Sletter.... +label.description=Beskrivelse label.destination.physical.network.id=Fysisk nettverksid-destinasjon +label.destination.zone=Destinasjonssone +label.destroy=Destruer label.destroy.router=Slett ruter +label.details=Detaljer +label.device.id=Enhets ID +label.devices=Enheter label.dhcp=DHCP label.DHCP.server.type=DHCP servertype label.disabled=Inaktiv label.disable.provider=Deaktiver tilbyder +label.disable.vpn=Dekativer VPN +label.disabling.vpn.access=Deaktiverer VPN Tilgang +label.disk.allocated=Disk allokert +label.disk.iops.max=Maks IOPS +label.disk.iops.min=Min IOPS +label.disk.iops.total=IOPS Totalt +label.disk.offering=Disktilbud +label.disk.read.bytes=Disk lese (Bytes) +label.disk.read.io=Disk lese (IO) +label.disk.size=Diskst\u00f8rrelse +label.disk.size.gb=Diskst\u00f8rrelse (i GB) +label.disk.total=Disk Totalt +label.disk.volume=Disk Volum +label.disk.write.bytes=Disk skrive (Bytes) +label.disk.write.io=Disk skrive (IO) label.display.name=Visningsnavn +label.display.text=Visningstekst +label.dns.1=DNS 1 +label.dns.2=DNS 2 +label.dns=DNS +label.DNS.domain.for.guest.networks=DNS domene for gjestenettverk +label.domain.admin=Domeneadministrator +label.domain=Domene +label.domain.id=Domene ID +label.domain.name=Domenenavn +label.domain.router=Domeneruter label.done=Utf\u00f8rt label.drag.new.position=Dra til ny posisjon +label.edit=Editer +label.edit.lb.rule=Endre LB-regel label.edit.network.details=Edit\u00e9r nettverksdetaljer label.edit.project.details=Editer prosjektdetaljer +label.edit.traffic.type=Endre trafikktype +label.edit.vpc=Rediger VPC label.elastic=Elastisk label.elastic.IP=Elastisk IP label.elastic.LB=Elastisk LB +label.email=E-post label.enable.provider=Aktiver tilbyder +label.enable.swift=Aktiver Swift label.enable.vpn=Aktiver VPN +label.enabling.vpn.access=Aktiverer VPN-tilgang +label.enabling.vpn=Aktiverer VPN label.end.IP=Slutt-IP +label.end.port=Sluttport label.end.vlan=Slutt-VLAN label.enter.token=Skriv inn koden label.error=Feil +label.esx.host=ESX/ESXi vert +label.example=Eksempel label.f5=F5 +label.failed=Feilet +label.fetch.latest=Hent siste label.filterBy=Filtrer etter +label.firewall=Brannmur +label.first.name=Fornavn +label.format=Format +label.friday=Fredag +label.full=Full +label.full.path=Full sti +label.general.alerts=Generelle varsler +label.go.step.2=G\u00e5 til steg 2 +label.go.step.3=G\u00e5 til steg 3 +label.go.step.4=G\u00e5 til steg 4 +label.go.step.5=G\u00e5 til steg 5 +label.group=Gruppe +label.group.optional=Gruppe (Valgfritt) +label.guest.cidr=Gjest CIDR label.guest.end.ip=Gjest slutt-IP label.guest=Gjest +label.guest.ip=Gjest IP-adresse +label.guest.ip.range=Gjest IP-rekke +label.guest.netmask=Gjest nettmaske label.guest.networks=Gjestenettverk label.guest.start.ip=Gjest start-IP label.guest.traffic=Gjestetrafikk +label.guest.type=Gjestetype +label.ha.enabled=HA Aktivert +label.help=Hjelp label.hints=Hint +label.home=Hjem +label.host.alerts=Vertsvarsler +label.host.MAC=Verts MAC +label.host.name=Vertsnavn +label.hosts=Verter +label.host=Vert +label.hourly=Hver time +label.id=ID +label.info=Info label.installWizard.addClusterIntro.subtitle=Hva er en klynge? label.installWizard.addClusterIntro.title=La oss legge til en klynge label.installWizard.addHostIntro.subtitle=Hva er en vert? @@ -129,62 +491,205 @@ label.installWizard.addZone.title=Legg til sone label.installWizard.click.launch=Klikk startknappen. label.installWizard.subtitle=Denne veiviseren vil hjelpe deg i din installasjon av CloudStack&\#8482 label.installWizard.title=Hei og velkommen til CloudStack&\#8482 +label.instance=Instans +label.instance.limits=Instans Begrensninger +label.instance.name=Instans Navn +label.instances=Instanser +label.internal.dns.1=Intern DNS 1 +label.internal.dns.2=Intern DNS 2 +label.internal.name=Internt navn label.introduction.to.cloudstack=Introduksjon til CloudStack&\#8482 label.invitations=Invitasjoner label.invited.accounts=Inviterte kontoer label.invite=Inviter label.invite.to=Inviter til -label.ip.ranges=IP-rekke +label.ip.address=IP-adresse +label.ipaddress=IP-adresse +label.ip.allocations=IP Allokeringer +label.ip=IP +label.ip.or.fqdn=IP eller FQDN +label.ip.range=IP-rekke +label.ip.ranges=IP-rekker +label.ips=IPer +label.is.default=Er standard +label.iso=ISO +label.isolated.networks=Isolerte nettverk +label.isolation.method=Isolasjonsmetode +label.isolation.mode=Isolasjonsmetode label.is.redundant.router=Redundant +label.is.shared=Er delt +label.is.system=Er system label.item.listing=Elementlisting +label.keep=Behold +label.key=N\u00f8kkel label.kvm.traffic.label=KVM trafikketikett +label.lang.arabic=Arabisk +label.lang.brportugese=Brasiliansk Portugisisk +label.lang.catalan=Katalansk +label.lang.chinese=Kinesisk (Forenklet) +label.lang.english=Engelsk +label.lang.french=Fransk +label.lang.german=Tysk +label.lang.italian=Italiensk +label.lang.japanese=Japanesisk +label.lang.korean=Koreansk +label.lang.norwegian=Norsk +label.lang.russian=Russisk +label.lang.spanish=Spansk +label.last.name=Etternavn +label.latest.events=Siste hendelser label.launch=Start label.launch.vm=Start VM label.LB.isolation=LB-isolering label.least.connections=F\u00e6rrest tilkoblinger +label.load.balancer=Lastbalanserer label.load.balancing=Lastbalansering label.load.balancing.policies=Regler for lastbalansering +label.loading=Laster +label.local=Lokal label.local.storage=Lokal lagring +label.logout=Logg ut +label.lun=LUN +label.LUN.number=LUN \# label.make.project.owner=Gj\u00f8r konto prosjekteier +label.manage=Administrer label.management=Administrasjon +label.management.ips=Administrasjons IP-adresser label.manage.resources=Behandle ressurser +label.maximum=Maksimum label.max.public.ips=Maks offentlige IPer label.max.snapshots=Maks \u00f8yeblikksbilder label.max.templates=Maks maler label.max.vms=Maks bruker-VMer label.max.volumes=Maks volumer label.may.continue=Du kan n\u00e5 fortsette. +label.memory.allocated=Minne allokert +label.memory.mb=Minne (i MB) +label.memory=Minne +label.memory.total=Minne totalt +label.memory.used=Minne brukt +label.menu.accounts=Kontoer +label.menu.alerts=Varsler +label.menu.all.accounts=Alle kontoer +label.menu.all.instances=Alle instanser +label.menu.configuration=Konfigurering +label.menu.domains=Domener +label.menu.events=Hendelser +label.menu.infrastructure=Infrastruktur +label.menu.instances=Instanser +label.menu.ipaddresses=IP-adresser +label.menu.isos=ISOer +label.menu.my.accounts=Mine kontoer +label.menu.my.instances=Mine instanser +label.menu.my.isos=Mine ISOer +label.menu.my.templates=Mine maler +label.menu.network=Nettverk +label.menu.network.offerings=Nettverkstilbud +label.menu.physical.resources=Fysiske ressurser +label.menu.regions=Regioner +label.menu.running.instances=Kj\u00f8rende instanser +label.menu.security.groups=Sikkerhetsgrupper +label.menu.service.offerings=Tjenestetilbud +label.menu.stopped.instances=Stoppede instanser +label.menu.storage=Lagring label.menu.system.service.offerings=Systemtilbud +label.menu.system=System +label.menu.system.vms=System VMer +label.menu.templates=Maler +label.menu.virtual.resources=Virtuelle ressurser +label.menu.volumes=Volumer label.migrate.instance.to.host=Migrer instansen til en annen vert +label.migrate.instance.to=Migrer instans til label.migrate.instance.to.ps=Migrer instansen til en annen sekund\u00e6r lagring. +label.migrate.router.to=Migrer Ruter til +label.migrate.systemvm.to=Migrer System VM til +label.migrate.to.host=Migrer til vert +label.migrate.to.storage=Migrer til lagring label.migrate.volume=Migrer volumet til en annen prim\u00e6rlagring. +label.minimum=Minimum +label.monday=Mandag +label.monthly=M\u00e5nedlig +label.more.templates=Flere maler label.move.down.row=Flytt \u00e9n rad ned +label.move.to.bottom=Flytt til bunnen label.move.to.top=Flytt til toppen label.move.up.row=Flytt \u00e9n rad opp +label.my.account=Min konto label.my.network=Mitt nettverk label.my.templates=Mine maler +label.name=Navn +label.name.optional=Navn (Valgfritt) +label.nat.port.range=NAT portrekke +label.netmask=Nettmaske label.netScaler=NetScaler +label.network.ACL=Nettverk ACL +label.network.ACLs=Nettverk ACLer +label.network.desc=Nettverksbeskrivelse label.network.device=Nettverksenhet label.network.device.type=Type nettverksenhet +label.network.domain=Nettverksdomene +label.network.domain.text=Nettverksdomene +label.network.id=Nettverks ID label.networking.and.security=Nettverk og sikkerhet label.network.label.display.for.blank.value=Bruk standard gateway +label.network.name=Nettverksdame +label.network=Nettverk label.networks=Nettverk label.new=Ny +label.new.password=Nytt passord label.new.project=Nytt prosjekt label.new.vm=Ny VM +label.next=Neste +label.nexusVswitch=Nexus 1000v +label.nfs=NFS +label.nfs.server=NFS Server +label.nfs.storage=NFS Lagring +label.nics=NICer label.no.data=Ingen data \u00e5 vise +label.no=Nei +label.none=Ingen +label.not.found=Ikke funnet label.no.thanks=Nei, takk label.notifications=Notifikasjoner +label.number.of.clusters=Antall klynger +label.number.of.pods=Antall pods +label.number.of.virtual.routers=Antall virtuelle rutere +label.number.of.zones=Antall soner +label.offer.ha=Tilby HA label.ok=OK +label.optional=Valgfritt label.order=Rekkef\u00f8lge +label.os.type=OS-type +label.PA=Palo Alto +label.password=Passord +label.path=Sti +label.physical.network=Fysisk nettverk label.physical.network.ID=Fysisk nettverksid label.PING.CIFS.password=PING CIFS passord label.PING.CIFS.username=PING CIFS brukernavn label.PING.dir=PING-mappe label.PING.storage.IP=PING lagrings-IP label.please.specify.netscaler.info=Vennligst spesifiser NetScaler-info +label.please.wait=Vennligst vent +label.pod.name=Pod navn +label.pod=Pod +label.pods=Pods label.port.forwarding.policies=Regler for portvideresending +label.port.forwarding=Portvideresending +label.port.range=Portrekke +label.prev=Forrige label.previous=Forrige +label.primary.allocated=Prim\u00e6rlagring allokert +label.primary.network=Prim\u00e6rnettverk +label.primary.storage=Prim\u00e6rlagring +label.primary.used=Prim\u00e6rlagring brukt +label.private.Gateway=Privat Gateway +label.private.ip=Privat IP-adresse +label.private.ip.range=Privat IP-rekke +label.private.ips=Private IP-adresser +label.private.network=Privat nettverk +label.private.port=Privat port +label.private.zone=Privat sone label.project.dashboard=Prosjektoversikt label.project.id=Prosjektid label.project.invite=Inviter til prosjekt @@ -192,82 +697,291 @@ label.project.name=Prosjektnavn label.project=Prosjekt label.projects=Prosjekter label.project.view=Prosjektvisning +label.protocol=Protokoll label.providers=Tilbydere +label.public.ip=Offentlig IP-adresse +label.public.ips=Offentlig IP-adresser label.public.network=Offentlig nettverk +label.public=Offentlig +label.public.port=Offentlig port +label.public.traffic=Offentlig trafikk +label.public.zone=Offentlig sone +label.purpose=Form\u00e5l label.Pxe.server.type=PXE Servertype +label.rbd=RBD +label.reboot=Restart label.redundant.router.capability=Redundant ruter label.redundant.router=Redundant ruter label.redundant.state=Redundant tilstand +label.refresh=Oppfrisk +label.region=Region +label.related=Relaterte label.remind.later=P\u00e5minn meg senere +label.remove.ACL=Fjern ACL +label.remove.from.load.balancer=Fjerner instans fra lastbalanserer label.remove.ip.range=Fjern IP-rekke +label.remove.pf=Fjern portvideresendingsregel +label.remove.region=Fjern region +label.remove.rule=Fjern regel +label.remove.static.nat.rule=Fjern statisk NAT-regel +label.remove.static.route=Fjern statisk rute +label.remove.vpc=fjern VPC label.removing=Fjerner +label.removing.user=Fjerner Bruker +label.required=P\u00e5krevd +label.reserved.system.ip=Reservert System IP +label.reset.VPN.connection=Resett VPN-tilkobling +label.resize.new.size=Ny st\u00f8rrelse(GB) +label.resource=Ressurs +label.resources=Ressurser label.restart.network=Nettverksomstart label.restart.required=Omstart p\u00e5krevd +label.restart.vpc=Omstart VPC +label.restore=Gjenopprett label.review=Gjennomg\u00e5 label.revoke.project.invite=Tilbakekall invitasjonen +label.role=Rolle +label.root.disk.size=Rotdiskst\u00f8rrelse label.round.robin=Ringdistribusjon +label.routing=Ruting +label.rules=Regler +label.running.vms=Kj\u00f8rende VMer +label.s3.nfs.path=S3 NFS Sti +label.s3.nfs.server=S3 NFS Server +label.s3.use_https=Bruk HTTPS +label.saturday=L\u00f8rdag label.save.and.continue=Lagre og fortsett +label.save=Lagre +label.saving.processing=Lagrer.... +label.search=S\u00f8k +label.secondary.storage=Sekund\u00e6rlagring +label.secondary.storage.vm=Sekund\u00e6rlagring VM +label.security.group.name=Sikkerhetsgruppenavn +label.security.group=Sikkerhetsgruppe +label.security.groups=Sikkerhetsgrupper label.select.a.template=Velg en mal label.select.a.zone=Velg en sone +label.select.instance.to.attach.volume.to=Velg instans for tildeling av volum +label.select.instance=Velg instans label.select.iso.or.template=Velg ISO eller mal +label.select.offering=Velg tilbud label.select.project=Velg prosjekt +label.select=Velg label.select-view=Velg visning +label.select.vm.for.static.nat=Velg instans for statisk NAT +label.sent=Sendt +label.server=Tjener +label.service.offering=Tjenestetilbud +label.service.state=Tjeneste Status +label.session.expired=Sesjon utl\u00f8pt label.setup.network=Nettverksoppsett label.setup=Oppsett label.setup.zone=Soneoppsett label.set.up.zone.type=Oppsett av sonetype +label.shared=Delt label.shutdown.provider=Steng tilbyder +label.size=St\u00f8rrelse label.skip.guide=Jeg har brukt CloudStack tidligere. Hopp over denne veiviseren label.source=Kilde +label.source.nat=Kilde NAT +label.specify.IP.ranges=Spesifiser IP-rekker +label.specify.vlan=Spesifiser VLAN +label.specify.vxlan=Spesifiser VXLAN label.SR.name = SR navnelapp label.srx=SRX label.start.IP=Start-IP +label.start.port=Start port label.start.vlan=Start-VLAN +label.start.vxlan=Start Vxlan label.static.nat.enabled=Statisk NAT aktivert +label.static.nat=Statistk NAT +label.static.nat.vm.details=Statisk NAT VM Detaljer +label.statistics=Statistikk +label.status=Status +label.step.1=Steg 1 +label.step.1.title=Steg 1\: Velg en mal +label.step.2=Steg 2 +label.step.2.title=Steg 2\: Tjenestetilbud +label.step.3=Steg 3 +label.step.3.title=Steg 3\: Velg et disktilbud +label.step.4=Steg 4 +label.step.4.title=Steg 4\: Nettverk +label.step.5=Steg 5 +label.step.5.title=Steg 5\: Repetere label.stickiness=Klebrighet +label.sticky.domain=Domene +label.sticky.expire=Utl\u00f8per +label.sticky.length=Lengde +label.stopped.vms=Stoppede VMer +label.stop=Stopp +label.storage=Lagring label.storage.tags=Merkelapper for lagring label.storage.traffic=Lagringstrafikk +label.storage.type=Lagringstype label.subdomain.access=Tilgang for underdomene +label.succeeded=Vellykket +label.sunday=S\u00f8ndag +label.supported.services=St\u00f8ttede Tjenester label.supported.source.NAT.type=Supporterte kilde-NAT typer label.suspend.project=Suspender prosjekt +label.switch.type=Svitsjtype +label.system.capacity=Systemkapasistet +label.system.offering=Systemtilbud +label.system.vms=System VMer +label.system.vm=System VM label.task.completed=Oppgave utf\u00f8rt +label.template=Mal label.TFTP.dir=TFTP-mappe +label.thursday=Torsdag label.timeout=Tidsavbrudd +label.time=Tid +label.time.zone=Tidssone +label.timezone=Tidssone label.token=Kode +label.total.cpu=Totalt CPU +label.total.CPU=Totalt CPU +label.total.hosts=Totalt Verter +label.total.memory=Totalt minne +label.total.of.ip=Totalt IP-adresser +label.total.of.vm=Totalt av VM +label.total.storage=Totalt lagring +label.traffic.label=Trafikketikett label.traffic.types=Trafikktyper +label.traffic.type=Trafikktype +label.tuesday=Tirsdag +label.type.id=Type ID +label.type=Type +label.unlimited=Ubegrenset label.update.project.resources=Oppdater prosjektressurser +label.update.ssl.cert= SSL-sertifikat +label.update.ssl= SSL-sertifikat +label.updating=Oppdaterer +label.upload=Last opp +label.upload.volume=Last opp volum +label.url=URL +label.used=Brukt +label.user=Bruker +label.username=Brukernavn +label.users=Brukere +label.use.vm.ip=Bruk VM IP\: +label.value=Verdi +label.vcdcname=vCenter DC navn +label.vcenter.cluster=vCenter Klynge +label.vcenter.host=vCenter Vert +label.vcenter.password=vCenter passord +label.vcenter.username=vCenter brukernavn +label.vcipaddress=vCenter IP-adresse +label.version=Versjon label.view.all=Vis alle label.view.console=Se konsoll label.viewing=Viser +label.view.more=Vis mer +label.view.secondary.ips=Se sekund\u00e6re IPer label.view=Vis label.virtual.machines=Virtuelle maskiner +label.virtual.network=Virtuelt-nettverk +label.virtual.routers=Virtuelle rutere label.virtual.router=Virtuell ruter +label.vlan.id=VLAN/VNI ID +label.vlan=VLAN/VNI +label.vm.add=Legg til Instans +label.vm.destroy=Destruer label.vm.display.name=Visningsnavn for VM label.VMFS.datastore=VMFS lagringsomr\u00e5de +label.vmfs=VMFS label.vm.name=VM-navn +label.vm.reboot=Restart +label.vmsnapshot.type=Type +label.vm.start=Start +label.vm.stop=Stopp +label.vms=VMer label.vmware.traffic.label=VMware trafikketikett +label.vnet.id=VLAN/VNI ID +label.vnet=VLAN/VNI label.volgroup=Volumgruppe +label.volume.limits=Volumbegrensninger +label.volume.name=Volumnavn +label.volumes=Volumer +label.volume=Volum +label.vpc.id=VPC ID +label.VPC.router.details=VPC ruterdetaljer +label.vpc=VPC +label.VPN.connection=VPN-tilkobling +label.VPN.gateway=VPN Gateway +label.vpn=VPN +label.vxlan.id=VXLAN ID +label.vxlan.range=VXLAN-rekke +label.vxlan=VXLAN +label.waiting=Venter +label.warn=Varsle +label.wednesday=Onsdag +label.weekly=Ukentlig +label.welcome.cloud.console=Velkommen til administrasjonskonsollet +label.welcome=Velkommen label.what.is.cloudstack=Hva er CloudStack&\#8482? label.xen.traffic.label=XenServer trafikketikett +label.yes=Ja label.zone.details=Sonedetaljer +label.zone.id=Sone ID label.zone.name=Sonenavn +label.zone=Sone +label.zones=Soner +label.zone.step.1.title=Steg 1\: Velg et nettverk +label.zone.step.2.title=Steg 2\: Legg til en sone +label.zone.step.3.title=Steg 3\: Legg til en pod +label.zone.step.4.title=Steg 4\: Legg til en IP-rekke label.zone.type=Sonetype +message.acquire.ip.nic=Vennligst bekreft at du vil allokere en ny sekund\u00e6r IP for dette nettverkskortet.
NB\: Du m\u00e5 manuelt konfigurere den nye sekund\u00e6r-IPen i den virtuelle maskinen. message.acquire.new.ip=Vennligst bekreft at du \u00f8nsker \u00e5 anskaffe en ny IP for dette nettverket +message.action.change.service.warning.for.router=Din ruter m\u00e5 v\u00e6re stoppet f\u00f8r du kan fors\u00f8ke \u00e5 endre n\u00e5v\u00e6rende servicetilbud. +message.action.delete.cluster=Vennligst bekreft at du vil slette denne klyngen. +message.action.delete.disk.offering=Vennligst bekreft at du \u00f8nsker \u00e5 slette dette disktilbudet. +message.action.delete.domain=Vennligst bekreft at du vil slette dette domenet. +message.action.delete.ingress.rule=Vennligst bekreft at du \u00f8nsker \u00e5 slette denne inng\u00e5ende regel. +message.action.delete.ISO.for.all.zones=Denne ISO er brukt av alle soner. Vennligst bekreft at du \u00f8nsker \u00e5 slette den fra alle soner. +message.action.delete.ISO=Vennligst bekreft at du vil slette denne ISO. +message.action.delete.network=Vennligst bekreft at du vil slette dette nettverket. +message.action.delete.nexusVswitch=Vennligst bekreft at du \u00f8nsker \u00e5 slette denne nexus 1000v +message.action.delete.physical.network=Vennligst bekreft at du \u00f8nsker \u00e5 slette dette fysiske nettverk +message.action.delete.pod=Vennligst bekreft at du vil slette denne pod. +message.action.delete.primary.storage=Vennligst bekreft at du \u00f8nsker \u00e5 slette denne prim\u00e6rlagring. +message.action.delete.secondary.storage=Vennligst bekreft at du \u00f8nsker \u00e5 slette denne sekund\u00e6rlagring. +message.action.delete.security.group=Vennligst bekreft at du \u00f8nsker \u00e5 slette denne sikkerhetsgruppe. +message.action.delete.service.offering=Vennligst bekreft at du \u00f8nsker \u00e5 slette dette servicetilbud. +message.action.delete.system.service.offering=Vennligst bekreft at du \u00f8nsker \u00e5 slette dette system-servicetilbud. +message.action.delete.template.for.all.zones=Denne mal er brukt av alle soner. Vennligst bekreft at du \u00f8nsker \u00e5 slette den fra alle soner. +message.action.delete.template=Vennligst bekreft at du vil slette denne mal. +message.action.delete.volume=Vennligst bekreft at du vil slette dette volumet. +message.action.delete.zone=Vennligst bekreft at du \u00f8nsker \u00e5 slette denne sone. +message.action.destroy.instance=Vennligst bekreft at du \u00f8nsker \u00e5 fjerne denne instansen. +message.action.disable.nexusVswitch=Vennligst bekreft at du \u00f8nsker \u00e5 deaktivere denne nexus 1000v +message.action.disable.physical.network=Vennligst bekreft at du \u00f8nsker \u00e5 deaktivere dette fysiske nettverket. message.action.disable.pod=Vennligst bekreft at du \u00f8nsker \u00e5 aktivere denne poden message.action.disable.zone=Vennligst bekreft at du \u00f8nsker \u00e5 deaktivere denne sonen. +message.action.download.iso=Vennligst bekreft at du \u00f8nsker \u00e5 laste ned denne ISO. +message.action.download.template=Vennligst bekreft at du \u00f8nsker \u00e5 laste ned denne malen. message.action.enable.cluster=Vennligst bekreft at du \u00f8nsker \u00e5 aktivere denne klyngen. +message.action.enable.nexusVswitch=Vennligst bekreft at du \u00f8nsker \u00e5 aktivere denne nexus 1000v +message.action.enable.physical.network=Vennligst bekreft at du \u00f8nsker \u00e5 aktivere dette fysiske nettverket. message.action.enable.pod=Vennligst bekreft at du \u00f8nsker \u00e5 aktivere denne poden. message.action.enable.zone=Vennligst bekreft at du \u00f8nsker \u00e5 aktivere denne sonen. +message.action.start.instance=Vennligst bekreft at du \u00f8nsker \u00e5 starte denne instansen. message.activate.project=Er du sikker p\u00e5 du \u00f8nsker \u00e5 aktivere dette prosjektet? +message.add.domain=Vennligst bekreft underdomenet du \u00f8nsker \u00e5 opprette under dette domenet message.add.guest.network=Vennligst bekreft at du \u00f8nsker \u00e5 legge til gjestenettverk message.adding.host=Legger til vert message.adding.Netscaler.device=Legg til NetScaler-enhet +message.add.load.balancer.under.ip=Lastbalanseringsregelen har blitt lagt til under IP\: +message.add.VPN.gateway=Vennligst bekreft at du \u00f8nsker \u00e5 legge til en VPN Gateway message.alert.state.detected=Alarm oppdaget message.change.password=Vennligst endre ditt passord message.configuring.guest.traffic=Konfigurerer gjestetrafikk message.configuring.physical.networks=Konfigurer fysisk nettverk message.configuring.public.traffic=Konfigurerer offentlig trafikk message.configuring.storage.traffic=Konfigurerer lagringstrafikk +message.confirm.delete.F5=Vennligst bekreft at du \u00f8nsker \u00e5 slette F5 +message.confirm.delete.NetScaler=Vennligst bekreft at du \u00f8nsker \u00e5 slette Netscaler +message.confirm.delete.SRX=Vennligst bekreft at du \u00f8nsker \u00e5 slette SRX message.confirm.destroy.router=Vennligst bekreft at du \u00f8nsker \u00e5 fjerne denne ruteren message.confirm.disable.provider=Vennligst bekreft at du \u00f8nsker \u00e5 deaktivere denne tilbyderen message.confirm.enable.provider=Vennligst bekreft at du \u00f8nsker \u00e5 aktivere denne tilbyderen @@ -275,16 +989,26 @@ message.confirm.join.project=Vennligst bekreft at du \u00f8nsker \u00e5 delta i message.confirm.shutdown.provider=Vennligst bekreft at du \u00f8nsker \u00e5 stenge denne tilbyderen message.create.template=Er du sikker p\u00e5 at du \u00f8nsker \u00e5 lage malen? message.creating.cluster=Oppretter klynge +message.creating.guest.network=Oppretter gjestenettverk +message.creating.physical.networks=Oppretter fysiske nettverk message.creating.pod=Oppretter pod message.creating.primary.storage=Oppretter prim\u00e6rlagring message.creating.secondary.storage=Oppretter sekund\u00e6rlagring +message.creating.zone=Oppretter sone message.decline.invitation=Er du sikker p\u00e5 du \u00f8nsker \u00e5 avvise denne prosjektinvitasjonen? +message.delete.gateway=Vennligst bekreft at du \u00f8nsker \u00e5 slette gateway message.delete.project=Er du sikker p\u00e5 du \u00f8nsker \u00e5 slette dette prosjektet? +message.delete.user=Vennligst bekreft at du \u00f8nsker \u00e5 slette denne bruker. +message.delete.VPN.connection=Vennligst bekreft at du \u00f8nsker \u00e5 slette VPN-tilkobling message.detach.disk=Er du sikker p\u00e5 at du \u00f8nsker \u00e5 frakoble denne disken? +message.disable.user=Vennligst bekreft at du \u00f8nsker \u00e5 deaktivere denne bruker. +message.disable.vpn=Er du sikker p\u00e5 at du vil deaktivere VPN? message.download.volume.confirm=Vennligst bekreft at du \u00f8nsker \u00e5 laste ned dette volumet +message.enable.user=Vennligst bekreft at du \u00f8nsker \u00e5 aktivere denne bruker. message.enable.vpn=Vennligst bekreft at du \u00f8nsker \u00e5 aktivere VPN-tilgang for denne IP-adressen message.enabling.zone=Aktiverer sonen message.enter.token=Vennligst skriv inn koden du fikk i invitasjonsmailen. +message.generate.keys=Vennligst bekreft at du \u00f8nsker \u00e5 generere nye n\u00f8kler for denne bruker. message.installWizard.click.retry=Klikk p\u00e5 knappen for \u00e5 pr\u00f8ve oppstart p\u00e5 nytt. message.installWizard.tooltip.addCluster.name=Klyngenavnet. Dette kan v\u00e6re hva som helst og er ikke benyttet av CloudStack. message.installWizard.tooltip.addHost.hostname=DNS-navnet eller IP-adressen til verten. @@ -311,6 +1035,8 @@ message.iso.desc=Diskimage som inneholder data etter oppstartsbar media for OS message.join.project=Du har n\u00e5 deltatt i et prosjekt. Vennligst bytt til prosjektvisning for \u00e5 se prosjektet. message.migrate.instance.to.host=Vennligst bekreft at du \u00f8nsker \u00e5 migrere instansen til en annen vert. message.migrate.instance.to.ps=Vennligst bekreft at du \u00f8nsker \u00e5 migrere instansen til en annen sekund\u00e6r lagring. +message.migrate.router.confirm=Vennligst bekreft verten du \u00f8nsker \u00e5 migrere ruteren til\: +message.migrate.systemvm.confirm=Vennligst bekreft verten du \u00f8nsker \u00e5 migrere system VM til\: message.migrate.volume=Vennligst bekreft at du \u00f8nsker \u00e5 migrere volumet til en annen prim\u00e6rlagring. message.no.projects.adminOnly=Du har ingen prosjekter.
Vennligst be din administrator om \u00e5 opprette et nytt prosjekt. message.no.projects=Du har ingen prosjekter.
Vennligst opprett et nytt fra prosjektseksjonen. @@ -323,17 +1049,28 @@ message.please.select.a.different.public.and.management.network.before.removing= message.please.select.networks=Vennligst velg nettverk for din VM message.please.wait.while.zone.is.being.created=Vennlist vent mens din sone opprettes. Dette kan ta noe tid... message.project.invite.sent=Invitasjon sendt til bruker. De vil bli lagt til prosjektet s\u00e5 snart de har akseptert invitasjonen +message.remove.region=Er du sikker p\u00e5 at du vil fjerne denne regionen fra denne administrasjonsserveren? +message.remove.vpc=Vennligst bekreft at du \u00f8nsker \u00e5 fjerne VPC message.reset.password.warning.notPasswordEnabled=Denne malen vil bli opprettet uten passord message.reset.password.warning.notStopped=Din instans m\u00e5 stoppes f\u00f8r man fors\u00f8ker \u00e5 bytte n\u00e5v\u00e6rende passord +message.reset.VPN.connection=Vennligst bekreft at du \u00f8nsker \u00e5 resette VPN-tilkobling +message.restart.mgmt.server=Vennlist restart administrajonsserveren(e) din(e) for at de nye innstillingene skal tr\u00e5 i kraft. +message.restart.vpc=Vennligst bekreft at du \u00f8nsker \u00e5 restarte VPC +message.select.instance=Vennligst velg en instans. message.select.iso=Vennligst velg en ISO for din nye virtuelle instans. message.select.item=Vennligst velg et element message.select.security.groups=Vennligst velg sikkerhetsgruppe(r) for din nye VM message.select.template=Vennligst velg en mal for din nye virtuelle instans. message.setup.successful=Oppsettet av nettskyen er vellykket\! +message.specify.url=Vennligst spesifiser URL message.step.2.desc= message.step.3.desc= message.suspend.project=Er du sikker du \u00f8nsker \u00e5 pause dette prosjektet? message.template.desc=OS-image som kan brukes til \u00e5 starte VMer +message.tooltip.pod.name=Et navn for denne pod. +message.tooltip.zone.name=Et navn for denne sonen. +message.validate.invalid.characters=Ugyldige tegn funnet; vennligst korriger. +message.vm.create.template.confirm=Oppretting av Mal vil restarte VM automatisk. message.vm.review.launch=Vennligst vurder f\u00f8lgende informasjon og bekreft at din virtuelle instans er korrekt f\u00f8r kj\u00f8ring message.you.must.have.at.least.one.physical.network=Du trenger minst ett fysisk nettverk message.Zone.creation.complete=Opprettelsen av sonen utf\u00f8rt @@ -345,6 +1082,7 @@ notification.stop.instance=Stopp instans state.Accepted=Akseptert state.Active=Aktiv state.Allocated=Allokert +state.Allocating=Allokerer state.BackedUp=Sikkerhetskopiert state.BackingUp=Sikkerhetskopierer state.Completed=Utf\u00f8rt @@ -352,14 +1090,18 @@ state.Creating=Oppretter state.Declined=Avvist state.Destroyed=Destruert state.Disabled=Inaktiv +state.enabled=Aktivert +state.Enabled=Aktivert state.Error=Feil state.Expunging=Fjerner +state.Migrating=Migrering state.Pending=Venter state.ready=Klar state.Ready=Klar state.Running=Kj\u00f8rer state.Starting=Starter state.Stopped=Stoppet +state.Stopping=Stopper state.Suspended=Pauset ui.listView.filters.all=Alle ui.listView.filters.mine=Mine diff --git a/client/WEB-INF/classes/resources/messages_nl_NL.properties b/client/WEB-INF/classes/resources/messages_nl_NL.properties new file mode 100644 index 000000000000..b1bfadb42af8 --- /dev/null +++ b/client/WEB-INF/classes/resources/messages_nl_NL.properties @@ -0,0 +1,1216 @@ +# 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. + +changed.item.properties=Item eigenschappen gewijzigd +confirm.enable.s3=Vul de volgende informatie in om ondersteuning voor S3-aangestuurde Secundaire Opslag te activeren +confirm.enable.swift=Vul de volgende informatie in om ondersteuning voor Swift te activeren +error.could.not.enable.zone=Kon zone niet activeren +error.installWizard.message=Er ging iets mis; je kunt teruggaan om de eventuele fouten te herstellen +error.invalid.username.password=Ongeldige gebruikersnaam of wachtwoord +error.login=Uw gebruikersnaam/wachtwoord komt niet overeen met onze gegevens +error.menu.select=Kan actie niet uitvoeren omdat geen items zijn geselecteerd +error.mgmt.server.inaccessible=The Management Server is niet toegankelijk. Probeer het later opnieuw. +error.password.not.match=De wachtwoord velden komen niet overeen +error.please.specify.physical.network.tags=Netwerk aanbiedingen zijn niet beschikbaar totdat u labels voor het fysieke netwerk specificeert. +error.session.expired=Uw sessie is verlopen +error.something.went.wrong.please.correct.the.following=Er is iets mis gegaan; Corrigeer het volgende +error.unable.to.reach.management.server=Niet in staat om de Management Server te bereiken +error.unresolved.internet.name=Uw internet naam kan niet worden omgezet. +extractable=Uitpakbaar +force.delete.domain.warning=Waarschuwing\: Wanneer u deze optie selecteert zullen alle onderliggende domeinen, hun gekoppelde accounts en hun verbruik worden verwijderd. +force.delete=Geforceerd verwijderen +force.remove=Geforceerd loskoppelen +force.remove.host.warning=Waarschuwing\: Wanneer u deze optie selecteert zal CloudStack alle draaiende virtuele machines geforceerd stoppen voordat de host van het cluster wordt verwijderd. +force.stop=Geforceerd stoppen +force.stop.instance.warning=Waarschuwing\: Een instantie geforceerd stoppen zou uw laatste optie moeten zijn. Het kan leiden tot dataverlies en inconsistent gedrag van de staat van de virtuele machine. +ICMP.code=ICMP Code +ICMP.type=ICMP Type +image.directory=Afbeelding Directory +inline=Inline +instances.actions.reboot.label=Herstart instantie +label.accept.project.invitation=Accepteer project uitnodiging +label.account=Account +label.account.and.security.group=Account, Security group +label.account.id=Account ID +label.account.name=Account Naam +label.accounts=Accounts +label.account.specific=Account-specifiek +label.acquire.new.ip=Bemachtig nieuw IP +label.action.attach.disk.processing=Schijf wordt toegevoegd.... +label.action.attach.disk=Schijf toevoegen +label.action.attach.iso=ISO toevoegen +label.action.attach.iso.processing=ISO wordt toegevoegd.... +label.action.cancel.maintenance.mode=Annuleer Onderhoudsmodus +label.action.cancel.maintenance.mode.processing=Onderhoudsmodus wordt geannuleerd.... +label.action.change.password=Wijzig Wachtwoord +label.action.change.service.processing=Service wordt gewijzigd.... +label.action.change.service=Wijzig Service +label.action.copy.ISO=Kopieer ISO +label.action.copy.ISO.processing=Kopi\u00ebren ISO.... +label.action.copy.template=Kopieer Template +label.action.copy.template.processing=Bezig met kopi\u00ebren Template.... +label.action.create.template=Cre\u00eber Template +label.action.create.template.from.vm=Cre\u00eber Template vanaf VM +label.action.create.template.from.volume=Cre\u00eber Template van Volume +label.action.create.template.processing=Bezig met aanmaken Template.... +label.action.create.vm=Cre\u00eber VM +label.action.create.vm.processing=Bezig met aanmaken VM.... +label.action.create.volume=Cre\u00eber Volume +label.action.create.volume.processing=Bezig met cre\u00ebren volume.... +label.action.delete.account.processing=Bezig met verwijderen account.... +label.action.delete.account=Verwijder account +label.action.delete.cluster.processing=Bezig met verwijderen van Cluster.... +label.action.delete.cluster=Verwijder Cluster +label.action.delete.disk.offering.processing=Bezig met verwijderen van Schijf Aanbieding.... +label.action.delete.disk.offering=Verwijder Schijf Aanbieding +label.action.delete.domain.processing=Bezig met verwijderen van Domein.... +label.action.delete.domain=Verwijder Domein +label.action.delete.firewall.processing=Bezig met verwijderen van Firewall.... +label.action.delete.firewall=Verwijder firewall regel +label.action.delete.ingress.rule.processing=Bezig met verwijderen van Inkomende Regel.... +label.action.delete.ingress.rule=Verwijder Inkomende Regel +label.action.delete.IP.range.processing=Bezig met verwijderen van IP Range.... +label.action.delete.IP.range=Verwijder IP Range +label.action.delete.ISO.processing=Bezig met verwijderen van ISO.... +label.action.delete.ISO=Verwijder ISO +label.action.delete.load.balancer.processing=Bezig met verwijderen van Load Balancer.... +label.action.delete.load.balancer=Verwijder load balancer regel +label.action.delete.network.processing=Bezig met verwijderen van Netwerk.... +label.action.delete.network=Verwijder Netwerk +label.action.delete.nexusVswitch=Verwijder Nexus 1000v +label.action.delete.physical.network=Verwijder fysiek netwerk +label.action.delete.pod.processing=Bezig met verwijderen van Pod.... +label.action.delete.pod=Verwijder Pod +label.action.delete.primary.storage.processing=Bezig met verwijderen van Primaire Opslag.... +label.action.delete.primary.storage=Verwijder Primaire Opslag +label.action.delete.secondary.storage.processing=Bezig met verwijderen van Secundaire Opslag.... +label.action.delete.secondary.storage=Verwijder Secundaire Opslag +label.action.delete.security.group.processing=Bezig met verwijderen van Security Group.... +label.action.delete.security.group=Verwijder Security Group +label.action.delete.service.offering.processing=Bezig met verwijderen van Service Aanbieding.... +label.action.delete.service.offering=Verwijder Service Aanbieding +label.action.delete.snapshot.processing=Bezig met verwijderen van Snapshot.... +label.action.delete.snapshot=Verwijder Snapshot +label.action.delete.system.service.offering=Verwijder Systeem Service Aanbieding +label.action.delete.template.processing=Bezig met verwijderen van Template.... +label.action.delete.template=Verwijder Template +label.action.delete.user.processing=Bezig met verwijderen Gebruiker.... +label.action.delete.user=Verwijder Gebruiker +label.action.delete.volume.processing=Bezig met verwijderen van Volume.... +label.action.delete.volume=Verwijder Volume +label.action.delete.zone.processing=Bezig met verwijderen van Zone.... +label.action.delete.zone=Verwijder Zone +label.action.destroy.instance.processing=Bezig met vernietigen van Instantie.... +label.action.destroy.instance=Verwijder Instantie +label.action.destroy.systemvm.processing=Bezig met vernietigen van Systeem VM.... +label.action.destroy.systemvm=Vernietig Systeem VM +label.action.detach.disk=Ontkoppel Schijf +label.action.detach.disk.processing=Bezig met ontkoppelen van Schijf.... +label.action.detach.iso=Ontkoppel ISO +label.action.detach.iso.processing=Bezig met ontkoppelen van ISO.... +label.action.disable.account=Deactiveer account +label.action.disable.account.processing=Bezig met deactiveren van account.... +label.action.disable.cluster=Deactiveer Cluster +label.action.disable.cluster.processing=Bezig met deactiveren van Cluster.... +label.action.disable.nexusVswitch=Deactiveer Nexus 1000v +label.action.disable.physical.network=Deactiveer fysiek netwerk +label.action.disable.pod=Deactiveer Pod +label.action.disable.pod.processing=Bezig met deactiveren van Pod.... +label.action.disable.static.NAT=Deactiveer Static NAT +label.action.disable.static.NAT.processing=Bezig met deactiveren van Static NAT.... +label.action.disable.user=Deactiveer Gebruiker +label.action.disable.user.processing=Bezig met deactiveren van Gebruiker.... +label.action.disable.zone=Deactiveer Zone +label.action.disable.zone.processing=Bezig met deactiveren van Zone.... +label.action.download.ISO=Download ISO +label.action.download.template=Download Template +label.action.download.volume=Download Volume +label.action.download.volume.processing=Bezig met downloaden van Volume.... +label.action.edit.account=Wijzig account +label.action.edit.disk.offering=Wijzig schijf aanbieding +label.action.edit.domain=Wijzig Domein +label.action.edit.global.setting=Wijzig Algemene Instellingen +label.action.edit.host=Wijzig Host +label.action.edit.instance=Wijzig Instantie +label.action.edit.ISO=Wijzig ISO +label.action.edit.network.offering=Wijzig Netwerk Aanbieding +label.action.edit.network.processing=Bezig met wijzigen van Netwerk... +label.action.edit.network=Wijzig Netwerk +label.action.edit.pod=Wijzig Pod +label.action.edit.primary.storage=Wijzig Primaire Opslag +label.action.edit.resource.limits=Wijzig verbruikslimieten +label.action.edit.service.offering=Wijzig Service Aanbieding +label.action.edit.template=Wijzig Template +label.action.edit.user=Wijzig Gebruiker +label.action.edit.zone=Wijzig Zone +label.action.enable.account=Activeer account +label.action.enable.account.processing=Bezig met activeren van account.... +label.action.enable.cluster=Activeer Cluster +label.action.enable.cluster.processing=Bezig met activeren van Cluster.... +label.action.enable.maintenance.mode=Activeer onderhoudsmodus +label.action.enable.maintenance.mode.processing=Bezig met activeren van Onderhoudsmodus +label.action.enable.nexusVswitch=Activeer Nexus 1000v +label.action.enable.physical.network=Activeer fysiek netwerk +label.action.enable.pod=Activeer Pod +label.action.enable.pod.processing=Bezig met activeren van Pod.... +label.action.enable.static.NAT=Activeer Static NAT +label.action.enable.static.NAT.processing=Bezig met activeren van Static NAT.... +label.action.enable.user=Activeer Gebruiker +label.action.enable.user.processing=Bezig met activeren van Gebruiker.... +label.action.enable.zone=Activeer Zone +label.action.enable.zone.processing=Bezig met activeren van Zone.... +label.action.force.reconnect=Forceer opnieuw verbinden +label.action.force.reconnect.processing=Bezig met opnieuw verbinden.... +label.action.generate.keys=Genereer Sleutels +label.action.generate.keys.processing=Bezig met generen van Sleutels.... +label.action.list.nexusVswitch=Toon Nexus 1000v +label.action.lock.account=Account op slot zetten +label.action.lock.account.processing=Bezig met account op slot zetten.... +label.action.manage.cluster=Beheer Cluster +label.action.manage.cluster.processing=Bezig met beheren van Cluster.... +label.action.migrate.instance=Migreer Instantie +label.action.migrate.instance.processing=Bezig met migreren van Instantie.... +label.action.migrate.router=MIgreer Router +label.action.migrate.router.processing=Bezig met migreren van Router.... +label.action.migrate.systemvm=Migreer Systeem VM +label.action.migrate.systemvm.processing=Bezig met migreren van Systeem VM.... +label.action.reboot.instance=Herstart Instantie +label.action.reboot.instance.processing=Bezig met herstarten van Instantie.... +label.action.reboot.router=Herstart Router +label.action.reboot.router.processing=Bezig met herstarten van Router.... +label.action.reboot.systemvm=Herstart Systeem VM +label.action.reboot.systemvm.processing=Bezig met herstarten van Systeem VM.... +label.action.recurring.snapshot=Terugkerende Snapshots +label.action.register.iso=Registreer ISO +label.action.register.template=Registreer Template +label.action.release.ip=Ontkoppel IP +label.action.release.ip.processing=Bezig met ontkoppelen van IP.... +label.action.remove.host.processing=Bezig met verwijderen van Host.... +label.action.remove.host=Verwijder Host +label.action.reset.password.processing=Bezig met resetten van wachtwoord.... +label.action.reset.password=Reset Wachtwoord +label.action.resize.volume.processing=Bezig met aanpassen van de grootte van het Volume +label.action.resize.volume=Wijzig de grootte van het volume +label.action.resource.limits=Verbruikslimieten +label.action.restore.instance=Herstel Instantie +label.action.restore.instance.processing=Bezig met herstellen van Instantie.... +label.actions=Acties +label.action.start.instance.processing=Bezig met starten van Instantie.... +label.action.start.instance=Start Instantie +label.action.start.router.processing=Start Router.... +label.action.start.router=Start Router +label.action.start.systemvm.processing=Bezig met starten van Systeem VM.... +label.action.start.systemvm=Start Systeem VM +label.action.stop.instance.processing=Bezig met stoppen van Instantie.... +label.action.stop.instance=Stop Instantie +label.action.stop.router.processing=Bezig met stoppen van Router.... +label.action.stop.router=Stop Router +label.action.stop.systemvm.processing=Bezig met stoppen van Systeem VM.... +label.action.stop.systemvm=Stop Systeem VM +label.action.take.snapshot=Neem Snapshot +label.action.take.snapshot.processing=Bezig met nemen van Snapshot.... +label.action.unmanage.cluster.processing=Bezig met uitschakelen van Clusterbeheer.... +label.action.unmanage.cluster=Schakel Clusterbeheer uit +label.action.update.OS.preference.processing=Bezig met wijzigen van OS voorkeuren.... +label.action.update.OS.preference=Wijzig OS voorkeuren +label.action.update.resource.count.processing=Bezig met updaten van verbruikslimieten.... +label.action.update.resource.count=Update Verbruikslimieten +label.action.vmsnapshot.create=Neem Snapshot van de VM +label.action.vmsnapshot.delete=Verwijder Snapshot van de VM +label.action.vmsnapshot.revert=Draai Snapshot van de VM terug +label.activate.project=Activeer Project +label.active.sessions=Actieve Sessies +label.add.accounts.to=Voeg accounts toe aan +label.add.accounts=Voeg accounts toe +label.add.account.to.project=Voeg account aan project toe +label.add.account=Voeg Account toe +label.add.ACL=Voeg ACL toe +label.add.BigSwitchVns.device=Voeg BigSwitch Vns Controller toe +label.add.by.cidr=Voeg toe door middel van CIDR +label.add.by.group=Voeg toe door middel van Groep +label.add.by=Voeg toe door middel van +label.add.cluster=Voeg Cluster toe +label.add.compute.offering=Voeg Compute aanbieding toe +label.add.direct.iprange=Voeg Direct IP Range toe +label.add.disk.offering=Voeg Schijf Aanbieding toe +label.add.domain=Voeg Domein toe +label.add.egress.rule=Voeg uitgaande regel toe +label.add.F5.device=Voeg F5 apparaat toe +label.add.firewall=Voeg firewall regel toe +label.add.guest.network=Gast netwerk toevoegen +label.add.host=Host toevoegen +label.adding.cluster=Bezig met toevoegen van Cluster +label.adding.failed=Toevoegen mislukt +label.adding.pod=Bezig met toevoegen van Pod +label.adding.processing=Toevoegen.... +label.add.ingress.rule=Voeg inkomende regel toe +label.adding.succeeded=Toevoegen geslaagd +label.adding=Toevoegen +label.adding.user=Bezig met toevoegen van Gebruiker +label.adding.zone=Bezig met toevoegen van Zone +label.add.ip.range=Voeg IP range toe +label.additional.networks=Additioneele Netwerken +label.add.load.balancer=Voeg Load Balancer toe +label.add.more=Voeg meer toe +label.add.netScaler.device=Voeg Netscaler apparaat toe +label.add.network.ACL=Voeg netwerk ACL toe +label.add.network.device=Voeg Netwerk Apparaat toe +label.add.network.offering=Voeg netwerk aanbieding toe +label.add.network=Voeg Netwerk toe +label.add.new.F5=Voeg nieuwe F5 toe +label.add.new.gateway=Voeg nieuwe gateway toe +label.add.new.NetScaler=Voeg nieuwe Netscaler toe +label.add.new.SRX=Voeg nieuwe SRX toe +label.add.new.tier=Voeg nieuwe Tier toe +label.add.NiciraNvp.device=Voeg NVP Controller toe +label.add.physical.network=Voeg fysiek netwerk toe +label.add.pod=Voeg Pod toe +label.add.port.forwarding.rule=Voeg port forwarding regel toe +label.add.primary.storage=Voeg Primaire Opslag toe +label.add.region=Voeg Regio toe +label.add.resources=Resources toevoegen +label.add.route=Route toevoegen +label.add.rule=Regel toevoegen +label.add.secondary.storage=Secundaire Opslag toevoegen +label.add.security.group=Security Group toevoegen +label.add.service.offering=Service Aanbieding toevoegen +label.add.SRX.device=SRX apparaat toevoegen +label.add.static.nat.rule=Statische NAT regel toevoegen +label.add.static.route=Statische route toevoegen +label.add.system.service.offering=Systeem Service Aanbieding toevoegen +label.add.template=Template toevoegen +label.add.to.group=Toevoegen aan groep +label.add.user=Gebruiker toevoegen +label.add.vlan=VLAN toevoegen +label.add.vms.to.lb=Voeg VM(s) toe aan load balancer regel +label.add.vms=VMs toevoegen +label.add.VM.to.tier=Voeg VM toe aan tier +label.add.vm=VM toevoegen +label.add=Voeg toe +label.add.volume=Volume toevoegen +label.add.vpc=VPC toevoegen +label.add.vpn.customer.gateway=VPN Customer Gateway toevoegen +label.add.VPN.gateway=VPN Gateway toevoegen +label.add.vpn.user=VPN gebruiker toevoegen +label.add.zone=Zone toevoegen +label.admin.accounts=Beheer Accounts +label.admin=Beheerder +label.advanced=Geavanceerd +label.advanced.mode=Geavanceerde Modus +label.advanced.search=Geavanceerd zoeken +label.agent.password=Agent wachtwoord +label.agent.username=Agent Gebruikersnaam +label.agree=Accepteren +label.alert=Alarm +label.algorithm=Algoritme +label.allocated=Gebruikt +label.allocation.state=Verbruik Staat +label.api.key=API Sleutel +label.apply=Uitvoeren +label.assign=Toevoegen +label.assign.to.load.balancer=Voeg instantie toe aan load balancer +label.associated.network=Bijbehorend Netwerk +label.associated.network.id=Bijbehorend Netwerk ID +label.attached.iso=Gekoppelde ISO +label.author.email=Auteur e-mail +label.author.name=Auteur naam +label.availability=Beschikbaarheid +label.availability.zone=Beschikbaarheids-zone +label.available=Beschikbaar +label.available.public.ips=Beschikbare Publieke IP adressen +label.back=Terug +label.bandwidth=Bandbreedte +label.basic=Basis +label.basic.mode=Basis Modus +label.bigswitch.controller.address=BigSwitch Vns Controller Adres +label.bootable=Bootable +label.broadcast.domain.range=Broadcast domain range +label.broadcast.domain.type=Broadcast Domain Type +label.broadcast.uri=Broadcast URI +label.by.account=Op Account +label.by.availability=Op Beschikbaarheid +label.by.domain=Op Domein +label.by.end.date=Op Eind Datum +label.by.level=Op Level +label.by.pod=Op Pod +label.by.role=Op Rol +label.by.start.date=Op Start Datum +label.by.state=Op Staat +label.bytes.received=Bytes Ontvangen +label.bytes.sent=Bytes Verzonden +label.by.traffic.type=Op Verkeerstype +label.by.type.id=Op Type ID +label.by.type=Op Type +label.by.zone=Op Zone +label.cancel=Annuleer +label.capacity=Capaciteit +label.certificate=Certificaat +label.change.service.offering=Wijzig service aanbieding +label.change.value=Wijzig waarde +label.character=Karakter +label.checksum=MD5 checksum +label.cidr.account=CIDRN of Account/Security Group +label.cidr=CIDR +label.cidr.list=Bron CIDR +label.CIDR.list=CIDR lijst +label.CIDR.of.destination.network=CIDR van bestemmingsnetwerk +label.clean.up=Opschonen +label.clear.list=Schoon lijst op +label.close=Sluiten +label.cloud.console=Cloud Beheers Console +label.cloud.managed=Cloud.com Managed +label.cluster=Cluster +label.cluster.name=Cluster Naam +label.clusters=Clusters +label.cluster.type=Cluster Type +label.clvm=CLVM +label.code=Code +label.community=Community +label.compute.and.storage=Compute en Opslag +label.compute=Compute +label.compute.offering=Compute aanbieding +label.configuration=Configuratie +label.configure=Configureer +label.configure.network.ACLs=Configureer Netwerk ACLs +label.configure.vpc=Configureer VPC +label.confirmation=Bevestiging +label.confirm.password=Bevestig wachtwoord +label.congratulations=Gefeliciteerd\! +label.conserve.mode=Conserveer modus +label.console.proxy=Console proxy +label.continue.basic.install=Ga door met basis installatie +label.continue=Ga door +label.corrections.saved=Correcties opgeslagen +label.cpu.allocated=CPU gebruik +label.cpu.allocated.for.VMs=CPU gebruikt voor VMs +label.CPU.cap=CPU Cap +label.cpu=CPU +label.cpu.limits=CPU limieten +label.cpu.mhz=CPU (in MHz) +label.cpu.utilized=CPU Verbruik +label.created=Aangemaakt +label.created.by.system=Aangemaakt door systeem +label.create.project=Nieuw project +label.create.template=Nieuwe template +label.create.VPN.connection=Nieuwe VPN connectie +label.cross.zones=Over Zones +label.custom.disk.size=Vrije schijf grootte +label.daily=Dagelijkse +label.data.disk.offering=Data Schijf Aanbieding +label.date=Datum +label.day.of.month=Dag van de Maand +label.day.of.week=Dag van de Week +label.dead.peer.detection=Dead Peer detectie +label.decline.invitation=Sla uitnodiging af +label.dedicated=Dedicated +label.default=Standaard +label.default.use=Standaard Gebruik +label.default.view=Standaard Weergave +label.delete.BigSwitchVns=Verwijder BigSwitch Vns Controller +label.delete.F5=Verwijder F5 +label.delete.gateway=Verwijder gateway +label.delete.NetScaler=Verwijder NetScaler +label.delete.NiciraNvp=Verwijder Nvp Controller +label.delete.project=Verwijder project +label.delete.SRX=Verwijder SRX +label.delete=Verwijder +label.delete.VPN.connection=Verwijder VPN connectie +label.delete.VPN.customer.gateway=Verwijder VPN Customer Gateway +label.delete.VPN.gateway=Verwijder VPN Gateway +label.delete.vpn.user=Verwijder VPN gebruiker +label.deleting.failed=Verwijderen Mislukt +label.deleting.processing=Verwijderen.... +label.description=Beschrijving +label.destination.physical.network.id=Bestemming fysiek netwerk ID +label.destination.zone=Bestemmingszone +label.destroy.router=Verwijder router +label.destroy=Verwijder +label.detaching.disk=Ontkoppelen Schijf +label.details=Details +label.device.id=Apparaat ID +label.devices=Apparaten +label.dhcp=DHCP +label.DHCP.server.type=DHCP Server Type +label.direct.ips=Shared Netwerk IPs +label.disabled=Uitgeschakeld +label.disable.provider=Provider uitschakelen +label.disable.vpn=VPN uitschakelen +label.disabling.vpn.access=Uitschakelen van VPN Toegang +label.disk.allocated=Schijfruimte gealloceerd +label.disk.offering=Schijf Aanbieding +label.disk.size.gb=Schijf Grootte (in GB) +label.disk.size=Schijf Grootte +label.disk.total=Schijf Totaal +label.disk.volume=Schijf Volume +label.display.name=Weergavenaam +label.display.text=Weergavetekst +label.dns.1=DNS 1 +label.dns.2=DNS 2 +label.dns=DNS +label.DNS.domain.for.guest.networks=DNS domein voor Gast Netwerken +label.domain.admin=Domein Beheerder +label.domain=Domein +label.domain.id=Domein ID +label.domain.name=Domeinnaam +label.domain.router=Domein router +label.domain.suffix=DNS domein achtervoegsel (v.b., xyz.com) +label.done=Klaar +label.double.quotes.are.not.allowed=Aanhalingstekens zijn hier niet toegestaan +label.download.progress=Download Voortgang +label.drag.new.position=Sleep naar nieuwe positie +label.edit.lb.rule=Wijzig LB regel +label.edit.network.details=Wijzig netwerk details +label.edit.project.details=Wijzig project details +label.edit.tags=Wijzig tags +label.edit.traffic.type=Wijzig traffic type +label.edit.vpc=Wijzig VPC +label.edit=Wijzig +label.egress.rules=Uitgaande regels +label.egress.rule=Uitgaande regel +label.elastic=Elastisch +label.elastic.IP=Elastisch IP +label.elastic.LB=Elastisch LB +label.email=Email +label.enable.provider=Provider inschakelen +label.enable.s3=S3-gebaseerde Secondary Storage inschakelen +label.enable.swift=Swift inschakelen +label.enable.vpn=VPN inschakelen +label.enabling.vpn.access=VPN toegang inschakelen +label.enabling.vpn=VPN inschakelen +label.end.IP=Eind IP +label.endpoint=Endpoint +label.endpoint.or.operation=Endpoint or Operation +label.end.port=Eind Poort +label.end.reserved.system.IP=Einde gereserveerde systeem IP +label.end.vlan=Einde Vlan +label.enter.token=Voer token in +label.error.code=Fout code +label.error=Fout +label.ESP.encryption=ESP Encryptie +label.ESP.hash=ESP Hash +label.ESP.lifetime=ESP Lifetime (secondes) +label.ESP.policy=ESP policy +label.esx.host=ESX/ESXi Host +label.example=Voorbeeld +label.external.link=Externe link +label.f5=F5 +label.failed=Mislukt +label.featured=Voorgesteld +label.fetch.latest=Haal laatste op +label.filterBy=Filter per +label.firewall=Firewall +label.first.name=Voornaam +label.format=Formaat +label.friday=Vrijdag +label.full.path=Volledig pad +label.full=Volledig +label.gateway=Gateway +label.general.alerts=Algemene Waarschuwingen +label.generating.url=Generen van URL +label.go.step.2=Ga naar Stap 2 +label.go.step.3=Ga naar Stap 3 +label.go.step.4=Ga naar Stap 4 +label.go.step.5=Ga naar Stap 5 +label.group=Groep +label.group.optional=Groep (Optioneel) +label.guest.cidr=Gast CIDR +label.guest.end.ip=Gast eind IP +label.guest=Gast +label.guest.gateway=Gast Gateway +label.guest.ip=Gast IP Adres +label.guest.ip.range=Gast IP range +label.guest.netmask=Gast Netmask +label.guest.networks=Gast netwerken +label.guest.start.ip=Gast start IP +label.guest.traffic=Gast verkeer +label.guest.type=Gast Type +label.ha.enabled=HA ingeschakeld +label.help=Help +label.hide.ingress.rule=Verberg Inkomende Regel +label.hints=Tips +label.host.alerts=Host Waarschuwingen +label.host=Host +label.host.MAC=Host MAC +label.host.name=Hostnaam +label.hosts=Hosts +label.host.tags=Host Tags +label.hourly=Uurlijks +label.hypervisor.capabilities=Hypervisor mogelijkheden +label.hypervisor=Hypervisor +label.hypervisor.type=Hypervisor Type +label.hypervisor.version=Hypervisor versie +label.id=ID +label.IKE.DH=IKE DH +label.IKE.encryption=IKE Encryptie +label.IKE.hash=IKE Hash +label.IKE.lifetime=IKE lifetime (secondes) +label.IKE.policy=IKE policy +label.info=Info +label.ingress.rule=Inkomende Regel +label.initiated.by=Ge\u00efnitieerd door +label.installWizard.addClusterIntro.subtitle=Wat is een cluster? +label.installWizard.addClusterIntro.title=Nu\: Cluster toevoegen +label.installWizard.addHostIntro.subtitle=Wat is een host? +label.installWizard.addHostIntro.title=Nu\: Host toevoegen +label.installWizard.addPodIntro.subtitle=Wat is een pod? +label.installWizard.addPodIntro.title=Nu\: Pod toevoegen +label.installWizard.addPrimaryStorageIntro.subtitle=Wat is primary storage? +label.installWizard.addPrimaryStorageIntro.title=Nu\: Primaire opslag toevoegen +label.installWizard.addSecondaryStorageIntro.subtitle=Wat is secundaire opslag? +label.installWizard.addSecondaryStorageIntro.title=Nu\: Secundaire opslag toevoegen +label.installWizard.addZoneIntro.subtitle=Wat is een zone? +label.installWizard.addZoneIntro.title=Nu\: Zone toevoegen +label.installWizard.addZone.title=Zone toevoegen +label.installWizard.click.launch=Klik op de lanceer knop. +label.installWizard.subtitle=Deze rondleiding gaat je helpen met het uitvoeren van de CloudStack&\#8482 installatie +label.installWizard.title=Hallo en welkom bij CloudStack&\#8482 +label.instance=Instantie +label.instance.limits=Instantie Limieten +label.instance.name=Instantie Naam +label.instances=Instanties +label.internal.dns.1=Interne DNS 1 +label.internal.dns.2=Interne DNS 2 +label.internal.name=Interne naam +label.interval.type=Interval Type +label.introduction.to.cloudstack=CloudStack&\#8482 Introductie +label.invalid.integer=Onjuiste Waarde +label.invalid.number=Onjuist nummer +label.invitations=Uitnodigingen +label.invited.accounts=Uitgenodigde accounts +label.invite.to=Nodig uit voor +label.invite=Uitnodigen +label.ip.address=IP Adres +label.ipaddress=IP Adres +label.ip.allocations=IP Allocaties +label.ip=IP +label.ip.limits=Publieke IP Limieten +label.ip.or.fqdn=IP of FQDN +label.ip.range=IP Range +label.ip.ranges=IP Ranges +label.IPsec.preshared.key=IPsec Preshared-Key +label.ips=IPs +label.iscsi=iSCSI +label.is.default=Is Standaard +label.iso.boot=ISO Boot +label.iso=ISO +label.isolated.networks=Geisoleerde netwerken +label.isolation.method=Isolatie methode +label.isolation.mode=Isolatie Modus +label.isolation.uri=Isolatie URI +label.is.redundant.router=Redundant +label.is.shared=Is Gedeeld +label.is.system=Is Systeem +label.item.listing=Items lijst +label.keep=Bewaar +label.keyboard.type=Toetsenbord type +label.key=Sleutel +label.kvm.traffic.label=KVM verkeer label +label.label=Label +label.lang.brportugese=Braziliaans Portgees +label.lang.chinese=Chinees (Simplified) +label.lang.english=Engels +label.lang.french=Frans +label.lang.japanese=Japans +label.lang.korean=Koreans +label.lang.russian=Russisch +label.lang.spanish=Spaans +label.last.disconnected=Laatse keer niet verbonden +label.last.name=Achternaam +label.latest.events=Laatste gebeurtenissen +label.launch=Lanceer +label.launch.vm=Lanceer VM +label.launch.zone=Lanceer zone +label.LB.isolation=LB isolatie +label.least.connections=Minste connecties +label.level=Level +label.load.balancer=Load Balancer +label.load.balancing=Load Balancing +label.load.balancing.policies=Load balancing policies +label.loading=Laden +label.local=Lokaal +label.local.storage.enabled=Lokale opslag ingeschakeld +label.local.storage=Lokale Opslag +label.login=Login +label.logout=Log uit +label.lun=LUN +label.LUN.number=LUN \# +label.make.project.owner=Maak account project eigenaar +label.manage=Beheer +label.management=Beheer +label.management.ips=Beheers IP Adressen +label.manage.resources=Beheer Resources +label.max.cpus=Max. CPU cores +label.max.guest.limit=Max. Instanties +label.maximum=Maximaal +label.max.memory=Max. geheugen (MiB) +label.max.networks=Max. netwerken +label.max.primary.storage=Max. primare opslag (GiB) +label.max.public.ips=Max. publieke IPs +label.max.secondary.storage=Max. secundaire opslag (GiB) +label.max.snapshots=Max. snapshots +label.max.templates=Max. templates +label.max.vms=Max. VMs per gebruiker +label.max.volumes=Max. volumes +label.max.vpcs=Max. VPCs +label.may.continue=U kunt nu verder gaan. +label.memory.allocated=Geheugen Gealloceerd +label.memory=Geheugen +label.memory.limits=Geheugen limieten (MiB) +label.memory.mb=Geheugen (in MB) +label.memory.total=Totaal Geheugen +label.memory.used=Geheugen gebruikt +label.menu.accounts=Accounts +label.menu.alerts=Waarschuwingen +label.menu.all.accounts=Alle Accounts +label.menu.all.instances=Alle Instanties +label.menu.community.isos=Community ISOs +label.menu.community.templates=Community Templates +label.menu.configuration=Configuratie +label.menu.dashboard=Dashboard +label.menu.destroyed.instances=Vernietigde Instanties +label.menu.disk.offerings=Schijf Aanbiedingen +label.menu.domains=Domeinen +label.menu.events=Gebeurtenissen +label.menu.featured.isos=Voorgestelde ISOs +label.menu.featured.templates=Voorgestelde Templates +label.menu.global.settings=Algemene Instellingen +label.menu.infrastructure=Infrastructuur +label.menu.instances=Instanties +label.menu.ipaddresses=IP Adressen +label.menu.isos=ISOs +label.menu.my.accounts=Mijn Accounts +label.menu.my.instances=Mijn Instanties +label.menu.my.isos=Mijn ISOs +label.menu.my.templates=Mijn Templates +label.menu.network=Netwerk +label.menu.network.offerings=Netwerk Aanbiedingen +label.menu.physical.resources=Fysieke Resources +label.menu.regions=Regio\\'s +label.menu.running.instances=Draaiende Instanties +label.menu.security.groups=Security Groups +label.menu.service.offerings=Service Aanbiedingen +label.menu.snapshots=Snapshots +label.menu.stopped.instances=Uitgeschakelde Instanties +label.menu.storage=Opslag +label.menu.system.service.offerings=Systeem Aanbiedingen +label.menu.system=Systeem +label.menu.system.vms=Systeem VMs +label.menu.templates=Templates +label.menu.virtual.appliances=Virtueele Appliances +label.menu.virtual.resources=Virtuele Resources +label.menu.volumes=Volumes +label.migrate.instance.to.host=Migreer instantie naar andere host +label.migrate.instance.to=Migreer instantie naar +label.migrate.instance.to.ps=Migreer instantie naar andere primaire opslag +label.migrate.router.to=Migreer Router naar +label.migrate.systemvm.to=Migreer Systeem VM naar +label.migrate.to.host=Migreer naar host +label.migrate.to.storage=Migreer naar opslag +label.migrate.volume=Migreer volume naar andere primaire opslag +label.minimum=Minimum +label.minute.past.hour=Minuten na het uur +label.monday=Maandag +label.monthly=Maandelijks +label.more.templates=Meer Templates +label.move.down.row=Verplaats \u00e9\u00e9n regel naar beneden +label.move.to.bottom=Verplaats naar beneden +label.move.to.top=Verplaats naar boven +label.move.up.row=Verplaats \u00e9\u00e9n regel naar boven +label.my.account=Mijn Account +label.my.network=Mijn netwerk +label.my.templates=Mijn templates +label.name=Naam +label.name.optional=Naam (Optioneel) +label.nat.port.range=NAT Poort Range +label.netmask=Netmask +label.netScaler=NetScaler +label.network.ACL=Netwerk ACL +label.network.ACLs=Netwerk ACLs +label.network.ACL.total=Netwerk ACL Totaal +label.network.desc=Netwerk Beschr. +label.network.device=Netwerk Apparaat +label.network.device.type=Netwerk Apparaat Type +label.network.domain=Netwerk Domein +label.network.domain.text=Netwerk Domein +label.network.id=Netwerk ID +label.networking.and.security=Netwerken en beveiliging +label.network.label.display.for.blank.value=Gebruik standaard gateway +label.network.name=Netwerk Naam +label.network=Netwerk +label.network.offering.display.text=Netwerk Aanbieding Weergave Tekst +label.network.offering.id=Netwerk Aanbieding ID +label.network.offering.name=Netwerk Aanbieding Naam +label.network.offering=Netwerk Aanbieding +label.network.read=Netwerk gelezen +label.network.service.providers=Netwerk Service Aanbieders +label.networks=Netwerken +label.network.type=Netwerk Type +label.network.write=Netwerk geschreven +label.new=Nieuw +label.new.password=Nieuw wachtwoord +label.new.project=Nieuw Project +label.new.vm=Nieuwe VM +label.next=Volgende +label.nexusVswitch=Nexus 1000v +label.nfs=NFS +label.nfs.server=NFS Server +label.nfs.storage=NFS Opslag +label.nic.adapter.type=NIC adapter type +label.nicira.controller.address=Controller Adres +label.nicira.l3gatewayserviceuuid=L3 Gateway Service Uuid +label.nicira.transportzoneuuid=Transport Zone Uuid +label.nics=NICs +label.no.actions=Geen Beschikbare Acties +label.no.alerts=Geen Recente Waarschuwingen +label.no.data=Geen data om weer te geven +label.no.errors=Geen Recente Fouten +label.no.isos=Geen beschikbare ISOs +label.no.items=Geen Beschikbare Items +label.no=Nee +label.none=Geen +label.no.security.groups=Geen Beschikbare Security Groups +label.not.found=Niet gevonden +label.no.thanks=Nee bedankt +label.notifications=Notificaties +label.number.of.clusters=Aantal Clusters +label.number.of.hosts=Aantal Hosts +label.number.of.pods=Aantal Pods +label.number.of.system.vms=Aantal Systeem VMs +label.number.of.virtual.routers=Aantal Virtual Routers +label.number.of.zones=Aantal Zones +label.num.cpu.cores=Aantal CPU Cores +label.numretries=Keren opnieuw geprorbeerd +label.ocfs2=OCFS2 +label.offer.ha=HA aanbieden +label.ok=OK +label.optional=Optioneel +label.order=Volgorde +label.os.preference=OS Voorkeur +label.os.type=OS Type +label.owned.public.ips=Publieke IP Adressen in beheer +label.owner.account=Account Eigenaar +label.owner.domain=Domein Eigenaar +label.parent.domain=Bovenliggend Domein +label.password.enabled=Wachtwoord Ingeschakeld +label.password=Wachtwoord +label.path=Pad +label.perfect.forward.secrecy=Perfect Forward Secrecy +label.physical.network=Fysiek Netwerk +label.physical.network.ID=Fysiek netwerk ID +label.PING.CIFS.password=PING CIFS wachtwoord +label.PING.CIFS.username=PING CIFS gebruikersnaam +label.PING.dir=PING Directory +label.PING.storage.IP=PING opslag IP +label.please.specify.netscaler.info=Geef hier informatie van de Netscaler op +label.please.wait=Een ogenblik geduld a.u.b. +label.plugin.details=Plugin details +label.plugins=Plugins +label.pod.name=Pod Naam +label.pod=Pod +label.pods=Pods +label.port.forwarding.policies=Port forwarding policies +label.port.forwarding=Port Forwarding +label.port.range=Port Range +label.PreSetup=PreSetup +label.previous=Vorige +label.prev=Terug +label.primary.allocated=Primaire Opslag Gealloceerd +label.primary.network=Primair Netwerk +label.primary.storage.count=Primaire Opslag Pools +label.primary.storage.limits=Primaire Opslag limieten (GiB) +label.primary.storage=Primaire Opslag +label.primary.used=Primaire Opslag Gebruikt +label.private.Gateway=Priv\u00e9 Gateway +label.private.interface=Priv\u00e9 Interface +label.private.ip=Priv\u00e9 IP Adres +label.private.ip.range=Priv\u00e9 IP Range +label.private.ips=Priv\u00e9 IP adressen +label.privatekey=PKCS\#8 Private Key +label.private.network=Priv\u00e9 Netwerk +label.private.port=Priv\u00e9 Port +label.private.zone=Priv\u00e9 Zone +label.project.dashboard=Project Dashboard +label.project.id=Project ID +label.project.invite=Nodig uit voor project +label.project.name=Project naam +label.project=Project +label.projects=Projecten +label.project.view=Project Weergave +label.protocol=Protocol +label.providers=Providers +label.public.interface=Publieke Interface +label.public.ip=Publiek IP Adres +label.public.ips=Publieke IP Adressen +label.public.network=Publiek netwerk +label.public.port=Publieke Poort +label.public=Publiek +label.public.traffic=Publiek verkeer +label.public.zone=Publieke Zone +label.purpose=Doel +label.Pxe.server.type=PXE Server Type +label.quickview=Sneloverzicht +label.reboot=Reboot +label.recent.errors=Recente Fouten +label.redundant.router.capability=Redundante router mogelijkheden +label.redundant.router=Redundante Router +label.redundant.state=Redundante staat +label.refresh=Ververs +label.region=Regio +label.related=Samenhangend +label.remind.later=Herinner me later +label.remove.ACL=Verwijder ACL +label.remove.egress.rule=Verwijder uitgaande regel +label.remove.from.load.balancer=Verwijder Instantie van load balancer +label.remove.ingress.rule=Verwijder inkomende regel +label.remove.ip.range=Verwijder IP range +label.remove.pf=Verwijder port forwarding regel +label.remove.project.account=Verwijder account van project +label.remove.region=Verwijder Regio +label.remove.rule=Verwijder regel +label.remove.static.nat.rule=Verwijder static NAT regel +label.remove.static.route=Verwijder statische route +label.remove.tier=Verwijder tier +label.remove.vm.from.lb=Verwijder VM van load balancer regel +label.remove.vpc=verwijder VPC +label.removing.user=Verwijderen Gebruiker +label.removing=Verwijderen +label.required=Vereist +label.reserved.system.gateway=Gereseveerde systeem gateway +label.reserved.system.ip=Gereserveerd Systeem IP +label.reserved.system.netmask=Gereserveerd systeem netmask +label.reset.VPN.connection=Reset VPN verbinding +label.resize.new.offering.id=Nieuwe Aanbieding +label.resize.new.size=Nieuwe Grootte(GB) +label.resize.shrink.ok=Verklein OK +label.resource.limits=Verbruikslimieten +label.resource.state=Verbruik staat +label.resources=Verbruiken +label.resource=Verbruik +label.restart.network=Herstart netwerk +label.restart.required=Herstart benodigd +label.restart.vpc=herstart VPC +label.restore=Herstel +label.review=Beoordeel +label.revoke.project.invite=Trek uitnodiging in +label.role=Rol +label.root.disk.controller=Root schijf controller +label.root.disk.offering=Root Schijf Aanbieding +label.round.robin=Round-robin +label.rules=Regels +label.running.vms=Draaiende VMs +label.s3.access_key=Toegangssleutel +label.s3.bucket=Bucket +label.s3.connection_timeout=Connectie Timeout +label.s3.endpoint=Endpoint +label.s3.max_error_retry=Max. opnieuw proberen na Fout +label.s3.secret_key=Geheime sleutel +label.s3.socket_timeout=Socket Timeout +label.s3.use_https=Gebruik HTTPS +label.saturday=Zaterdag +label.save.and.continue=Opslaan en verder gaan +label.save=Opslaan +label.saving.processing=Opslaan.... +label.scope=Scope +label.search=Zoeken +label.secondary.storage.count=Secundaire Opslag Pools +label.secondary.storage.limits=Secundaire Opslag limieten (GiB) +label.secondary.storage=Secundaire Opslag +label.secondary.storage.vm=Secundaire Opslag VM +label.secondary.used=Secundaire Opslag Gebruikt +label.secret.key=Geheime sleutel +label.security.group.name=Security Group Naam +label.security.group=Security Group +label.security.groups.enabled=Security Groups Ingeschakeld +label.security.groups=Security Groups +label.select.a.template=Selecteer een template +label.select.a.zone=Selecteer een zone +label.select.instance=Selecteer een instance +label.select.instance.to.attach.volume.to=Selecteer een instance om het volume aan te koppelen +label.select.iso.or.template=Selecteer een ISO of template +label.select.offering=Selecteer Aanbieding +label.select.project=Selecteer Project +label.select=Selecteer +label.select.tier=Selecteer Tier +label.select-view=Selecteer Weergave +label.select.vm.for.static.nat=Selecteer VM voor static NAT +label.sent=Verstuurd +label.server=Server +label.service.capabilities=Service Mogelijkheden +label.service.offering=Service Aanbieding +label.session.expired=Sessie Verlopen +label.setup=Instellen +label.setup.network=Stel Netwerk in +label.setup.zone=Stel Zone in +label.set.up.zone.type=Stel zone type in +label.shared=Gedeeld +label.SharedMountPoint=SharedMountPoint +label.show.ingress.rule=Toon Inkomende Regel +label.shutdown.provider=Schakel provider uit +label.site.to.site.VPN=Site-to-site VPN +label.size=Grootte +label.skip.guide=Ik heb CloudStack al eerder gebruikt, sla deze stap over +label.snapshot.limits=Snapshot Limieten +label.snapshot.name=Snapshot Naam +label.snapshot.schedule=Stel herhalende Snapshot in +label.snapshot=Snapshot +label.snapshot.s=Snapshot (s) +label.snapshots=Snapshots +label.source=Bron +label.source.nat=Source NAT +label.specify.IP.ranges=Specificeer IP ranges +label.specify.vlan=Specificeer VLAN +label.SR.name = SR Name-Label +label.srx=SRX +label.start.IP=Start IP +label.start.port=Start Poort +label.start.reserved.system.IP=Start gereseveerd systeem IP +label.start.vlan=Start VLAN +label.state=Staat +label.static.nat.enabled=Static NAT Ingeschakeld +label.static.nat=Static NAT +label.static.nat.to=Static NAT naar +label.static.nat.vm.details=Static NAT VM Details +label.statistics=Statistieken +label.status=Status +label.step.1=Stap 1 +label.step.1.title=Stap 1\: Selecteer een Template +label.step.2=Stap 2 +label.step.2.title=Stap 2\: Service Aanbieding +label.step.3=Stap 3 +label.step.3.title=Stap 4\: Selecteer een Schijf Aanbieding +label.step.4=Stap 4 +label.step.4.title=Stap 4\: Netwerk +label.step.5=Stap 5 +label.step.5.title=Stap 5\: Beoordeel +label.stickiness=Stickiness +label.sticky.cookie-name=Cookie naam +label.sticky.domain=Domein +label.sticky.expire=Verloopt +label.sticky.holdtime=Wacht tijd +label.sticky.indirect=Indirect +label.sticky.length=Lengte +label.sticky.mode=Modus +label.sticky.nocache=Geen cache +label.sticky.postonly=Alleen Post +label.sticky.prefix=Prefix +label.sticky.request-learn=Request learn +label.sticky.tablesize=Tabel grootte +label.stopped.vms=Uitgeschakelde VMs +label.stop=Stop +label.storage=Opslag +label.storage.tags=Opslag Tags +label.storage.traffic=Opslag Verkeer +label.storage.type=Opslag Type +label.subdomain.access=Subdomein Toegang +label.submitted.by=[Verstuurd door\: ] +label.submit=Verstuur +label.succeeded=Geslaagd +label.sunday=Zondag +label.super.cidr.for.guest.networks=Super CIDR voor Gast Netwerken +label.supported.services=Geondersteunde Diensten +label.supported.source.NAT.type=Ondersteunde Source NAT type +label.suspend.project=Pauzeer Project +label.system.capacity=Systeem Capaciteit +label.system.offering=Systeem Aanbieding +label.system.service.offering=Systeem Service Aanbieding +label.system.vms=Systeem VMs +label.system.vm=Systeem VM +label.system.vm.type=Systeem VM type +label.system.wide.capacity=Systeembreede capaciteit +label.tagged=Tagged +label.tags=Tags +label.target.iqn=Doel IQN +label.task.completed=Taak uitgevoerd +label.template.limits=Template Limieten +label.template=Template +label.TFTP.dir=TFTP Directory +label.theme.default=Standaard Thema +label.theme.grey=Aangepast - Grijs +label.theme.lightblue=Aangepast - Licht Blauw +label.thursday=Donderdag +label.tier.details=Tier details +label.tier=Tier +label.timeout.in.second = Timeout(seconden) +label.timeout=Timeout +label.time=Tijd +label.time.zone=Tijdzone +label.timezone=Tijdzone +label.token=Token +label.total.cpu=Totaal CPU +label.total.CPU=Totaal CPU +label.total.hosts=Totaal Hosts +label.total.memory=Totaal Geheugen +label.total.of.ip=Totaal aantal IP Adressen +label.total.of.vm=Totaal aantal VM +label.total.storage=Totaal Opslag +label.total.vms=Totaal VMs +label.traffic.label=Verkeerslabel +label.traffic.types=Verkeer Types +label.traffic.type=Verkeer Type +label.tuesday=Dinsdag +label.type.id=Type ID +label.type=Type +label.unavailable=Niet beschikbaar +label.unlimited=Ongelimiteerd +label.untagged=Untagged +label.update.project.resources=Update project verbruik +label.update.ssl.cert= SSL Certificaat +label.update.ssl= SSL Certificaat +label.updating=Bezig met updaten +label.upload=Upload +label.upload.volume=Upload Volume +label.url=URL +label.usage.interface=Verbruik Interface +label.used=Gebruikt +label.user=Gebruiker +label.username=Gebruikersnaam +label.users=Gebruikers +label.use.vm.ip=Gebruik VM IP\: +label.value=Waarde +label.vcdcname=vCenter DC naam +label.vcenter.cluster=vCenter Cluster +label.vcenter.datacenter=vCenter Datacenter +label.vcenter.datastore=VCenter Datastore +label.vcenter.host=vCenter Host +label.vcenter.password=vCenter Wachtwoord +label.vcenter.username=vCenter Gebruikersnaam +label.vcipaddress=vCenter IP Adres +label.version=Versie +label.view.all=Toon alle +label.view.console=Toon console +label.viewing=Weergeven +label.view.more=Toon meer +label.view=Toon +label.virtual.appliances=Virtueele Appliances +label.virtual.appliance=Virtuele Appliance +label.virtual.machines=Virtuele machines +label.virtual.network=Virtueel Netwerk +label.virtual.routers=Virtuele Routers +label.virtual.router=Virtuele Router +label.vm.add=Instantie Toevoegen +label.vm.destroy=Verwijder +label.vm.display.name=VM weergave naam +label.VMFS.datastore=VMFS datastore +label.vmfs=VMFS +label.vm.name=VM naam +label.vm.reboot=Reboot +label.VMs.in.tier=VMs in tier +label.vmsnapshot.current=isHuidige +label.vmsnapshot.memory=Snapshot geheugen +label.vmsnapshot.parentname=Bovenliggend +label.vmsnapshot.type=Type +label.vmsnapshot=VM Snapshots +label.vm.start=Start +label.vm.state=VM staat +label.vm.stop=Stop +label.vms=VMs +label.vmware.traffic.label=VMware verkeerslabel +label.volgroup=Volume Groep +label.volume.limits=Volume Limieten +label.volume.name=Volume Naam +label.volumes=Volumes +label.volume=Volume +label.vpc.id=VPC ID +label.VPC.router.details=VPC router details +label.vpc=VPC +label.VPN.connection=VPN Connectie +label.vpn.customer.gateway=VPN Customer Gateway +label.VPN.customer.gateway=VPN Customer Gateway +label.VPN.gateway=VPN Gateway +label.vpn=VPN +label.vsmctrlvlanid=Controle VLAN ID +label.vsmpktvlanid=Pakket VLAN ID +label.vsmstoragevlanid=Opslag VLAN ID +label.vsphere.managed=vSphere beheerd +label.waiting=Wachten +label.warn=Waarschuwing +label.wednesday=Woensdag +label.weekly=Wekelijks +label.welcome.cloud.console=Welkom op de Management Console +label.welcome=Welkom +label.what.is.cloudstack=Wat is CloudStack&\#8482? +label.xen.traffic.label=XenServer verkeerslabel +label.yes=Ja +label.zone.details=Zone details +label.zone.id=Zone ID +label.zone.name=Zone naam +label.zone.step.1.title=Stap 1\: Selecteer een Netwerk +label.zone.step.2.title=Stap 2\: Zone toevoegen +label.zone.step.3.title=Stap 3\: Pod toevoegen +label.zone.step.4.title=Step 4\: IP range toevoegen +label.zones=Zones +label.zone.type=Type Zone +label.zone.wide=Zone breed +label.zoneWizard.trafficType.guest=Gast\: Verkeer tussen virtuele machines van de eindgebruiker +label.zoneWizard.trafficType.public=Publiek\: Verkeer tussen het internet en virtueele machines in de cloud. +label.zoneWizard.trafficType.storage=Opslag\: Verkeer tussen de primaire en secundaire opslag servers zoals VM templates en snapshots +label.zone=Zone +managed.state=Beheersstaat +message.acquire.new.ip=Bevestigen dat je een nieuw IP voor dit netwerk wilt verkrijgen. +message.acquire.new.ip.vpc=Bevestig dat u een nieuw IP wilt verkrijgen voor deze VPC. +message.acquire.public.ip=Selecteer de zone waarvan u een nieuw IP wenst te verkrijgen. +message.action.cancel.maintenance=Het onderhoud voor de host is succesvol geannuleerd. Het daadwerkelijke proces kan echter enkele minuten duren. +message.action.cancel.maintenance.mode=Bevestig dat u het onderhoud wilt annuleren. +message.action.change.service.warning.for.instance=Uw instantie moet uitgeschakeld zijn voordat u de service aanbieding kunt wijzigen. +message.action.change.service.warning.for.router=Uw router moet uitgeschakeld zijn voordat u de service aanbieding kunt wijzigen. +message.action.delete.cluster=Bevestig dat u dit cluster wilt verwijderen. +message.action.delete.disk.offering=Bevestig dat u deze schijf aanbieding wilt verwijderen. +message.action.delete.domain=Bevestig dat u dit domein wilt verwijderen. +message.action.delete.external.firewall=Bevestig dat u deze externe firewall wilt verwijderen. Waarschuwing\: Als u van plan bent dezelfde firewall opnieuw toe te voegen, dient u de verbruiksstatistieken eerst te resetten. +message.action.delete.external.load.balancer=Bevestig dat u deze externe loadbalancer wilt verwijderen. Waarschuwing\: Als u van plan bent dezelfde loadbalancer opnieuw toe te voegen, dient u de verbruiksstatistieken eerst te resetten. +message.action.delete.ingress.rule=Bevestig dat u deze inkomende regel wilt verwijderen. +message.action.delete.ISO=Bevestig dat u deze ISO wilt verwijderen. +message.action.delete.ISO.for.all.zones=Deze ISO wordt gebruikt door alle zones. Bevestig dat u deze wilt verwijderen van alle zones. +message.action.delete.network=Bevestig dat u dit netwerk wilt verwijderen. +message.action.delete.nexusVswitch=Bevestig dat u deze nexus 1000v wilt verwijderen +message.action.delete.physical.network=Bevestig dat u dit fysieke netwerk wilt verwijderen. +message.action.delete.pod=Bevestig dat u deze pod wilt verwijderen. +message.action.delete.primary.storage=Bevestig dat u deze primaire opslag wilt verwijderen. +message.action.delete.secondary.storage=Bevestig dat u deze secudaire opslag wilt verwijderen. +message.action.delete.security.group=Bevestig dat u deze security group wilt verwijderen. +message.action.delete.service.offering=Bevestig dat u deze service aanbieding wilt verwijderen. +message.action.delete.snapshot=Bevestig dat u deze snapshot wilt verwijderen. +message.action.delete.system.service.offering=Bevestig dat u deze systeem service aanbieding wilt verwijderen. +message.action.delete.template=Bevestig dat u deze template wilt verwijderen +message.action.delete.template.for.all.zones=Deze template wordt gebruikt door alle zones. Bevestig dat u deze wilt verwijderen van alle zones. +message.action.delete.volume=Bevestig dat u dit volume wilt verwijderen +message.action.delete.zone=Bevestig dat u deze zone wilt verwijderen +message.action.destroy.instance=Bevestig dat u deze instantie wilt vernietigen +message.action.destroy.systemvm=Bevestig dat u deze Systeem VM wilt vernietigen +message.action.disable.cluster=Bevestig dat u dit cluster wilt uitschakelen. +message.action.disable.nexusVswitch=Bevestig dat u deze nexus 1000v wilt uitschakelen. +message.action.disable.physical.network=Bevestig dat u dit fysieke netwerk wilt uitschakelen. +message.action.disable.pod=Bevestig dat u deze pod wilt uitschakelen. +message.action.disable.static.NAT=Bevestig dat u static NAT wilt uitschakelen. +message.action.disable.zone=Bevestig dat u deze zone wilt uitschakelen. +message.action.download.iso=Bevestig dat u deze ISO wilt downloaden. +message.action.download.template=Bevestig dat u deze template wilt downloaden. +message.action.enable.cluster=Bevestig dat u dit cluster wilt inschakelen. +message.action.enable.maintenance=Uw host is succesvol voorbereid op onderhoud. Het proces kan echter een paar minuten duren afhankelijk van de hoeveelheid VMs op de host. +message.action.enable.nexusVswitch=Bevestig dat u deze nexus 1000v wilt inschakelen +message.action.enable.physical.network=Bevestig dat u dit fysieke netwerk wilt inschakelen. +message.action.enable.pod=Bevestigd dat u deze pod wilt inschakelen. +message.action.enable.zone=Bevestig dat u deze zone wilt inschakelen. +message.action.force.reconnect=De host is succesvol geforceerd om opnieuw te verbinden. Dit proces kan echter enkele minuten duren. +message.action.host.enable.maintenance.mode=Het inschakelen van de onderhoudsmodus zorgt ervoor dat alle draaiende instanties worden gemigreerd naar andere beschikbare hosts. +message.step.2.desc= +message.step.3.desc= +mode=Modus +notification.reboot.instance=Herstart instantie +state.Allocated=Gebruikt +state.Disabled=Uitgeschakeld +state.Error=Fout diff --git a/client/WEB-INF/classes/resources/messages_pl.properties b/client/WEB-INF/classes/resources/messages_pl.properties new file mode 100644 index 000000000000..9024030f51ed --- /dev/null +++ b/client/WEB-INF/classes/resources/messages_pl.properties @@ -0,0 +1,469 @@ +# 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. + +error.invalid.username.password=B\u0142\u0119dna nazwa u\u017cytkownika lub has\u0142o +label.account.id=ID konta +label.account=Konto +label.account.name=Nazwa konta +label.accounts=Konta +label.action.attach.disk=Dodaj dysk +label.action.attach.disk.processing=Dodawanie dysku +label.action.attach.iso=Dodaj obraz ISO +label.action.attach.iso.processing=Dodawanie obrazu ISO +label.action.change.password=Zmie\u0144 has\u0142o +label.action.copy.ISO=Kopiuj ISO +label.action.copy.ISO.processing=Kopiuj ISO.... +label.action.copy.template=Kopij szablon +label.action.copy.template.processing=Kopije szablon.... +label.action.create.template.from.vm=Utw\u00f3rz szablon z VM +label.action.create.template.from.volume=Utw\u00f3rz Szablon z wolumenu +label.action.create.template.processing=Tworz\u0119 szablon +label.action.create.template=Utw\u00f3rz szablon +label.action.create.vm.processing=Tworz\u0119 VM.... +label.action.create.vm=Utw\u00f3rz VM +label.action.create.volume.processing=Tworz\u0119 wolumen.... +label.action.create.volume=Utw\u00f3rz wolumen +label.action.delete.account.processing=Usuwanie dost\u0119pu.... +label.action.delete.account=Usu\u0144 dost\u0119p +label.action.delete.cluster.processing=Usuwam klaster.... +label.action.delete.cluster=Usu\u0144 klaster +label.action.delete.domain.processing=Usuwam domen\u0119.... +label.action.delete.domain=Usu\u0144 domen\u0119 +label.action.delete.firewall.processing=Usuwam Firewall +label.action.delete.firewall=Usu\u0144 regu\u0142\u0119 Firewall +label.action.delete.ISO.processing=Usuwam ISO.... +label.action.delete.ISO=Usu\u0144 ISO +label.action.delete.network.processing=Usuwam sie\u0107.... +label.action.delete.network=Usu\u0144 sie\u0107 +label.action.delete.nexusVswitch=Usu\u0144 Nexus 1000v +label.action.delete.physical.network=Usu\u0144 fizyczn\u0105 sie\u0107 +label.action.delete.user.processing=Usuwam u\u017cytkownika.... +label.action.delete.user=Usu\u0144 u\u017cytkownika +label.action.delete.volume.processing=Usuwam wolumen.... +label.action.delete.volume=Usu\u0144 wolumen +label.action.delete.zone.processing=Usuwam stref\u0119.... +label.action.delete.zone=Usu\u0144 stref\u0119 +label.action.destroy.instance.processing=Usuwam instancj\u0119 +label.action.destroy.instance=Usu\u0144 instancj\u0119 +label.action.detach.disk=Od\u0142\u0105cz dysk +label.action.detach.disk.processing=Od\u0142\u0105czanie dysku.... +label.action.detach.iso=Od\u0142\u0105cz obraz ISO +label.action.detach.iso.processing=Od\u0142\u0105czanie obrazu ISO +label.action.disable.account.processing=Wy\u0142\u0105czam dost\u0119p.... +label.action.disable.account=Wy\u0142\u0105cz dost\u0119p +label.action.disable.cluster.processing=Wy\u0142\u0105czam klaster.... +label.action.disable.cluster=Wy\u0142\u0105cz klaster +label.action.disable.nexusVswitch=Wy\u0142\u0105cz Nexus 1000v +label.action.disable.physical.network=Wy\u0142\u0105cz fizyczn\u0105 sie\u0107 +label.action.disable.user.processing=Wy\u0142\u0105czam u\u017cytkownika +label.action.disable.user=Wy\u0142\u0105cz u\u017cytkownika +label.action.disable.zone.processing=Wy\u0142\u0105czam stref\u0119.... +label.action.disable.zone=Wy\u0142\u0105cz stref\u0119 +label.action.download.ISO=Pobierz ISO +label.action.download.template=Pobierz szablon +label.action.download.volume=Pobierz wolumen +label.action.download.volume.processing=Pobieram wolumen.... +label.action.edit.account=Edytuj dost\u0119p +label.action.edit.domain=Edytuj domen\u0119 +label.action.edit.global.setting=Edytuj Globalne ustawienia +label.action.edit.host=Edytuj host +label.action.edit.instance=Edytuj instancj\u0119 +label.action.edit.ISO=Edytuj ISO +label.action.edit.network=Edytuj sie\u0107 +label.action.edit.network.processing=Zmieniam sie\u0107.... +label.action.edit.template=Edytuj szablon +label.action.edit.user=Edytuj u\u017cytkownika +label.action.edit.zone=Edytuj stref\u0119 +label.action.enable.account.processing=W\u0142\u0105czam dost\u0119p.... +label.action.enable.account=W\u0142\u0105cz dost\u0119p +label.action.enable.cluster.processing=W\u0142\u0105czam klaster.... +label.action.enable.cluster=W\u0142\u0105cz klaster +label.action.enable.nexusVswitch=W\u0142\u0105cz Nexus 1000v +label.action.enable.physical.network=W\u0142\u0105cz fizyczn\u0105 sie\u0107 +label.action.enable.user.processing=W\u0142\u0105czam u\u017cytkownika.... +label.action.enable.user=W\u0142\u0105cz u\u017cytkownika +label.action.enable.zone.processing=W\u0142\u0105czam stref\u0119.... +label.action.enable.zone=W\u0142\u0105cz stref\u0119 +label.action.generate.keys=Generuj klucze +label.action.generate.keys.processing=Generuj\u0119 klucze.... +label.action.list.nexusVswitch=Kista Nexus 1000v +label.action.lock.account.processing=Blokuj\u0119 dost\u0119p.... +label.action.lock.account=Zablokuj dost\u0119p +label.action.manage.cluster.processing=Zarz\u0105dzam klastrem.... +label.action.manage.cluster=Zarz\u0105dzaj klastrem +label.action.migrate.instance=Migruj instancj\u0119 +label.action.migrate.instance.processing=Migruj\u0119 instancj\u0119.... +label.action.migrate.router=Migruj router +label.action.migrate.router.processing=Migruje router.... +label.action.migrate.systemvm=Migruj system VM +label.action.migrate.systemvm.processing=Migruj\u0119 system VM.... +label.action.reboot.instance.processing=Restartuje instancj\u0119 +label.action.reboot.instance=Restartuj instancj\u0119 +label.action.reboot.router.processing=Restartuje router..... +label.action.reboot.router=Restartuj router +label.action.reboot.systemvm.processing=Restartuje system VM.... +label.action.reboot.systemvm=Restartuj system VM +label.action.register.iso=Rejestruj ISO +label.action.register.template=Rejestruj szablon +label.action.remove.host.processing=Usuwam host.... +label.action.remove.host=Usu\u0144 host +label.action.reset.password.processing=Resetuj\u0119 has\u0142o.... +label.action.reset.password=Resetuj has\u0142o +label.action.resize.volume.processing=Zmieniam wielko\u015b\u0107 wolumenu.... +label.action.resize.volume=Zmie\u0144 wielko\u015b\u0107 wolumenu +label.action.restore.instance=Przywr\u00f3\u0107 instancj\u0119 +label.actions=Akcje +label.action.start.instance.processing=Uruchamiam instancj\u0119.... +label.action.start.instance=Uruchom instancj\u0119 +label.action.start.router.processing=Uruchamiam router.... +label.action.start.router=Uruchom router +label.action.start.systemvm.processing=Uruchamiam system VM... +label.action.start.systemvm=Uruchom system VM +label.action.stop.instance.processing=Zatrzymuj\u0119 instancj\u0119.... +label.action.stop.instance=Zatrzymaj instancj\u0119 +label.action.stop.router.processing=Zatrzymuj\u0119 router... +label.action.stop.router=Zatrzymaj router +label.action.stop.systemvm.processing=Zatrzymuj\u0119 system VM.... +label.action.stop.systemvm=Zatrzymaj system VM +label.action.take.snapshot.processing=Tworz\u0119 snapshot.... +label.action.take.snapshot=Zr\u00f3b snapshot +label.activate.project=Aktywuj projekt +label.add.account=Dodaj konto +label.add.accounts=Dodaj konta +label.add.accounts.to=Dodaj konto do +label.add.account.to.project=Dodaj konto do projektu +label.add.ACL=Dodaj ACL +label.add.by.cidr=Dodaj przez CIDR +label.add.by=Dodaj przez +label.add.by.group=Dodaj przez grup\u0119 +label.add.cluster=Dodaj klaster +label.add=Dodaj +label.add.domain=Dodaj domen\u0119 +label.add.firewall=Dodaj regu\u0142\u0119 firewall +label.add.host=Dodaj host +label.adding=Dodawanie +label.adding.failed=Dodanie nieudane +label.adding.processing=Dodawanie +label.adding.succeeded=Dodanie udane +label.add.more=Dodaj wi\u0119cej +label.add.network.device=Dodaj urz\u0105dzenie sieciowe +label.add.network=Dodaj sie\u0107 +label.add.new.F5=Dodaj nowy F5 +label.add.new.SRX=Dodaj nowy SRX +label.add.region=Dodaj region +label.add.rule=Dodaj regu\u0142\u0119 +label.add.to.group=Dodaj do grupy +label.add.user=Dodaj u\u017cytkownika +label.add.vlan=Dodaj VLAN +label.add.vm=Dodaj VM +label.add.vms=Dodaj VM-ny +label.add.volume=Dodaj wolumen +label.add.vpc=Dodaj VPC +label.add.zone=Dodaj stref\u0119 +label.admin=Admin +label.api.key=Klucz API +label.apply=Zastosuj +label.author.name=Imi\u0119 autora +label.available=Dost\u0119pne +label.available.public.ips=Dost\u0119pne publiczne adresy IP +label.back=Wstecz +label.bandwidth=Przepustowo\u015b\u0107 +label.cancel=Zako\u0144cz +label.certificate=Certyfikat +label.cidr=CIDR +label.CIDR.list=Lista CIDR +label.clean.up=Wyczy\u015b\u0107 +label.clear.list=Wyczy\u015b\u0107 list\u0119 +label.close=Zamknij +label.clvm=CLVM +label.code=Kod +label.community=Spo\u0142eczno\u015b\u0107 +label.configuration=Konfiguracja +label.configure=Konfiguruj +label.configure.vpc=Konfiguruj VPC +label.confirmation=Potwierdzenie +label.confirm.password=Potwierd\u017a has\u0142o +label.congratulations=Gratulacje\! +label.continue=Kontynuuj +label.corrections.saved=Poprawka zapisana +label.cpu=CPU +label.cpu.limits=Limit CPU +label.cpu.mhz=CPU (w MHz) +label.created.by.system=Utworzono przez system +label.created=Utworzono +label.create.project=Stw\u00f3rz projekt +label.daily=Dziennie +label.date=Data +label.day.of.month=Dzie\u0144 miesi\u0105ca +label.day.of.week=Dzie\u0144 tygodnia +label.dedicated=Dedykowany +label.default=Domy\u015blnie +label.default.view=Widok domy\u015blny +label.delete.F5=Usu\u0144 F5 +label.delete.project=Usu\u0144 projekt +label.delete.SRX=Usu\u0144 SRX +label.delete=Usu\u0144 +label.deleting.failed=Usuwanie nieudane +label.deleting.processing=Usuwanie.... +label.destroy.router=Zniszcz router +label.destroy=Zniszcz +label.detaching.disk=Od\u0142\u0105czanie dysku +label.details=Szczeg\u00f3\u0142y +label.disabled=Wy\u0142\u0105czony +label.disable.vpn=Wy\u0142\u0105cz VPN +label.disk.size.gb=Wielko\u015b\u0107 dysku (w GB) +label.disk.size=Wielko\u015b\u0107 dysku +label.display.name=Wy\u015bwietlana nazwa +label.domain.admin=Administrator domeny +label.domain=Domena +label.domain.id=ID domeny +label.domain.name=Nazwa domeny +label.done=Sko\u0144czono +label.download.progress=Post\u0119p w pobieraniu +label.drag.new.position=Przenie\u015b w nowe miejsce +label.edit=Edytuj +label.edit.network.details=Edytuj szczeg\u00f3\u0142y sieci +label.edit.project.details=Zmie\u0144 szczeg\u00f3\u0142y projektu +label.edit.vpc=Edytuj VPC +label.elastic=Elastyczny +label.elastic.IP=Zmienne IP +label.email=Poczta +label.enable.vpn=W\u0142\u0105cz VPN +label.error=B\u0142\u0105d +label.f5=F5 +label.featured=Polecane +label.filterBy=Filtrowanie wg +label.firewall=Zapora +label.first.name=Pierwsza nazwa +label.format=Format +label.friday=Pi\u0105tek +label.full.path=Pe\u0142na \u015bcie\u017cka +label.go.step.2=Id\u017a do punktu 2 +label.go.step.3=Id\u017a do punktu 3 +label.go.step.4=Id\u017a do punktu 4 +label.go.step.5=Id\u017a do punktu 5 +label.group=Grupa +label.group.optional=Grupa (opcjonalnie) +label.guest=Go\u015b\u0107 +label.guest.type=Rodzaj go\u015bci +label.help=Pomoc +label.hints=Podpowiedzi +label.id=ID +label.info=Informacje +label.instances=Instancje +label.invitations=Zaproszenia +label.invited.accounts=Zaproszone konta +label.invite.to=Zapro\u015b do +label.invite=Zapro\u015b +label.ip=IP +label.iso=ISO +label.keep=Zostaw +label.key=Klucz +label.lang.english=Angielski +label.lang.french=Francuski +label.lang.japanese=Japo\u0144ski +label.lang.korean=Korea\u0144ski +label.lang.russian=Rosyjski +label.lang.spanish=Hiszpia\u0144ski +label.last.name=Nazwisko +label.least.connections=Ostatnie po\u0142\u0105czenie +label.level=Poziom +label.loading=Wczytywanie +label.local=Lokalne +label.local.storage.enabled=Pami\u0119\u0107 lokalna w\u0142\u0105czona +label.local.storage=Pami\u0119\u0107 lokalna +label.login=Zaloguj +label.logout=Wyloguj +label.lun=LUN +label.LUN.number=LUN \# +label.max.guest.limit=Maksymalna liczba go\u015bci +label.maximum=Maksimum +label.max.public.ips=Maksymalna liczba publicznych adres\u00f3w IP +label.memory.limits=Limit pami\u0119ci (MiB) +label.memory.mb=Pami\u0119\u0107 (w MB) +label.memory=Pami\u0119\u0107 +label.menu.accounts=Konta +label.menu.alerts=Alarmy +label.menu.all.accounts=Wszystkie konta +label.menu.all.instances=Wszystkie instancje +label.menu.configuration=Konfiguracja +label.menu.domains=Domeny +label.menu.infrastructure=Infrastruktura +label.menu.instances=Instancje +label.menu.ipaddresses=Adresy IP +label.menu.isos=ISO +label.menu.my.accounts=Moje konta +label.menu.my.instances=Moje instancje +label.menu.my.isos=Moje ISO +label.menu.network=Sie\u0107 +label.menu.regions=Regiony +label.menu.system=System +label.minimum=Minimum +label.monday=Poniedzia\u0142ek +label.monthly=Miesi\u0119cznie +label.move.down.row=Jeden rz\u0105d na d\u00f3\u0142 +label.move.to.top=Przenie\u015b na sam\u0105 g\u00f3r\u0119 +label.move.up.row=Jeden rz\u0105d do g\u00f3ry +label.my.account=Moje konto +label.my.network=Moja sie\u0107 +label.name=Nazwa +label.name.optional=Nazwa (opcjonalnie) +label.network.id=ID sieci +label.network.name=Nazwa sieci +label.network=Sie\u0107 +label.networks=Sieci +label.new=Nowy +label.new.project=Nowy projekt +label.next=Nast\u0119pny +label.nfs=NFS +label.nfs.server=Serwer NFS +label.no.data=Brak danych +label.none=Brak +label.no=Nie +label.no.thanks=Nie dzi\u0119kuj\u0119 +label.notifications=Przypomnienia +label.number.of.hosts=Liczba host\u00f3w +label.ok=OK +label.order=Zadanie +label.password=Has\u0142o +label.path=\u015acie\u017cka +label.please.wait=Prosz\u0119 czeka\u0107 +label.plugin.details=Szczeg\u00f3\u0142y wtyczki +label.plugins=Wtyczki +label.previous=Wstecz +label.private.network=Sie\u0107 prywatna +label.project.id=Nazwa ID projektu +label.project.invite=Zapro\u015b do projektu +label.project.name=Nazwa projektu +label.project=Projekt +label.projects=Projekty +label.protocol=Protok\u00f3\u0142 +label.providers=Dostawcy +label.public.ip=Publiczny adres IP +label.public.ips=Publiczne adresy IP +label.public.network=Sie\u0107 publiczna +label.public=Pobliczny +label.public.port=Publiczny port +label.reboot=Uruchom ponownie +label.refresh=Od\u015bwie\u017c +label.region=Region +label.remind.later=Przypomnij p\u00f3\u017aniej +label.remove.rule=Usu\u0144 regu\u0142\u0119 +label.remove.vpc=Usu\u0144 VPC +label.removing.user=Usu\u0144 u\u017cytkownika +label.removing=Usuwanie +label.required=Wymagane +label.resource.limits=Limit zasob\u00f3w +label.resources=Zasoby +label.resource=Zas\u00f3b +label.restart.required=Wymagany restart +label.rules=Zasady +label.saturday=Sobota +label.save.and.continue=Zapisz i kontynuuj +label.save=Zapisz +label.saving.processing=Zapisywanie.... +label.search=Szukaj +label.select.instance=Wybierz instancj\u0119 +label.select.project=Wybierz projekt +label.select=Wybierz +label.sent=Wys\u0142ano +label.server=Serwer +label.size=Wielko\u015bc +label.specify.IP.ranges=Wyszczeg\u00f3lnij zasi\u0119g adres\u00f3w IP +label.srx=SRX +label.statistics=Statystyki +label.status=Status +label.step.1=Krok 1 +label.step.2=Krok 2 +label.step.3=Krok 3 +label.step.4=Krok 4 +label.step.5=Krok 5 +label.sticky.domain=Domena +label.sticky.expire=Wygasa +label.sticky.length=D\u0142ugo\u015b\u0107 +label.sticky.mode=Tryb +label.sticky.prefix=Prefiks +label.stop=Stop +label.sunday=Niedziela +label.suspend.project=Zawie\u015b projekt +label.tagged=Otagowany +label.tags=Tagi +label.task.completed=Zadania uko\u0144czone +label.time=Czas +label.time.zone=Strefa czasowa +label.timezone=Strefa czasowa +label.type.id=Wpisz ID +label.type=Wpisz +label.unavailable=Niedost\u0119pny +label.unlimited=Nieograniczony +label.untagged=Nieotagowany +label.updating=Aktualizowanie +label.url=URL +label.used=U\u017cyte +label.username=Nazwa u\u017cytkownika +label.users=U\u017cytkownicy +label.user=U\u017cytkowni +label.version=Wersja +label.view.all=Zobacz wszystko +label.view=Zobacz +label.vm.add=Dodaj instancj\u0119 +label.vm.destroy=Zniszcz +label.vmfs=VMFS +label.vm.name=Nazwa VM +label.vm.reboot=Uruchom ponownie +label.vmsnapshot.type=Wpisz +label.vm.start=Rozpocznij +label.vm.stop=Stop +label.vms=VMs +label.vpc=VPC +label.vpn=VPN +label.waiting=Czekanie +label.warn=Ostrze\u017cenie +label.wednesday=\u015aroda +label.weekly=Tygodniowo +label.welcome=Witaj +label.what.is.cloudstack=Czym jest CloudStack&\#8482? +label.yes=Tak +message.action.delete.nexusVswitch=Potwierd\u017a, \u017ce chcesz usun\u0105\u0107\: nexus 1000v +message.action.download.iso=Potwierd\u017a, \u017ce chcesz pobra\u0107 ten obraz ISO. +message.activate.project=Czy na pewno chcesz aktywowa\u0107 ten projekt? +message.confirm.delete.F5=Czy na pewno chcesz usun\u0105\u0107 F5? +message.confirm.delete.SRX=Czy na pewno chcesz usun\u0105\u0107 SRX? +message.delete.project=Czy na pewno chcesz usun\u0105\u0107 ten projekt? +message.disable.vpn=Czy na pewno chcesz wy\u0142\u0105czy\u0107 VPN? +message.no.projects=Nie posiadasz \u017cadnych projekt\u00f3w.
Utw\u00f3rz nowy projekt w zak\u0142adce projekty +message.please.proceed=Przejd\u017a do nast\u0119pnego punktu +message.step.2.desc= +message.step.3.desc= +message.suspend.project=Czy na pewno chcesz zawiesi\u0107 ten projekt +mode=Tryb +state.Accepted=Akceptowano +state.Active=Aktywny +state.Completed=Uko\u0144czono +state.Creating=Tworzenie +state.Declined=Odrzucono +state.Destroyed=Zniszczono +state.Disabled=Wy\u0142\u0105czony +state.enabled=W\u0142\u0105czone +state.Enabled=W\u0142\u0105czone +state.Error=B\u0142\u0105d +state.ready=Gotowe +state.Ready=Gotowe +state.Starting=Rozpoczynanie +state.Stopped=Zatrzymano +state.Suspended=Zawieszono +ui.listView.filters.all=Wszystko diff --git a/client/WEB-INF/classes/resources/messages_pt_BR.properties b/client/WEB-INF/classes/resources/messages_pt_BR.properties index 86bb83177a83..c565924c7909 100644 --- a/client/WEB-INF/classes/resources/messages_pt_BR.properties +++ b/client/WEB-INF/classes/resources/messages_pt_BR.properties @@ -15,21 +15,23 @@ # specific language governing permissions and limitations # under the License. -changed.item.properties=Alteradas propriedades do item -confirm.enable.s3=Por favor preencha as informa\u00e7\u00f5es abaixo para habilitar suporte a storage secund\u00e1ria fornecida por S3 -confirm.enable.swift=Por favor preencha as informa\u00e7\u00f5es abaixo para habilitar suporte ao Swift +changed.item.properties=Propriedades do item alteradas +confirm.enable.s3=Por favor, preencha as informa\u00e7\u00f5es abaixo para habilitar suporte o Storage Secund\u00e1rio fornecido por S3 +confirm.enable.swift=Por favor, preencha as informa\u00e7\u00f5es abaixo para habilitar suporte ao Swift +error.could.not.change.your.password.because.ldap.is.enabled=Erro\: a nuvem n\u00e3o alterou sua senha porque o LDAP est\u00e1 ativo. error.could.not.enable.zone=N\u00e3o foi poss\u00edvel habilitar a zona error.installWizard.message=Alguma coisa est\u00e1 errada; voc\u00ea pode voltar e corrigir quaisquer erros error.invalid.username.password=Usu\u00e1rio ou senha inv\u00e1lidos -error.login=Usu\u00e1rio ou senha inv\u00e1lido. +error.login=O seu usu\u00e1rio/senha n\u00e3o coincidem com nossos registros. error.menu.select=N\u00e3o foi poss\u00edvel realizar a a\u00e7\u00e3o pois nenhum item foi selecionado. -error.mgmt.server.inaccessible=O servidor de gerenciamento est\u00e1 inacess\u00edvel. Tente novamente mais tarde. +error.mgmt.server.inaccessible=O Servidor de Gerenciamento est\u00e1 inacess\u00edvel. Tente novamente mais tarde. error.password.not.match=Os campos de senha n\u00e3o combinam -error.please.specify.physical.network.tags=Ofertas de Rede n\u00e3o estar\u00e3o dispon\u00edveis enquanto voc\u00ea n\u00e3o especificar tags para esta interface f\u00edsica. +error.please.specify.physical.network.tags=As Ofertas de Rede n\u00e3o estar\u00e3o dispon\u00edveis enquanto voc\u00ea n\u00e3o especificar tags para esta interface f\u00edsica. error.session.expired=Sua sess\u00e3o expirou. -error.something.went.wrong.please.correct.the.following=Algo deu errado; por favor corrija abaixo +error.something.went.wrong.please.correct.the.following=Alguma coisa est\u00e1 errada; por favor corrija abaixo error.unable.to.reach.management.server=N\u00e3o foi poss\u00edvel acessar o Servidor de Gerenciamento error.unresolved.internet.name=Imposs\u00edvel resolver DNS +extractable=Extra\u00edvel force.delete.domain.warning=Aten\u00e7\u00e3o\: Esta op\u00e7\u00e3o remover\u00e1 todos os dom\u00ednios, contas e recursos associados. force.delete=For\u00e7ar Exclus\u00e3o force.remove=For\u00e7ar Remo\u00e7\u00e3o @@ -39,7 +41,10 @@ force.stop.instance.warning=Aviso\: For\u00e7ar o desligamento desta inst\u00e2n ICMP.code=C\u00f3digo ICMP ICMP.type=Tipo ICMP image.directory=Diret\u00f3rio da Imagem +inline=Inline instances.actions.reboot.label=Reiniciar inst\u00e2ncia +label.about.app=Sobre o CloudStack +label.about=Sobre label.accept.project.invitation=Aceitar convite de projeto. label.account.and.security.group=Contas, grupos de Seguran\u00e7a label.account=Conta @@ -48,6 +53,7 @@ label.account.name=Nome da Conta label.accounts=Contas label.account.specific=Conta-Specific label.acquire.new.ip=Adquirir novo IP +label.acquire.new.secondary.ip=Adquira um novo IP secund\u00e1rio label.action.attach.disk=Anexar Disco label.action.attach.disk.processing=Anexando Disco.... label.action.attach.iso=Anexar ISO @@ -90,6 +96,7 @@ label.action.delete.load.balancer=Remover regra de balanceador de carga label.action.delete.network.processing=Removendo Rede.... label.action.delete.network=Remover Rede label.action.delete.nexusVswitch=Remover NexusVswitch +label.action.delete.nic=Remover Interface de Rede label.action.delete.physical.network=Deletar rede f\u00edsica label.action.delete.pod.processing=Removendo POD.... label.action.delete.pod=Remover POD @@ -112,8 +119,8 @@ label.action.delete.volume.processing=Removendo Disco.... label.action.delete.volume=Remover Disco label.action.delete.zone.processing=Removendo Zona.... label.action.delete.zone=Remover Zona -label.action.destroy.instance=Apagar Cloud Server -label.action.destroy.instance.processing=Apagando Cloud Server.... +label.action.destroy.instance=Apagar Inst\u00e2ncia +label.action.destroy.instance.processing=Apagando Inst\u00e2ncia.... label.action.destroy.systemvm=Apagar VM de Sistema label.action.destroy.systemvm.processing=Apagando VM de Sistema.... label.action.detach.disk=Desplugar Disco @@ -143,7 +150,7 @@ label.action.edit.disk.offering=Editar Oferta de Disco label.action.edit.domain=Editar Dom\u00ednio label.action.edit.global.setting=Editar Configura\u00e7\u00f5es Globais label.action.edit.host=Editar Host -label.action.edit.instance=Editar Cloud Server +label.action.edit.instance=Editar Inst\u00e2ncia label.action.edit.ISO=Editar ISO label.action.edit.network=Editar Rede label.action.edit.network.offering=Editar Oferta de Rede @@ -171,6 +178,8 @@ label.action.enable.user=Habilitar usu\u00e1rio label.action.enable.user.processing=Habilitando Usu\u00e1rio... label.action.enable.zone=Ativar Zona label.action.enable.zone.processing=Ativando Zona.... +label.action.expunge.instance=Eliminar Inst\u00e2ncia +label.action.expunge.instance.processing=Expurgando Inst\u00e2ncia.... label.action.force.reconnect=Force Reconnect label.action.force.reconnect.processing=Reconectando.... label.action.generate.keys=Gerar Chaves @@ -180,18 +189,19 @@ label.action.lock.account=Bloquear conta label.action.lock.account.processing=Bloqueando conta.... label.action.manage.cluster.processing=Vinculando o Cluster.... label.action.manage.cluster=Vincular Cluster -label.action.migrate.instance=Migrar Cloud Server -label.action.migrate.instance.processing=Migrando Cloud Server... +label.action.migrate.instance=Migrar Inst\u00e2ncia +label.action.migrate.instance.processing=Migrando Inst\u00e2ncia.... label.action.migrate.router=Migrar Roteador label.action.migrate.router.processing=Migrando Roteador... label.action.migrate.systemvm=Migrar VM de Sistema label.action.migrate.systemvm.processing=Migrando VM de Sistema... -label.action.reboot.instance.processing=Reiniciando Cloud Server... -label.action.reboot.instance=Reiniciar Cloud Server +label.action.reboot.instance.processing=Reiniciando Inst\u00e2ncia... +label.action.reboot.instance=Reiniciar Inst\u00e2ncia label.action.reboot.router.processing=Reiniciando Roteador.... label.action.reboot.router=Reiniciar Roteador label.action.reboot.systemvm.processing=Reiniciando VM de Sistema.... label.action.reboot.systemvm=Reiniciar VM de Sistema +label.action.recurring.snapshot=Snapshots recorrentes label.action.register.iso=Registrar ISO label.action.register.template=Registrar template label.action.release.ip=Liberar IP @@ -203,17 +213,19 @@ label.action.reset.password=Recuperar Senha label.action.resize.volume.processing=Resizing Volume.... label.action.resize.volume=Resize Volume label.action.resource.limits=Limite de Recursos -label.action.restore.instance.processing=Restaurando Cloud Server... -label.action.restore.instance=Restaurar Cloud Server -label.actions=A\u00c3\u00a7\u00c3\u00b5es -label.action.start.instance=Iniciar Cloud Server -label.action.start.instance.processing=Iniciando Cloud Server... +label.action.restore.instance.processing=Restaurando Inst\u00e2ncia... +label.action.restore.instance=Restaurar Inst\u00e2ncia +label.action.revert.snapshot.processing=Revertendo para Snapshot... +label.action.revert.snapshot=Reverter para Snapshot +label.actions=A\u00e7\u00f5es +label.action.start.instance=Iniciar Inst\u00e2ncia +label.action.start.instance.processing=Iniciando Inst\u00e2ncia... label.action.start.router=Iniciar Roteador label.action.start.router.processing=Iniciando Roteador.... label.action.start.systemvm=Iniciar VM de Sistema label.action.start.systemvm.processing=Iniciando VM de Sistema.... -label.action.stop.instance=Parar Cloud Server -label.action.stop.instance.processing=Parando Cloud Server... +label.action.stop.instance=Parar Inst\u00e2ncia +label.action.stop.instance.processing=Parando Inst\u00e2ncia... label.action.stop.router=Parar Roteador label.action.stop.router.processing=Parando Roteador.... label.action.stop.systemvm=Parar VM de Sistema @@ -226,6 +238,9 @@ label.action.update.OS.preference=Atualizar Prefer\u00eancia de SO label.action.update.OS.preference.processing=Atualizando Prefer\u00eancia de SO.... label.action.update.resource.count=Atualiza Contador de Recursos label.action.update.resource.count.processing=Atualizando Contador de Recursos.... +label.action.vmsnapshot.create=Fazer Snapshot de VM +label.action.vmsnapshot.delete=Remover snapshot de VM +label.action.vmsnapshot.revert=Reverter snapshot de VM label.activate.project=Ativar Projeto label.active.sessions=Sess\u00f5es Ativas label.add.account=Adicionar Conta @@ -234,6 +249,8 @@ label.add.accounts.to=Adicionar contas para label.add.account.to.project=Adicionar conta ao projeto label.add.ACL=Adicionar ACL label.add=Adicionar +label.add.affinity.group=Adicionar um grupo de afinidade +label.add.BigSwitchVns.device=Adicionar BigSwitch Vns Controller label.add.by=Adicionado por label.add.by.cidr=Adicionar por CIDR label.add.by.group=Adicionar por Grupo @@ -268,12 +285,16 @@ label.add.network.offering=Adicionar oferta de rede label.add.new.F5=Adicionar um novo F5 label.add.new.gateway=Adicionar novo gateway label.add.new.NetScaler=Adicionar um novo NetScaler +label.add.new.PA=Adicionar novo Palo Alto label.add.new.SRX=Adicionar um novo SRX label.add.new.tier=Adicionar nova camada +label.add.NiciraNvp.device=Adicionar Controlador Nvp +label.add.PA.device=Adicionar dispositivo Palo Alto label.add.physical.network=Adicionar rede f\u00edsica label.add.pod=Adicionar POD label.add.port.forwarding.rule=Adicionar regra de encaminhamento de porta label.add.primary.storage=Adicionar Storage Prim\u00e1rio +label.add.region=Adicionar Regi\u00e3o label.add.resources=Adicionar Recursos label.add.route=Adicionar rota label.add.rule=Adicionar regra @@ -288,7 +309,6 @@ label.add.template=Adicionar Template label.add.to.group=Adicionar ao grupo label.add.user=Adicionar Usu\u00e1rio label.add.vlan=Adicionar VLAN -label.add.vxlan=Adicionar VXLAN label.add.vm=Adicionar VM label.add.vms=Adicionar VMs label.add.vms.to.lb=Add VM(s) na regra de balanceamento de carga @@ -298,12 +318,16 @@ label.add.vpc=Adicionar VPC label.add.vpn.customer.gateway=Adicionar Gateway de VPN de usu\u00e1rio label.add.VPN.gateway=Adicionar gateway de VPN label.add.vpn.user=Adicionar usu\u00e1rio VPN +label.add.vxlan=Adicionar VXLAN label.add.zone=Adicionar Zona label.admin.accounts=Contas Administrativas label.admin=Administrador label.advanced=Avan\u00e7ado label.advanced.mode=Modo Avan\u00e7ado label.advanced.search=Busca Avan\u00e7ada +label.affinity=Afinidade +label.affinity.group=Grupo de Afinidade +label.affinity.groups=Grupos de Afinidade label.agent.password=Senha do Agente label.agent.username=Usu\u00e1rio do Agente label.agree=Concordo @@ -311,13 +335,21 @@ label.alert=Alerta label.algorithm=Algoritmo label.allocated=Alocado label.allocation.state=Status da Aloca\u00e7\u00e3o +label.anti.affinity=Anti-afinidade +label.anti.affinity.group=Grupo de Anti-afinidade +label.anti.affinity.groups=Grupos de Anti-afinidade label.api.key=API Key label.apply=Aplicar +label.app.name=CloudStack +label.archive.alerts=Guardar alertas +label.archive.events=Guardar eventos label.assign=Atribuir -label.assign.to.load.balancer=Atribuindo o Cloud Server ao Load Balancer +label.assign.to.load.balancer=Atribuindo Inst\u00e2ncia ao balanceador de carga label.associated.network.id=ID de Rede Associado label.associated.network=Rede associada label.attached.iso=Imagem ISO Plugada +label.author.email=E-mail do autor +label.author.name=Nome do autor label.availability=Availability label.availability.zone=Datacenter label.available=Dispon\u00edvel @@ -326,14 +358,19 @@ label.back=Voltar label.bandwidth=Bandwidth label.basic=B\u00e1sico label.basic.mode=Modo B\u00e1sico +label.bigswitch.controller.address=Endere\u00e7o do Controlador BigSwitch Vns label.bootable=Inicializ\u00e1vel label.broadcast.domain.range=Range do dom\u00ednio de Broadcast label.broadcast.domain.type=Tipo de Dom\u00ednio Broadcast label.broadcast.uri=URI de broadcast label.by.account=por Conta +label.by.alert.type=Por tipo de alerta label.by.availability=By Availability +label.by.date.end=Por data (final) +label.by.date.start=Por data (in\u00edcio) label.by.domain=por Dom\u00ednio label.by.end.date=por Data Final +label.by.event.type=Por tipo de evento label.by.level=por N\u00edvel label.by.pod=por Pod label.by.role=por Fun\u00e7\u00e3o @@ -370,14 +407,18 @@ label.clvm=CLVM label.code=C\u00f3digo label.community=Comunidade label.compute.and.storage=Processamento e Armazenamento +label.compute=Computa\u00e7\u00e3o label.compute.offering=Oferta de Computa\u00e7\u00e3o +label.compute.offerings=Oferta de Computa\u00e7\u00e3o label.configuration=Configura\u00e7\u00e3o label.configure=Configurar +label.configure.ldap=Configurar LDAP label.configure.network.ACLs=Configure ACLs de rede label.configure.vpc=Configurar VPC label.confirmation=Confirma\u00e7\u00e3o label.confirm.password=Confirme a senha label.congratulations=Parab\u00e9ns\! +label.conserve.mode=Modo Conservativo label.console.proxy=Console proxy label.continue.basic.install=Continuar com a instala\u00e7\u00e3o b\u00e1sica label.continue=Continuar @@ -386,14 +427,17 @@ label.cpu.allocated=CPU Alocada label.cpu.allocated.for.VMs=CPU Alocada por VMs label.CPU.cap=CPU Cap label.cpu=CPU +label.cpu.limits=Limite de CPU label.cpu.mhz=CPU (em MHz) label.cpu.utilized=CPU Utilizada label.created.by.system=Criado pelo sistema label.created=Criado +label.create.nfs.secondary.staging.store=Criar storage staging secund\u00e1rio NFS label.create.project=Criar um projeto label.create.template=Criar template label.create.VPN.connection=Criar uma conex\u00e3o VPN label.cross.zones=Inter Zonas +label.custom.disk.iops=IOPS personalizado label.custom.disk.size=Tamanho Customizado label.daily=Di\u00e1rio label.data.disk.offering=Oferta de Disco Adicional @@ -406,9 +450,15 @@ label.dedicated=Dedicado label.default=Padr\u00e3o label.default.use=Uso padr\u00e3o label.default.view=Vis\u00e3o Padr\u00e3o +label.delete.affinity.group=Deletar Grupo de Afinidade +label.delete.alerts=Remover alertas +label.delete.BigSwitchVns=Remover Controlador BigSwitch Vns +label.delete.events=Remover eventos label.delete.F5=Remover F5 label.delete.gateway=delete gateway label.delete.NetScaler=Remover NetScaler +label.delete.NiciraNvp=Remover Controlador Nvp +label.delete.PA=Remover Palo Alto label.delete.project=Deletar projeto label.delete=Remover label.delete.SRX=Remover SRX @@ -418,6 +468,7 @@ label.delete.VPN.gateway=deletar um gateway de VPN label.delete.vpn.user=Deletar usu\u00e1rio VPN label.deleting.failed=Falha ao remover label.deleting.processing=Removendo.... +label.deployment.planner=Deployment planejado label.description=Descri\u00e7\u00e3o label.destination.physical.network.id=ID de destino da rede f\u00edsica label.destination.zone=Zona de Destino @@ -435,11 +486,22 @@ label.disable.provider=Desabilitar Provider label.disable.vpn=Desabilitar VPN label.disabling.vpn.access=Desativando Acesso VPN label.disk.allocated=Disco Alocado +label.disk.bytes.read.rate=Taxa de Leitura do Disco (BPS) +label.disk.bytes.write.rate=Taxa de Escrita no Disco (BPS) +label.disk.iops.max=M\u00e1x IOPS +label.disk.iops.min=M\u00edn IOPS +label.disk.iops.read.rate=Taxa de Leitura do Disco (IOPS) +label.disk.iops.total=IOPS Total +label.disk.iops.write.rate=Taxa de Escrita no Disco (IOPS) label.disk.offering=Oferta de Disco +label.disk.read.bytes=Leitura do Disco (Bytes) +label.disk.read.io=Leitura do Disk (I/O) label.disk.size.gb=Tamanho (em GB) label.disk.size=Tamanho do Disco label.disk.total=Disco Total label.disk.volume=Disco +label.disk.write.bytes=Escrita no Disco (Bytes) +label.disk.write.io=Escrita no Disco (I/O) label.display.name=Nome de exibi\u00e7\u00e3o label.display.text=Descri\u00e7\u00e3o label.dns.1=DNS 1 @@ -456,6 +518,7 @@ label.done=Pronto label.double.quotes.are.not.allowed=Aspas duplas n\u00e3o s\u00e3o permitidas label.download.progress=Status do Download label.drag.new.position=Arrastar para uma nova posi\u00e7\u00e3o +label.edit.affinity.group=Editar Grupo de Afinidade label.edit=Editar label.edit.lb.rule=Editar regra de LB label.edit.network.details=Editar detalhes de rede @@ -463,6 +526,7 @@ label.edit.project.details=Editar detalhes do projeto label.edit.tags=Edite etiquetas label.edit.traffic.type=Editar tipo de tr\u00e1fego label.edit.vpc=Editar VPC +label.egress.default.policy=Pol\u00edtica de Entrada Padr\u00e3o label.egress.rule=Regra Egress label.egress.rules=Regras de sa\u00edda label.elastic=El\u00e1stico @@ -487,9 +551,12 @@ label.error.code=C\u00f3digo de Erro label.error=Erro label.ESP.encryption=Encripta\u00e7\u00e3o ESP label.ESP.hash=Hash ESP +label.ESP.lifetime=Tempo de vida do ESP (segundos) label.ESP.policy=Pol\u00edtica ESP label.esx.host=ESX/ESXi Host label.example=Examplo +label.expunge=Eliminar +label.external.link=Link externo label.f5=F5 label.failed=Falhou label.featured=Featured @@ -516,7 +583,7 @@ label.guest.gateway=Gateway de rede Convidado label.guest=Guest label.guest.ip=Endere\u00e7o IP Convidado label.guest.ip.range=Intervalo de rede convidado -label.guest.netmask=M\u00e1scara de rede Convidado +label.guest.netmask=M\u00e1scara de rede Guest label.guest.networks=Redes Guest label.guest.start.ip=IP de in\u00edcio do guest label.guest.traffic=Tr\u00e1fego de h\u00f3spedes @@ -525,6 +592,7 @@ label.ha.enabled=HA Ativado label.help=Ajuda label.hide.ingress.rule=Ocultar Regra de Entrada label.hints=Dicas +label.home=Home label.host.alerts=Alertas de Host label.host=Host label.host.MAC=Host MAC @@ -534,12 +602,15 @@ label.host.tags=Tags de Host label.hourly=A cada hora label.hypervisor.capabilities=Recursos de Virtualizador label.hypervisor=Hipervisor +label.hypervisors=Hypervisors +label.hypervisor.snapshot.reserve=Reserva de Snapshot do Hypervisor label.hypervisor.type=Tipo do Hypervisor label.hypervisor.version=Vers\u00e3o de Virtualizador label.id=ID label.IKE.DH=DH IKE label.IKE.encryption=Encripta\u00e7\u00e3o IKE label.IKE.hash=Hash IKE +label.IKE.lifetime=Tempo de vida IKE (segundos) label.IKE.policy=Pol\u00edtica IKE label.info=Info label.ingress.rule=Regra de Entrada @@ -560,10 +631,10 @@ label.installWizard.addZone.title=Adicionar zona label.installWizard.click.launch=Click no bot\u00e3o executar. label.installWizard.subtitle=Este tour vai auxiliar voc\u00ea na configura\u00e7\u00e3o da sua instala\u00e7\u00e3o de CloudStack&\#8482 label.installWizard.title=Ol\u00e1, seja bem vindo ao CloudStack&\#8482 -label.instance=Cloud Server -label.instance.limits=Limites do Cloud Server -label.instance.name=Nome do Cloud Server -label.instances=Cloud Servers +label.instance=Inst\u00e2ncia +label.instance.limits=Limites da Inst\u00e2ncia +label.instance.name=Nome da Inst\u00e2ncia +label.instances=Inst\u00e2ncias label.internal.dns.1=DNS 1 Interno label.internal.dns.2=DNS 2 Interno label.internal.name=Nome interno @@ -602,12 +673,17 @@ label.keyboard.type=Tipo de Teclado label.key=Chave label.kvm.traffic.label=Etiqueta de tr\u00e1fego KVM label.label=Etiqueta +label.lang.arabic=Arabe label.lang.brportugese=Portugu\u00eas brasileiro +label.lang.catalan=Catal\u00e3o label.lang.chinese=Chinese (Simplified) label.lang.english=English label.lang.french=Franc\u00eas +label.lang.german=Alem\u00e3o +label.lang.italian=Italiano label.lang.japanese=Japanese label.lang.korean=Coreano +label.lang.norwegian=Noruegu\u00eas label.lang.russian=Russo label.lang.spanish=Spanish label.last.disconnected=Last Disconnected @@ -617,8 +693,12 @@ label.launch=Executar label.launch.vm=Executar VM label.launch.zone=Executar zona. label.LB.isolation=Isolamento de LB +label.ldap.configuration=Configura\u00e7\u00e3o do LDAP +label.ldap.group.name=Grupo LDAP +label.ldap.port=Porta do LDAP label.least.connections=Least connections label.level=N\u00edvel +label.linklocal.ip=Endere\u00e7o IP do Link Local label.load.balancer=Load Balancer label.load.balancing=Balanceamento de Carga label.load.balancing.policies=Pol\u00edticas de balanceamento de carga @@ -635,16 +715,22 @@ label.manage=Gerenciar label.management=Gerenciamento label.management.ips=Gerenciamento de Endere\u00e7os IP label.manage.resources=Gerenciar Recursos +label.max.cpus=M\u00e1ximo de cores de CPU label.max.guest.limit=Limite m\u00e1x. de guest label.maximum=M\u00e1ximo +label.max.memory=M\u00e1x. de mem\u00f3ria (MiB) label.max.networks=M\u00e1x. de redes +label.max.primary.storage=M\u00e1x. prim\u00e1rio (GiB) label.max.public.ips=M\u00e1x. IPs p\u00fablicos +label.max.secondary.storage=Max. Secund\u00e1rio (GiB) label.max.snapshots=Max. snapshots label.max.templates=M\u00e1x. templates label.max.vms=M\u00e1x. VMs de usu\u00e1rio label.max.volumes=M\u00e1x. volumes +label.max.vpcs=M\u00e1x. VPCs label.may.continue=Voc\u00ea pode continuar agora label.memory.allocated=Mem\u00f3ria Alocada +label.memory.limits=Limites de mem\u00f3ria (MiB) label.memory.mb=Mem\u00f3ria (em MB) label.memory=Mem\u00f3ria (em MB) label.memory.total=Mem\u00f3ria Total @@ -652,34 +738,35 @@ label.memory.used=Mem\u00f3ria Usada label.menu.accounts=Contas label.menu.alerts=Alertas label.menu.all.accounts=Todas as Contas -label.menu.all.instances=Todos Cloud Servers +label.menu.all.instances=Todas Inst\u00e2ncias label.menu.community.isos=ISOs P\u00fablicas label.menu.community.templates=Templates P\u00fablicos label.menu.configuration=Configura\u00e7\u00e3o label.menu.dashboard=Dashboard -label.menu.destroyed.instances=Cloud Servers Apagados +label.menu.destroyed.instances=Inst\u00e2ncias Apagadas label.menu.disk.offerings=Oferta de Discos -label.menu.domains=dom\u00ednios +label.menu.domains=Dom\u00ednios label.menu.events=Eventos label.menu.featured.isos=ISOs Customizada label.menu.featured.templates=Templates Customizados label.menu.global.settings=Configura\u00e7\u00f5es Globais label.menu.infrastructure=Infra-estrutura -label.menu.instances=Cloud Servers +label.menu.instances=Inst\u00e2ncias label.menu.ipaddresses=Endere\u00e7os IP label.menu.isos=ISOs label.menu.my.accounts=Minhas Contas -label.menu.my.instances=Meus Cloud Servers +label.menu.my.instances=Minhas Inst\u00e2ncias label.menu.my.isos=Minhas ISOs label.menu.my.templates=Meus Templates label.menu.network.offerings=Oferta de Rede label.menu.network=Rede label.menu.physical.resources=Recursos B\u00e1\u00adsicos -label.menu.running.instances=Cloud Servers Rodando +label.menu.regions=Regi\u00f5es +label.menu.running.instances=Inst\u00e2ncias Rodando label.menu.security.groups=Grupos de seguran\u00e7a -label.menu.service.offerings=Planos +label.menu.service.offerings=Oferta de Servi\u00e7os label.menu.snapshots=Snapshots -label.menu.stopped.instances=Cloud Servers Parados +label.menu.stopped.instances=Inst\u00e2ncias Paradas label.menu.storage=Storage label.menu.system.service.offerings=Ofertas do Sistema label.menu.system=Sistema @@ -689,11 +776,12 @@ label.menu.virtual.appliances=Appliance Virtual label.menu.virtual.resources=Recursos Virtuais label.menu.volumes=Discos label.migrate.instance.to.host=Migrar inst\u00e2ncia para outro host -label.migrate.instance.to=Migrar Cloud Server para +label.migrate.instance.to=Migrar Inst\u00e2ncia para label.migrate.instance.to.ps=Migrar inst\u00e2ncia para outro storage prim\u00e1rio label.migrate.router.to=Migrar Roteador para label.migrate.systemvm.to=Migrar VM de sistema para label.migrate.to.host=Migrar para outro host +label.migrate.to.storage=Migrar para storage label.migrate.volume=Migrar volume para outro storage prim\u00e1rio label.minimum=M\u00ed\u00adnimo label.minute.past.hour=minuto(s) \u00daltima hora @@ -701,6 +789,7 @@ label.monday=Segunda label.monthly=Mensal label.more.templates=Mais Templates label.move.down.row=Mover uma c\u00e9lula para baixo +label.move.to.bottom=Mover para baixo label.move.to.top=Mover para o topo label.move.up.row=Mover uma c\u00e9lula para cima label.my.account=Minha Conta @@ -709,10 +798,11 @@ label.my.templates=Meus templates label.name=Nome label.name.optional=Nome (Opcional) label.nat.port.range=Range de Portas NAT -label.netmask=M\u00c3\u00a1srca de Rede +label.netmask=M\u00e1scara de Rede label.netScaler=NetScaler label.network.ACL=ACL de rede label.network.ACLs=Network ACLs +label.network.ACL.total=Total de rede ACL label.network.desc=Descri\u00e7\u00e3o de Rede label.network.device=Dispositivo de Rede label.network.device.type=Tipo de Dispositivo de Rede @@ -721,11 +811,13 @@ label.network.domain.text=Texto do dom\ufffdnio de rede label.network.id=ID de Rede label.networking.and.security=Rede e seguran\u00e7a label.network.label.display.for.blank.value=Utilizar gateway default +label.network.limits=Limites de rede label.network.name=Nome da Rede label.network.offering.display.text=Network Offering Display Text label.network.offering.id=Network Offering ID label.network.offering.name=Network Offering Name label.network.offering=Network Offering +label.network.rate.megabytes=Taxa de Rede (MB/s) label.network.rate=Taxa de Transfer\u00eancia label.network.read=Network Read label.network=Rede @@ -742,8 +834,11 @@ label.nexusVswitch=Nexus Vswitch label.nfs=NFS label.nfs.server=Servidor NFS label.nfs.storage=Storage NFS -label.nic.adapter.type=Tipo de adaptador NIC -label.nics=REDE +label.nic.adapter.type=Tipo de adaptador de Rede +label.nicira.controller.address=Endere\u00e7o do Controlador +label.nicira.l3gatewayserviceuuid=Uuid do Servi\u00e7o de Gateway L3 +label.nicira.transportzoneuuid=Uuid da Zona de Transporte +label.nics=Adaptadores de Rede label.no.actions=Sem A\u00e7\u00f5es Dispon\u00edveis label.no.alerts=Sem Alertas Recentes label.no.data=Sem dados para mostrar @@ -774,23 +869,31 @@ label.os.type=Tipo de SO label.owned.public.ips=IP P\u00fablico Utilizado label.owner.account=Dono da Conta label.owner.domain=Dono do Dom\u00ednio +label.PA.log.profile=Palo Alto Log Profile +label.PA=Palo Alto label.parent.domain=Dom\u00ednio Principal label.password.enabled=Senha Ativada label.password=Senha label.path=Caminho (Path) +label.PA.threat.profile=Palo Alto Threat Profile +label.perfect.forward.secrecy=Perfect Forward Secrecy label.physical.network.ID=ID da rede f\u00edsica label.physical.network=Rede F\u00edsica label.PING.CIFS.password=PING CIFS password label.PING.CIFS.username=PING CIFS username label.PING.dir=PING Directory label.PING.storage.IP=Disparar PING para IP do Storage +label.planner.mode=Modo planejado label.please.specify.netscaler.info=Por favor especifique as informa\u00e7\u00f5es do Netscaler label.please.wait=Por Favor Aguarde +label.plugin.details=Detalhes do plugin +label.plugins=Plugins label.pod.name=Nome do Pod label.pod=POD label.pods=Pods label.port.forwarding=Encaminhamento de Porta label.port.forwarding.policies=Pol\u00edticas de redirecionamento de portas +label.port=Porta label.port.range=Range de Porta label.PreSetup=PreSetup label.previous=Anterior @@ -798,6 +901,7 @@ label.prev=Prev label.primary.allocated=Aloca\u00e7\u00e3o do Storage Prim\u00e1rio label.primary.network=Rede Prim\u00e1ria label.primary.storage.count=Pools de Storage Prim\u00e1rios +label.primary.storage.limits=Limites do Storage Prim\u00e1rio (GiB) label.primary.storage=Storage Prim\u00e1rio label.primary.used=Uso do Storage Prim\u00e1rio label.private.Gateway=Gateway privado @@ -828,21 +932,32 @@ label.public.traffic=Tr\u00e1fego P\u00fablico label.public.zone=Zona P\u00fablica label.purpose=Prop\u00f3sito label.Pxe.server.type=Tipo de Servidor PXE +label.qos.type=Tipo de QoS label.quickview=Visualiza\u00e7\u00e3o r\u00e1pida +label.quiesce.vm=Quiesce VM +label.rbd.id=Usu\u00e1rio Ceph +label.rbd.monitor=Monitor Ceph +label.rbd.pool=Pool Ceph +label.rbd=RDB +label.rbd.secret=Cephx secret label.reboot=Reiniciar label.recent.errors=Erros Recentes label.redundant.router.capability=Recurso de roteador redundante label.redundant.router=Roteador Redundantee +label.redundant.state=Estado redundante label.refresh=Atualizar +label.region=Regi\u00e3o label.related=Relacionado label.remind.later=Me lembre depois label.remove.ACL=Remove ACL label.remove.egress.rule=Remover regra egress -label.remove.from.load.balancer=Removendo Cloud Server do Load Balancer +label.remove.from.load.balancer=Removendo Inst\u00e2ncia do balanceador de carga label.remove.ingress.rule=Remover regra ingress label.remove.ip.range=Remover range de IP +label.remove.ldap=Remover LDAP label.remove.pf=Remover regra de redirecionamento de porta label.remove.project.account=Remover conta de projeto +label.remove.region=Remover Regi\u00e3o label.remove.rule=Remover regra label.remove.static.nat.rule=Remover regra de NAT est\u00e1tico label.remove.static.route=Remover rota est\u00e1tica @@ -854,7 +969,7 @@ label.removing.user=Removendo Usu\u00e1rio label.required=Obrigat\u00f3rio label.reserved.system.gateway=Gateway de sistema reservado label.reserved.system.ip=IP de Sistema Reservado -label.reserved.system.netmask=M\u00e1scara de rede do sistema reservado +label.reserved.system.netmask=M\u00e1scara de rede reservada do sistema label.reset.VPN.connection=Resetar a conex\u00e3o VPN label.resize.new.offering.id=New Offering label.resize.new.size=New Size(GB) @@ -872,7 +987,9 @@ label.revoke.project.invite=Revogar convite label.role=Fun\u00e7\u00e3o label.root.disk.controller=Controlador do disco Root label.root.disk.offering=Oferta de Disco ROOT +label.root.disk.size=Tamanho do disco root label.round.robin=Round-robin +label.routing=Roteamento label.rules=Regras label.running.vms=VMs Rodando label.s3.access_key=Chave de acesso @@ -880,6 +997,8 @@ label.s3.bucket=Balde label.s3.connection_timeout=Tempo limite de conex\u00e3o label.s3.endpoint=Ponto de acesso label.s3.max_error_retry=Limite de tentativas de recupera\u00e7\u00e3o de erro +label.s3.nfs.path=Caminho NFS S3 +label.s3.nfs.server=Servidor NFS S3 label.s3.secret_key=Chave Secreta label.s3.socket_timeout=Tempo limite no socket label.s3.use_https=Use HTTPS @@ -890,6 +1009,7 @@ label.saving.processing=Salvando.... label.scope=Escopo label.search=Pesquisar label.secondary.storage.count=Pools de Storage secund\u00e1rios +label.secondary.storage.limits=Limites do Storage Secund\u00e1rio (GiB) label.secondary.storage=Storage Secund\u00e1rio label.secondary.storage.vm=VM de storage secund\u00e1rio label.secondary.used=Uso do Storage Secund\u00c3\u00a1rio @@ -913,6 +1033,7 @@ label.sent=Enviado label.server=Servidor label.service.capabilities=Recursos de servi\u00e7os label.service.offering=Plano +label.service.state=Estado do Servi\u00e7o label.session.expired=Sess\u00e3o Expirada label.setup=Configura\u00e7\u00e3o label.setup.network=Configurar Rede @@ -921,14 +1042,20 @@ label.set.up.zone.type=Configurar tipo de zona label.shared=Compatilhado label.SharedMountPoint=SharedMountPoint label.show.ingress.rule=Mostrar Regra de Entrada +label.shutdown.provider=Desabilitar provider label.site.to.site.VPN=Site-to-site VPN label.size=Tamanho label.skip.guide=Eu utilizei o CloudStack antes, pular este guia +label.smb.domain=Dom\u00ednio SMB +label.smb.password=Senha SMB +label.smb.username=Usu\u00e1rio SMB label.snapshot.limits=Limites de Snapshot label.snapshot.name=Nome do Snapshot +label.snapshot.schedule=Configure Snapshots recorrentes label.snapshot=Snapshot label.snapshot.s=Snapshot (s) label.snapshots=Snapshots +label.sockets=Sockets label.source.nat=Source NAT label.source=Origem label.specify.IP.ranges=Especifique range de IP @@ -958,6 +1085,7 @@ label.step.4=Passo 4 label.step.4.title=Passo 4\: Rede label.step.5=Passo 5 label.step.5.title=Passo 5\: Revisar +label.stickiness=Ader\u00eancia label.sticky.cookie-name=Nome do Cookie label.sticky.domain=Dom\u00ednio label.sticky.expire=Expires @@ -968,6 +1096,7 @@ label.sticky.mode=Modo label.sticky.nocache=Sem Cache label.sticky.postonly=Apenas publicar label.sticky.prefix=Prefixo +label.sticky.request-learn=Solicitar para aprender label.sticky.tablesize=Tamanho da Tabela label.stop=Parar label.stopped.vms=VMs Paradas @@ -984,6 +1113,7 @@ label.super.cidr.for.guest.networks=Super CIDR para redes h\u00f3spedes label.supported.services=Servi\u00e7os Suportados label.supported.source.NAT.type=Tipo de Source NAT Suportado label.suspend.project=Suspender Projeto +label.switch.type=Tipo de Switch label.system.capacity=Capacidade do Sistema label.system.offering=Ofertas de Sistema label.system.service.offering=System Service Offering @@ -1039,6 +1169,7 @@ label.used=Usado label.username=Nome de usu\u00e1rio label.users=Usu\u00e1rios label.user=Usu\u00e1rio +label.use.vm.ip=Usar IP da VM\: label.value=Valor label.vcdcname=Nome do vCenter DC label.vcenter.cluster=vCenter Cluster @@ -1053,6 +1184,7 @@ label.view.all=Visualizar tudo label.view.console=Visualizar Console label.viewing=Visualizar label.view.more=Ver mais +label.view.secondary.ips=Visualizar os IPs secund\u00e1rios label.view=Visualizar label.virtual.appliance=Appliance Virtual label.virtual.appliances=Appliance Virtual @@ -1063,10 +1195,7 @@ label.virtual.routers=Roteadores Virtuais label.vlan.id=VLAN ID label.vlan.range=Intervalo de VLAN label.vlan=VLAN -label.vxlan.id=VXLAN ID -label.vxlan.range=Intervalo de VXLAN -label.vxlan=VXLAN -label.vm.add=Adicionar Cloud Server +label.vm.add=Adicionar Inst\u00e2ncia label.vm.destroy=Apagar label.vm.display.name=Nome de exibi\u00e7\u00e3o da VM label.VMFS.datastore=VMFS datastore @@ -1074,12 +1203,19 @@ label.vmfs=VMFS label.vm.name=Nome da VM label.vm.reboot=Reiniciar label.VMs.in.tier=M\u00e1quinas virtuais em camadas +label.vmsnapshot.current=isCurrent +label.vmsnapshot.memory=Snapshot da mem\u00f3ria +label.vmsnapshot.parentname=Pai +label.vmsnapshot=Snapshot da VM label.vmsnapshot.type=Tipo label.vm.start=In\u00edcio label.vm.state=Estado da VM label.vm.stop=Parar label.vms=VMs label.vmware.traffic.label=Etiqueta de tr\u00e1fego VMware +label.vnet.id=VLAN ID +label.vnet=VLAN +label.volatile=Vol\u00e1til label.volgroup=Grupo de Volume label.volume=Disco label.volume.limits=Limites de Disco @@ -1097,6 +1233,9 @@ label.vsmctrlvlanid=Control VLAN ID label.vsmpktvlanid=Packet VLAN ID label.vsmstoragevlanid=Storage VLAN ID label.vsphere.managed=vSphere Managed +label.vxlan.id=VXLAN ID +label.vxlan.range=Intervalo de VXLAN +label.vxlan=VXLAN label.waiting=Aguardando label.warn=Avisar label.wednesday=Quarta-Feira @@ -1117,17 +1256,18 @@ label.zones=Zonas label.zone.type=Tipo de Zona label.zone.wide=Zone-Wide label.zoneWizard.trafficType.guest=H\u00f3spede\: tr\u00e1fego entre m\u00e1quinas virtuais de usu\u00e1rios finais -label.zoneWizard.trafficType.management=Ger\u00eancia\: tr\u00e1fego entre recursos internos do CloudStack, incluindo quaisquer componentes que se comunicam com o servidor de gerenciamento, tais como hosts e m\u00e1quinas virtuais de sistema do CloudStack +label.zoneWizard.trafficType.management=Ger\u00eancia\: Tr\u00e1fego entre recursos internos do CloudStack incluindo quaisquer componentes que se comunicam com o servidor de gerenciamento tais como hosts e m\u00e1quinas virtuais de sistema do CloudStack label.zoneWizard.trafficType.public=P\u00fablico\: tr\u00e1fego entre a internet e m\u00e1quinas virtuais na nuvem. label.zoneWizard.trafficType.storage=Storage\: tr\u00e1fego entre servidores de storage prim\u00e1ria e secund\u00e1ria, tais como templates de m\u00e1quinas virtuais e snapshots label.zone=Zona managed.state=Status do Gerenciamento +message.acquire.ip.nic=Por favor, confirme que voc\u00ea deseja adquirir um novo IP secund\u00e1rio para esta Interface de Rede.
NOTA\: Voc\u00ea precisa configurar manualmente o novo IP secund\u00e1rio dentro da maquinas virtual. message.acquire.new.ip=Por favor confirme que voc\u00ea gostaria de adquirir um novo IP para esta rede. message.acquire.new.ip.vpc=Por favor confirme que voc\u00ea gostaria de adquirir um novo IP para esta VPC. message.acquire.public.ip=Selecione a zona de onde voc\u00ea deseja adquirir o novo IP message.action.cancel.maintenance=A Manuten\u00e7\u00e3o do seu HOST foi cancelada com sucesso message.action.cancel.maintenance.mode=Confirme que voc\u00ea deseja cancelar esta Manuten\u00e7\u00e3o -message.action.change.service.warning.for.instance=Para troca de plano \u00e9 necess\u00e1rio parar o Cloud Server. +message.action.change.service.warning.for.instance=Sua inst\u00e2ncia deve ser desligada antes de tentar alterar a oferta de servi\u00e7os utilizada. message.action.change.service.warning.for.router=O roteador precisa ser desligado antes de trocar o plano/tamanho. message.action.delete.cluster=Confirme que voc\u00ea deseja excluir este HOST message.action.delete.disk.offering=Confirme que voc\u00ea deseja excluir esta oferta de disco @@ -1139,6 +1279,7 @@ message.action.delete.ISO=Confirme que voc\u00ea deseja excluir esta ISO message.action.delete.ISO.for.all.zones=Esta ISO \u00e9 usada por todas as Zonas. Confirme se voc\u00ea deseja excluir a ISO de todas as Zonas message.action.delete.network=Confirme que voc\u00ea deseja remover esta rede. message.action.delete.nexusVswitch=Por favor confirme que voc\ufffd deseja remover este nexusVswitch. +message.action.delete.nic=Por favor, confirme que deseja remover esta Interface de Rede, esta a\u00e7\u00e3o tamb\u00e9m ir\u00e1 remover a rede associada \u00e0 VM. message.action.delete.physical.network=Por favor confirme que voc\u00ea deseja deletar esta rede f\u00edsica message.action.delete.pod=Confirme que voc\u00ea deseja remover este POD. message.action.delete.primary.storage=Confirme que voc\u00ea deseja remover este Storage Prim\u00e1rio. @@ -1151,7 +1292,7 @@ message.action.delete.template=Confirme que voc\u00ea deseja remover este Templa message.action.delete.template.for.all.zones=Este Template \u00e9 usado por todas as zonas. Confirme que voc\u00ea deseja remover o Template de todas as zonas. message.action.delete.volume=Confirme que voc\u00ea deseja remover este Disco. message.action.delete.zone=Confirme que voc\u00ea deseja remover esta Zona. -message.action.destroy.instance=Confirme que voc\u00ea deseja excluir este Cloud Server. +message.action.destroy.instance=Por favor, confirme que voc\u00ea deseja excluir esta Inst\u00e2ncia. message.action.destroy.systemvm=Confirme que voc\u00ea deseja excluir esta VM de Sistema. message.action.disable.cluster=Confirma a desativa\u00e7\u00e3o do cluster. message.action.disable.nexusVswitch=Por favor confirme que voc\ufffd deseja desabilitar este nexusVswitch @@ -1167,27 +1308,31 @@ message.action.enable.nexusVswitch=Por favor confirme que voc\ufffd deseja habil message.action.enable.physical.network=Por favor confirme que voc\u00ea deseja habilitar esta rede f\u00edsica. message.action.enable.pod=Confirma a ativa\u00e7\u00e3o do POD. message.action.enable.zone=Confirma a ativa\u00e7\u00e3o da zona. +message.action.expunge.instance=Por favor, confirme que voc\u00ea deseja eliminar esta inst\u00e2ncia. message.action.force.reconnect=O procedimento de reconex\u00e3o for\u00e7ada foi preparado com sucesso. Este processo poder\u00e1 levar alguns minutos. -message.action.host.enable.maintenance.mode=Ativar o modo de Manuten\u00e7\u00e3o ir\u00e1 causar o live migration de todos Cloud Server hospedados neste Host para o pr\u00f3ximo dispon\u00edvel. +message.action.host.enable.maintenance.mode=Ativar o modo de Manuten\u00e7\u00e3o ir\u00e1 causar o live migration de todas as Inst\u00e2ncias hospedadas neste Host para o pr\u00f3ximo dispon\u00edvel. message.action.instance.reset.password=Por favor confirme que voc\u00ea deseja alterar a senha de ROOT para est\u00e1 m\u00e1quina virtual. message.action.manage.cluster=Confirma a vincula\u00e7\u00e3o do cluster. message.action.primarystorage.enable.maintenance.mode=Aviso\: Colocar o Storage prim\u00e1rio em modo de Manuten\u00e7\u00e3o ir\u00e1 causar a parada de todas as VMs hospedadas nesta unidade. Deseja continuar? -message.action.reboot.instance=Confirme que voc\u00ea deseja reiniciar este Cloud Server. +message.action.reboot.instance=Por favor, confirme que voc\u00ea deseja reiniciar esta inst\u00e2ncia. message.action.reboot.router=Confirme que voc\ufffd deseja reiniciar este roteador. message.action.reboot.systemvm=Confirme que voc\u00ea deseja reiniciar esta VM de sistema. message.action.release.ip=Confirme que voc\u00ea deseja liberar este IP. message.action.remove.host=Favor confirmar que voc\u00ea deseja remover este host. -message.action.reset.password.off=Seu Cloud Server n\u00e3o suporta esta funcionalidade. -message.action.reset.password.warning=Para recuperar a senha \u00e9 necess\u00e1rio parar o Cloud Server. -message.action.restore.instance=Confirme que voc\u00ea deseja restaurar este Cloud Server. -message.action.start.instance=Confirme que voc\u00ea deseja iniciar este Cloud Server. +message.action.reset.password.off=Sua Inst\u00e2ncia n\u00e3o suporta esta funcionalidade. +message.action.reset.password.warning=Para recuperar a senha \u00e9 necess\u00e1rio parar a Inst\u00e2ncia. +message.action.restore.instance=Por favor, confirme que voc\u00ea deseja restaurar esta Inst\u00e2ncia. +message.action.revert.snapshot=Por favor, confirme que voc\u00ea deseja reverter o seu volume deste snapshot. +message.action.start.instance=Por favor, confirme que voc\u00ea deseja iniciar esta Inst\u00e2ncia. message.action.start.router=Confirme que voc\u00ea deseja inciar este roteador. message.action.start.systemvm=Confirme que voc\u00ea deseja iniciar esta VM de sistema. -message.action.stop.instance=Confirme que voc\u00ea deseja parar este Cloud Server. +message.action.stop.instance=Por favor, confirme que voc\u00ea deseja parar esta inst\u00e2ncia. message.action.stop.router=Confirme que voc\ufffd deseja parar este roteador. message.action.stop.systemvm=Confirme que voc\u00ea deseja parar esta VM de Sistema. message.action.take.snapshot=Por favor confirme que voc\u00ea deseja criar um snapshot deste volume. message.action.unmanage.cluster=Confirma a desvincula\u00e7\u00e3o do cluster. +message.action.vmsnapshot.delete=Por favor, confirme que voc\u00ea deseja excluir este snapshot da VM. +message.action.vmsnapshot.revert=Reverter snapshot da VM message.activate.project=Voc\u00ea tem certeza que deseja ativar este projeto ? message.add.cluster=Add a hypervisor managed cluster for zone , pod message.add.cluster.zone=Add a hypervisor managed cluster for zone @@ -1202,14 +1347,16 @@ message.adding.Netscaler.provider=Adicionando Netscaler provider message.add.ip.range=Add an IP range to public network in zone message.add.ip.range.direct.network=Add an IP range to direct network in zone message.add.ip.range.to.pod=

Add an IP range to pod\:

-message.additional.networks.desc=Selecione a(s) rede(s) adicionais que seu Cloud Server ter\u00c3\u00a1 acesso. +message.additional.networks.desc=Por favor, selecione a(s) rede(s) adicionais que sua inst\u00e2ncia virtual estar\u00e1 conectada. message.add.load.balancer=Add a load balancer to zone message.add.load.balancer.under.ip=A regra do balanceador de carga foi adicionada para o IP\: message.add.network=Add a new network for zone\: message.add.new.gateway.to.vpc=Favor especificar a informa\u00e7\u00e3o para adicionar um novo gateway a esta VPC. message.add.pod=Add a new pod for zone +message.add.pod.during.zone.creation=Cada zona deve conter um ou mais pods e iremos adicionar o primeiro pod agora. Um pod cont\u00e9m hosts e servidores de storage prim\u00e1rio que ser\u00e3o adicionados em uma etapa posterior. Inicialmente, configure um intervalo de endere\u00e7os IP reservados para o tr\u00e1fego de gerenciamento interno do CloudStack. A faixa de IP reservados devem ser \u00fanicos para cada zona na nuvem. message.add.primary=Especifique os seguintes par\u00e2metros para adicionar um novo Storage prim\u00e1rio. message.add.primary.storage=Adicionar novo Storage prim\u00e1rio \u00c3\u00a0 zona , pod +message.add.region=Por favor, especifique as informa\u00e7\u00f5es necess\u00e1rias para adicionar uma nova regi\u00e3o. message.add.secondary.storage=Add a new storage for zone message.add.service.offering=Por favor preencha os dados abaixo para adicionar uma nova oferta de computa\u00e7\u00e3o. message.add.system.service.offering=Por favor preencha os dados abaixo para adicionar uma nova oferta de servi\u00e7o de sistema. @@ -1224,12 +1371,13 @@ message.after.enable.swift=Swift Configurado. Nota\: Ap\u00f3s deixar esta p\u00 message.alert.state.detected=Alerta de estado detectado message.allow.vpn.access=Entre com nome de Usu\u00e1rio e senha do Usu\u00e1rio que ter\u00e1 acesso VPN. message.apply.snapshot.policy=Voc\u00ea atualizou com sucesso sua pol\u00edtica de Snapshot. -message.attach.iso.confirm=Confirme que voc\u00ea deseja conectar a ISO ao Cloud Server. -message.attach.volume=Preencha os seguintes dados para conectar o novo disco. Se voc\u00ea Est\u00e1 conectando um disco a um Cloud Server Windows, ser\u00e1 necess\u00e1rio reiniciar o Cloud Server para visualizar o novo disco. -message.basic.mode.desc=Escolha este modelo de rede se voc\u00ea *n\u00e3o* quer suporte a VLAN. Todo Cloud Server criado neste modelo de rede estar\u00e1 ligado diretamente a um IP da rede e ser\u00e1 usado Security Groups para prover seguran\u00e7a e separa\u00e7\u00e3o. -message.change.offering.confirm=Confirme que voc\u00ea deseja mudar o plano deste Cloud Server. +message.attach.iso.confirm=Por favor, confirme que voc\u00ea deseja conectar o ISO \u00e0 esta inst\u00e2ncia virtual. +message.attach.volume=Preencha os seguintes dados para conectar o novo disco. Se voc\u00ea Est\u00e1 conectando um disco a uma maquina virtual Windows, ser\u00e1 necess\u00e1rio reiniciar a Inst\u00e2ncia para visualizar o novo disco. +message.basic.mode.desc=Escolha este modelo de rede se voc\u00ea *n\u00e3o* quer suporte a VLAN. Toda Inst\u00e2ncia criada neste modelo de rede estar\u00e1 ligado diretamente a um IP da rede e ser\u00e1 usado Security Groups para prover seguran\u00e7a e segrega\u00e7\u00e3o. +message.change.offering.confirm=Por favor, confirme que voc\u00ea deseja mudar a oferta de servi\u00e7o desta inst\u00e2ncia virtual. message.change.password=Por favor, troque sua senha. message.configure.all.traffic.types=Voc\u00ea tem m\u00faltiplas redes f\u00edsicas; favor configurar etiquetas para cada tipo de tr\u00e1fego clicando no bot\u00e3o Edit. +message.configure.ldap=Por favor, confirme que voc\u00ea deseja configurar o LDAP. message.configuring.guest.traffic=Configurando tr\u00e1fego do guest message.configuring.physical.networks=Configurando redes f\u00edsicas message.configuring.public.traffic=Configurando tr\u00e1fego p\u00fablico @@ -1237,6 +1385,7 @@ message.configuring.storage.traffic=Configurando tr\u00e1fego de storage message.confirm.action.force.reconnect=Por favor confirme que voc\u00ea deseja for\u00e7ar a reconex\u00e3o com este host. message.confirm.delete.F5=Por favor confirme que voc\u00ea deseja remover o F5 message.confirm.delete.NetScaler=Por favor confirme que voc\u00ea deseja remover o NetScaler +message.confirm.delete.PA=Por favor, confirme que voc\u00ea deseja remover Palo Alto message.confirm.delete.SRX=Por favor confirme que voc\u00ea deseja remover o SRX message.confirm.destroy.router=Por favor confirme que voc\u00ea gostaria de destruir este roteador message.confirm.disable.provider=Por favor confirme que voc\u00ea gostaria de desabilitar este provider @@ -1257,15 +1406,24 @@ message.creating.primary.storage=Criando storage prim\u00e1rio message.creating.secondary.storage=Criando storage secund\u00e1rio message.creating.zone=Criando zona. message.decline.invitation=Voc\u00ea tem certeza que quer rejeitar este convite de projeto ? +message.dedicate.zone=Zona dedicada message.delete.account=Confirme se voc\u00ea deseja excluir esta conta. +message.delete.affinity.group=Por favor, confirme que voc\u00ea deseja remover este grupo de afinidade message.delete.gateway=Favor confirmar que voc\u00ea deseja deleta o gateway message.delete.project=Voc\u00ea tem certeza que deseja deletar este projeto ? message.delete.user=Por favor confirme que voc\u00ea deseja deletar este usu\u00e1rio. message.delete.VPN.connection=Favor confirmar que voc\u00ea deseja deletar esta conex\u00e3o VPN message.delete.VPN.customer.gateway=Favor confirmar que voc\u00ea deseja deletar este gateway de VPN de usu\u00e1rio message.delete.VPN.gateway=Favor confirmar que voc\u00ea deseja deletar este gateway de VPN +message.desc.advanced.zone=Para topologias de rede mais sofisticadas. Este modelo fornece maior flexibilidade na defini\u00e7\u00e3o de redes de clientes e fornece ofertas de rede personalizadas, tais como firewall, VPN ou de balanceamento de carga. +message.desc.basic.zone=Fornece uma \u00fanica rede onde em cada inst\u00e2ncia de VM \u00e9 atribu\u00eddo um IP diretamente na rede. O isolamento Guest podem ser fornecidos atrav\u00e9s de camada-3 da rede com grupos de seguran\u00e7a (filtragem da fonte de endere\u00e7os IP). +message.desc.cluster=Cada pod deve conter um ou mais clusters, e iremos adicionar o primeiro cluster agora. Um cluster fornece uma maneira de agrupamento de hosts. Os hosts de um cluster t\u00eam hardware id\u00eantico, executam o mesmo hypervisor, est\u00e3o na mesma sub-rede e acessam o mesmo storage compartilhado. Cada cluster \u00e9 constitu\u00eddo por um ou mais hosts e um ou mais servidores de storage prim\u00e1rio. +message.desc.host=Cada cluster deve conter pelo menos um host (computador) para as VMs guest serem executadas e iremos adicionar o primeira host agora. Para um host funcionar no CloudStack, voc\u00ea deve instalar um hypervisor no host, atribuir um endere\u00e7o IP e garantir que o host est\u00e1 conectado ao servidor de gerenciamento do CloudStack.

Forne\u00e7a o hostname ou o endere\u00e7o IP do host, o nome de usu\u00e1rio (geralmente root) e a senha e qualquer label que voc\u00ea utiliza para categorizar os hosts. +message.desc.primary.storage=Cada cluster deve conter um ou mais servidores de storage prim\u00e1rio e iremos adicionar o primeiro agora. Um storage prim\u00e1rio, cont\u00e9m os volumes de disco para todas as VMs em execu\u00e7\u00e3o nos hosts do cluster. Utiliza qualquer protocolo compat\u00edvel com os padr\u00f5es que \u00e9 suportado pelo hypervisor utilizado. +message.desc.secondary.storage=Cada zona deve ter pelo menos um NFS ou servidor de storage secund\u00e1rio e iremos adicionar o primeiro agora. Um storage secund\u00e1rios armazena templates de VM, imagens ISO e snapshots do volume de disco da VM. Esse servidor deve estar dispon\u00edvel para todos os hosts na zona.

Fornecer o endere\u00e7o IP e o caminho exportados. +message.desc.zone=Uma zona \u00e9 a maior unidade organizacional no CloudStack e normalmente corresponde \u00e0 um \u00fanico datacenter. As Zonas disponibilizam isolamento f\u00edsico e redund\u00e2ncia. Uma zona \u00e9 composta por um ou mais pods (cada um dos quais cont\u00e9m os hosts e servidores de storage prim\u00e1rio) e um servidor de storage secund\u00e1rio que \u00e9 compartilhado por todos os pods na zona. message.detach.disk=Voc\u00ea tem certeza que deseja desconectar este disco ? -message.detach.iso.confirm=Confirme se voc\u00ea deseja desconectar a ISO do Cloud Server. +message.detach.iso.confirm=Confirme se voc\u00ea deseja desconectar o ISO da inst\u00e2ncia virtual. message.disable.account=Por favor confirme que voc\u00ea deseja desabilitar esta conta. Ap\u00f3s desabilitar uma conta, todos os usu\u00e1rios desta conta n\u00e3o ir\u00e3o possuir mais acesso aos seus recursos da cloud. Todas as m\u00e1quinas virtuais ser\u00e3o automaticamente desligadas. message.disable.snapshot.policy=Voc\u00ea desativou com sucesso sua pol\u00edtica de Snapshot. message.disable.user=Por favor confirme que voc\u00ea deseja desabilitar este usu\u00e1rio. @@ -1289,6 +1447,8 @@ message.enabling.security.group.provider=Habilitar provider de grupo de seguran\ message.enabling.zone=Habilitando zona message.enter.token=Por favor entre o token que voc\u00ea recebeu no e-mail privado. message.generate.keys=Por favor confirme que voc\u00ea deseja gerar novas chaves para este usu\u00e1rio. +message.guest.traffic.in.advanced.zone=O tr\u00e1fego de rede guest \u00e9 para comunica\u00e7\u00e3o entre m\u00e1quinas virtuais do usu\u00e1rio final. Especifique um intervalo de IDs de VLAN para transportar o tr\u00e1fego do guest para cada rede f\u00edsica. +message.guest.traffic.in.basic.zone=O tr\u00e1fego de rede guest \u00e9 para comunica\u00e7\u00e3o entre m\u00e1quinas virtuais do usu\u00e1rio final. Especifique um intervalo de endere\u00e7os IP para que CloudStack possa atribuir \u00e0s VMs. Certifique-se que este intervalo n\u00e3o se sobreponha o range de IPs reservados do sistema. message.installWizard.click.retry=Click no bot\u00e3o para tentar executar novamente. message.installWizard.copy.whatIsACluster=Um cluster prov\u00ea uma maneira de agrupar hosts. Os hosts em um cluster tem hardware id\u00eantico, rodam o mesmo hypervisor, est\u00e3o na mesma subnet, acessam o mesmo storage compartilhado. Inst\u00e2ncias de m\u00e1quinas virtuais (VMs) podem ser migradas a quente - live migration - de um host para outro host no mesmo cluster, sem interromper o servi\u00e7o para o usu\u00e1rio. Um Cluster \u00e9 a terceira maior unidade organizacional em uma instala\u00e7\u00e3o CloudStack&\#8482; . Clusters est\u00e3o contidos em pods e pods est\u00e3o contidos em zonas.

O CloudStack&\#8482; permite m\u00faltiplos clusters em uma mesma cloud, entretanto para a instala\u00e7\u00e3o b\u00e1sica, n\u00f3s iremos precisar apenas de um cluster. message.installWizard.copy.whatIsAHost=Um host \u00e9 um \u00fanico computador. Os Hosts prov\u00eaem os recursos computacionais para executar as m\u00e1quinas virtuais. Cada host possu\u00ed o software do hypervisor instalado nele para gerenciar as guest VMs (Exceto os hosts bare metal, que s\u00e3o um caso especial discutido no Guia Avan\u00e7ado de Instala\u00e7\u00e3o). Por exemplo, um servidor Linux com KVM habilitado, um servidor Citrix XenServer e um servidor ESXi s\u00e3o hosts. Na Instala\u00e7\u00e3o B\u00e1sica, n\u00f3s utilizamos um \u00fanico host rodando XenServer ou KVM.

O host \u00e9 a menor unidade organizacional dentro de uma instala\u00e7\u00e3o CloudStack&\#8482; . Hosts est\u00e3o contidos dentro de Clusters, clusters est\u00e3o contidos dentro de pods e pods est\u00e3o contidos dentro de zonas. @@ -1318,25 +1478,26 @@ message.installWizard.tooltip.addZone.internaldns1=Estes s\u00e3o os servidores message.installWizard.tooltip.addZone.internaldns2=Estes s\u00e3o os servidores DNS utilizados pelas VMs de sistema nesta zona. Estes servidores DNS ser\u00e3o acessados atrav\u00e9s da interface de rede privada das VMs de sistema. O endere\u00e7o IP privado que voc\u00ea configurar para os pods deve possuir uma rota para os servidores DNS configurados aqui. message.installWizard.tooltip.addZone.name=Um nome para a zona message.installWizard.tooltip.configureGuestTraffic.description=Uma descri\u00e7\u00e3o da sua rede -message.installWizard.tooltip.configureGuestTraffic.guestEndIp=O range de endere\u00e7os IP que estar\u00e1 dispon\u00edvel para aloca\u00e7\u00e3o para os guests nesta zona. Caso uma NIC seja utilizada, estes IPs devem estar no mesmo CIDR que o CIDR do pod. +message.installWizard.tooltip.configureGuestTraffic.guestEndIp=O range de endere\u00e7os IP que estar\u00e1 dispon\u00edvel para aloca\u00e7\u00e3o para os guests nesta zona. Caso uma Interface de Rede seja utilizada, estes IPs devem estar no mesmo CIDR que o CIDR do pod. message.installWizard.tooltip.configureGuestTraffic.guestGateway=O gateway que os guests devem usar message.installWizard.tooltip.configureGuestTraffic.guestNetmask=A m\u00e1scara de rede da subrede que os guests devem usar -message.installWizard.tooltip.configureGuestTraffic.guestStartIp=O range de endere\u00e7os IP que estar\u00e1 dispon\u00edvel para aloca\u00e7\u00e3o para os guests nesta zona. Caso uma NIC seja utilizada, estes IPs devem estar no mesmo CIDR que o CIDR do pod. +message.installWizard.tooltip.configureGuestTraffic.guestStartIp=O range de endere\u00e7os IP que estar\u00e1 dispon\u00edvel para aloca\u00e7\u00e3o para os guests nesta zona. Caso uma Interface de Rede seja utilizada, estes IPs devem estar no mesmo CIDR que o CIDR do pod. message.installWizard.tooltip.configureGuestTraffic.name=Um nome para sua rede message.instanceWizard.noTemplates=Voc\u00ea n\u00e3o possui nenhum template dispon\u00edvel; por favor adicione um template compat\u00edvel e reinicie o wizard de inst\u00e2ncia. message.ip.address.changed=Seu endere\u00e7o IP pode ter mudado; voc\u00ea gostaria de atualizar a listagem ? Note que neste caso o painel de detalhes ir\u00e1 fechar. message.iso.desc=Imagem de disco contendo dados ou m\u00eddia de sistema operacional boot\u00e1vel message.join.project=Voc\u00ea agora entrou em um projeto. Por favor troque para a vis\u00e3o de Projeto para visualizar o projeto. -message.launch.vm.on.private.network=Voc\u00ea deseja executar sua inst\u00e2ncia na sua pr\u00f3pria rede privada dedicada ? -message.launch.zone=A zona est\u00e1 pronta para ser executada; por favor continue para o pr\u00f3ximo passo. +message.launch.vm.on.private.network=Voc\u00ea deseja executar a sua inst\u00e2ncia na sua pr\u00f3pria rede privada dedicada? +message.launch.zone=A zona est\u00e1 pronta para ser executada; por favor, v\u00e1 para o pr\u00f3ximo passo. message.lock.account=Confirme se voc\u00ea deseja bloquear esta conta. Bloqueando a conta, todos os Usu\u00e1rios desta conta n\u00e3o estar\u00e3o mais habilitados a gerenciar os recursos na nuvem. Os recursos existentes (Cloud Server) ainda poder\u00e3o ser acessados. -message.migrate.instance.confirm=Confirme o host que voc\u00ea deseja migrar o Cloud Server. +message.migrate.instance.confirm=Confirme o host que voc\u00ea deseja migrar a inst\u00e2ncia virtual. message.migrate.instance.to.host=Por favor confirme que voc\u00ea deseja migrar a inst\u00e2ncia para outro host. message.migrate.instance.to.ps=Por favor confirme que voc\u00ea deseja migrar a inst\u00e2ncia para outro storage prim\u00e1rio. message.migrate.router.confirm=Por favor confirme o host que voc\u00ea deseja migrar o roteador para\: message.migrate.systemvm.confirm=Por favor confirme o host para o qual voc\u00ea deseja migrar a VM de sistema\: message.migrate.volume=Por favor confirme que voc\u00ea deseja migrar o volume para outro storage prim\u00e1rio. message.new.user=Especifique abaixo para adicionar novos usu\u00e1rios para a conta +message.no.affinity.groups=Voc\u00ea n\u00e3o tem nenhum grupo de afinidade. Por favor, v\u00e1 para o pr\u00f3ximo passo. message.no.network.support.configuration.not.true=Voc\u00ea n\u00e3o possui nenhuma zona com grupos de seguran\u00e7a habilitado. Assim sendo, n\u00e3o possui recursos adicionais de rede. Por favor continue para o passo 5. message.no.network.support=O hypervisor escolhido, vSphere, n\u00e3o possui nenhum recurso de rede adicional. Por favor, v\u00e1 para o passo 5. message.no.projects.adminOnly=Voc\u00ea n\u00e3o possui nenhum projeto.
Por favor solicite ao seu administrador a cria\u00e7\u00e3o de um novo projeto. @@ -1349,15 +1510,20 @@ message.number.zones=

Zonas

message.pending.projects.1=Voc\u00ea possui convites de projetos pendentes\: message.pending.projects.2=Para visualizar, por favor acesse a se\u00e7\u00e3o de projetos, depois selecione os convites no menu drop-down. message.please.add.at.lease.one.traffic.range=Por favor adicione pelo menos um range de tr\u00e1fego. -message.please.proceed=Por favor continue para o pr\u00f3ximo passo. +message.please.proceed=Por favor, v\u00e1 para o pr\u00f3ximo passo. message.please.select.a.configuration.for.your.zone=Por favor selecione uma configuracao para sua zona. message.please.select.a.different.public.and.management.network.before.removing=Por favor selecione uma rede p\u00fablica e de gerenciamento diferente antes de remover message.please.select.networks=Por favor selecione as redes para sua m\u00e1quina virtual. message.please.wait.while.zone.is.being.created=Por favor, espere enquanto sua zona est\u00e1 sendo criada; isto pode demorar um pouco... message.project.invite.sent=Convite enviado para o usu\u00e1rio; Eles ser\u00e3o adicionados ao projeto ap\u00f3s aceitarem o convite +message.public.traffic.in.advanced.zone=O tr\u00e1fego p\u00fablico \u00e9 gerado quando as VMs na nuvem acessam a internet. Os IPs acess\u00edveis ao p\u00fablico devem ser alocados para essa finalidade. Os usu\u00e1rios finais podem usar a interface do usu\u00e1rio CloudStack para adquirir esses IPs afim de implementar NAT entre a sua rede de guests e sua rede p\u00fablica.

Forne\u00e7a pelo menos um intervalo de endere\u00e7os IP para o tr\u00e1fego de internet. +message.public.traffic.in.basic.zone=O tr\u00e1fego p\u00fablico \u00e9 gerado quando as VMs na nuvem acessam a Internet ou prestam servi\u00e7os aos clientes atrav\u00e9s da Internet. Os IPs acess\u00edveis ao p\u00fablico devem ser alocados para essa finalidade. Quando uma inst\u00e2ncia \u00e9 criada, um IP a partir deste conjunto de IPs p\u00fablicos ser\u00e3o destinados \u00e0 inst\u00e2ncia, al\u00e9m do endere\u00e7o IP guest. Um NAT est\u00e1tico 1-1 ser\u00e1 criada automaticamente entre o IP p\u00fablico e IP guest. Os usu\u00e1rios finais tamb\u00e9m podem usar a interface de usu\u00e1rio CloudStack para adquirir IPs adicionais afim de se implementar NAT est\u00e1tico entre suas inst\u00e2ncias e o IP p\u00fablico. +message.redirecting.region=Redirecionando para regi\u00e3o... +message.remove.ldap=Voc\u00ea tem certeza que deseja deletar a configura\u00e7\u00e3o LDAP? +message.remove.region=Voc\u00ea tem certeza que deseja remover esta regi\u00e3o deste servidor de gerenciamento? message.remove.vpc=Favor confirmar que voc\u00ea deseja remover a VPC message.remove.vpn.access=Confirme se voc\u00ea deseja remover acesso VPN do seguinte Usu\u00e1rio. -message.reset.password.warning.notPasswordEnabled=O template desta inst\u00e2ncia foi criado sem senha habilitada +message.reset.password.warning.notPasswordEnabled=O template desta inst\u00e2ncia foi criado sem uma senha habilitada message.reset.password.warning.notStopped=Sua inst\u00e2ncia deve estar parada antes de tentar trocar sua senha atual message.reset.VPN.connection=Favor confirmar que voc\u00ea deseja resetar a conex\u00e3o VPN message.restart.mgmt.server=Reinicie o(s) servidor(es) de gerenciamento para que a nova configura\u00c3\u00a7\u00c3\u00a3o tenha efeito. @@ -1365,26 +1531,30 @@ message.restart.mgmt.usage.server=Por favor reinicie seu servidor(es) de gerenci message.restart.network=Por favor confirme que voc\ufffd deseja reiniciar a rede message.restart.vpc=Favor confirmar que voc\u00ea deseja reiniciar a VPC message.security.group.usage=(Use Ctrl-clique para selecionar todos os Security Groups) +message.select.affinity.groups=Por favor, selecione quaisquer grupos de afinidade que voc\u00ea deseja que esta VM perten\u00e7a\: message.select.a.zone=A zone tipicamente corresponde a um \u00fanico datacenter. M\u00faltiplas zonas auxiliam a cloud a ser mais confi\u00e1vel provendo isolamento f\u00edsico e redund\u00e2ncia. message.select.instance=Por favor selecione uma inst\u00e2ncia. message.select.iso=Por favor selecione um ISO para sua nova inst\u00e2ncia virtual message.select.item=Por favor selecione um item. message.select.security.groups=Por favor selecione o(s) grupo(s) de seguran\u00e7a para sua nova VM message.select.template=Por favor selecione um template para sua nova inst\u00e2ncia virtual. -message.setup.physical.network.during.zone.creation.basic=Quando adicionar uma zona b\u00e1sica, voc\u00ea pode configurar uma rede f\u00edsica, que corresponde a uma NIC no hypervisor. A rede carrega diversos tipos de tr\u00e1fego.

Voc\u00ea pode adicionar e remover outros tipos de tr\u00e1fego na mesma interface de rede f\u00edsica. +message.setup.physical.network.during.zone.creation=Ao adicionar uma zona avan\u00e7ada, voc\u00ea precisa configurar uma ou mais redes f\u00edsicas. Cada rede corresponde \u00e0 uma Interface de Rede no hypervisor. Cada rede f\u00edsica pode ser utilizada para transportar um ou mais tipos de tr\u00e1fego, com certas restri\u00e7\u00f5es sobre como eles podem ser combinados.
Arraste e solte um ou mais tipos de tr\u00e1fego em cada rede f\u00edsica. +message.setup.physical.network.during.zone.creation.basic=Quando adicionar uma zona b\u00e1sica, voc\u00ea pode configurar uma rede f\u00edsica, que corresponde a uma Interface de Rede no hypervisor. A rede carrega diversos tipos de tr\u00e1fego.

Voc\u00ea pode adicionar e remover outros tipos de tr\u00e1fego na mesma interface de rede f\u00edsica. message.setup.successful=Cloud configurada com sucesso\! message.snapshot.schedule=Voc\u00ea pode configurar Snapshots recorrentes agendados selecionando as op\u00e7\u00f5es Dispon\u00edveis abaixo message.specify.url=Por favor especifique a URL message.step.1.continue=Selecione o template ou ISO para continuar -message.step.1.desc=Selecione o template para o novo Cloud Server. +message.step.1.desc=Por favor, selecione um template para a sua nova inst\u00e2ncia virtual. Voc\u00ea pode tamb\u00e9m escolher um template limpo e instalar a partir de uma imagem ISO. message.step.2.continue=Selecione o plano message.step.2.desc= message.step.3.continue=Seleciona a oferta de disco message.step.3.desc= message.step.4.continue=Selecione pelo menos uma rede para continuar -message.step.4.desc=Selecione a rede principal que seu Cloud Server ser\u00e1 conectado. +message.step.4.desc=Selecione a rede principal que a sua inst\u00e2ncia virtual estar\u00e1 conectada. +message.storage.traffic=Tr\u00e1fego entre os recursos internos do CloudStack, incluindo todos os componentes que se comunicam com o servidor de gerenciamento tais como hosts e m\u00e1quinas virtuais de sistema CloudStack. Por favor, configure o tr\u00e1fego do storage aqui. message.suspend.project=Voc\u00ea tem certeza que deseja suspender este projeto ? message.template.desc=Imagem de SO que pode ser utilizada para bootar VMs +message.tooltip.dns.1=Endere\u00e7o de um servidor DNS que ser\u00e1 utilizado por todas as VMs da Zone. A faixa de IPs p\u00fablicos para essa Zone deve possuir uma rota para o servidor configurado. message.tooltip.dns.2=Um servidor DNS secund\u00e1rio para ser utilizado pelas VMs nesta zona. Os endere\u00e7os IP p\u00fablicos nesta zona devem ter rota para este servidor. message.tooltip.internal.dns.1=Nome de um servidor DNS que ser\u00e1 utilizado pelas VMs internas de sistema do CloudStack nesta zona. Os endere\u00e7os privados dos pods devem ter uma rota para este servidor. message.tooltip.internal.dns.2=Nome de um servidor DNS que ser\u00e1 utilizado pelas VMs internas de sistema do CloudStack nesta zona. Os endere\u00e7os privados dos pods devem ter uma rota para este servidor. @@ -1393,10 +1563,11 @@ message.tooltip.pod.name=Um nome para este pod. message.tooltip.reserved.system.gateway=O gateway para os hosts neste pod. message.tooltip.reserved.system.netmask=O prefixo de rede que define a subrede deste pod. Utilize a nota\u00e7\u00e3o CIDR. message.tooltip.zone.name=Um nome para a zona. -message.update.os.preference=Escolha o SO de preferencia para este host. Todos Cloud Server com preferencias similares ser\u00e3o alocados neste host antes de tentar em outro. +message.update.os.preference=Escolha o SO de preferencia para este host. Todas Inst\u00e2ncias com preferencias similares ser\u00e3o alocadas neste host antes de tentar em outro. message.update.resource.count=Por favor confirme que voc\u00ea quer atualizar a contagem de recursos para esta conta. message.update.ssl=Envie o novo certificado SSL X.509 para ser atualizado em cada console proxy\: message.validate.instance.name=Nomes de inst\u00e2ncias n\u00e3o podem ter mais de 63 caracteres. Somente letras ASCII a~z, A~Z, d\u00edgitos 0~9 e h\u00edfen s\u00e3o permitidos. Deve come\u00e7ar com uma letra e terminar com uma letra ou d\u00edgito. +message.validate.invalid.characters=Caracteres inv\u00e1lidos encontrados, por favor corrija. message.virtual.network.desc=Rede virtual dedicado para sua conta. O Dom\u00ednio de broadcast Est\u00e1 na VLAN e todo acesso a internet \u00e9 roteado atrav\u00e9s do virtual router. message.vm.create.template.confirm=Criar Template reiniciar\u00e1 a VM automaticamente. message.vm.review.launch=Por favor revise a informa\u00e7\u00e3o abaixo e confirme que sua inst\u00e2ncia virtual est\u00e1 correta antes de executa-la. @@ -1419,6 +1590,8 @@ state.Accepted=Aceito state.Active=Ativo state.Allocated=Alocado state.Allocating=Alocando +state.BackedUp=Back up realizado com sucesso +state.BackingUp=Realizando Back up state.Completed=Completo state.Creating=Criando state.Declined=Recusado @@ -1427,6 +1600,7 @@ state.Disabled=Desativado state.enabled=Habilitado state.Enabled=Habilitado state.Error=Erro +state.Expunging=Removendo state.Migrating=Migrando state.Pending=Pendente state.ready=Pronto diff --git a/client/WEB-INF/classes/resources/messages_ru_RU.properties b/client/WEB-INF/classes/resources/messages_ru_RU.properties index 62c791f61b9f..63a746222a92 100644 --- a/client/WEB-INF/classes/resources/messages_ru_RU.properties +++ b/client/WEB-INF/classes/resources/messages_ru_RU.properties @@ -283,12 +283,12 @@ label.add.to.group=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043 label.add=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c label.add.user=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f label.add.vlan=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c VLAN -label.add.vxlan=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c VXLAN label.add.vms.to.lb=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0412\u041c \u0432 \u043f\u0440\u0430\u0432\u0438\u043b\u043e \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u0438 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 label.add.vms=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0412\u041c label.add.vm=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0412\u041c label.add.volume=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043c label.add.vpn.user=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f VPN +label.add.vxlan=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c VXLAN label.add.zone=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0437\u043e\u043d\u0443 label.admin.accounts=\u0410\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0441\u043a\u0438\u0435 \u0443\u0447\u0451\u0442\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 label.admin=\u0410\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440 @@ -1005,9 +1005,6 @@ label.virtual.router=\u0412\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044 label.vlan.id=ID VLAN label.vlan.range=\u0414\u0438\u0430\u043f\u0430\u0437\u043e\u043d VLAN label.vlan=VLAN -label.vxlan.id=VXLAN ID -label.vxlan.range=\u0414\u0438\u0430\u043f\u0430\u0437\u043e\u043d Range -label.vxlan=VXLAN label.vm.add=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043c\u0430\u0448\u0438\u043d\u044b label.vm.destroy=\u0423\u043d\u0438\u0447\u0442\u043e\u0436\u0438\u0442\u044c label.vm.display.name=\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u043e\u0435 \u0438\u043c\u044f \u0412\u041c @@ -1021,6 +1018,8 @@ label.vm.state=\u0421\u0442\u0430\u0442\u0443\u0441 \u0441\u0435\u0440\u0432\u04 label.vm.stop=\u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c label.vms=\u0412\u041c label.vmware.traffic.label=\u041c\u0435\u0442\u043a\u0430 \u0442\u0440\u0430\u0444\u0438\u043a\u0430 VMware +label.vnet.id=ID VLAN +label.vnet=VLAN label.volgroup=\u0413\u0440\u0443\u043f\u043f\u0430 \u0442\u043e\u043c\u0430 label.volume.limits=\u041f\u0440\u0435\u0434\u0435\u043b\u044b \u0442\u043e\u043c\u043e\u0432 label.volume.name=\u0418\u043c\u044f \u0442\u043e\u043c\u0430 @@ -1031,6 +1030,9 @@ label.vsmctrlvlanid=\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 label.vsmpktvlanid=\u041f\u0430\u043a\u0435\u0442 VLAN ID label.vsmstoragevlanid=\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435 VLAN ID label.vsphere.managed=\u041e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u0435 vSphere +label.vxlan.id=VXLAN ID +label.vxlan.range=\u0414\u0438\u0430\u043f\u0430\u0437\u043e\u043d Range +label.vxlan=VXLAN label.waiting=\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 label.warn=\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435 label.wednesday=\u0421\u0440\u0435\u0434\u0430 diff --git a/client/WEB-INF/classes/resources/messages_zh_CN.properties b/client/WEB-INF/classes/resources/messages_zh_CN.properties index acb67bb51f7d..abab7c7dcdd0 100644 --- a/client/WEB-INF/classes/resources/messages_zh_CN.properties +++ b/client/WEB-INF/classes/resources/messages_zh_CN.properties @@ -14,32 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -label.delete.events=\u5220\u9664\u4e8b\u4ef6 -label.delete.alerts=\u5220\u9664\u8b66\u62a5 -label.archive.alerts=\u5b58\u6863\u8b66\u62a5 -label.archive.events=\u5b58\u6863\u4e8b\u4ef6 -label.by.alert.type=\u6309\u8b66\u62a5\u7c7b\u578b -label.by.event.type=\u6309\u4e8b\u4ef6\u7c7b\u578b -label.by.date.start=\u6309\u65e5\u671f(\u5f00\u59cb\u65e5\u671f) -label.by.date.end=\u6309\u65e5\u671f(\u7ed3\u675f\u65e5\u671f) -label.switch.type=\u4ea4\u6362\u673a\u7c7b\u578b -label.service.state=\u670d\u52a1\u72b6\u6001 -label.egress.default.policy=\u51fa\u53e3\u9ed8\u8ba4\u7b56\u7565 -label.routing=\u6b63\u5728\u8def\u7531 -label.about=\u5173\u4e8e -label.app.name=CloudStack -label.about.app=\u5173\u4e8e CloudStack -label.custom.disk.iops=\u81ea\u5b9a\u4e49 IOPS -label.disk.iops.min=\u6700\u5c0f IOPS -label.disk.iops.max=\u6700\u5927 IOPS -label.disk.iops.total=\u603b IOPS -label.view.secondary.ips=\u67e5\u770b\u8f85\u52a9 IP -message.validate.invalid.characters=\u67e5\u627e\u5230\u65e0\u6548\u5b57\u7b26\uff0c\u8bf7\u66f4\u6b63\u3002 -message.acquire.ip.nic=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u83b7\u53d6\u6b64 NIC \u7684\u65b0\u8f85\u52a9 IP\u3002
\u6ce8\u610f: \u60a8\u9700\u8981\u5728\u865a\u62df\u673a\u5185\u90e8\u624b\u52a8\u914d\u7f6e\u65b0\u83b7\u53d6\u7684\u8f85\u52a9 IP\u3002 -message.select.affinity.groups=\u8bf7\u9009\u62e9\u60a8\u5e0c\u671b\u6b64 VM \u6240\u5c5e\u7684\u4efb\u4f55\u5173\u8054\u6027\u7ec4: -message.no.affinity.groups=\u60a8\u6ca1\u6709\u4efb\u4f55\u5173\u8054\u6027\u7ec4\u3002\u8bf7\u7ee7\u7eed\u6267\u884c\u4e0b\u4e00\u6b65\u64cd\u4f5c\u3002 -label.action.delete.nic=\u79fb\u9664 NIC -message.action.delete.nic=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u79fb\u9664\u6b64 NIC\uff0c\u6b64\u64cd\u4f5c\u8fd8\u5c06\u4ece VM \u4e2d\u79fb\u9664\u5173\u8054\u7684\u7f51\u7edc\u3002 + changed.item.properties=\u66f4\u6539\u9879\u76ee\u5c5e\u6027 confirm.enable.s3=\u8bf7\u586b\u5199\u4ee5\u4e0b\u4fe1\u606f\u4ee5\u542f\u7528\u5bf9 S3 \u652f\u6301\u7684\u8f85\u52a9\u5b58\u50a8\u7684\u652f\u6301 confirm.enable.swift=\u8bf7\u586b\u5199\u4ee5\u4e0b\u4fe1\u606f\u4ee5\u542f\u7528\u5bf9 SWIFT \u7684\u652f\u6301 @@ -67,13 +42,15 @@ ICMP.type=ICMP \u7c7b\u578b image.directory=\u56fe\u7247\u76ee\u5f55 inline=\u5185\u8054 instances.actions.reboot.label=\u91cd\u65b0\u542f\u52a8\u5b9e\u4f8b +label.about.app=\u5173\u4e8e CloudStack +label.about=\u5173\u4e8e label.accept.project.invitation=\u63a5\u53d7\u9879\u76ee\u9080\u8bf7 label.account.and.security.group=\u5e10\u6237\u3001\u5b89\u5168\u7ec4 label.account.id=\u5e10\u6237 ID label.account.name=\u5e10\u6237\u540d\u79f0 label.account.specific=\u5e10\u6237\u4e13\u7528 -label.account=\u5e10\u6237 label.accounts=\u5e10\u6237 +label.account=\u5e10\u6237 label.acquire.new.ip=\u83b7\u53d6\u65b0 IP label.acquire.new.secondary.ip=\u83b7\u53d6\u65b0\u8f85\u52a9 IP label.action.attach.disk.processing=\u6b63\u5728\u9644\u52a0\u78c1\u76d8... @@ -118,6 +95,7 @@ label.action.delete.load.balancer=\u5220\u9664\u8d1f\u8f7d\u5e73\u8861\u5668\u89 label.action.delete.network.processing=\u6b63\u5728\u5220\u9664\u7f51\u7edc... label.action.delete.network=\u5220\u9664\u7f51\u7edc label.action.delete.nexusVswitch=\u5220\u9664 Nexus 1000v +label.action.delete.nic=\u79fb\u9664 NIC label.action.delete.physical.network=\u5220\u9664\u7269\u7406\u7f51\u7edc label.action.delete.pod.processing=\u6b63\u5728\u5220\u9664\u63d0\u4f9b\u70b9... label.action.delete.pod=\u5220\u9664\u63d0\u4f9b\u70b9 @@ -246,6 +224,7 @@ label.action.stop.router.processing=\u6b63\u5728\u505c\u6b62\u8def\u7531\u5668.. label.action.stop.router=\u505c\u6b62\u8def\u7531\u5668 label.action.stop.systemvm.processing=\u6b63\u5728\u505c\u6b62\u7cfb\u7edf VM... label.action.stop.systemvm=\u505c\u6b62\u7cfb\u7edf VM +label.actions=\u64cd\u4f5c label.action.take.snapshot.processing=\u6b63\u5728\u521b\u5efa\u5feb\u7167... label.action.take.snapshot=\u521b\u5efa\u5feb\u7167 label.action.unmanage.cluster.processing=\u6b63\u5728\u53d6\u6d88\u6258\u7ba1\u7fa4\u96c6... @@ -257,13 +236,12 @@ label.action.update.resource.count=\u66f4\u65b0\u8d44\u6e90\u6570\u91cf label.action.vmsnapshot.create=\u521b\u5efa VM \u5feb\u7167 label.action.vmsnapshot.delete=\u5220\u9664 VM \u5feb\u7167 label.action.vmsnapshot.revert=\u8fd8\u539f\u5230 VM \u5feb\u7167 -label.actions=\u64cd\u4f5c label.activate.project=\u6fc0\u6d3b\u9879\u76ee label.active.sessions=\u6d3b\u52a8\u4f1a\u8bdd -label.add.account.to.project=\u5411\u9879\u76ee\u4e2d\u6dfb\u52a0\u5e10\u6237 -label.add.account=\u6dfb\u52a0\u5e10\u6237 label.add.accounts.to=\u6dfb\u52a0\u5e10\u6237\u81f3 label.add.accounts=\u6dfb\u52a0\u5e10\u6237 +label.add.account.to.project=\u5411\u9879\u76ee\u4e2d\u6dfb\u52a0\u5e10\u6237 +label.add.account=\u6dfb\u52a0\u5e10\u6237 label.add.ACL=\u6dfb\u52a0 ACL label.add.affinity.group=\u6dfb\u52a0\u65b0\u5173\u8054\u6027\u7ec4 label.add.BigSwitchVns.device=\u6dfb\u52a0 BigSwitch Vns \u63a7\u5236\u5668 @@ -280,8 +258,17 @@ label.add.F5.device=\u6dfb\u52a0 F5 \u8bbe\u5907 label.add.firewall=\u6dfb\u52a0\u9632\u706b\u5899\u89c4\u5219 label.add.guest.network=\u6dfb\u52a0\u6765\u5bbe\u7f51\u7edc label.add.host=\u6dfb\u52a0\u4e3b\u673a +label.adding.cluster=\u6b63\u5728\u6dfb\u52a0\u7fa4\u96c6 +label.adding.failed=\u6dfb\u52a0\u5931\u8d25 +label.adding.pod=\u6b63\u5728\u6dfb\u52a0\u63d0\u4f9b\u70b9 +label.adding.processing=\u6b63\u5728\u6dfb\u52a0... label.add.ingress.rule=\u6dfb\u52a0\u5165\u53e3\u89c4\u5219 +label.adding.succeeded=\u5df2\u6210\u529f\u6dfb\u52a0 +label.adding=\u6b63\u5728\u6dfb\u52a0 +label.adding.user=\u6b63\u5728\u6dfb\u52a0\u7528\u6237 +label.adding.zone=\u6b63\u5728\u6dfb\u52a0\u533a\u57df label.add.ip.range=\u6dfb\u52a0 IP \u8303\u56f4 +label.additional.networks=\u5176\u4ed6\u7f51\u7edc label.add.load.balancer=\u6dfb\u52a0\u8d1f\u8f7d\u5e73\u8861\u5668 label.add.more=\u6dfb\u52a0\u66f4\u591a label.add.netScaler.device=\u6dfb\u52a0 Netscaler \u8bbe\u5907 @@ -312,36 +299,27 @@ label.add.static.route=\u6dfb\u52a0\u9759\u6001\u8def\u7531 label.add.system.service.offering=\u6dfb\u52a0\u7cfb\u7edf\u670d\u52a1\u65b9\u6848 label.add.template=\u6dfb\u52a0\u6a21\u677f label.add.to.group=\u6dfb\u52a0\u5230\u7ec4 +label.add=\u6dfb\u52a0 label.add.user=\u6dfb\u52a0\u7528\u6237 label.add.vlan=\u6dfb\u52a0 VLAN -label.add.vxlan=\u6dfb\u52a0 VXLAN -label.add.VM.to.tier=\u5411\u5c42\u4e2d\u6dfb\u52a0 VM -label.add.vm=\u6dfb\u52a0 VM label.add.vms.to.lb=\u5411\u8d1f\u8f7d\u5e73\u8861\u5668\u89c4\u5219\u4e2d\u6dfb\u52a0 VM label.add.vms=\u6dfb\u52a0 VM +label.add.VM.to.tier=\u5411\u5c42\u4e2d\u6dfb\u52a0 VM +label.add.vm=\u6dfb\u52a0 VM label.add.volume=\u6dfb\u52a0\u5377 label.add.vpc=\u6dfb\u52a0 VPC label.add.vpn.customer.gateway=\u6dfb\u52a0 VPN \u5ba2\u6237\u7f51\u5173 label.add.VPN.gateway=\u6dfb\u52a0 VPN \u7f51\u5173 label.add.vpn.user=\u6dfb\u52a0 VPN \u7528\u6237 +label.add.vxlan=\u6dfb\u52a0 VXLAN label.add.zone=\u6dfb\u52a0\u533a\u57df -label.add=\u6dfb\u52a0 -label.adding.cluster=\u6b63\u5728\u6dfb\u52a0\u7fa4\u96c6 -label.adding.failed=\u6dfb\u52a0\u5931\u8d25 -label.adding.pod=\u6b63\u5728\u6dfb\u52a0\u63d0\u4f9b\u70b9 -label.adding.processing=\u6b63\u5728\u6dfb\u52a0... -label.adding.succeeded=\u5df2\u6210\u529f\u6dfb\u52a0 -label.adding.user=\u6b63\u5728\u6dfb\u52a0\u7528\u6237 -label.adding.zone=\u6b63\u5728\u6dfb\u52a0\u533a\u57df -label.adding=\u6b63\u5728\u6dfb\u52a0 -label.additional.networks=\u5176\u4ed6\u7f51\u7edc label.admin.accounts=\u7ba1\u7406\u5458\u5e10\u6237 label.admin=\u7ba1\u7406\u5458 label.advanced.mode=\u9ad8\u7ea7\u6a21\u5f0f label.advanced.search=\u9ad8\u7ea7\u641c\u7d22 label.advanced=\u9ad8\u7ea7 -label.affinity.group=\u5173\u8054\u6027\u7ec4 label.affinity.groups=\u5173\u8054\u6027\u7ec4 +label.affinity.group=\u5173\u8054\u6027\u7ec4 label.affinity=\u5173\u8054\u6027 label.agent.password=\u4ee3\u7406\u5bc6\u7801 label.agent.username=\u4ee3\u7406\u7528\u6237\u540d @@ -350,11 +328,14 @@ label.alert=\u8b66\u62a5 label.algorithm=\u7b97\u6cd5 label.allocated=\u5df2\u5206\u914d label.allocation.state=\u5206\u914d\u72b6\u6001 -label.anti.affinity.group=\u53cd\u5173\u8054\u6027\u7ec4 label.anti.affinity.groups=\u53cd\u5173\u8054\u6027\u7ec4 +label.anti.affinity.group=\u53cd\u5173\u8054\u6027\u7ec4 label.anti.affinity=\u53cd\u5173\u8054\u6027 label.api.key=API \u5bc6\u94a5 label.apply=\u5e94\u7528 +label.app.name=CloudStack +label.archive.alerts=\u5b58\u6863\u8b66\u62a5 +label.archive.events=\u5b58\u6863\u4e8b\u4ef6 label.assign.to.load.balancer=\u6b63\u5728\u5c06\u5b9e\u4f8b\u5206\u914d\u7ed9\u8d1f\u8f7d\u5e73\u8861\u5668 label.assign=\u5206\u914d label.associated.network.id=\u5df2\u5173\u8054\u7f51\u7edc ID @@ -362,8 +343,8 @@ label.associated.network=\u5173\u8054\u7f51\u7edc label.attached.iso=\u5df2\u9644\u52a0 ISO label.author.email=\u4f5c\u8005\u7535\u5b50\u90ae\u4ef6 label.author.name=\u4f5c\u8005\u59d3\u540d -label.availability.zone=\u53ef\u7528\u533a\u57df label.availability=\u53ef\u7528\u6027 +label.availability.zone=\u53ef\u7528\u533a\u57df label.available.public.ips=\u53ef\u7528\u516c\u7528 IP \u5730\u5740 label.available=\u53ef\u7528 label.back=\u540e\u9000 @@ -376,20 +357,24 @@ label.broadcast.domain.range=\u5e7f\u64ad\u57df\u8303\u56f4 label.broadcast.domain.type=\u5e7f\u64ad\u57df\u7c7b\u578b label.broadcast.uri=\u5e7f\u64ad URI label.by.account=\u6309\u5e10\u6237 +label.by.alert.type=\u6309\u8b66\u62a5\u7c7b\u578b label.by.availability=\u6309\u53ef\u7528\u6027 +label.by.date.end=\u6309\u65e5\u671f(\u7ed3\u675f\u65e5\u671f) +label.by.date.start=\u6309\u65e5\u671f(\u5f00\u59cb\u65e5\u671f) label.by.domain=\u6309\u57df label.by.end.date=\u6309\u7ed3\u675f\u65e5\u671f +label.by.event.type=\u6309\u4e8b\u4ef6\u7c7b\u578b label.by.level=\u6309\u7ea7\u522b label.by.pod=\u6309\u63d0\u4f9b\u70b9 label.by.role=\u6309\u89d2\u8272 label.by.start.date=\u6309\u5f00\u59cb\u65e5\u671f label.by.state=\u6309\u72b6\u6001 +label.bytes.received=\u63a5\u6536\u7684\u5b57\u8282\u6570 +label.bytes.sent=\u53d1\u9001\u7684\u5b57\u8282\u6570 label.by.traffic.type=\u6309\u901a\u4fe1\u7c7b\u578b label.by.type.id=\u6309\u7c7b\u578b ID label.by.type=\u6309\u7c7b\u578b label.by.zone=\u6309\u533a\u57df -label.bytes.received=\u63a5\u6536\u7684\u5b57\u8282\u6570 -label.bytes.sent=\u53d1\u9001\u7684\u5b57\u8282\u6570 label.cancel=\u53d6\u6d88 label.capacity=\u5bb9\u91cf label.certificate=\u8bc1\u4e66 @@ -398,32 +383,32 @@ label.change.value=\u66f4\u6539\u503c label.character=\u5b57\u7b26 label.checksum=MD5 \u6821\u9a8c\u548c label.cidr.account=CIDR \u6216\u5e10\u6237/\u5b89\u5168\u7ec4 +label.cidr=CIDR label.CIDR.list=CIDR \u5217\u8868 label.cidr.list=\u6e90 CIDR label.CIDR.of.destination.network=\u76ee\u7684\u5730\u7f51\u7edc\u7684 CIDR -label.cidr=CIDR label.clean.up=\u6e05\u7406 label.clear.list=\u6e05\u9664\u5217\u8868 label.close=\u5173\u95ed label.cloud.console=\u4e91\u7ba1\u7406\u63a7\u5236\u53f0 label.cloud.managed=\u7531 Cloud.com \u7ba1\u7406 label.cluster.name=\u7fa4\u96c6\u540d\u79f0 +label.clusters=\u7fa4\u96c6 label.cluster.type=\u7fa4\u96c6\u7c7b\u578b label.cluster=\u7fa4\u96c6 -label.clusters=\u7fa4\u96c6 label.clvm=CLVM label.code=\u4ee3\u7801 label.community=\u793e\u533a label.compute.and.storage=\u8ba1\u7b97\u4e0e\u5b58\u50a8 -label.compute.offering=\u8ba1\u7b97\u65b9\u6848 label.compute.offerings=\u8ba1\u7b97\u65b9\u6848 +label.compute.offering=\u8ba1\u7b97\u65b9\u6848 label.compute=\u8ba1\u7b97 label.configuration=\u914d\u7f6e label.configure.network.ACLs=\u914d\u7f6e\u7f51\u7edc ACL -label.configure.vpc=\u914d\u7f6e VPC label.configure=\u914d\u7f6e -label.confirm.password=\u786e\u8ba4\u5bc6\u7801 +label.configure.vpc=\u914d\u7f6e VPC label.confirmation=\u786e\u8ba4 +label.confirm.password=\u786e\u8ba4\u5bc6\u7801 label.congratulations=\u795d\u8d3a\u60a8\! label.conserve.mode=\u4fdd\u62a4\u6a21\u5f0f label.console.proxy=\u63a7\u5236\u53f0\u4ee3\u7406 @@ -433,16 +418,17 @@ label.corrections.saved=\u5df2\u4fdd\u5b58\u4fee\u6b63 label.cpu.allocated.for.VMs=\u5df2\u5206\u914d\u7ed9 VM \u7684 CPU label.cpu.allocated=\u5df2\u5206\u914d\u7684 CPU label.CPU.cap=CPU \u4e0a\u9650 +label.cpu=CPU label.cpu.limits=CPU \u9650\u5236 label.cpu.mhz=CPU (MHz) label.cpu.utilized=CPU \u5229\u7528\u7387 -label.cpu=CPU +label.created.by.system=\u7531\u7cfb\u7edf\u521b\u5efa +label.created=\u521b\u5efa\u65e5\u671f label.create.project=\u521b\u5efa\u9879\u76ee label.create.template=\u521b\u5efa\u6a21\u677f label.create.VPN.connection=\u521b\u5efa VPN \u8fde\u63a5 -label.created.by.system=\u7531\u7cfb\u7edf\u521b\u5efa -label.created=\u521b\u5efa\u65e5\u671f label.cross.zones=\u8de8\u533a\u57df +label.custom.disk.iops=\u81ea\u5b9a\u4e49 IOPS label.custom.disk.size=\u81ea\u5b9a\u4e49\u78c1\u76d8\u5927\u5c0f label.daily=\u6bcf\u5929 label.data.disk.offering=\u6570\u636e\u78c1\u76d8\u65b9\u6848 @@ -452,22 +438,24 @@ label.day.of.week=\u661f\u671f label.dead.peer.detection=\u5931\u6548\u5bf9\u7b49\u4f53\u68c0\u6d4b label.decline.invitation=\u62d2\u7edd\u9080\u8bf7 label.dedicated=\u4e13\u7528 +label.default=\u9ed8\u8ba4\u8bbe\u7f6e label.default.use=\u9ed8\u8ba4\u4f7f\u7528 label.default.view=\u9ed8\u8ba4\u89c6\u56fe -label.default=\u9ed8\u8ba4\u8bbe\u7f6e label.delete.affinity.group=\u5220\u9664\u5173\u8054\u6027\u7ec4 +label.delete.alerts=\u5220\u9664\u8b66\u62a5 label.delete.BigSwitchVns=\u79fb\u9664 BigSwitch Vns \u63a7\u5236\u5668 +label.delete.events=\u5220\u9664\u4e8b\u4ef6 label.delete.F5=\u5220\u9664 F5 label.delete.gateway=\u5220\u9664\u7f51\u5173 label.delete.NetScaler=\u5220\u9664 NetScaler label.delete.NiciraNvp=\u79fb\u9664 Nvp \u63a7\u5236\u5668 label.delete.project=\u5220\u9664\u9879\u76ee label.delete.SRX=\u5220\u9664 SRX +label.delete=\u5220\u9664 label.delete.VPN.connection=\u5220\u9664 VPN \u8fde\u63a5 label.delete.VPN.customer.gateway=\u5220\u9664 VPN \u5ba2\u6237\u7f51\u5173 label.delete.VPN.gateway=\u5220\u9664 VPN \u7f51\u5173 label.delete.vpn.user=\u5220\u9664 VPN \u7528\u6237 -label.delete=\u5220\u9664 label.deleting.failed=\u5220\u9664\u5931\u8d25 label.deleting.processing=\u6b63\u5728\u5220\u9664... label.description=\u8bf4\u660e @@ -479,17 +467,20 @@ label.detaching.disk=\u6b63\u5728\u53d6\u6d88\u9644\u52a0\u78c1\u76d8 label.details=\u8be6\u7ec6\u4fe1\u606f label.device.id=\u8bbe\u5907 ID label.devices=\u8bbe\u5907 -label.DHCP.server.type=DHCP \u670d\u52a1\u5668\u7c7b\u578b label.dhcp=DHCP +label.DHCP.server.type=DHCP \u670d\u52a1\u5668\u7c7b\u578b label.direct.ips=\u5171\u4eab\u7f51\u7edc IP +label.disabled=\u5df2\u7981\u7528 label.disable.provider=\u7981\u7528\u63d0\u4f9b\u7a0b\u5e8f label.disable.vpn=\u7981\u7528 VPN -label.disabled=\u5df2\u7981\u7528 label.disabling.vpn.access=\u6b63\u5728\u7981\u7528 VPN \u8bbf\u95ee label.disk.allocated=\u5df2\u5206\u914d\u7684\u78c1\u76d8 label.disk.bytes.read.rate=\u78c1\u76d8\u8bfb\u53d6\u901f\u5ea6(BPS) label.disk.bytes.write.rate=\u78c1\u76d8\u5199\u5165\u901f\u5ea6(BPS) +label.disk.iops.max=\u6700\u5927 IOPS +label.disk.iops.min=\u6700\u5c0f IOPS label.disk.iops.read.rate=\u78c1\u76d8\u8bfb\u53d6\u901f\u5ea6(IOPS) +label.disk.iops.total=\u603b IOPS label.disk.iops.write.rate=\u78c1\u76d8\u5199\u5165\u901f\u5ea6(IOPS) label.disk.offering=\u78c1\u76d8\u65b9\u6848 label.disk.read.bytes=\u78c1\u76d8\u8bfb\u53d6(\u5b57\u8282) @@ -504,8 +495,8 @@ label.display.name=\u663e\u793a\u540d\u79f0 label.display.text=\u663e\u793a\u6587\u672c label.dns.1=DNS 1 label.dns.2=DNS 2 -label.DNS.domain.for.guest.networks=\u6765\u5bbe\u7f51\u7edc\u7684 DNS \u57df label.dns=DNS +label.DNS.domain.for.guest.networks=\u6765\u5bbe\u7f51\u7edc\u7684 DNS \u57df label.domain.admin=\u57df\u7ba1\u7406\u5458 label.domain.id=\u57df ID label.domain.name=\u57df\u540d @@ -522,10 +513,11 @@ label.edit.network.details=\u7f16\u8f91\u7f51\u7edc\u8be6\u60c5 label.edit.project.details=\u7f16\u8f91\u9879\u76ee\u8be6\u60c5 label.edit.tags=\u7f16\u8f91\u6807\u7b7e label.edit.traffic.type=\u7f16\u8f91\u901a\u4fe1\u7c7b\u578b -label.edit.vpc=\u7f16\u8f91 VPC label.edit=\u7f16\u8f91 -label.egress.rule=\u51fa\u53e3\u89c4\u5219 +label.edit.vpc=\u7f16\u8f91 VPC +label.egress.default.policy=\u51fa\u53e3\u9ed8\u8ba4\u7b56\u7565 label.egress.rules=\u51fa\u53e3\u89c4\u5219 +label.egress.rule=\u51fa\u53e3\u89c4\u5219 label.elastic.IP=\u5f39\u6027 IP label.elastic.LB=\u5f39\u6027\u8d1f\u8f7d\u5e73\u8861\u5668 label.elastic=\u5f39\u6027 @@ -537,12 +529,12 @@ label.enable.vpn=\u542f\u7528 VPN label.enabling.vpn.access=\u6b63\u5728\u542f\u7528 VPN \u8bbf\u95ee label.enabling.vpn=\u6b63\u5728\u542f\u7528 VPN label.end.IP=\u7ed3\u675f IP +label.endpoint.or.operation=\u7aef\u70b9\u6216\u64cd\u4f5c +label.endpoint=\u7aef\u70b9 label.end.port=\u7ed3\u675f\u7aef\u53e3 label.end.reserved.system.IP=\u7ed3\u675f\u9884\u7559\u7cfb\u7edf IP label.end.vlan=\u7ed3\u675f VLAN label.end.vxlan=\u7ed3\u675f VXLAN -label.endpoint.or.operation=\u7aef\u70b9\u6216\u64cd\u4f5c -label.endpoint=\u7aef\u70b9 label.enter.token=\u8f93\u5165\u4ee4\u724c label.error.code=\u9519\u8bef\u4ee3\u7801 label.error=\u9519\u8bef @@ -591,14 +583,14 @@ label.hints=\u63d0\u793a label.host.alerts=\u4e3b\u673a\u8b66\u62a5 label.host.MAC=\u4e3b\u673a MAC label.host.name=\u4e3b\u673a\u540d\u79f0 +label.hosts=\u4e3b\u673a label.host.tags=\u4e3b\u673a\u6807\u7b7e label.host=\u4e3b\u673a -label.hosts=\u4e3b\u673a label.hourly=\u6bcf\u5c0f\u65f6 label.hypervisor.capabilities=\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u529f\u80fd label.hypervisor.type=\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u7c7b\u578b -label.hypervisor.version=\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u7248\u672c label.hypervisor=\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f +label.hypervisor.version=\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u7248\u672c label.id=ID label.IKE.DH=IKE DH \u7b97\u6cd5 label.IKE.encryption=IKE \u52a0\u5bc6\u7b97\u6cd5 @@ -618,16 +610,16 @@ label.installWizard.addPrimaryStorageIntro.subtitle=\u4ec0\u4e48\u662f\u4e3b\u5b label.installWizard.addPrimaryStorageIntro.title=\u6dfb\u52a0\u4e00\u4e2a\u4e3b\u5b58\u50a8 label.installWizard.addSecondaryStorageIntro.subtitle=\u4ec0\u4e48\u662f\u8f85\u52a9\u5b58\u50a8? label.installWizard.addSecondaryStorageIntro.title=\u6dfb\u52a0\u4e00\u4e2a\u8f85\u52a9\u5b58\u50a8 -label.installWizard.addZone.title=\u6dfb\u52a0\u533a\u57df label.installWizard.addZoneIntro.subtitle=\u4ec0\u4e48\u662f\u533a\u57df? label.installWizard.addZoneIntro.title=\u6dfb\u52a0\u4e00\u4e2a\u533a\u57df +label.installWizard.addZone.title=\u6dfb\u52a0\u533a\u57df label.installWizard.click.launch=\u8bf7\u5355\u51fb\u201c\u542f\u52a8\u201d\u6309\u94ae\u3002 label.installWizard.subtitle=\u6b64\u6559\u7a0b\u5c06\u5e2e\u52a9\u60a8\u8bbe\u7f6e CloudStack&\#8482 \u5b89\u88c5 label.installWizard.title=\u60a8\u597d\uff0c\u6b22\u8fce\u4f7f\u7528 CloudStack&\#8482 label.instance.limits=\u5b9e\u4f8b\u9650\u5236 label.instance.name=\u5b9e\u4f8b\u540d\u79f0 -label.instance=\u5b9e\u4f8b label.instances=\u5b9e\u4f8b +label.instance=\u5b9e\u4f8b label.internal.dns.1=\u5185\u90e8 DNS 1 label.internal.dns.2=\u5185\u90e8 DNS 2 label.internal.name=\u5185\u90e8\u540d\u79f0 @@ -636,34 +628,34 @@ label.introduction.to.cloudstack=CloudStack&\#8482 \u7b80\u4ecb label.invalid.integer=\u65e0\u6548\u6574\u6570 label.invalid.number=\u65e0\u6548\u6570\u5b57 label.invitations=\u9080\u8bf7 +label.invited.accounts=\u5df2\u9080\u8bf7\u7684\u5e10\u6237 label.invite.to=\u9080\u8bf7\u52a0\u5165 label.invite=\u9080\u8bf7 -label.invited.accounts=\u5df2\u9080\u8bf7\u7684\u5e10\u6237 label.ip.address=IP \u5730\u5740 +label.ipaddress=IP \u5730\u5740 label.ip.allocations=IP \u5206\u914d +label.ip=IP label.ip.limits=\u516c\u7528 IP \u9650\u5236 label.ip.or.fqdn=IP \u6216 FQDN label.ip.range=IP \u8303\u56f4 label.ip.ranges=IP \u8303\u56f4 -label.ip=IP -label.ipaddress=IP \u5730\u5740 -label.ips=IP label.IPsec.preshared.key=IPsec \u9884\u5171\u4eab\u5bc6\u94a5 -label.is.default=\u662f\u5426\u4e3a\u9ed8\u8ba4\u8bbe\u7f6e -label.is.redundant.router=\u5197\u4f59 -label.is.shared=\u662f\u5426\u5171\u4eab -label.is.system=\u662f\u5426\u4e3a\u7cfb\u7edf +label.ips=IP label.iscsi=iSCSI +label.is.default=\u662f\u5426\u4e3a\u9ed8\u8ba4\u8bbe\u7f6e label.iso.boot=ISO \u542f\u52a8 label.iso=ISO label.isolated.networks=\u9694\u79bb\u7f51\u7edc label.isolation.method=\u9694\u79bb\u65b9\u6cd5 label.isolation.mode=\u9694\u79bb\u6a21\u5f0f label.isolation.uri=\u9694\u79bb URI +label.is.redundant.router=\u5197\u4f59 +label.is.shared=\u662f\u5426\u5171\u4eab +label.is.system=\u662f\u5426\u4e3a\u7cfb\u7edf label.item.listing=\u9879\u76ee\u5217\u8868 label.keep=\u4fdd\u7559 -label.key=\u5bc6\u94a5 label.keyboard.type=\u952e\u76d8\u7c7b\u578b +label.key=\u5bc6\u94a5 label.kvm.traffic.label=KVM \u901a\u4fe1\u6807\u7b7e label.label=\u6807\u7b7e label.lang.arabic=\u963f\u62c9\u4f2f\u8bed @@ -682,9 +674,9 @@ label.lang.spanish=\u897f\u73ed\u7259\u8bed label.last.disconnected=\u4e0a\u6b21\u65ad\u5f00\u8fde\u63a5\u65f6\u95f4 label.last.name=\u59d3\u6c0f label.latest.events=\u6700\u65b0\u4e8b\u4ef6 +label.launch=\u542f\u52a8 label.launch.vm=\u542f\u52a8 VM label.launch.zone=\u542f\u52a8\u533a\u57df -label.launch=\u542f\u52a8 label.LB.isolation=\u8d1f\u8f7d\u5e73\u8861\u5668\u9694\u79bb label.least.connections=\u6700\u5c11\u8fde\u63a5\u7b97\u6cd5 label.level=\u7ea7\u522b @@ -698,15 +690,16 @@ label.local.storage=\u672c\u5730\u5b58\u50a8 label.local=\u672c\u5730 label.login=\u767b\u5f55 label.logout=\u6ce8\u9500 -label.LUN.number=LUN \u53f7 label.lun=LUN +label.LUN.number=LUN \u53f7 label.make.project.owner=\u8bbe\u4e3a\u5e10\u6237\u9879\u76ee\u6240\u6709\u8005 -label.manage.resources=\u7ba1\u7406\u8d44\u6e90 -label.manage=\u6258\u7ba1 label.management.ips=\u7ba1\u7406\u7c7b IP \u5730\u5740 label.management=\u7ba1\u7406 +label.manage.resources=\u7ba1\u7406\u8d44\u6e90 +label.manage=\u6258\u7ba1 label.max.cpus=\u6700\u5927 CPU \u5185\u6838\u6570 label.max.guest.limit=\u6700\u5927\u6765\u5bbe\u6570\u9650\u5236 +label.maximum=\u6700\u5927\u503c label.max.memory=\u6700\u5927\u5185\u5b58(MiB) label.max.networks=\u6700\u5927\u7f51\u7edc\u6570 label.max.primary.storage=\u6700\u5927\u4e3b\u5b58\u50a8(GiB) @@ -717,14 +710,13 @@ label.max.templates=\u6700\u5927\u6a21\u677f\u6570 label.max.vms=\u6700\u5927\u7528\u6237 VM \u6570 label.max.volumes=\u6700\u5927\u5377\u6570 label.max.vpcs=\u6700\u5927 VPC \u6570 -label.maximum=\u6700\u5927\u503c label.may.continue=\u60a8\u73b0\u5728\u53ef\u4ee5\u7ee7\u7eed\u8fdb\u884c\u64cd\u4f5c\u3002 label.memory.allocated=\u5df2\u5206\u914d\u7684\u5185\u5b58 label.memory.limits=\u5185\u5b58\u9650\u5236(MiB) label.memory.mb=\u5185\u5b58(MB) label.memory.total=\u5185\u5b58\u603b\u91cf -label.memory.used=\u5df2\u4f7f\u7528\u7684\u5185\u5b58 label.memory=\u5185\u5b58 +label.memory.used=\u5df2\u4f7f\u7528\u7684\u5185\u5b58 label.menu.accounts=\u5e10\u6237 label.menu.alerts=\u8b66\u62a5 label.menu.all.accounts=\u6240\u6709\u5e10\u6237 @@ -759,8 +751,8 @@ label.menu.snapshots=\u5feb\u7167 label.menu.stopped.instances=\u5df2\u505c\u6b62\u7684\u5b9e\u4f8b label.menu.storage=\u5b58\u50a8 label.menu.system.service.offerings=\u7cfb\u7edf\u65b9\u6848 -label.menu.system.vms=\u7cfb\u7edf VM label.menu.system=\u7cfb\u7edf +label.menu.system.vms=\u7cfb\u7edf VM label.menu.templates=\u6a21\u677f label.menu.virtual.appliances=\u865a\u62df\u8bbe\u5907 label.menu.virtual.resources=\u865a\u62df\u8d44\u6e90 @@ -790,15 +782,16 @@ label.name=\u540d\u79f0 label.nat.port.range=NAT \u7aef\u53e3\u8303\u56f4 label.netmask=\u7f51\u7edc\u63a9\u7801 label.netScaler=NetScaler +label.network.ACLs=\u7f51\u7edc ACL label.network.ACL.total=\u7f51\u7edc ACL \u603b\u6570 label.network.ACL=\u7f51\u7edc ACL -label.network.ACLs=\u7f51\u7edc ACL label.network.desc=\u7f51\u7edc\u63cf\u8ff0 label.network.device.type=\u7f51\u7edc\u8bbe\u5907\u7c7b\u578b label.network.device=\u7f51\u7edc\u8bbe\u5907 label.network.domain.text=\u7f51\u7edc\u57df label.network.domain=\u7f51\u7edc\u57df label.network.id=\u7f51\u7edc ID +label.networking.and.security=\u7f51\u7edc\u8fde\u63a5\u4e0e\u5b89\u5168 label.network.label.display.for.blank.value=\u4f7f\u7528\u9ed8\u8ba4\u7f51\u5173 label.network.name=\u7f51\u7edc\u540d\u79f0 label.network.offering.display.text=\u7f51\u7edc\u65b9\u6848\u663e\u793a\u6587\u672c @@ -809,20 +802,19 @@ label.network.rate.megabytes=\u7f51\u7edc\u901f\u7387(MB/\u79d2) label.network.rate=\u7f51\u7edc\u901f\u7387(MB/\u79d2) label.network.read=\u7f51\u7edc\u8bfb\u53d6\u91cf label.network.service.providers=\u7f51\u7edc\u670d\u52a1\u63d0\u4f9b\u7a0b\u5e8f +label.networks=\u7f51\u7edc label.network.type=\u7f51\u7edc\u7c7b\u578b -label.network.write=\u7f51\u7edc\u5199\u5165\u91cf label.network=\u7f51\u7edc -label.networking.and.security=\u7f51\u7edc\u8fde\u63a5\u4e0e\u5b89\u5168 -label.networks=\u7f51\u7edc +label.network.write=\u7f51\u7edc\u5199\u5165\u91cf label.new.password=\u65b0\u5bc6\u7801 label.new.project=\u65b0\u5efa\u9879\u76ee -label.new.vm=\u65b0\u5efa VM label.new=\u65b0\u5efa +label.new.vm=\u65b0\u5efa VM label.next=\u4e0b\u4e00\u6b65 label.nexusVswitch=Nexus 1000v +label.nfs=NFS label.nfs.server=NFS \u670d\u52a1\u5668 label.nfs.storage=NFS \u5b58\u50a8 -label.nfs=NFS label.nic.adapter.type=NIC \u9002\u914d\u5668\u7c7b\u578b label.nicira.controller.address=\u63a7\u5236\u5668\u5730\u5740 label.nicira.l3gatewayserviceuuid=L3 Gateway Service UUID @@ -834,19 +826,19 @@ label.no.data=\u65e0\u53ef\u663e\u793a\u7684\u6570\u636e label.no.errors=\u65e0\u6700\u8fd1\u51fa\u73b0\u7684\u9519\u8bef label.no.isos=\u65e0\u53ef\u7528 ISO label.no.items=\u65e0\u53ef\u7528\u9879\u76ee -label.no.security.groups=\u65e0\u53ef\u7528\u5b89\u5168\u7ec4 -label.no.thanks=\u4e0d\uff0c\u8c22\u8c22 -label.no=\u5426 label.none=\u65e0 +label.no.security.groups=\u65e0\u53ef\u7528\u5b89\u5168\u7ec4 label.not.found=\u672a\u627e\u5230 +label.no.thanks=\u4e0d\uff0c\u8c22\u8c22 label.notifications=\u901a\u77e5 -label.num.cpu.cores=CPU \u5185\u6838\u6570 +label.no=\u5426 label.number.of.clusters=\u7fa4\u96c6\u6570\u91cf label.number.of.hosts=\u4e3b\u673a\u6570\u91cf label.number.of.pods=\u63d0\u4f9b\u70b9\u6570\u91cf label.number.of.system.vms=\u7cfb\u7edf VM \u6570 label.number.of.virtual.routers=\u865a\u62df\u8def\u7531\u5668\u6570 label.number.of.zones=\u533a\u57df\u6570\u91cf +label.num.cpu.cores=CPU \u5185\u6838\u6570 label.numretries=\u91cd\u8bd5\u6b21\u6570 label.ocfs2=OCFS2 label.offer.ha=\u63d0\u4f9b\u9ad8\u53ef\u7528\u6027 @@ -874,14 +866,14 @@ label.please.wait=\u8bf7\u7a0d\u5019 label.plugin.details=\u63d2\u4ef6\u8be6\u7ec6\u4fe1\u606f label.plugins=\u63d2\u4ef6 label.pod.name=\u63d0\u4f9b\u70b9\u540d\u79f0 -label.pod=\u63d0\u4f9b\u70b9 label.pods=\u63d0\u4f9b\u70b9 +label.pod=\u63d0\u4f9b\u70b9 label.port.forwarding.policies=\u7aef\u53e3\u8f6c\u53d1\u7b56\u7565 label.port.forwarding=\u7aef\u53e3\u8f6c\u53d1 label.port.range=\u7aef\u53e3\u8303\u56f4 label.PreSetup=PreSetup -label.prev=\u4e0a\u4e00\u9875 label.previous=\u4e0a\u4e00\u6b65 +label.prev=\u4e0a\u4e00\u9875 label.primary.allocated=\u5df2\u5206\u914d\u7684\u4e3b\u5b58\u50a8 label.primary.network=\u4e3b\u7f51\u7edc label.primary.storage.count=\u4e3b\u5b58\u50a8\u6c60 @@ -891,31 +883,32 @@ label.primary.used=\u5df2\u4f7f\u7528\u7684\u4e3b\u5b58\u50a8 label.private.Gateway=\u4e13\u7528\u7f51\u5173 label.private.interface=\u4e13\u7528\u63a5\u53e3 label.private.ip.range=\u4e13\u7528 IP \u8303\u56f4 -label.private.ip=\u4e13\u7528 IP \u5730\u5740 label.private.ips=\u4e13\u7528 IP \u5730\u5740 +label.private.ip=\u4e13\u7528 IP \u5730\u5740 +label.privatekey=PKCS\#8 \u79c1\u94a5 label.private.network=\u4e13\u7528\u7f51\u7edc label.private.port=\u4e13\u7528\u7aef\u53e3 label.private.zone=\u4e13\u7528\u533a\u57df -label.privatekey=PKCS\#8 \u79c1\u94a5 label.project.dashboard=\u9879\u76ee\u63a7\u5236\u677f label.project.id=\u9879\u76ee ID label.project.invite=\u9080\u8bf7\u52a0\u5165\u9879\u76ee label.project.name=\u9879\u76ee\u540d\u79f0 -label.project.view=\u9879\u76ee\u89c6\u56fe -label.project=\u9879\u76ee label.projects=\u9879\u76ee +label.project=\u9879\u76ee +label.project.view=\u9879\u76ee\u89c6\u56fe label.protocol=\u534f\u8bae label.providers=\u63d0\u4f9b\u7a0b\u5e8f label.public.interface=\u516c\u7528\u63a5\u53e3 -label.public.ip=\u516c\u7528 IP \u5730\u5740 label.public.ips=\u516c\u7528 IP \u5730\u5740 +label.public.ip=\u516c\u7528 IP \u5730\u5740 label.public.network=\u516c\u7528\u7f51\u7edc label.public.port=\u516c\u7528\u7aef\u53e3 label.public.traffic=\u516c\u5171\u901a\u4fe1 -label.public.zone=\u516c\u7528\u533a\u57df label.public=\u516c\u7528 +label.public.zone=\u516c\u7528\u533a\u57df label.purpose=\u76ee\u7684 label.Pxe.server.type=Pxe \u670d\u52a1\u5668\u7c7b\u578b +label.qos.type=QoS \u7c7b\u578b label.quickview=\u5feb\u901f\u67e5\u770b label.reboot=\u91cd\u65b0\u542f\u52a8 label.recent.errors=\u6700\u8fd1\u51fa\u73b0\u7684\u9519\u8bef @@ -940,8 +933,8 @@ label.remove.static.route=\u5220\u9664\u9759\u6001\u8def\u7531 label.remove.tier=\u5220\u9664\u5c42 label.remove.vm.from.lb=\u4ece\u8d1f\u8f7d\u5e73\u8861\u5668\u89c4\u5219\u4e2d\u5220\u9664 VM label.remove.vpc=\u5220\u9664 VPC -label.removing.user=\u6b63\u5728\u5220\u9664\u7528\u6237 label.removing=\u6b63\u5728\u5220\u9664 +label.removing.user=\u6b63\u5728\u5220\u9664\u7528\u6237 label.required=\u5fc5\u586b\u9879 label.reserved.system.gateway=\u9884\u7559\u7684\u7cfb\u7edf\u7f51\u5173 label.reserved.system.ip=\u9884\u7559\u7684\u7cfb\u7edf IP @@ -952,8 +945,8 @@ label.resize.new.size=\u65b0\u5efa\u5927\u5c0f(GB) label.resize.shrink.ok=\u662f\u5426\u786e\u5b9e\u8981\u7f29\u5c0f\u5377\u5927\u5c0f label.resource.limits=\u8d44\u6e90\u9650\u5236 label.resource.state=\u8d44\u6e90\u72b6\u6001 -label.resource=\u8d44\u6e90 label.resources=\u8d44\u6e90 +label.resource=\u8d44\u6e90 label.restart.network=\u91cd\u65b0\u542f\u52a8\u7f51\u7edc label.restart.required=\u9700\u8981\u91cd\u65b0\u542f\u52a8 label.restart.vpc=\u91cd\u65b0\u542f\u52a8 VPC @@ -964,6 +957,7 @@ label.role=\u89d2\u8272 label.root.disk.controller=\u6839\u78c1\u76d8\u63a7\u5236\u5668 label.root.disk.offering=\u6839\u78c1\u76d8\u65b9\u6848 label.round.robin=\u8f6e\u8be2\u7b97\u6cd5 +label.routing=\u6b63\u5728\u8def\u7531 label.rules=\u89c4\u5219 label.running.vms=\u6b63\u5728\u8fd0\u884c\u7684 VM label.s3.access_key=\u8bbf\u95ee\u5bc6\u94a5 @@ -982,15 +976,14 @@ label.scope=\u8303\u56f4 label.search=\u641c\u7d22 label.secondary.storage.count=\u8f85\u52a9\u5b58\u50a8\u6c60 label.secondary.storage.limits=\u8f85\u52a9\u5b58\u50a8\u9650\u5236(GiB) -label.secondary.storage.vm=\u8f85\u52a9\u5b58\u50a8 VM label.secondary.storage=\u8f85\u52a9\u5b58\u50a8 +label.secondary.storage.vm=\u8f85\u52a9\u5b58\u50a8 VM label.secondary.used=\u5df2\u4f7f\u7528\u7684\u8f85\u52a9\u5b58\u50a8 label.secret.key=\u5bc6\u94a5 label.security.group.name=\u5b89\u5168\u7ec4\u540d\u79f0 -label.security.group=\u5b89\u5168\u7ec4 label.security.groups.enabled=\u5df2\u542f\u7528\u5b89\u5168\u7ec4 label.security.groups=\u5b89\u5168\u7ec4 -label.select-view=\u9009\u62e9\u89c6\u56fe +label.security.group=\u5b89\u5168\u7ec4 label.select.a.template=\u9009\u62e9\u4e00\u4e2a\u6a21\u677f label.select.a.zone=\u9009\u62e9\u4e00\u4e2a\u533a\u57df label.select.instance.to.attach.volume.to=\u9009\u62e9\u8981\u5c06\u5377\u9644\u52a0\u5230\u7684\u5b9e\u4f8b @@ -999,19 +992,21 @@ label.select.iso.or.template=\u9009\u62e9 ISO \u6216\u6a21\u677f label.select.offering=\u9009\u62e9\u65b9\u6848 label.select.project=\u9009\u62e9\u9879\u76ee label.select.tier=\u9009\u62e9\u5c42 -label.select.vm.for.static.nat=\u4e3a\u9759\u6001 NAT \u9009\u62e9 VM label.select=\u9009\u62e9 +label.select-view=\u9009\u62e9\u89c6\u56fe +label.select.vm.for.static.nat=\u4e3a\u9759\u6001 NAT \u9009\u62e9 VM label.sent=\u5df2\u53d1\u9001 label.server=\u670d\u52a1\u5668 label.service.capabilities=\u670d\u52a1\u529f\u80fd label.service.offering=\u670d\u52a1\u65b9\u6848 +label.service.state=\u670d\u52a1\u72b6\u6001 label.session.expired=\u4f1a\u8bdd\u5df2\u8fc7\u671f -label.set.up.zone.type=\u8bbe\u7f6e\u533a\u57df\u7c7b\u578b label.setup.network=\u8bbe\u7f6e\u7f51\u7edc -label.setup.zone=\u8bbe\u7f6e\u533a\u57df label.setup=\u8bbe\u7f6e -label.shared=\u5df2\u5171\u4eab +label.set.up.zone.type=\u8bbe\u7f6e\u533a\u57df\u7c7b\u578b +label.setup.zone=\u8bbe\u7f6e\u533a\u57df label.SharedMountPoint=SharedMountPoint +label.shared=\u5df2\u5171\u4eab label.show.ingress.rule=\u663e\u793a\u5165\u53e3\u89c4\u5219 label.shutdown.provider=\u5173\u95ed\u63d0\u4f9b\u7a0b\u5e8f label.site.to.site.VPN=\u70b9\u5bf9\u70b9 VPN @@ -1019,10 +1014,10 @@ label.size=\u5927\u5c0f label.skip.guide=\u6211\u4ee5\u524d\u4f7f\u7528\u8fc7 CloudStack\uff0c\u8df3\u8fc7\u6b64\u6307\u5357 label.snapshot.limits=\u5feb\u7167\u9650\u5236 label.snapshot.name=\u5feb\u7167\u540d\u79f0 -label.snapshot.s=\u5feb\u7167 label.snapshot.schedule=\u8bbe\u7f6e\u91cd\u73b0\u5feb\u7167 -label.snapshot=\u5feb\u7167 +label.snapshot.s=\u5feb\u7167 label.snapshots=\u5feb\u7167 +label.snapshot=\u5feb\u7167 label.source.nat=\u6e90 NAT label.source=\u6e90\u7b97\u6cd5 label.specify.IP.ranges=\u6307\u5b9a IP \u8303\u56f4 @@ -1038,8 +1033,8 @@ label.start.vxlan=\u8d77\u59cb VXLAN label.state=\u72b6\u6001 label.static.nat.enabled=\u5df2\u542f\u7528\u9759\u6001 NAT label.static.nat.to=\u9759\u6001 NAT \u76ee\u6807 -label.static.nat.vm.details=\u9759\u6001 NAT VM \u8be6\u60c5 label.static.nat=\u9759\u6001 NAT +label.static.nat.vm.details=\u9759\u6001 NAT VM \u8be6\u60c5 label.statistics=\u7edf\u8ba1\u6570\u636e label.status=\u72b6\u6001 label.step.1.title=\u6b65\u9aa4 1\: \u9009\u62e9\u4e00\u4e2a\u6a21\u677f @@ -1065,28 +1060,28 @@ label.sticky.postonly=postonly label.sticky.prefix=prefix label.sticky.request-learn=request-learn label.sticky.tablesize=\u8868\u5927\u5c0f -label.stop=\u505c\u6b62 label.stopped.vms=\u5df2\u505c\u6b62\u7684 VM +label.stop=\u505c\u6b62 label.storage.tags=\u5b58\u50a8\u6807\u7b7e label.storage.traffic=\u5b58\u50a8\u901a\u4fe1 label.storage.type=\u5b58\u50a8\u7c7b\u578b -label.qos.type=QoS \u7c7b\u578b label.storage=\u5b58\u50a8 label.subdomain.access=\u5b50\u57df\u8bbf\u95ee -label.submit=\u63d0\u4ea4 label.submitted.by=[\u63d0\u4ea4\u8005\: ] +label.submit=\u63d0\u4ea4 label.succeeded=\u6210\u529f label.sunday=\u661f\u671f\u65e5 label.super.cidr.for.guest.networks=\u6765\u5bbe\u7f51\u7edc\u7684\u8d85\u7ea7 CIDR label.supported.services=\u652f\u6301\u7684\u670d\u52a1 label.supported.source.NAT.type=\u652f\u6301\u7684\u6e90 NAT \u7c7b\u578b label.suspend.project=\u6682\u505c\u9879\u76ee +label.switch.type=\u4ea4\u6362\u673a\u7c7b\u578b label.system.capacity=\u7cfb\u7edf\u5bb9\u91cf label.system.offering=\u7cfb\u7edf\u65b9\u6848 label.system.service.offering=\u7cfb\u7edf\u670d\u52a1\u65b9\u6848 +label.system.vms=\u7cfb\u7edf VM label.system.vm.type=\u7cfb\u7edf VM \u7c7b\u578b label.system.vm=\u7cfb\u7edf VM -label.system.vms=\u7cfb\u7edf VM label.system.wide.capacity=\u6574\u4e2a\u7cfb\u7edf\u7684\u5bb9\u91cf label.tagged=\u5df2\u6807\u8bb0 label.tags=\u6807\u7b7e @@ -1101,14 +1096,14 @@ label.theme.lightblue=\u81ea\u5b9a\u4e49 - \u6de1\u84dd\u8272 label.thursday=\u661f\u671f\u56db label.tier.details=\u5c42\u8be6\u7ec6\u4fe1\u606f label.tier=\u5c42 -label.time.zone=\u65f6\u533a -label.time=\u65f6\u95f4 label.timeout.in.second = \u8d85\u65f6(\u79d2) label.timeout=\u8d85\u65f6 +label.time=\u65f6\u95f4 +label.time.zone=\u65f6\u533a label.timezone=\u65f6\u533a label.token=\u4ee4\u724c -label.total.CPU=CPU \u603b\u91cf label.total.cpu=CPU \u603b\u91cf +label.total.CPU=CPU \u603b\u91cf label.total.hosts=\u603b\u4e3b\u673a\u6570 label.total.memory=\u5185\u5b58\u603b\u91cf label.total.of.ip=\u603b IP \u5730\u5740\u6570 @@ -1116,8 +1111,8 @@ label.total.of.vm=\u603b VM \u6570 label.total.storage=\u5b58\u50a8\u603b\u91cf label.total.vms=\u603b VM \u6570 label.traffic.label=\u901a\u4fe1\u6807\u7b7e -label.traffic.type=\u901a\u4fe1\u7c7b\u578b label.traffic.types=\u901a\u4fe1\u7c7b\u578b +label.traffic.type=\u901a\u4fe1\u7c7b\u578b label.tuesday=\u661f\u671f\u4e8c label.type.id=\u7c7b\u578b ID label.type=\u7c7b\u578b @@ -1128,15 +1123,15 @@ label.update.project.resources=\u66f4\u65b0\u9879\u76ee\u8d44\u6e90 label.update.ssl.cert= SSL \u8bc1\u4e66 label.update.ssl= SSL \u8bc1\u4e66 label.updating=\u6b63\u5728\u66f4\u65b0 -label.upload.volume=\u4e0a\u8f7d\u5377 label.upload=\u4e0a\u8f7d +label.upload.volume=\u4e0a\u8f7d\u5377 label.url=URL label.usage.interface=\u4f7f\u7528\u754c\u9762 -label.use.vm.ip=\u4f7f\u7528 VM IP\: label.used=\u5df2\u4f7f\u7528 -label.user=\u7528\u6237 label.username=\u7528\u6237\u540d label.users=\u7528\u6237 +label.user=\u7528\u6237 +label.use.vm.ip=\u4f7f\u7528 VM IP\: label.value=\u503c label.vcdcname=vCenter DC \u540d\u79f0 label.vcenter.cluster=vCenter \u7fa4\u96c6 @@ -1149,56 +1144,59 @@ label.vcipaddress=vCenter IP \u5730\u5740 label.version=\u7248\u672c label.view.all=\u67e5\u770b\u5168\u90e8 label.view.console=\u67e5\u770b\u63a7\u5236\u53f0 +label.viewing=\u67e5\u770b label.view.more=\u67e5\u770b\u66f4\u591a +label.view.secondary.ips=\u67e5\u770b\u8f85\u52a9 IP label.view=\u67e5\u770b -label.viewing=\u67e5\u770b -label.virtual.appliance=\u865a\u62df\u8bbe\u5907 label.virtual.appliances=\u865a\u62df\u8bbe\u5907 +label.virtual.appliance=\u865a\u62df\u8bbe\u5907 label.virtual.machines=\u865a\u62df\u673a label.virtual.network=\u865a\u62df\u7f51\u7edc -label.virtual.router=\u865a\u62df\u8def\u7531\u5668 label.virtual.routers=\u865a\u62df\u8def\u7531\u5668 +label.virtual.router=\u865a\u62df\u8def\u7531\u5668 label.vlan.id=VLAN ID label.vlan.range=VLAN \u8303\u56f4 label.vlan=VLAN -label.vxlan.id=VXLAN ID -label.vxlan.range=VXLAN Range -label.vxlan=VXLAN label.vm.add=\u6dfb\u52a0\u5b9e\u4f8b label.vm.destroy=\u9500\u6bc1 label.vm.display.name=VM \u663e\u793a\u540d\u79f0 -label.vm.name=VM \u540d\u79f0 -label.vm.reboot=\u91cd\u65b0\u542f\u52a8 -label.vm.start=\u542f\u52a8 -label.vm.state=VM \u72b6\u6001 -label.vm.stop=\u505c\u6b62 label.VMFS.datastore=VMFS \u6570\u636e\u5b58\u50a8 label.vmfs=VMFS +label.vm.name=VM \u540d\u79f0 +label.vm.reboot=\u91cd\u65b0\u542f\u52a8 label.VMs.in.tier=\u5c42\u4e2d\u7684 VM -label.vms=VM label.vmsnapshot.current=\u6700\u65b0\u7248\u672c label.vmsnapshot.memory=\u5feb\u7167\u5185\u5b58 label.vmsnapshot.parentname=\u7236\u540d\u79f0 label.vmsnapshot.type=\u7c7b\u578b label.vmsnapshot=VM \u5feb\u7167 +label.vm.start=\u542f\u52a8 +label.vm.state=VM \u72b6\u6001 +label.vm.stop=\u505c\u6b62 +label.vms=VM label.vmware.traffic.label=VMware \u901a\u4fe1\u6807\u7b7e +label.vnet.id=VLAN ID +label.vnet=VLAN label.volgroup=\u5377\u7ec4 label.volume.limits=\u5377\u9650\u5236 label.volume.name=\u5377\u540d\u79f0 -label.volume=\u5377 label.volumes=\u5377 +label.volume=\u5377 label.vpc.id=VPC ID label.VPC.router.details=VPC \u8def\u7531\u5668\u8be6\u7ec6\u4fe1\u606f label.vpc=VPC label.VPN.connection=VPN \u8fde\u63a5 -label.VPN.customer.gateway=VPN \u5ba2\u6237\u7f51\u5173 label.vpn.customer.gateway=VPN \u5ba2\u6237\u7f51\u5173 +label.VPN.customer.gateway=VPN \u5ba2\u6237\u7f51\u5173 label.VPN.gateway=VPN \u7f51\u5173 label.vpn=VPN label.vsmctrlvlanid=\u63a7\u5236 VLAN ID label.vsmpktvlanid=\u6570\u636e\u5305 VLAN ID label.vsmstoragevlanid=\u5b58\u50a8 VLAN ID label.vsphere.managed=\u7531 vSphere \u7ba1\u7406 +label.vxlan.id=VXLAN ID +label.vxlan.range=VXLAN Range +label.vxlan=VXLAN label.waiting=\u6b63\u5728\u7b49\u5f85 label.warn=\u8b66\u544a label.wednesday=\u661f\u671f\u4e09 @@ -1215,17 +1213,18 @@ label.zone.step.1.title=\u6b65\u9aa4 1\: \u9009\u62e9\u4e00\u4e2a\u7f51\ label.zone.step.2.title=\u6b65\u9aa4 2\: \u6dfb\u52a0\u4e00\u4e2a\u533a\u57df label.zone.step.3.title=\u6b65\u9aa4 3\: \u6dfb\u52a0\u4e00\u4e2a\u63d0\u4f9b\u70b9 label.zone.step.4.title=\u6b65\u9aa4 4\: \u6dfb\u52a0\u4e00\u4e2a IP \u8303\u56f4 +label.zones=\u533a\u57df label.zone.type=\u533a\u57df\u7c7b\u578b -label.zone.wide=\u6574\u4e2a\u533a\u57df label.zone=\u533a\u57df -label.zones=\u533a\u57df +label.zone.wide=\u6574\u4e2a\u533a\u57df label.zoneWizard.trafficType.guest=\u6765\u5bbe\: \u6700\u7ec8\u7528\u6237\u865a\u62df\u673a\u4e4b\u95f4\u7684\u901a\u4fe1 label.zoneWizard.trafficType.management=\u7ba1\u7406\: CloudStack \u7684\u5185\u90e8\u8d44\u6e90(\u5305\u62ec\u4e0e\u7ba1\u7406\u670d\u52a1\u5668\u901a\u4fe1\u7684\u4efb\u4f55\u7ec4\u4ef6\uff0c\u4f8b\u5982\u4e3b\u673a\u548c CloudStack \u7cfb\u7edf VM)\u4e4b\u95f4\u7684\u901a\u4fe1 label.zoneWizard.trafficType.public=\u516c\u7528\: \u4e91\u4e2d Internet \u4e0e\u865a\u62df\u673a\u4e4b\u95f4\u7684\u901a\u4fe1\u3002 label.zoneWizard.trafficType.storage=\u5b58\u50a8\: \u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u4e0e\u8f85\u52a9\u5b58\u50a8\u670d\u52a1\u5668(\u4f8b\u5982 VM \u6a21\u677f\u4e0e\u5feb\u7167)\u4e4b\u95f4\u7684\u901a\u4fe1 managed.state=\u6258\u7ba1\u72b6\u6001 -message.acquire.new.ip.vpc=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u4e3a\u6b64 VPC \u83b7\u53d6\u4e00\u4e2a\u65b0 IP\u3002 +message.acquire.ip.nic=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u83b7\u53d6\u6b64 NIC \u7684\u65b0\u8f85\u52a9 IP\u3002
\u6ce8\u610f\: \u60a8\u9700\u8981\u5728\u865a\u62df\u673a\u5185\u90e8\u624b\u52a8\u914d\u7f6e\u65b0\u83b7\u53d6\u7684\u8f85\u52a9 IP\u3002 message.acquire.new.ip=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u4e3a\u6b64\u7f51\u7edc\u83b7\u53d6\u4e00\u4e2a\u65b0 IP\u3002 +message.acquire.new.ip.vpc=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u4e3a\u6b64 VPC \u83b7\u53d6\u4e00\u4e2a\u65b0 IP\u3002 message.acquire.public.ip=\u8bf7\u9009\u62e9\u4e00\u4e2a\u8981\u4ece\u4e2d\u83b7\u53d6\u65b0 IP \u7684\u533a\u57df\u3002 message.action.cancel.maintenance.mode=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u53d6\u6d88\u6b64\u7ef4\u62a4\u6a21\u5f0f\u3002 message.action.cancel.maintenance=\u5df2\u6210\u529f\u53d6\u6d88\u7ef4\u62a4\u60a8\u7684\u4e3b\u673a\u3002\u6b64\u8fc7\u7a0b\u53ef\u80fd\u9700\u8981\u957f\u8fbe\u51e0\u5206\u949f\u65f6\u95f4\u3002 @@ -1241,6 +1240,7 @@ message.action.delete.ISO.for.all.zones=\u6b64 ISO \u7531\u6240\u6709\u533a\u57d message.action.delete.ISO=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64 ISO\u3002 message.action.delete.network=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u7f51\u7edc\u3002 message.action.delete.nexusVswitch=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64 Nexus 1000v +message.action.delete.nic=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u79fb\u9664\u6b64 NIC\uff0c\u6b64\u64cd\u4f5c\u8fd8\u5c06\u4ece VM \u4e2d\u79fb\u9664\u5173\u8054\u7684\u7f51\u7edc\u3002 message.action.delete.physical.network=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u7269\u7406\u7f51\u7edc message.action.delete.pod=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u63d0\u4f9b\u70b9\u3002 message.action.delete.primary.storage=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u4e3b\u5b58\u50a8\u3002 @@ -1293,18 +1293,22 @@ message.action.unmanage.cluster=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u53d6 message.action.vmsnapshot.delete=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64 VM \u5feb\u7167\u3002 message.action.vmsnapshot.revert=\u8fd8\u539f VM \u5feb\u7167 message.activate.project=\u662f\u5426\u786e\u5b9e\u8981\u6fc0\u6d3b\u6b64\u9879\u76ee? -message.add.cluster.zone=\u5411\u533a\u57df \u4e2d\u6dfb\u52a0\u4e00\u4e2a\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u6258\u7ba1\u7684\u7fa4\u96c6 message.add.cluster=\u5411\u533a\u57df \u3001\u63d0\u4f9b\u70b9 \u4e2d\u6dfb\u52a0\u4e00\u4e2a\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u6258\u7ba1\u7684\u7fa4\u96c6 +message.add.cluster.zone=\u5411\u533a\u57df \u4e2d\u6dfb\u52a0\u4e00\u4e2a\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u6258\u7ba1\u7684\u7fa4\u96c6 message.add.disk.offering=\u8bf7\u6307\u5b9a\u4ee5\u4e0b\u53c2\u6570\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u65b0\u7684\u78c1\u76d8\u65b9\u6848 message.add.domain=\u8bf7\u6307\u5b9a\u8981\u5728\u6b64\u57df\u4e0b\u521b\u5efa\u7684\u5b50\u57df message.add.firewall=\u5411\u533a\u57df\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u9632\u706b\u5899 message.add.guest.network=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u6dfb\u52a0\u4e00\u4e2a\u6765\u5bbe\u7f51\u7edc message.add.host=\u8bf7\u6307\u5b9a\u4ee5\u4e0b\u53c2\u6570\u4ee5\u6dfb\u52a0\u4e00\u53f0\u65b0\u4e3b\u673a +message.adding.host=\u6b63\u5728\u6dfb\u52a0\u4e3b\u673a +message.adding.Netscaler.device=\u6b63\u5728\u6dfb\u52a0 Netscaler \u8bbe\u5907 +message.adding.Netscaler.provider=\u6b63\u5728\u6dfb\u52a0 Netscaler \u63d0\u4f9b\u7a0b\u5e8f message.add.ip.range.direct.network=\u5411\u533a\u57df \u4e2d\u7684\u76f4\u63a5\u7f51\u7edc \u6dfb\u52a0\u4e00\u4e2a IP \u8303\u56f4 message.add.ip.range.to.pod=

\u5411\u63d0\u4f9b\u70b9\u6dfb\u52a0\u4e00\u4e2a IP \u8303\u56f4\:

message.add.ip.range=\u5411\u533a\u57df\u4e2d\u7684\u516c\u7528\u7f51\u7edc\u6dfb\u52a0\u4e00\u4e2a IP \u8303\u56f4 -message.add.load.balancer.under.ip=\u5df2\u5728\u4ee5\u4e0b IP \u4e0b\u6dfb\u52a0\u8d1f\u8f7d\u5e73\u8861\u5668\u89c4\u5219\: +message.additional.networks.desc=\u8bf7\u9009\u62e9\u865a\u62df\u673a\u8981\u8fde\u63a5\u5230\u7684\u5176\u4ed6\u7f51\u7edc\u3002 message.add.load.balancer=\u5411\u533a\u57df\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u8d1f\u8f7d\u5e73\u8861\u5668 +message.add.load.balancer.under.ip=\u5df2\u5728\u4ee5\u4e0b IP \u4e0b\u6dfb\u52a0\u8d1f\u8f7d\u5e73\u8861\u5668\u89c4\u5219\: message.add.network=\u4e3a\u533a\u57df \u6dfb\u52a0\u4e00\u4e2a\u65b0\u7f51\u7edc message.add.new.gateway.to.vpc=\u8bf7\u6307\u5b9a\u5c06\u65b0\u7f51\u5173\u6dfb\u52a0\u5230\u6b64 VPC \u6240\u9700\u7684\u4fe1\u606f\u3002 message.add.pod.during.zone.creation=\u6bcf\u4e2a\u533a\u57df\u4e2d\u5fc5\u987b\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u63d0\u4f9b\u70b9\uff0c\u73b0\u5728\u6211\u4eec\u5c06\u6dfb\u52a0\u7b2c\u4e00\u4e2a\u63d0\u4f9b\u70b9\u3002\u63d0\u4f9b\u70b9\u4e2d\u5305\u542b\u4e3b\u673a\u548c\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\uff0c\u60a8\u5c06\u5728\u968f\u540e\u7684\u67d0\u4e2a\u6b65\u9aa4\u4e2d\u6dfb\u52a0\u8fd9\u4e9b\u4e3b\u673a\u548c\u670d\u52a1\u5668\u3002\u9996\u5148\uff0c\u8bf7\u4e3a CloudStack \u7684\u5185\u90e8\u7ba1\u7406\u901a\u4fe1\u914d\u7f6e\u4e00\u4e2a\u9884\u7559 IP \u5730\u5740\u8303\u56f4\u3002\u9884\u7559\u7684 IP \u8303\u56f4\u5bf9\u4e91\u4e2d\u7684\u6bcf\u4e2a\u533a\u57df\u6765\u8bf4\u5fc5\u987b\u552f\u4e00\u3002 @@ -1318,10 +1322,6 @@ message.add.system.service.offering=\u8bf7\u586b\u5199\u4ee5\u4e0b\u6570\u636e\u message.add.template=\u8bf7\u8f93\u5165\u4ee5\u4e0b\u6570\u636e\u4ee5\u521b\u5efa\u65b0\u6a21\u677f message.add.volume=\u8bf7\u586b\u5199\u4ee5\u4e0b\u6570\u636e\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u65b0\u5377\u3002 message.add.VPN.gateway=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u6dfb\u52a0 VPN \u7f51\u5173 -message.adding.host=\u6b63\u5728\u6dfb\u52a0\u4e3b\u673a -message.adding.Netscaler.device=\u6b63\u5728\u6dfb\u52a0 Netscaler \u8bbe\u5907 -message.adding.Netscaler.provider=\u6b63\u5728\u6dfb\u52a0 Netscaler \u63d0\u4f9b\u7a0b\u5e8f -message.additional.networks.desc=\u8bf7\u9009\u62e9\u865a\u62df\u673a\u8981\u8fde\u63a5\u5230\u7684\u5176\u4ed6\u7f51\u7edc\u3002 message.advanced.mode.desc=\u5982\u679c\u60a8\u5e0c\u671b\u542f\u7528 VLAN \u652f\u6301\uff0c\u8bf7\u9009\u62e9\u6b64\u7f51\u7edc\u6a21\u5f0f\u3002\u6b64\u7f51\u7edc\u6a21\u5f0f\u5728\u5141\u8bb8\u7ba1\u7406\u5458\u63d0\u4f9b\u9632\u706b\u5899\u3001VPN \u6216\u8d1f\u8f7d\u5e73\u8861\u5668\u652f\u6301\u7b49\u81ea\u5b9a\u4e49\u7f51\u7edc\u65b9\u6848\u4ee5\u53ca\u542f\u7528\u76f4\u63a5\u7f51\u7edc\u8fde\u63a5\u4e0e\u865a\u62df\u7f51\u7edc\u8fde\u63a5\u7b49\u65b9\u9762\u63d0\u4f9b\u4e86\u6700\u5927\u7684\u7075\u6d3b\u6027\u3002 message.advanced.security.group=\u5982\u679c\u8981\u4f7f\u7528\u5b89\u5168\u7ec4\u63d0\u4f9b\u6765\u5bbe VM \u9694\u79bb\uff0c\u8bf7\u9009\u62e9\u6b64\u6a21\u5f0f\u3002 message.advanced.virtual=\u5982\u679c\u8981\u4f7f\u7528\u6574\u4e2a\u533a\u57df\u7684 VLAN \u63d0\u4f9b\u6765\u5bbe VM \u9694\u79bb\uff0c\u8bf7\u9009\u62e9\u6b64\u6a21\u5f0f\u3002 @@ -1352,9 +1352,9 @@ message.confirm.remove.IP.range=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220 message.confirm.shutdown.provider=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5173\u95ed\u6b64\u63d0\u4f9b\u7a0b\u5e8f message.copy.iso.confirm=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5c06 ISO \u590d\u5236\u5230 message.copy.template=\u5c06\u6a21\u677f XXX \u4ece\u533a\u57df \u590d\u5236\u5230 +message.create.template=\u662f\u5426\u786e\u5b9e\u8981\u521b\u5efa\u6a21\u677f? message.create.template.vm=\u57fa\u4e8e\u6a21\u677f \u521b\u5efa VM message.create.template.volume=\u8bf7\u5148\u6307\u5b9a\u4ee5\u4e0b\u4fe1\u606f\uff0c\u7136\u540e\u518d\u521b\u5efa\u78c1\u76d8\u5377 \u7684\u6a21\u677f\u3002\u521b\u5efa\u6a21\u677f\u53ef\u80fd\u9700\u8981\u51e0\u5206\u949f\u5230\u66f4\u957f\u7684\u65f6\u95f4\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u78c1\u76d8\u5377\u7684\u5927\u5c0f\u3002 -message.create.template=\u662f\u5426\u786e\u5b9e\u8981\u521b\u5efa\u6a21\u677f? message.creating.cluster=\u6b63\u5728\u521b\u5efa\u7fa4\u96c6 message.creating.guest.network=\u6b63\u5728\u521b\u5efa\u6765\u5bbe\u7f51\u7edc message.creating.physical.networks=\u6b63\u5728\u521b\u5efa\u7269\u7406\u7f51\u7edc @@ -1395,11 +1395,11 @@ message.edit.confirm=\u8bf7\u5148\u786e\u8ba4\u60a8\u6240\u505a\u7684\u66f4\u653 message.edit.limits=\u8bf7\u6307\u5b9a\u5bf9\u4ee5\u4e0b\u8d44\u6e90\u7684\u9650\u5236\u3002\u201c-1\u201d\u8868\u793a\u4e0d\u9650\u5236\u8981\u521b\u5efa\u7684\u8d44\u6e90\u6570\u3002 message.edit.traffic.type=\u8bf7\u6307\u5b9a\u60a8\u5e0c\u671b\u4e0e\u6b64\u901a\u4fe1\u7c7b\u578b\u5173\u8054\u7684\u901a\u4fe1\u6807\u7b7e\u3002 message.enable.account=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u542f\u7528\u6b64\u5e10\u6237\u3002 +message.enabled.vpn.ip.sec=\u60a8\u7684 IPSec \u9884\u5171\u4eab\u5bc6\u94a5 +message.enabled.vpn=\u60a8\u7684 VPN \u8bbf\u95ee\u529f\u80fd\u5f53\u524d\u5df2\u542f\u7528\uff0c\u53ef\u4ee5\u901a\u8fc7 IP \u8fdb\u884c\u8bbf\u95ee message.enable.user=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u542f\u7528\u6b64\u7528\u6237\u3002 message.enable.vpn.access=\u5f53\u524d\u5df2\u5bf9\u6b64 IP \u5730\u5740\u7981\u7528\u4e86 VPN\u3002\u662f\u5426\u8981\u542f\u7528 VPN \u8bbf\u95ee? message.enable.vpn=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5bf9\u6b64 IP \u5730\u5740\u542f\u7528 VPN \u8bbf\u95ee\u3002 -message.enabled.vpn.ip.sec=\u60a8\u7684 IPSec \u9884\u5171\u4eab\u5bc6\u94a5 -message.enabled.vpn=\u60a8\u7684 VPN \u8bbf\u95ee\u529f\u80fd\u5f53\u524d\u5df2\u542f\u7528\uff0c\u53ef\u4ee5\u901a\u8fc7 IP \u8fdb\u884c\u8bbf\u95ee message.enabling.security.group.provider=\u6b63\u5728\u542f\u7528\u5b89\u5168\u7ec4\u63d0\u4f9b\u7a0b\u5e8f message.enabling.zone=\u6b63\u5728\u542f\u7528\u533a\u57df message.enter.token=\u8bf7\u8f93\u5165\u60a8\u5728\u9080\u8bf7\u7535\u5b50\u90ae\u4ef6\u4e2d\u6536\u5230\u7684\u4ee4\u724c\u3002 @@ -1412,7 +1412,7 @@ message.installWizard.copy.whatIsAHost=\u4e3b\u673a\u662f\u6307\u4e00\u53f0\u8ba message.installWizard.copy.whatIsAPod=\u4e00\u4e2a\u63d0\u4f9b\u70b9\u901a\u5e38\u4ee3\u8868\u4e00\u4e2a\u673a\u67b6\u3002\u540c\u4e00\u63d0\u4f9b\u70b9\u4e2d\u7684\u4e3b\u673a\u4f4d\u4e8e\u540c\u4e00\u5b50\u7f51\u4e2d\u3002

\u63d0\u4f9b\u70b9\u662f CloudStack&\#8482; \u90e8\u7f72\u4e2d\u7684\u7b2c\u4e8c\u5927\u7ec4\u7ec7\u5355\u4f4d\u3002\u63d0\u4f9b\u70b9\u5305\u542b\u5728\u533a\u57df\u4e2d\u3002\u6bcf\u4e2a\u533a\u57df\u4e2d\u53ef\u4ee5\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u63d0\u4f9b\u70b9\uff1b\u5728\u57fa\u672c\u5b89\u88c5\u4e2d\uff0c\u60a8\u7684\u533a\u57df\u4e2d\u5c06\u4ec5\u5305\u542b\u4e00\u4e2a\u63d0\u4f9b\u70b9\u3002 message.installWizard.copy.whatIsAZone=\u533a\u57df\u662f CloudStack&\#8482; \u90e8\u7f72\u4e2d\u6700\u5927\u7684\u7ec4\u7ec7\u5355\u4f4d\u3002\u867d\u7136\u5141\u8bb8\u4e00\u4e2a\u6570\u636e\u4e2d\u5fc3\u4e2d\u5b58\u5728\u591a\u4e2a\u533a\u57df\uff0c\u4f46\u662f\u4e00\u4e2a\u533a\u57df\u901a\u5e38\u4e0e\u4e00\u4e2a\u6570\u636e\u4e2d\u5fc3\u76f8\u5bf9\u5e94\u3002\u5c06\u57fa\u7840\u67b6\u6784\u7f16\u7ec4\u5230\u533a\u57df\u4e2d\u7684\u597d\u5904\u662f\u53ef\u4ee5\u63d0\u4f9b\u7269\u7406\u9694\u79bb\u548c\u5197\u4f59\u3002\u4f8b\u5982\uff0c\u6bcf\u4e2a\u533a\u57df\u90fd\u53ef\u4ee5\u62e5\u6709\u5404\u81ea\u7684\u7535\u6e90\u4f9b\u5e94\u548c\u7f51\u7edc\u4e0a\u884c\u65b9\u6848\uff0c\u5e76\u4e14\u5404\u533a\u57df\u53ef\u4ee5\u5728\u5730\u7406\u4f4d\u7f6e\u4e0a\u76f8\u9694\u5f88\u8fdc(\u867d\u7136\u5e76\u975e\u5fc5\u987b\u76f8\u9694\u5f88\u8fdc)\u3002 message.installWizard.copy.whatIsCloudStack=CloudStack&\#8482 \u662f\u4e00\u4e2a\u8f6f\u4ef6\u5e73\u53f0\uff0c\u53ef\u5c06\u8ba1\u7b97\u8d44\u6e90\u96c6\u4e2d\u5728\u4e00\u8d77\u4ee5\u6784\u5efa\u516c\u5171\u3001\u79c1\u6709\u548c\u6df7\u5408\u57fa\u7840\u8bbe\u65bd\u5373\u670d\u52a1(IaaS)\u4e91\u3002CloudStack&\#8482 \u8d1f\u8d23\u7ba1\u7406\u7ec4\u6210\u4e91\u57fa\u7840\u67b6\u6784\u7684\u7f51\u7edc\u3001\u5b58\u50a8\u548c\u8ba1\u7b97\u8282\u70b9\u3002\u4f7f\u7528 CloudStack&\#8482 \u53ef\u4ee5\u90e8\u7f72\u3001\u7ba1\u7406\u548c\u914d\u7f6e\u4e91\u8ba1\u7b97\u73af\u5883\u3002

CloudStack&\#8482 \u901a\u8fc7\u6269\u5c55\u5546\u7528\u786c\u4ef6\u4e0a\u8fd0\u884c\u7684\u6bcf\u4e2a\u865a\u62df\u673a\u6620\u50cf\u7684\u8303\u56f4\uff0c\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5b9e\u65f6\u53ef\u7528\u7684\u4e91\u57fa\u7840\u67b6\u6784\u8f6f\u4ef6\u5806\u6808\u7528\u4e8e\u4ee5\u670d\u52a1\u65b9\u5f0f\u4ea4\u4ed8\u865a\u62df\u6570\u636e\u4e2d\u5fc3\uff0c\u5373\u4ea4\u4ed8\u6784\u5efa\u3001\u90e8\u7f72\u548c\u7ba1\u7406\u591a\u5c42\u6b21\u548c\u591a\u79df\u6237\u4e91\u5e94\u7528\u7a0b\u5e8f\u5fc5\u9700\u7684\u6240\u6709\u7ec4\u4ef6\u3002\u5f00\u6e90\u7248\u672c\u548c Premium \u7248\u672c\u90fd\u5df2\u53ef\u7528\uff0c\u4e14\u63d0\u4f9b\u7684\u529f\u80fd\u51e0\u4e4e\u5b8c\u5168\u76f8\u540c\u3002 -message.installWizard.copy.whatIsPrimaryStorage=CloudStack&\#8482; \u4e91\u57fa\u7840\u67b6\u6784\u4f7f\u7528\u4ee5\u4e0b\u4e24\u79cd\u7c7b\u578b\u7684\u5b58\u50a8: \u4e3b\u5b58\u50a8\u548c\u8f85\u52a9\u5b58\u50a8\u3002\u8fd9\u4e24\u79cd\u7c7b\u578b\u7684\u5b58\u50a8\u53ef\u4ee5\u662f iSCSI \u6216 NFS \u670d\u52a1\u5668\uff0c\u4e5f\u53ef\u4ee5\u662f\u672c\u5730\u78c1\u76d8\u3002

\u4e3b\u5b58\u50a8\u4e0e\u7fa4\u96c6\u76f8\u5173\u8054\uff0c\u7528\u4e8e\u5b58\u50a8\u8be5\u7fa4\u96c6\u4e2d\u7684\u4e3b\u673a\u4e0a\u6b63\u5728\u8fd0\u884c\u7684\u6240\u6709 VM \u5bf9\u5e94\u7684\u6bcf\u4e2a\u6765\u5bbe VM \u7684\u78c1\u76d8\u5377\u3002\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u901a\u5e38\u4f4d\u4e8e\u9760\u8fd1\u4e3b\u673a\u7684\u4f4d\u7f6e\u3002 +message.installWizard.copy.whatIsPrimaryStorage=CloudStack&\#8482; \u4e91\u57fa\u7840\u67b6\u6784\u4f7f\u7528\u4ee5\u4e0b\u4e24\u79cd\u7c7b\u578b\u7684\u5b58\u50a8\: \u4e3b\u5b58\u50a8\u548c\u8f85\u52a9\u5b58\u50a8\u3002\u8fd9\u4e24\u79cd\u7c7b\u578b\u7684\u5b58\u50a8\u53ef\u4ee5\u662f iSCSI \u6216 NFS \u670d\u52a1\u5668\uff0c\u4e5f\u53ef\u4ee5\u662f\u672c\u5730\u78c1\u76d8\u3002

\u4e3b\u5b58\u50a8\u4e0e\u7fa4\u96c6\u76f8\u5173\u8054\uff0c\u7528\u4e8e\u5b58\u50a8\u8be5\u7fa4\u96c6\u4e2d\u7684\u4e3b\u673a\u4e0a\u6b63\u5728\u8fd0\u884c\u7684\u6240\u6709 VM \u5bf9\u5e94\u7684\u6bcf\u4e2a\u6765\u5bbe VM \u7684\u78c1\u76d8\u5377\u3002\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u901a\u5e38\u4f4d\u4e8e\u9760\u8fd1\u4e3b\u673a\u7684\u4f4d\u7f6e\u3002 message.installWizard.copy.whatIsSecondaryStorage=\u8f85\u52a9\u5b58\u50a8\u4e0e\u533a\u57df\u76f8\u5173\u8054\uff0c\u7528\u4e8e\u5b58\u50a8\u4ee5\u4e0b\u9879\u76ee\:
  • \u6a21\u677f - \u53ef\u7528\u4e8e\u542f\u52a8 VM \u5e76\u53ef\u4ee5\u5305\u542b\u5176\u4ed6\u914d\u7f6e\u4fe1\u606f(\u4f8b\u5982\uff0c\u5df2\u5b89\u88c5\u7684\u5e94\u7528\u7a0b\u5e8f)\u7684\u64cd\u4f5c\u7cfb\u7edf\u6620\u50cf
  • ISO \u6620\u50cf - \u53ef\u91cd\u65b0\u542f\u52a8\u6216\u4e0d\u53ef\u91cd\u65b0\u542f\u52a8\u7684\u64cd\u4f5c\u7cfb\u7edf\u6620\u50cf
  • \u78c1\u76d8\u5377\u5feb\u7167 - \u5df2\u4fdd\u5b58\u7684 VM \u6570\u636e\u526f\u672c\uff0c\u53ef\u7528\u4e8e\u6267\u884c\u6570\u636e\u6062\u590d\u6216\u521b\u5efa\u65b0\u6a21\u677f
message.installWizard.now.building=\u73b0\u5728\u6b63\u5728\u6784\u5efa\u60a8\u7684\u4e91... message.installWizard.tooltip.addCluster.name=\u7fa4\u96c6\u7684\u540d\u79f0\u3002\u6b64\u540d\u79f0\u53ef\u4ee5\u662f\u60a8\u9009\u62e9\u7684\u6587\u672c\uff0c\u4e14\u672a\u7531 CloudStack \u4f7f\u7528\u3002 @@ -1454,6 +1454,7 @@ message.migrate.router.confirm=\u8bf7\u786e\u8ba4\u60a8\u8981\u5c06\u8def\u7531\ message.migrate.systemvm.confirm=\u8bf7\u786e\u8ba4\u60a8\u8981\u5c06\u7cfb\u7edf VM \u8fc1\u79fb\u5230\u7684\u4e3b\u673a\: message.migrate.volume=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5c06\u5377\u8fc1\u79fb\u5230\u5176\u4ed6\u4e3b\u5b58\u50a8\u3002 message.new.user=\u8bf7\u6307\u5b9a\u4ee5\u4e0b\u4fe1\u606f\u4ee5\u5411\u5e10\u6237\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u65b0\u7528\u6237 +message.no.affinity.groups=\u60a8\u6ca1\u6709\u4efb\u4f55\u5173\u8054\u6027\u7ec4\u3002\u8bf7\u7ee7\u7eed\u6267\u884c\u4e0b\u4e00\u6b65\u64cd\u4f5c\u3002 message.no.network.support.configuration.not.true=\u60a8\u7684\u6240\u6709\u533a\u57df\u90fd\u672a\u542f\u7528\u5b89\u5168\u7ec4\uff0c\u56e0\u6b64\u65e0\u5176\u4ed6\u7f51\u7edc\u529f\u80fd\u3002\u8bf7\u7ee7\u7eed\u6267\u884c\u6b65\u9aa4 5\u3002 message.no.network.support=\u60a8\u9009\u62e9\u7684\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f vSphere \u6ca1\u6709\u4efb\u4f55\u5176\u4ed6\u7f51\u7edc\u529f\u80fd\u3002\u8bf7\u7ee7\u7eed\u6267\u884c\u6b65\u9aa4 5\u3002 message.no.projects.adminOnly=\u60a8\u6ca1\u6709\u4efb\u4f55\u9879\u76ee\u3002
\u8bf7\u8981\u6c42\u7ba1\u7406\u5458\u521b\u5efa\u4e00\u4e2a\u65b0\u9879\u76ee\u3002 @@ -1486,6 +1487,7 @@ message.restart.mgmt.usage.server=\u8bf7\u91cd\u65b0\u542f\u52a8\u7ba1\u7406\u67 message.restart.network=\u6b64\u7f51\u7edc\u63d0\u4f9b\u7684\u6240\u6709\u670d\u52a1\u90fd\u5c06\u4e2d\u65ad\u3002\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u91cd\u65b0\u542f\u52a8\u6b64\u7f51\u7edc\u3002 message.restart.vpc=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u91cd\u65b0\u542f\u52a8 VPC message.security.group.usage=(\u6309\u4f4f Ctrl \u952e\u5e76\u5355\u51fb\u9f20\u6807\u53ef\u9009\u62e9\u6240\u6709\u9002\u7528\u7684\u5b89\u5168\u7ec4) +message.select.affinity.groups=\u8bf7\u9009\u62e9\u60a8\u5e0c\u671b\u6b64 VM \u6240\u5c5e\u7684\u4efb\u4f55\u5173\u8054\u6027\u7ec4\: message.select.a.zone=\u4e00\u4e2a\u533a\u57df\u901a\u5e38\u4e0e\u4e00\u4e2a\u6570\u636e\u4e2d\u5fc3\u76f8\u5bf9\u5e94\u3002\u591a\u4e2a\u533a\u57df\u53ef\u4ee5\u63d0\u4f9b\u7269\u7406\u9694\u79bb\u548c\u5197\u4f59\uff0c\u6709\u52a9\u4e8e\u4f7f\u4e91\u66f4\u52a0\u53ef\u9760\u3002 message.select.instance=\u8bf7\u9009\u62e9\u4e00\u4e2a\u5b9e\u4f8b\u3002 message.select.iso=\u8bf7\u4e3a\u60a8\u7684\u65b0\u865a\u62df\u5b9e\u4f8b\u9009\u62e9\u4e00\u4e2a ISO\u3002 @@ -1521,13 +1523,14 @@ message.update.os.preference=\u8bf7\u4e3a\u6b64\u4e3b\u673a\u9009\u62e9\u4e00\u4 message.update.resource.count=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u66f4\u65b0\u6b64\u5e10\u6237\u7684\u8d44\u6e90\u6570\u3002 message.update.ssl=\u8bf7\u63d0\u4ea4\u4e00\u4e2a\u65b0\u7684 X.509 \u517c\u5bb9\u7684 SSL \u8bc1\u4e66\uff0c\u4ee5\u4fbf\u5c06\u5176\u66f4\u65b0\u5230\u6bcf\u4e2a\u63a7\u5236\u53f0\u4ee3\u7406\u865a\u62df\u5b9e\u4f8b\: message.validate.instance.name=\u5b9e\u4f8b\u540d\u79f0\u4e0d\u5f97\u8d85\u8fc7 63 \u4e2a\u5b57\u7b26\u3002\u4ec5\u5141\u8bb8\u4f7f\u7528 ASCII \u5b57\u6bcd a - z \u6216 A - Z\u3001\u6570\u5b57 0 - 9 \u4ee5\u53ca\u8fde\u5b57\u7b26\u3002\u5b9e\u4f8b\u540d\u79f0\u5fc5\u987b\u4ee5\u5b57\u6bcd\u5f00\u5934\u5e76\u4ee5\u5b57\u6bcd\u6216\u6570\u5b57\u7ed3\u675f\u3002 +message.validate.invalid.characters=\u67e5\u627e\u5230\u65e0\u6548\u5b57\u7b26\uff0c\u8bf7\u66f4\u6b63\u3002 message.virtual.network.desc=\u60a8\u7684\u5e10\u6237\u7684\u4e13\u7528\u865a\u62df\u7f51\u7edc\u3002\u5e7f\u64ad\u57df\u5305\u542b\u5728 VLAN \u4e2d\uff0c\u5e76\u4e14\u6240\u6709\u516c\u7528\u7f51\u7edc\u8bbf\u95ee\u90fd\u7531\u865a\u62df\u8def\u7531\u5668\u8def\u7531\u51fa\u53bb\u3002 message.vm.create.template.confirm=\u521b\u5efa\u6a21\u677f\u5c06\u81ea\u52a8\u91cd\u65b0\u542f\u52a8 VM\u3002 message.vm.review.launch=\u8bf7\u5148\u6838\u5bf9\u4ee5\u4e0b\u4fe1\u606f\uff0c\u786e\u8ba4\u60a8\u7684\u865a\u62df\u5b9e\u4f8b\u6b63\u786e\u65e0\u8bef\uff0c\u7136\u540e\u518d\u542f\u52a8\u3002 message.volume.create.template.confirm=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u4e3a\u6b64\u78c1\u76d8\u5377\u521b\u5efa\u4e00\u4e2a\u6a21\u677f\u3002\u521b\u5efa\u6a21\u677f\u53ef\u80fd\u9700\u8981\u51e0\u5206\u949f\u5230\u66f4\u957f\u7684\u65f6\u95f4\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u5377\u7684\u5927\u5c0f\u3002 message.you.must.have.at.least.one.physical.network=\u60a8\u5fc5\u987b\u81f3\u5c11\u62e5\u6709\u4e00\u4e2a\u7269\u7406\u7f51\u7edc -message.zone.creation.complete.would.you.like.to.enable.this.zone=\u5df2\u5b8c\u6210\u521b\u5efa\u533a\u57df\u3002\u662f\u5426\u8981\u542f\u7528\u6b64\u533a\u57df? message.Zone.creation.complete=\u5df2\u5b8c\u6210\u521b\u5efa\u533a\u57df +message.zone.creation.complete.would.you.like.to.enable.this.zone=\u5df2\u5b8c\u6210\u521b\u5efa\u533a\u57df\u3002\u662f\u5426\u8981\u542f\u7528\u6b64\u533a\u57df? message.zone.no.network.selection=\u6240\u9009\u533a\u57df\u65e0\u4efb\u4f55\u7f51\u7edc\u9009\u9879\u3002 message.zone.step.1.desc=\u8bf7\u4e3a\u60a8\u7684\u533a\u57df\u9009\u62e9\u4e00\u79cd\u7f51\u7edc\u6a21\u5f0f\u3002 message.zone.step.2.desc=\u8bf7\u8f93\u5165\u4ee5\u4e0b\u4fe1\u606f\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u65b0\u533a\u57df @@ -1550,14 +1553,14 @@ state.Creating=\u6b63\u5728\u521b\u5efa state.Declined=\u5df2\u62d2\u7edd state.Destroyed=\u5df2\u9500\u6bc1 state.Disabled=\u5df2\u7981\u7528 -state.Enabled=\u5df2\u542f\u7528 state.enabled=\u5df2\u542f\u7528 +state.Enabled=\u5df2\u542f\u7528 state.Error=\u9519\u8bef state.Expunging=\u6b63\u5728\u5220\u9664 state.Migrating=\u6b63\u5728\u8fc1\u79fb state.Pending=\u5f85\u5b9a -state.Ready=\u5df2\u5c31\u7eea state.ready=\u5df2\u5c31\u7eea +state.Ready=\u5df2\u5c31\u7eea state.Running=\u6b63\u5728\u8fd0\u884c state.Starting=\u6b63\u5728\u542f\u52a8 state.Stopped=\u5df2\u505c\u6b62 diff --git a/client/pom.xml b/client/pom.xml index a15a409a33c9..253b3585f4cc 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloudstack - 4.3.0-SNAPSHOT + 4.3.0 @@ -176,6 +176,11 @@ cloud-plugin-planner-user-dispersing ${project.version} + + org.apache.cloudstack + cloud-plugin-planner-skip-heurestics + ${project.version} + org.apache.cloudstack cloud-plugin-planner-user-concentrated-pod @@ -345,6 +350,14 @@ org.mortbay.jetty maven-jetty-plugin 6.1.26 + + + + mysql + mysql-connector-java + ${cs.mysql.version} + + 0 9966 diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index cb9dcf0b0710..add35ddaed1c 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -71,7 +71,7 @@ assignVirtualMachine=7 migrateVirtualMachine=1 migrateVirtualMachineWithVolume=1 recoverVirtualMachine=7 -expungeVirtualMachine=1 +expungeVirtualMachine=7 #### snapshot commands createSnapshot=15 @@ -246,6 +246,7 @@ deleteEvents=15 listAlerts=3 archiveAlerts=1 deleteAlerts=1 +generateAlert=1 #### system capacity commands listCapacity=3 @@ -265,7 +266,7 @@ deleteImageStore=1 createSecondaryStagingStore=1 listSecondaryStagingStores=1 deleteSecondaryStagingStore=1 -prepareSecondaryStorageForMigration=1 +updateCloudToUseObjectStore=1 #### host commands addHost=3 @@ -543,10 +544,6 @@ listSrxFirewalls=1 listSrxFirewallNetworks=1 #### Palo Alto firewall commands -addExternalFirewall=1 -deleteExternalFirewall=1 -listExternalFirewalls=1 - addPaloAltoFirewall=1 deletePaloAltoFirewall=1 configurePaloAltoFirewall=1 @@ -590,6 +587,11 @@ addBigSwitchVnsDevice=1 deleteBigSwitchVnsDevice=1 listBigSwitchVnsDevices=1 +#### stratosphere ssp commands + +addStratosphereSsp=1 +deleteStratoshereSsp=1 + #### host simulator commands configureSimulator=1 @@ -636,8 +638,12 @@ addUcsManager=1 listUcsManagers=1 listUcsProfiles=1 listUcsBlades=1 +listUcsTemplates=1 associateUcsProfileToBlade=1 -removedeleteUcsManager=1 +deleteUcsManager=1 +disassociateUcsProfileFromBlade=1 +refreshUcsBlades=1 +instantiateUcsTemplateAndAssocaciateToBlade=1 #### New Load Balancer commands createLoadBalancer=15 diff --git a/client/tomcatconf/db.properties.in b/client/tomcatconf/db.properties.in index 31e080333703..b224cec97001 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/pom.xml b/core/pom.xml index 9fa011d226a1..0dca31e7315b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack - 4.3.0-SNAPSHOT + 4.3.0 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 a8b2e2954af5..5e799c064838 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 @@ -77,6 +77,11 @@ + + + + @@ -213,6 +218,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 3388ca41284c..a54d58818bc4 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/resources/META-INF/cloudstack/planner/spring-core-lifecycle-planner-context-inheritable.xml b/core/resources/META-INF/cloudstack/planner/spring-core-lifecycle-planner-context-inheritable.xml index 715f86d9c28f..80779e434668 100644 --- a/core/resources/META-INF/cloudstack/planner/spring-core-lifecycle-planner-context-inheritable.xml +++ b/core/resources/META-INF/cloudstack/planner/spring-core-lifecycle-planner-context-inheritable.xml @@ -38,4 +38,9 @@ value="org.apache.cloudstack.affinity.AffinityGroupProcessor" /> + + + + + diff --git a/core/src/com/cloud/agent/api/MigrateWithStorageAnswer.java b/core/src/com/cloud/agent/api/MigrateWithStorageAnswer.java index 6468884f4644..3812c2c3114f 100644 --- a/core/src/com/cloud/agent/api/MigrateWithStorageAnswer.java +++ b/core/src/com/cloud/agent/api/MigrateWithStorageAnswer.java @@ -25,7 +25,7 @@ public class MigrateWithStorageAnswer extends Answer { List volumeTos; public MigrateWithStorageAnswer(MigrateWithStorageCommand cmd, Exception ex) { - super(cmd, ex); + super(cmd, false, ex.getLocalizedMessage()); volumeTos = null; } diff --git a/core/src/com/cloud/agent/api/PingRoutingCommand.java b/core/src/com/cloud/agent/api/PingRoutingCommand.java index e25ac62786f4..cffa7ecab216 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.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 51226bc36c1c..5a25a7583cec 100644 --- a/core/src/com/cloud/agent/api/PingRoutingWithNwGroupsCommand.java +++ b/core/src/com/cloud/agent/api/PingRoutingWithNwGroupsCommand.java @@ -31,8 +31,10 @@ protected PingRoutingWithNwGroupsCommand() { 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 d44987b20fd6..b87dd0a7e96f 100644 --- a/core/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java +++ b/core/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java @@ -31,8 +31,10 @@ protected PingRoutingWithOvsCommand() { } 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/SetupCommand.java b/core/src/com/cloud/agent/api/SetupCommand.java index 65700e9453cb..ee43c5933dab 100644 --- a/core/src/com/cloud/agent/api/SetupCommand.java +++ b/core/src/com/cloud/agent/api/SetupCommand.java @@ -23,8 +23,6 @@ public class SetupCommand extends Command { HostEnvironment env; boolean multipath; boolean needSetup; - String secondaryStorage; - String systemVmIso; public boolean needSetup() { return needSetup; @@ -38,8 +36,6 @@ public SetupCommand(HostEnvironment env) { this.env = env; this.multipath = false; this.needSetup = false; - secondaryStorage = null; - systemVmIso = null; } public HostEnvironment getEnvironment() { @@ -57,22 +53,6 @@ public boolean useMultipath() { return multipath; } - public void setSecondaryStorage(String secondaryStorage) { - this.secondaryStorage = secondaryStorage; - } - - public String getSecondaryStorage() { - return this.secondaryStorage; - } - - public void setSystemVmIso(String systemVmIso) { - this.systemVmIso = systemVmIso; - } - - public String getSystemVmIso() { - return this.systemVmIso; - } - @Override public boolean executeInSequence() { return true; diff --git a/core/src/com/cloud/agent/api/StartCommand.java b/core/src/com/cloud/agent/api/StartCommand.java index 308730ab5b77..88810c6ba5d2 100644 --- a/core/src/com/cloud/agent/api/StartCommand.java +++ b/core/src/com/cloud/agent/api/StartCommand.java @@ -25,6 +25,7 @@ public class StartCommand extends Command { VirtualMachineTO vm; String hostIp; boolean executeInSequence = false; + String secondaryStorage; public VirtualMachineTO getVirtualMachine() { return vm; @@ -42,9 +43,18 @@ public StartCommand(VirtualMachineTO vm, Host host, boolean executeInSequence) { this.vm = vm; this.hostIp = host.getPrivateIpAddress(); this.executeInSequence = executeInSequence; + this.secondaryStorage = null; } public String getHostIp() { return this.hostIp; } + + public String getSecondaryStorage() { + return this.secondaryStorage; + } + + public void setSecondaryStorage(String secondary) { + this.secondaryStorage = secondary; + } } diff --git a/core/src/com/cloud/agent/api/StartupRoutingCommand.java b/core/src/com/cloud/agent/api/StartupRoutingCommand.java index f312e0fc72dd..c75b6d1e73f9 100755 --- a/core/src/com/cloud/agent/api/StartupRoutingCommand.java +++ b/core/src/com/cloud/agent/api/StartupRoutingCommand.java @@ -48,8 +48,18 @@ public String getHost() { 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 StartupRoutingCommand(int cpus, 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 StartupRoutingCommand(int cpus, 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 @@ public StartupRoutingCommand(int cpus, 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 @@ public StartupRoutingCommand(int cpus, 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 @@ public String getHypervisorVersion() { 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/StopAnswer.java b/core/src/com/cloud/agent/api/StopAnswer.java index 614835e2a37e..e417e0bb89ff 100755 --- a/core/src/com/cloud/agent/api/StopAnswer.java +++ b/core/src/com/cloud/agent/api/StopAnswer.java @@ -18,36 +18,29 @@ public class StopAnswer extends RebootAnswer { - private String hypervisortoolsversion; - Integer timeOffset; + private String platform; protected StopAnswer() { } - public StopAnswer(StopCommand cmd, String details, String hypervisortoolsversion, Integer timeOffset, boolean success) { + public StopAnswer(StopCommand cmd, String details, String platform, boolean success) { super(cmd, details, success); - this.hypervisortoolsversion = hypervisortoolsversion; - this.timeOffset = timeOffset; + this.platform = platform; } public StopAnswer(StopCommand cmd, String details, boolean success) { super(cmd, details, success); - this.hypervisortoolsversion = null; - this.timeOffset = null; + this.platform = null; } public StopAnswer(StopCommand cmd, Exception e) { super(cmd, e); - this.hypervisortoolsversion = null; - this.timeOffset = null; + this.platform = null; } - public String getHypervisorToolsVersion() { - return hypervisortoolsversion; + public String getPlatform() { + return platform; } - public Integer getTimeOffset() { - return timeOffset; - } } diff --git a/core/src/com/cloud/agent/api/routing/NetworkElementCommand.java b/core/src/com/cloud/agent/api/routing/NetworkElementCommand.java index 843d213896e7..23b75fd671b3 100644 --- a/core/src/com/cloud/agent/api/routing/NetworkElementCommand.java +++ b/core/src/com/cloud/agent/api/routing/NetworkElementCommand.java @@ -34,6 +34,8 @@ public abstract class NetworkElementCommand extends Command { public static final String GUEST_BRIDGE = "guest.bridge"; public static final String VPC_PRIVATE_GATEWAY = "vpc.gateway.private"; public static final String FIREWALL_EGRESS_DEFAULT = "firewall.egress.default"; + public static final String ROUTER_MONITORING_DISABLE = "router.monitor.disable"; + protected NetworkElementCommand() { diff --git a/core/src/com/cloud/agent/api/storage/MigrateVolumeCommand.java b/core/src/com/cloud/agent/api/storage/MigrateVolumeCommand.java index b82d8481f2c4..b73a48a1b37b 100644 --- a/core/src/com/cloud/agent/api/storage/MigrateVolumeCommand.java +++ b/core/src/com/cloud/agent/api/storage/MigrateVolumeCommand.java @@ -25,6 +25,7 @@ public class MigrateVolumeCommand extends Command { long volumeId; String volumePath; StorageFilerTO pool; + String attachedVmName; public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool) { this.volumeId = volumeId; @@ -32,6 +33,13 @@ public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool) this.pool = new StorageFilerTO(pool); } + public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool, String attachedVmName) { + this.volumeId = volumeId; + this.volumePath = volumePath; + this.pool = new StorageFilerTO(pool); + this.attachedVmName = attachedVmName; + } + @Override public boolean executeInSequence() { return true; @@ -48,4 +56,8 @@ public long getVolumeId() { public StorageFilerTO getPool() { return pool; } + + public String getAttachedVmName() { + return attachedVmName; + } } \ No newline at end of file diff --git a/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java b/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java index b124aa68f5fd..035a5b3e1309 100755 --- a/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java +++ b/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java @@ -35,6 +35,7 @@ import javax.ejb.Local; import javax.naming.ConfigurationException; +import com.cloud.agent.api.routing.SetMonitorServiceCommand; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; @@ -169,6 +170,8 @@ public Answer executeRequest(final Command cmd) { return execute((Site2SiteVpnCfgCommand)cmd); } else if (cmd instanceof CheckS2SVpnConnectionsCommand) { return execute((CheckS2SVpnConnectionsCommand)cmd); + } else if (cmd instanceof SetMonitorServiceCommand) { + return execute((SetMonitorServiceCommand) cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); @@ -667,7 +670,7 @@ private CheckS2SVpnConnectionsAnswer execute(CheckS2SVpnConnectionsCommand cmd) } final String result = routerProxy("checkbatchs2svpn.sh", routerIP, args); - if (result != null) { + if (result == null || result.isEmpty()) { return new CheckS2SVpnConnectionsAnswer(cmd, false, "CheckS2SVpnConneciontsCommand failed"); } return new CheckS2SVpnConnectionsAnswer(cmd, true, result); @@ -818,9 +821,12 @@ private Answer executeProxyLoadScan(final Command cmd, final long proxyVmId, fin return new ConsoleProxyLoadAnswer(cmd, proxyVmId, proxyVmName, success, result); } - public String configureMonitor(final String routerIP, final String config) { + public String configureMonitor(final String routerIP, final String config, final String disable) { String args= " -c " + config; + if (disable != null) { + args = args + "-d"; + } return routerProxy("monitor_service.sh", routerIP, args); } @@ -962,6 +968,22 @@ private SetStaticRouteAnswer execute(SetStaticRouteCommand cmd) { } } + private Answer execute(SetMonitorServiceCommand cmd) { + + String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP); + String disable = cmd.getAccessDetail(NetworkElementCommand.ROUTER_MONITORING_DISABLE); + String config = cmd.getConfiguration(); + + + String result = configureMonitor(routerIp, config, disable); + + if (result != null) { + return new Answer(cmd, false, "SetMonitorServiceCommand failed"); + } + return new Answer(cmd); + + } + public String assignPublicIpAddress(final String vmName, final String privateIpAddress, final String publicIpAddress, final boolean add, final boolean firstIP, final boolean sourceNat, @@ -1291,4 +1313,5 @@ public void setRunLevel(int level) { // TODO Auto-generated method stub } + } diff --git a/core/src/com/cloud/agent/transport/Request.java b/core/src/com/cloud/agent/transport/Request.java index cbeb112fea76..2b545a173a39 100755 --- a/core/src/com/cloud/agent/transport/Request.java +++ b/core/src/com/cloud/agent/transport/Request.java @@ -23,6 +23,7 @@ import java.lang.reflect.Type; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.zip.GZIPInputStream; @@ -49,6 +50,7 @@ import com.cloud.serializer.GsonHelper; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; +import com.cloud.utils.StringUtils; import com.cloud.utils.exception.CloudRuntimeException; /** @@ -439,11 +441,35 @@ protected String log(String msg, boolean logContent, Level level) { } buf.append(", Ver: ").append(_ver.toString()); buf.append(", Flags: ").append(Integer.toBinaryString(getFlags())).append(", "); - buf.append(content); + String cleanContent = content.toString(); + if(cleanContent.contains("password")) { + buf.append(cleanPassword(cleanContent)); + } else { + buf.append(content); + } buf.append(" }"); return buf.toString(); } + public static String cleanPassword(String logString) { + String cleanLogString = null; + if (logString != null) { + cleanLogString = logString; + String[] temp = logString.split(","); + int i = 0; + if (temp != null) { + while (i < temp.length) { + temp[i] = StringUtils.cleanString(temp[i]); + i++; + } + List stringList = new ArrayList(); + Collections.addAll(stringList, temp); + cleanLogString = StringUtils.join(stringList, ","); + } + } + return cleanLogString; + } + /** * Factory method for Request and Response. It expects the bytes to be * correctly formed so it's possible that it throws underflow exceptions diff --git a/core/src/com/cloud/host/HostInfo.java b/core/src/com/cloud/host/HostInfo.java index af929e3c924a..3364e8f5ad7e 100644 --- a/core/src/com/cloud/host/HostInfo.java +++ b/core/src/com/cloud/host/HostInfo.java @@ -21,5 +21,6 @@ public final class HostInfo { public static final String HOST_OS = "Host.OS"; //Fedora, XenServer, Ubuntu, etc public static final String HOST_OS_VERSION = "Host.OS.Version"; //12, 5.5, 9.10, etc public static final String HOST_OS_KERNEL_VERSION = "Host.OS.Kernel.Version"; //linux-2.6.31 etc + public static final String XS620_SNAPSHOT_HOTFIX = "xs620_snapshot_hotfix"; } diff --git a/core/src/com/cloud/info/ConsoleProxyInfo.java b/core/src/com/cloud/info/ConsoleProxyInfo.java index 3439f3d3bfa2..096302c5ae6a 100644 --- a/core/src/com/cloud/info/ConsoleProxyInfo.java +++ b/core/src/com/cloud/info/ConsoleProxyInfo.java @@ -32,17 +32,17 @@ public ConsoleProxyInfo(boolean sslEnabled, String proxyIpAddress, int port, int this.sslEnabled = sslEnabled; if(sslEnabled) { - StringBuffer sb = new StringBuffer(proxyIpAddress); - for(int i = 0; i < sb.length(); i++) - if(sb.charAt(i) == '.') - sb.setCharAt(i, '-'); - if(consoleProxyUrlDomain!=null && consoleProxyUrlDomain.length()>0) - { - sb.append("."); - sb.append(consoleProxyUrlDomain); - } - else + StringBuffer sb = new StringBuffer(); + if (consoleProxyUrlDomain.startsWith("*")) { + sb.append(proxyIpAddress); + for (int i = 0; i < proxyIpAddress.length(); i++) + if (sb.charAt(i) == '.') + sb.setCharAt(i, '-'); + sb.append(consoleProxyUrlDomain.substring(1)); //skip the * + } else { + //LB address sb.append(".realhostip.com"); + } proxyAddress = sb.toString(); proxyPort = port; diff --git a/core/src/org/apache/cloudstack/storage/command/AttachCommand.java b/core/src/org/apache/cloudstack/storage/command/AttachCommand.java index 7e47ba4e3177..303457b4a4b8 100644 --- a/core/src/org/apache/cloudstack/storage/command/AttachCommand.java +++ b/core/src/org/apache/cloudstack/storage/command/AttachCommand.java @@ -24,6 +24,7 @@ public final class AttachCommand extends Command implements StorageSubSystemCommand { private DiskTO disk; private String vmName; + private boolean inSeq = false; public AttachCommand(DiskTO disk, String vmName) { super(); @@ -51,4 +52,9 @@ public String getVmName() { public void setVmName(String vmName) { this.vmName = vmName; } + + @Override + public void setExecuteInSequence(boolean inSeq) { + this.inSeq = inSeq; + } } diff --git a/core/src/org/apache/cloudstack/storage/command/AttachPrimaryDataStoreCmd.java b/core/src/org/apache/cloudstack/storage/command/AttachPrimaryDataStoreCmd.java index 2083876b5677..25679ba28c4f 100644 --- a/core/src/org/apache/cloudstack/storage/command/AttachPrimaryDataStoreCmd.java +++ b/core/src/org/apache/cloudstack/storage/command/AttachPrimaryDataStoreCmd.java @@ -21,6 +21,11 @@ import com.cloud.agent.api.Command; public final class AttachPrimaryDataStoreCmd extends Command implements StorageSubSystemCommand { + @Override + public void setExecuteInSequence(boolean inSeq) { + + } + private final String dataStore; public AttachPrimaryDataStoreCmd(String uri) { diff --git a/core/src/org/apache/cloudstack/storage/command/CopyCommand.java b/core/src/org/apache/cloudstack/storage/command/CopyCommand.java index e9ec0b35f110..e4681b8a43db 100644 --- a/core/src/org/apache/cloudstack/storage/command/CopyCommand.java +++ b/core/src/org/apache/cloudstack/storage/command/CopyCommand.java @@ -16,6 +16,9 @@ // under the License. package org.apache.cloudstack.storage.command; +import java.util.HashMap; +import java.util.Map; + import com.cloud.agent.api.Command; import com.cloud.agent.api.to.DataTO; @@ -24,6 +27,7 @@ public final class CopyCommand extends Command implements StorageSubSystemComman private DataTO destTO; private DataTO cacheTO; boolean executeInSequence = false; + Map options = new HashMap(); public CopyCommand(DataTO srcData, DataTO destData, int timeout, boolean executeInSequence) { @@ -67,4 +71,16 @@ public int getWaitInMillSeconds() { return this.getWait() * 1000; } + public void setOptions(Map options) { + this.options = options; + } + + public Map getOptions() { + return options; + } + + @Override + public void setExecuteInSequence(boolean inSeq) { + this.executeInSequence = inSeq; + } } diff --git a/core/src/org/apache/cloudstack/storage/command/CreateObjectCommand.java b/core/src/org/apache/cloudstack/storage/command/CreateObjectCommand.java index 121a7ee449c8..8c239b530473 100644 --- a/core/src/org/apache/cloudstack/storage/command/CreateObjectCommand.java +++ b/core/src/org/apache/cloudstack/storage/command/CreateObjectCommand.java @@ -42,4 +42,8 @@ public DataTO getData() { return this.data; } + @Override + public void setExecuteInSequence(boolean inSeq) { + + } } diff --git a/core/src/org/apache/cloudstack/storage/command/CreatePrimaryDataStoreCmd.java b/core/src/org/apache/cloudstack/storage/command/CreatePrimaryDataStoreCmd.java index b536028927f3..21716cf1113d 100644 --- a/core/src/org/apache/cloudstack/storage/command/CreatePrimaryDataStoreCmd.java +++ b/core/src/org/apache/cloudstack/storage/command/CreatePrimaryDataStoreCmd.java @@ -35,4 +35,8 @@ public boolean executeInSequence() { return false; } + @Override + public void setExecuteInSequence(boolean inSeq) { + + } } diff --git a/core/src/org/apache/cloudstack/storage/command/DeleteCommand.java b/core/src/org/apache/cloudstack/storage/command/DeleteCommand.java index 76696da30ae1..744505076311 100644 --- a/core/src/org/apache/cloudstack/storage/command/DeleteCommand.java +++ b/core/src/org/apache/cloudstack/storage/command/DeleteCommand.java @@ -42,4 +42,8 @@ public DataTO getData() { return this.data; } + @Override + public void setExecuteInSequence(boolean inSeq) { + + } } diff --git a/core/src/org/apache/cloudstack/storage/command/DettachCommand.java b/core/src/org/apache/cloudstack/storage/command/DettachCommand.java index 61cb88b284ac..1e501d9600d7 100644 --- a/core/src/org/apache/cloudstack/storage/command/DettachCommand.java +++ b/core/src/org/apache/cloudstack/storage/command/DettachCommand.java @@ -87,4 +87,9 @@ public void setStoragePort(int storagePort) { public int getStoragePort() { return _storagePort; } + + @Override + public void setExecuteInSequence(boolean inSeq) { + + } } diff --git a/core/src/org/apache/cloudstack/storage/command/ForgetObjectCmd.java b/core/src/org/apache/cloudstack/storage/command/ForgetObjectCmd.java index 58fb7802019d..919dc3670896 100644 --- a/core/src/org/apache/cloudstack/storage/command/ForgetObjectCmd.java +++ b/core/src/org/apache/cloudstack/storage/command/ForgetObjectCmd.java @@ -34,4 +34,9 @@ public DataTO getDataTO() { public boolean executeInSequence() { return false; } + + @Override + public void setExecuteInSequence(boolean inSeq) { + + } } diff --git a/core/src/org/apache/cloudstack/storage/command/IntroduceObjectCmd.java b/core/src/org/apache/cloudstack/storage/command/IntroduceObjectCmd.java index 1aabed2d279c..a2be64fc92cf 100644 --- a/core/src/org/apache/cloudstack/storage/command/IntroduceObjectCmd.java +++ b/core/src/org/apache/cloudstack/storage/command/IntroduceObjectCmd.java @@ -35,4 +35,9 @@ public DataTO getDataTO() { public boolean executeInSequence() { return false; } + + @Override + public void setExecuteInSequence(boolean inSeq) { + + } } diff --git a/core/src/org/apache/cloudstack/storage/command/StorageSubSystemCommand.java b/core/src/org/apache/cloudstack/storage/command/StorageSubSystemCommand.java index d14161ae4c58..fb7b37368444 100644 --- a/core/src/org/apache/cloudstack/storage/command/StorageSubSystemCommand.java +++ b/core/src/org/apache/cloudstack/storage/command/StorageSubSystemCommand.java @@ -19,5 +19,5 @@ package org.apache.cloudstack.storage.command; public interface StorageSubSystemCommand { - + void setExecuteInSequence(boolean inSeq); } diff --git a/core/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java b/core/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java index 34e977c6421b..aa2a4f58e59d 100644 --- a/core/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java +++ b/core/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java @@ -16,13 +16,16 @@ // under the License. package org.apache.cloudstack.storage.to; +import java.util.ArrayList; + import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.commons.lang.ArrayUtils; import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; public class SnapshotObjectTO implements DataTO { private String path; @@ -34,6 +37,9 @@ public class SnapshotObjectTO implements DataTO { private HypervisorType hypervisorType; private long id; private boolean quiescevm; + private String[] parents; + private Long physicalSize = (long) 0; + public SnapshotObjectTO() { @@ -49,9 +55,17 @@ public SnapshotObjectTO(SnapshotInfo snapshot) { } SnapshotInfo parentSnapshot = snapshot.getParent(); + ArrayList parentsArry = new ArrayList(); if (parentSnapshot != null) { this.parentSnapshotPath = parentSnapshot.getPath(); + while(parentSnapshot != null) { + parentsArry.add(parentSnapshot.getPath()); + parentSnapshot = parentSnapshot.getParent(); + } + parents = parentsArry.toArray(new String[parentsArry.size()]); + ArrayUtils.reverse(parents); } + this.dataStore = snapshot.getDataStore().getTO(); this.setName(snapshot.getName()); this.hypervisorType = snapshot.getHypervisorType(); @@ -81,6 +95,14 @@ public void setPath(String path) { this.path = path; } + public Long getPhysicalSize() { + return this.physicalSize; + } + + public void setPhysicalSize(Long physicalSize ) { + this.physicalSize = physicalSize; + } + public VolumeObjectTO getVolume() { return volume; } @@ -139,6 +161,10 @@ public void setQuiescevm(boolean quiescevm) { this.quiescevm = quiescevm; } + public String[] getParents() { + return parents; + } + @Override public String toString() { return new StringBuilder("SnapshotTO[datastore=").append(dataStore).append("|volume=").append(volume).append("|path") diff --git a/core/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java b/core/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java index a7a1fd2a3c79..f8c779777d8e 100644 --- a/core/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java +++ b/core/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java @@ -24,6 +24,7 @@ import java.text.SimpleDateFormat; import java.util.Date; +import com.cloud.hypervisor.Hypervisor; import org.junit.Test; import com.cloud.agent.api.BackupSnapshotCommand; @@ -34,6 +35,11 @@ public class BackupSnapshotCommandTest { public StoragePool pool = new StoragePool() { + @Override + public Hypervisor.HypervisorType getHypervisor() { + return null; + } + @Override public long getId() { return 1L; diff --git a/core/test/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java b/core/test/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java index b834a26b6cc4..1e3ff7f08228 100644 --- a/core/test/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java +++ b/core/test/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java @@ -22,6 +22,7 @@ import com.cloud.agent.api.storage.ResizeVolumeCommand; import com.cloud.agent.api.to.StorageFilerTO; +import com.cloud.hypervisor.Hypervisor; import com.cloud.storage.Storage; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolStatus; @@ -185,7 +186,14 @@ public String getStorageProviderName() { public boolean isInMaintenance() { // TODO Auto-generated method stub return false; - }; + } + + @Override + public Hypervisor.HypervisorType getHypervisor() { + return null; + } + + ; }; Long newSize = 4194304L; diff --git a/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java b/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java index 031ef5cfea81..e8090db55272 100644 --- a/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java +++ b/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java @@ -76,6 +76,10 @@ public String getPrivateIpAddress() { return "10.1.1.1"; }; + public String getStorageUrl() { + return null; + } + public String getStorageIpAddress() { return "10.1.1.2"; }; diff --git a/core/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java b/core/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java index 35bdfc8c8836..b3933db1d31f 100644 --- a/core/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java +++ b/core/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java @@ -24,6 +24,7 @@ import java.text.SimpleDateFormat; import java.util.Date; +import com.cloud.hypervisor.Hypervisor; import org.junit.Before; import org.junit.Test; @@ -128,7 +129,14 @@ public String getStorageProviderName() { public boolean isInMaintenance() { // TODO Auto-generated method stub return false; - }; + } + + @Override + public Hypervisor.HypervisorType getHypervisor() { + return null; + } + + ; }; SnapshotCommand ssc = new SnapshotCommand(pool, diff --git a/debian/cloudstack-management.install b/debian/cloudstack-management.install index f06ab86dda12..ea3f93ba0cb6 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/debian/control b/debian/control index c756dcd0d8e8..c23ab3a73061 100644 --- a/debian/control +++ b/debian/control @@ -15,7 +15,7 @@ Description: A common package which contains files which are shared by several C Package: cloudstack-management Architecture: all -Depends: cloudstack-common (= ${source:Version}), tomcat6, sysvinit-utils, sudo, jsvc, python-mysqldb, python-paramiko, augeas-tools +Depends: cloudstack-common (= ${source:Version}), tomcat6, sysvinit-utils, sudo, jsvc, python-mysqldb, libmysql-java, python-paramiko, augeas-tools Conflicts: cloud-server, cloud-client, cloud-client-ui Description: CloudStack server library The CloudStack management server diff --git a/debian/rules b/debian/rules index 4edf8930605c..66800dea831c 100755 --- a/debian/rules +++ b/debian/rules @@ -12,7 +12,7 @@ DEBVERS := $(shell dpkg-parsechangelog | sed -n -e 's/^Version: //p') VERSION := $(shell echo '$(DEBVERS)' | sed -e 's/^[[:digit:]]*://' -e 's/[~-].*//') -MVNADD := $(shell if echo '$(DEBVERS)' | grep -q snapshot; then echo -SNAPSHOT; fi ) +MVNADD := $(shell if echo '$(DEBVERS)' | grep -q snapshot; then echo ; fi ) PACKAGE = $(shell dh_listpackages|head -n 1|cut -d '-' -f 1) SYSCONFDIR = "/etc" DESTDIR = "debian/tmp" diff --git a/deps/XenServerJava/pom.xml b/deps/XenServerJava/pom.xml index 0cf21135e312..01a54c6f1498 100644 --- a/deps/XenServerJava/pom.xml +++ b/deps/XenServerJava/pom.xml @@ -21,7 +21,7 @@ org.apache.cloudstack cloudstack - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml xapi diff --git a/deps/XenServerJava/src/com/xensource/xenapi/Event.java b/deps/XenServerJava/src/com/xensource/xenapi/Event.java index 3574cd19b0f7..e1273a5efd3f 100644 --- a/deps/XenServerJava/src/com/xensource/xenapi/Event.java +++ b/deps/XenServerJava/src/com/xensource/xenapi/Event.java @@ -301,4 +301,19 @@ public static String inject(Connection c, String clazz, String ref) throws return Types.toString(result); } + public static Map properFrom(Connection c, Set classes, String token, Double timeout) throws BadServerResponse, XenAPIException, XmlRpcException, + Types.SessionNotRegistered, + Types.EventsLost { + String method_call = "event.from"; + String session = c.getSessionReference(); + Object[] method_params = {Marshalling.toXMLRPC(session), Marshalling.toXMLRPC(classes), Marshalling.toXMLRPC(token), Marshalling.toXMLRPC(timeout)}; + Map response = c.dispatch(method_call, method_params); + Object result = response.get("Value"); + Map value = (Map)result; + Map from = new HashMap(); + from.put("token", value.get("token")); + from.put("events", Types.toSetOfEventRecord(value.get("events"))); + return from; + } + } \ No newline at end of file diff --git a/deps/XenServerJava/src/com/xensource/xenapi/Types.java b/deps/XenServerJava/src/com/xensource/xenapi/Types.java index bde887a4ec3a..36e38c16eb46 100644 --- a/deps/XenServerJava/src/com/xensource/xenapi/Types.java +++ b/deps/XenServerJava/src/com/xensource/xenapi/Types.java @@ -1278,6 +1278,17 @@ static Map checkResponse(Map response) throws XenAPIException, BadServerResponse String p1 = ErrorDescription.length > 1 ? ErrorDescription[1] : ""; throw new Types.CrlNameInvalid(p1); } + if (ErrorDescription[0].equals("VDI_NOT_SPARSE")) + { + String p1 = ErrorDescription.length > 1 ? ErrorDescription[1] : ""; + throw new Types.VdiNotSparse(p1); + } + if (ErrorDescription[0].equals("VDI_TOO_SMALL")) + { + String p1 = ErrorDescription.length > 1 ? ErrorDescription[1] : ""; + String p2 = ErrorDescription.length > 2 ? ErrorDescription[2] : ""; + throw new Types.VdiTooSmall(p1, p2); + } if (ErrorDescription[0].equals("HOST_POWER_ON_MODE_DISABLED")) { throw new Types.HostPowerOnModeDisabled(); @@ -7573,6 +7584,45 @@ public VdiNotInMap(String vdi) { } + /** + * The VDI is too small. Please resize it to at least the minimum size. + */ + public static class VdiTooSmall extends XenAPIException { + public final String vdi; + public final String minimumSize; + + /** + * Create a new VdiTooSmall + * + * @param vdi + * @param minimumSize + */ + public VdiTooSmall(String vdi, String minimumSize) { + super("The VDI is too small. Please resize it to at least the minimum size."); + this.vdi = vdi; + this.minimumSize = minimumSize; + } + + } + + /** + * The VDI is not stored using a sparse format. It is not possible to query and manipulate only the changed blocks (or 'block differences' or 'disk deltas') between two VDIs. Please select a VDI which uses a sparse-aware technology such as VHD. + */ + public static class VdiNotSparse extends XenAPIException { + public final String vdi; + + /** + * Create a new VdiNotSparse + * + * @param vdi + */ + public VdiNotSparse(String vdi) { + super("The VDI is not stored using a sparse format. It is not possible to query and manipulate only the changed blocks (or 'block differences' or 'disk deltas') between two VDIs. Please select a VDI which uses a sparse-aware technology such as VHD."); + this.vdi = vdi; + } + + } + /** * The hosts in this pool are not homogeneous. */ diff --git a/deps/XenServerJava/src/com/xensource/xenapi/VDI.java b/deps/XenServerJava/src/com/xensource/xenapi/VDI.java index 4ea9daff1fa5..167c5a04717a 100644 --- a/deps/XenServerJava/src/com/xensource/xenapi/VDI.java +++ b/deps/XenServerJava/src/com/xensource/xenapi/VDI.java @@ -1593,6 +1593,29 @@ public void update(Connection c) throws return; } + /** + * Copy either a full VDI or the block differences between two VDIs into either a fresh VDI or an existing VDI. + * + * @param sr The destination SR (only required if the destination VDI is not specified + * @param baseVdi The base VDI (only required if copying only changed blocks, by default all blocks will be copied) + * @param intoVdi The destination VDI to copy blocks into (if omitted then a destination SR must be provided and a fresh VDI will be created) + * @return Task + */ + public Task copyAsync2(Connection c, SR sr, VDI baseVdi, VDI intoVdi) throws + BadServerResponse, + XenAPIException, + XmlRpcException, + Types.VdiReadonly, + Types.VdiTooSmall, + Types.VdiNotSparse { + String method_call = "Async.VDI.copy"; + String session = c.getSessionReference(); + Object[] method_params = {Marshalling.toXMLRPC(session), Marshalling.toXMLRPC(this.ref), Marshalling.toXMLRPC(sr), Marshalling.toXMLRPC(baseVdi), Marshalling.toXMLRPC(intoVdi)}; + Map response = c.dispatch(method_call, method_params); + Object result = response.get("Value"); + return Types.toTask(result); + } + /** * Make a fresh VDI in the specified SR and copy the supplied VDI's data to the new disk * @@ -1600,9 +1623,9 @@ public void update(Connection c) throws * @return Task */ public Task copyAsync(Connection c, SR sr) throws - BadServerResponse, - XenAPIException, - XmlRpcException { + BadServerResponse, + XenAPIException, + XmlRpcException { String method_call = "Async.VDI.copy"; String session = c.getSessionReference(); Object[] method_params = {Marshalling.toXMLRPC(session), Marshalling.toXMLRPC(this.ref), Marshalling.toXMLRPC(sr)}; diff --git a/developer/pom.xml b/developer/pom.xml index 0eb18bf2d3f6..f2f5f771dfc0 100644 --- a/developer/pom.xml +++ b/developer/pom.xml @@ -18,7 +18,7 @@ org.apache.cloudstack cloudstack - 4.3.0-SNAPSHOT + 4.3.0 @@ -114,6 +114,14 @@ org.codehaus.mojo exec-maven-plugin 1.2.1 + + + + mysql + mysql-connector-java + ${cs.mysql.version} + + process-resources @@ -125,6 +133,7 @@ com.cloud.upgrade.DatabaseCreator + true ${basedir}/../utils/conf/db.properties @@ -182,6 +191,13 @@ org.codehaus.mojo exec-maven-plugin + + + mysql + mysql-connector-java + ${cs.mysql.version} + + 1.2.1 @@ -194,6 +210,7 @@ com.cloud.upgrade.DatabaseCreator + true ${basedir}/../utils/conf/db.properties @@ -201,6 +218,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/pom.xml b/engine/api/pom.xml index 5f170d131b0f..a74323cd47c1 100644 --- a/engine/api/pom.xml +++ b/engine/api/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml diff --git a/engine/api/src/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/com/cloud/vm/VirtualMachineManager.java index cb6c62dd69dc..58e9280a1df0 100644 --- a/engine/api/src/com/cloud/vm/VirtualMachineManager.java +++ b/engine/api/src/com/cloud/vm/VirtualMachineManager.java @@ -18,8 +18,11 @@ import java.net.URI; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import org.apache.cloudstack.framework.config.ConfigKey; + import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.deploy.DeployDestination; @@ -46,16 +49,21 @@ * Manages allocating resources to vms. */ public interface VirtualMachineManager extends Manager { - - public interface Topics { + + static final ConfigKey ExecuteInSequence = new ConfigKey("Advanced", Boolean.class, "execute.in.sequence.hypervisor.commands", "false", + "If set to true, StartCommand, StopCommand, CopyCommand, MigrateCommand will be synchronized on the agent side." + + " If set to false, these commands become asynchronous. Default value is false.", false); + + + public interface Topics { public static final String VM_POWER_STATE = "vm.powerstate"; } - + /** * Allocates a new virtual machine instance in the CloudStack DB. This * orchestrates the creation of all virtual resources needed in CloudStack * DB to bring up a VM. - * + * * @param vmInstanceName Instance name of the VM. This name uniquely * a VM in CloudStack's deploy environment. The caller gets to * define this VM but it must be unqiue for all of CloudStack. @@ -74,14 +82,14 @@ void allocate(String vmInstanceName, ServiceOffering serviceOffering, Pair rootDiskOffering, LinkedHashMap dataDiskOfferings, - LinkedHashMap auxiliaryNetworks, + LinkedHashMap> auxiliaryNetworks, DeploymentPlan plan, HypervisorType hyperType) throws InsufficientCapacityException; void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering, - LinkedHashMap networkProfiles, + LinkedHashMap> networkProfiles, DeploymentPlan plan, HypervisorType hyperType) throws InsufficientCapacityException; @@ -97,19 +105,22 @@ void allocate(String vmInstanceName, boolean stateTransitTo(VirtualMachine vm, VirtualMachine.Event e, Long hostId) throws NoTransitionException; - void advanceStart(String vmUuid, Map params) throws InsufficientCapacityException, ResourceUnavailableException, + void advanceStart(String vmUuid, Map params, DeploymentPlanner planner) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException; - void advanceStart(String vmUuid, Map params, DeploymentPlan planToDeploy) throws InsufficientCapacityException, + void advanceStart(String vmUuid, Map params, DeploymentPlan planToDeploy, DeploymentPlanner planner) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException; + void orchestrateStart(String vmUuid, Map params, DeploymentPlan planToDeploy, DeploymentPlanner planner) throws InsufficientCapacityException, + ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException; + void advanceStop(String vmUuid, boolean cleanupEvenIfUnableToStop) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException; void advanceExpunge(String vmUuid) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException; void destroy(String vmUuid) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException; - void migrateAway(String vmUuid, long hostId) throws InsufficientServerCapacityException; + void migrateAway(String vmUuid, long hostId, DeploymentPlanner planner) throws InsufficientServerCapacityException; void migrate(String vmUuid, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException; @@ -122,22 +133,22 @@ void advanceReboot(String vmUuid, Map param /** * Check to see if a virtual machine can be upgraded to the given service offering - * + * * @param vm * @param offering * @return true if the host can handle the upgrade, false otherwise */ boolean isVirtualMachineUpgradable(final VirtualMachine vm, final ServiceOffering offering); - + VirtualMachine findById(long vmId); void storageMigration(String vmUuid, StoragePool storagePoolId); /** * @param vmInstance - * @param newServiceOfferingId + * @param newServiceOffering */ - void checkIfCanUpgrade(VirtualMachine vmInstance, long newServiceOfferingId); + void checkIfCanUpgrade(VirtualMachine vmInstance, ServiceOffering newServiceOffering); /** * @param vmId @@ -156,7 +167,7 @@ void advanceReboot(String vmUuid, Map param * @throws InsufficientCapacityException */ NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException, - ResourceUnavailableException, InsufficientCapacityException; + ResourceUnavailableException, InsufficientCapacityException; /** * @param vm @@ -191,12 +202,11 @@ NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile request */ VirtualMachineTO toVmTO(VirtualMachineProfile profile); - - VirtualMachine reConfigureVm(String vmUuid, ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException; + VirtualMachine reConfigureVm(String vmUuid, ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException, + InsufficientServerCapacityException; void findHostAndMigrate(String vmUuid, Long newSvcOfferingId, DeploymentPlanner.ExcludeList excludeHostList) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException; void migrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long newSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException; - } diff --git a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java index 173feef51d7a..e3dbeeac1438 100755 --- a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java +++ b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java @@ -76,7 +76,7 @@ List setupNetwork(Account owner, NetworkOffering offering, De List setupNetwork(Account owner, NetworkOffering offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean errorIfAlreadySetup, Long domainId, ACLType aclType, Boolean subdomainAccess, Long vpcId, Boolean isDisplayNetworkEnabled) throws ConcurrentOperationException; - void allocate(VirtualMachineProfile vm, LinkedHashMap networks) throws InsufficientCapacityException, ConcurrentOperationException; + void allocate(VirtualMachineProfile vm, LinkedHashMap> networks) throws InsufficientCapacityException, ConcurrentOperationException; void prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException; @@ -123,7 +123,7 @@ void prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationC boolean shutdownNetwork(long networkId, ReservationContext context, boolean cleanupElements); - boolean destroyNetwork(long networkId, ReservationContext context); + boolean destroyNetwork(long networkId, ReservationContext context, boolean forced); Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr, diff --git a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java index ad957d5ac8f1..92daf8809e5f 100644 --- a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java +++ b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java @@ -39,10 +39,12 @@ import com.cloud.storage.Volume.Type; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; +import com.cloud.uservm.UserVm; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; +import org.apache.cloudstack.framework.config.ConfigKey; /** * VolumeOrchestrationService is a PURE orchestration service on CloudStack @@ -52,6 +54,21 @@ * to provision volumes. */ public interface VolumeOrchestrationService { + + static final ConfigKey CustomDiskOfferingMinSize = new ConfigKey("Advanced", + Long.class, + "custom.diskoffering.size.min", + "1", + "Minimum size in GB for custom disk offering.", + true + ); + static final ConfigKey CustomDiskOfferingMaxSize = new ConfigKey("Advanced", + Long.class, + "custom.diskoffering.size.max", + "1024", + "Maximum size in GB for custom disk offering.", + true + ); VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType) throws ConcurrentOperationException, StorageUnavailableException; Volume allocateDuplicateVolume(Volume oldVol, Long templateId); @@ -62,7 +79,7 @@ public interface VolumeOrchestrationService { String getVmNameOnVolume(Volume volume); - VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot) throws StorageUnavailableException; + VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot, UserVm vm) throws StorageUnavailableException; Volume migrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException; @@ -76,6 +93,8 @@ public interface VolumeOrchestrationService { void cleanupVolumes(long vmId) throws ConcurrentOperationException; + void disconnectVolumesFromHost(long vmId, long hostId); + void migrateVolumes(VirtualMachine vm, VirtualMachineTO vmTo, Host srcHost, Host destHost, Map volumeToPool); boolean storageMigration(VirtualMachineProfile vm, StoragePool destPool) throws StorageUnavailableException; @@ -86,7 +105,7 @@ public interface VolumeOrchestrationService { boolean canVmRestartOnAnotherServer(long vmId); - DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, VirtualMachineTemplate template, VirtualMachine vm, Account owner); + DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, VirtualMachineTemplate template, VirtualMachine vm, Account owner); String getVmNameFromVolumeId(long volumeId); diff --git a/engine/api/src/org/apache/cloudstack/engine/service/api/OrchestrationService.java b/engine/api/src/org/apache/cloudstack/engine/service/api/OrchestrationService.java index 8c582276ade4..64ef063d0964 100755 --- a/engine/api/src/org/apache/cloudstack/engine/service/api/OrchestrationService.java +++ b/engine/api/src/org/apache/cloudstack/engine/service/api/OrchestrationService.java @@ -55,7 +55,6 @@ public interface OrchestrationService { * @param computeTags tags for the compute * @param rootDiskTags tags for the root disk * @param networks networks that this VM should join - * @param rootDiskSize size the root disk in case of templates. * @return VirtualMachineEntity */ @POST @@ -74,8 +73,7 @@ VirtualMachineEntity createVirtualMachine( @QueryParam("compute-tags") List computeTags, @QueryParam("root-disk-tags") List rootDiskTags, @QueryParam("network-nic-map") Map networkNicMap, - @QueryParam("deploymentplan") DeploymentPlan plan, - @QueryParam("root-disk-size") Long rootDiskSize + @QueryParam("deploymentplan") DeploymentPlan plan ) throws InsufficientCapacityException; @POST 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 000000000000..79ce92e08653 --- /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 127b85899871..9e7329f118e8 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 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/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java index 7fbec0ad35f9..5ebef031c5c6 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java @@ -27,6 +27,8 @@ public interface DataStoreManager { DataStore getPrimaryDataStore(long storeId); + DataStore getPrimaryDataStore(String storeUuid); + DataStore getDataStore(String uuid, DataStoreRole role); List getImageStoresByScope(ZoneScope scope); @@ -40,4 +42,6 @@ public interface DataStoreManager { List listImageStores(); List listImageCacheStores(); + + boolean isRegionStore(DataStore store); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java index b812f6efd994..4657316dd8a0 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java @@ -23,11 +23,17 @@ public interface EndPointSelector { EndPoint select(DataObject srcData, DataObject destData); + EndPoint select(DataObject srcData, DataObject destData, StorageAction action); + EndPoint select(DataObject object); EndPoint select(DataStore store); + EndPoint select(DataObject object, StorageAction action); + List selectAll(DataStore store); EndPoint select(Scope scope, Long storeId); + + EndPoint selectHypervisorHost(Scope scope); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java index b124d835dda7..aad94944fa68 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java @@ -21,8 +21,15 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.command.CommandResult; +import com.cloud.host.Host; +import com.cloud.storage.StoragePool; +import com.cloud.storage.Volume; + public interface PrimaryDataStoreDriver extends DataStoreDriver { public ChapInfo getChapInfo(VolumeInfo volumeInfo); + public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore); + public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore); + public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool); public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback); public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java index d5255f404076..01b0cde84961 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java @@ -30,4 +30,6 @@ public interface SnapshotDataFactory { SnapshotInfo getSnapshot(long snapshotId, DataStoreRole role); List listSnapshotOnCache(long snapshotId); + + SnapshotInfo getReadySnapshotOnCache(long snapshotId); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java index e953eb6e21b0..000b9ec4e606 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java @@ -25,4 +25,6 @@ public interface SnapshotService { boolean deleteSnapshot(SnapshotInfo snapshot); boolean revertSnapshot(Long snapshotId); + + void syncVolumeSnapshotsToRegionStore(long volumeId, DataStore store); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageAction.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageAction.java new file mode 100644 index 000000000000..4fbb20ed29e5 --- /dev/null +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageAction.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 org.apache.cloudstack.engine.subsystem.api.storage; + +public enum StorageAction { + TAKESNAPSHOT, + BACKUPSNAPSHOT, + DELETESNAPSHOT +} diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java index 92724c918899..92263a7e7c87 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java @@ -20,6 +20,8 @@ public interface StorageCacheManager { DataStore getCacheStorage(Scope scope); + + DataStore getCacheStorage(DataObject data, Scope scope); DataObject createCacheObject(DataObject data, Scope scope); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateDataFactory.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateDataFactory.java index 801c4427f50e..fd22da12e483 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateDataFactory.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateDataFactory.java @@ -25,6 +25,8 @@ public interface TemplateDataFactory { TemplateInfo getTemplate(long templateId, DataStore store); + TemplateInfo getReadyTemplateOnImageStore(long templateId, Long zoneId); + TemplateInfo getTemplate(DataObject obj, DataStore store); TemplateInfo getTemplate(long templateId, DataStoreRole storeRole); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java index 3b4aba970ba0..30bb870ff094 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java @@ -21,6 +21,7 @@ import com.cloud.agent.api.Answer; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Volume; +import com.cloud.vm.VirtualMachine; public interface VolumeInfo extends DataObject, Volume { boolean isAttachedVM(); @@ -34,6 +35,7 @@ public interface VolumeInfo extends DataObject, Volume { Long getLastPoolId(); String getAttachedVmName(); + VirtualMachine getAttachedVM(); void processEventOnly(ObjectInDataStoreStateMachine.Event event); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java index 7515088f331e..bdd4a17a53b8 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java @@ -19,6 +19,7 @@ package org.apache.cloudstack.engine.subsystem.api.storage; import java.util.Map; +import java.util.List; import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; import org.apache.cloudstack.framework.async.AsyncCallFuture; @@ -44,6 +45,10 @@ public VolumeInfo getVolume() { ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore); + boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore); + + void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore); + /** * Creates the volume based on the given criteria * diff --git a/engine/components-api/pom.xml b/engine/components-api/pom.xml index 5b82b2966b6c..a5523e696b76 100644 --- a/engine/components-api/pom.xml +++ b/engine/components-api/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml diff --git a/engine/components-api/src/com/cloud/alert/AlertManager.java b/engine/components-api/src/com/cloud/alert/AlertManager.java index 1ae6b1b72164..6a3218d4530a 100755 --- a/engine/components-api/src/com/cloud/alert/AlertManager.java +++ b/engine/components-api/src/com/cloud/alert/AlertManager.java @@ -16,41 +16,13 @@ // under the License. package com.cloud.alert; +import org.apache.cloudstack.alert.AlertService; import org.apache.cloudstack.framework.config.ConfigKey; -import com.cloud.capacity.CapacityVO; import com.cloud.utils.component.Manager; -public interface AlertManager extends Manager { - public static final short ALERT_TYPE_MEMORY = CapacityVO.CAPACITY_TYPE_MEMORY; - public static final short ALERT_TYPE_CPU = CapacityVO.CAPACITY_TYPE_CPU; - public static final short ALERT_TYPE_STORAGE = CapacityVO.CAPACITY_TYPE_STORAGE; - public static final short ALERT_TYPE_STORAGE_ALLOCATED = CapacityVO.CAPACITY_TYPE_STORAGE_ALLOCATED; - public static final short ALERT_TYPE_VIRTUAL_NETWORK_PUBLIC_IP = CapacityVO.CAPACITY_TYPE_VIRTUAL_NETWORK_PUBLIC_IP; - public static final short ALERT_TYPE_PRIVATE_IP = CapacityVO.CAPACITY_TYPE_PRIVATE_IP; - public static final short ALERT_TYPE_SECONDARY_STORAGE = CapacityVO.CAPACITY_TYPE_SECONDARY_STORAGE; - public static final short ALERT_TYPE_HOST = 7; - public static final short ALERT_TYPE_USERVM = 8; - public static final short ALERT_TYPE_DOMAIN_ROUTER = 9; - public static final short ALERT_TYPE_CONSOLE_PROXY = 10; - public static final short ALERT_TYPE_ROUTING = 11; // lost connection to default route (to the gateway) - public static final short ALERT_TYPE_STORAGE_MISC = 12; // lost connection to default route (to the gateway) - public static final short ALERT_TYPE_USAGE_SERVER = 13; // lost connection to default route (to the gateway) - public static final short ALERT_TYPE_MANAGMENT_NODE = 14; // lost connection to default route (to the gateway) - public static final short ALERT_TYPE_DOMAIN_ROUTER_MIGRATE = 15; - public static final short ALERT_TYPE_CONSOLE_PROXY_MIGRATE = 16; - public static final short ALERT_TYPE_USERVM_MIGRATE = 17; - public static final short ALERT_TYPE_VLAN = 18; - public static final short ALERT_TYPE_SSVM = 19; - public static final short ALERT_TYPE_USAGE_SERVER_RESULT = 20; // Usage job result - public static final short ALERT_TYPE_STORAGE_DELETE = 21; - public static final short ALERT_TYPE_UPDATE_RESOURCE_COUNT = 22; // Generated when we fail to update the resource - // count - public static final short ALERT_TYPE_USAGE_SANITY_RESULT = 23; - public static final short ALERT_TYPE_DIRECT_ATTACHED_PUBLIC_IP = 24; - public static final short ALERT_TYPE_LOCAL_STORAGE = 25; - public static final short ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED = 26; // Generated when the resource limit exceeds the limit. Currently used for recurring snapshots only - +public interface AlertManager extends Manager, AlertService{ + static final ConfigKey StorageCapacityThreshold = new ConfigKey(Double.class, "cluster.storage.capacity.notificationthreshold", "Alert", "0.75", "Percentage (as a value between 0 and 1) of storage utilization above which alerts will be sent about low storage available.", true, ConfigKey.Scope.Cluster, null); static final ConfigKey CPUCapacityThreshold = new ConfigKey(Double.class, "cluster.cpu.allocated.capacity.notificationthreshold", "Alert", "0.75", @@ -61,9 +33,10 @@ public interface AlertManager extends Manager { "0.75", "Percentage (as a value between 0 and 1) of allocated storage utilization above which alerts will be sent about low storage available.", true, ConfigKey.Scope.Cluster, null); - void clearAlert(short alertType, long dataCenterId, long podId); - - void sendAlert(short alertType, long dataCenterId, Long podId, String subject, String body); + void clearAlert(AlertType alertType, long dataCenterId, long podId); void recalculateCapacity(); + + void sendAlert(AlertType alertType, long dataCenterId, Long podId, String subject, String body); + } diff --git a/engine/components-api/src/com/cloud/capacity/CapacityManager.java b/engine/components-api/src/com/cloud/capacity/CapacityManager.java index 979c6f7f5eda..0cda826eec1b 100755 --- a/engine/components-api/src/com/cloud/capacity/CapacityManager.java +++ b/engine/components-api/src/com/cloud/capacity/CapacityManager.java @@ -75,4 +75,24 @@ public interface CapacityManager { * @return true if the count of host's running VMs >= hypervisor limit */ boolean checkIfHostReachMaxGuestLimit(Host host); + + /** + * Check if specified host has capability to support cpu cores and speed freq + * @param hostId the host to be checked + * @param cpuNum cpu number to check + * @param cpuSpeed cpu Speed to check + * @return true if the count of host's running VMs >= hypervisor limit + */ + boolean checkIfHostHasCpuCapability(long hostId, Integer cpuNum, Integer cpuSpeed); + + /** + * Check if cluster will cross threshold if the cpu/memory requested are accomodated + * @param clusterId the clusterId to check + * @param cpuRequested cpu requested + * @param ramRequested cpu requested + * @return true if the customer crosses threshold, false otherwise + */ + boolean checkIfClusterCrossesThreshold(Long clusterId, Integer cpuRequested, long ramRequested); + + float getClusterOverProvisioningFactor(Long clusterId, short capacityType); } diff --git a/engine/components-api/src/com/cloud/deploy/DeploymentPlanningManager.java b/engine/components-api/src/com/cloud/deploy/DeploymentPlanningManager.java index 7dde8158bb1f..4fa05346219b 100644 --- a/engine/components-api/src/com/cloud/deploy/DeploymentPlanningManager.java +++ b/engine/components-api/src/com/cloud/deploy/DeploymentPlanningManager.java @@ -40,7 +40,7 @@ public interface DeploymentPlanningManager extends Manager { * */ DeployDestination planDeployment(VirtualMachineProfile vmProfile, DeploymentPlan plan, - ExcludeList avoids) throws InsufficientServerCapacityException, AffinityConflictException; + ExcludeList avoids, DeploymentPlanner planner) throws InsufficientServerCapacityException, AffinityConflictException; String finalizeReservation(DeployDestination plannedDestination, VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoids) diff --git a/engine/components-api/src/com/cloud/network/rules/FirewallManager.java b/engine/components-api/src/com/cloud/network/rules/FirewallManager.java index 57ea88f07844..3717bb87861d 100644 --- a/engine/components-api/src/com/cloud/network/rules/FirewallManager.java +++ b/engine/components-api/src/com/cloud/network/rules/FirewallManager.java @@ -85,5 +85,5 @@ void validateFirewallRule(Account caller, IPAddressVO ipAddress, Integer portSta */ void removeRule(FirewallRule rule); - boolean applyDefaultEgressFirewallRule(Long networkId, boolean defaultPolicy) throws ResourceUnavailableException; + boolean applyDefaultEgressFirewallRule(Long networkId, boolean defaultPolicy, boolean add) throws ResourceUnavailableException; } diff --git a/engine/components-api/src/com/cloud/resource/ResourceManager.java b/engine/components-api/src/com/cloud/resource/ResourceManager.java index 97d9a59d4e2b..c52b96b5ad24 100755 --- a/engine/components-api/src/com/cloud/resource/ResourceManager.java +++ b/engine/components-api/src/com/cloud/resource/ResourceManager.java @@ -1,3 +1,4 @@ + // 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 @@ -84,6 +85,8 @@ public Host createHostAndAgent(Long hostId, ServerResource resource, Map handleVmWorkJob(VmWork work) throws Exception; +} diff --git a/engine/components-api/src/com/cloud/vm/VmWorkJobHandlerProxy.java b/engine/components-api/src/com/cloud/vm/VmWorkJobHandlerProxy.java new file mode 100644 index 000000000000..ce10a83c7cd7 --- /dev/null +++ b/engine/components-api/src/com/cloud/vm/VmWorkJobHandlerProxy.java @@ -0,0 +1,133 @@ +// 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.vm; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; + +import com.google.gson.Gson; + +import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper; +import org.apache.cloudstack.jobs.JobInfo; + +import com.cloud.serializer.GsonHelper; +import com.cloud.utils.Pair; + +/** + * VmWorkJobHandlerProxy can not be used as standalone due to run-time + * reflection usage in its implementation, run-time reflection conflicts with Spring proxy mode. + * It means that we can not instantiate VmWorkJobHandlerProxy beans directly in Spring and expect + * it can handle VmWork directly from there. + * + */ +public class VmWorkJobHandlerProxy implements VmWorkJobHandler { + + private static final Logger s_logger = Logger.getLogger(VmWorkJobHandlerProxy.class); + + private Object _target; + private Map, Method> _handlerMethodMap = new HashMap, Method>(); + + private Gson _gsonLogger; + + public VmWorkJobHandlerProxy(Object target) { + _gsonLogger = GsonHelper.getGsonLogger(); + + buildLookupMap(target.getClass()); + _target = target; + } + + private void buildLookupMap(Class hostClass) { + Class clz = hostClass; + while (clz != null && clz != Object.class) { + Method[] hostHandlerMethods = clz.getDeclaredMethods(); + + for (Method method : hostHandlerMethods) { + if (isVmWorkJobHandlerMethod(method)) { + Class paramType = method.getParameterTypes()[0]; + assert (_handlerMethodMap.get(paramType) == null); + + method.setAccessible(true); + _handlerMethodMap.put(paramType, method); + } + } + + clz = clz.getSuperclass(); + } + } + + @SuppressWarnings("deprecation") + private boolean isVmWorkJobHandlerMethod(Method method) { + if (method.getParameterTypes().length != 1) + return false; + + Class returnType = method.getReturnType(); + if (!Pair.class.isAssignableFrom(returnType)) + return false; + + Class paramType = method.getParameterTypes()[0]; + if (!VmWork.class.isAssignableFrom(paramType)) + return false; + + return true; + } + + private Method getHandlerMethod(Class paramType) { + return _handlerMethodMap.get(paramType); + } + + @SuppressWarnings("unchecked") + @Override + public Pair handleVmWorkJob(VmWork work) throws Exception { + + Method method = getHandlerMethod(work.getClass()); + if (method != null) { + + try { + if (s_logger.isDebugEnabled()) + s_logger.debug("Execute VM work job: " + work.getClass().getName() + _gsonLogger.toJson(work)); + + Object obj = method.invoke(_target, work); + + if (s_logger.isDebugEnabled()) + s_logger.debug("Done executing VM work job: " + work.getClass().getName() + _gsonLogger.toJson(work)); + + assert (obj instanceof Pair); + return (Pair)obj; + } catch (InvocationTargetException e) { + s_logger.error("Invocation exception, caused by: " + e.getCause()); + + // legacy CloudStack code relies on checked exception for error handling + // we need to re-throw the real exception here + if (e.getCause() != null && e.getCause() instanceof Exception) { + s_logger.info("Rethrow exception " + e.getCause()); + throw (Exception)e.getCause(); + } + + throw e; + } + } else { + s_logger.error("Unable to find handler for VM work job: " + work.getClass().getName() + _gsonLogger.toJson(work)); + + RuntimeException ex = new RuntimeException("Unable to find handler for VM work job: " + work.getClass().getName()); + return new Pair(JobInfo.Status.FAILED, JobSerializerHelper.toObjectSerializedString(ex)); + } + } +} diff --git a/engine/components-api/src/com/cloud/vm/VmWorkSerializer.java b/engine/components-api/src/com/cloud/vm/VmWorkSerializer.java new file mode 100644 index 000000000000..9a1aaaced676 --- /dev/null +++ b/engine/components-api/src/com/cloud/vm/VmWorkSerializer.java @@ -0,0 +1,75 @@ +// 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.vm; + +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; + +public class VmWorkSerializer { + static class StringMapTypeAdapter implements JsonDeserializer { + + @Override + public Map deserialize(JsonElement src, Type srcType, JsonDeserializationContext context) throws JsonParseException { + + Map obj = new HashMap(); + JsonObject json = src.getAsJsonObject(); + + for (Entry entry : json.entrySet()) { + obj.put(entry.getKey(), entry.getValue().getAsString()); + } + + return obj; + } + } + + protected static Gson s_gson; + static { + GsonBuilder gBuilder = new GsonBuilder(); + gBuilder.setVersion(1.3); + gBuilder.registerTypeAdapter(Map.class, new StringMapTypeAdapter()); + s_gson = gBuilder.create(); + } + + public static String serialize(VmWork work) { + // TODO: there are way many generics, too tedious to get serialization work under GSON + // use java binary serialization instead + // + return JobSerializerHelper.toObjectSerializedString(work); + // return s_gson.toJson(work); + } + + public static T deserialize(Class clazz, String workInJsonText) { + // TODO: there are way many generics, too tedious to get serialization work under GSON + // use java binary serialization instead + // + return (T)JobSerializerHelper.fromObjectSerializedString(workInJsonText); + // return (T)s_gson.fromJson(workInJsonText, clazz); + } +} + diff --git a/engine/components-api/src/com/cloud/vm/snapshot/VMSnapshotManager.java b/engine/components-api/src/com/cloud/vm/snapshot/VMSnapshotManager.java index c60900551ee0..1385f129ea6c 100644 --- a/engine/components-api/src/com/cloud/vm/snapshot/VMSnapshotManager.java +++ b/engine/components-api/src/com/cloud/vm/snapshot/VMSnapshotManager.java @@ -23,11 +23,11 @@ public interface VMSnapshotManager extends VMSnapshotService, Manager { public static final int VMSNAPSHOTMAX = 10; - + /** * Delete all VM snapshots belonging to one VM * @param id, VM id - * @param type, + * @param type, * @return true for success, false for failure */ boolean deleteAllVMSnapshots(long id, VMSnapshot.Type type); @@ -35,7 +35,7 @@ public interface VMSnapshotManager extends VMSnapshotService, Manager { /** * Sync VM snapshot state when VM snapshot in reverting or snapshoting or expunging state * Used for fullsync after agent connects - * + * * @param vm, the VM in question * @param hostId * @return true if succeeds, false if fails @@ -43,5 +43,4 @@ public interface VMSnapshotManager extends VMSnapshotService, Manager { boolean syncVMSnapshot(VMInstanceVO vm, Long hostId); boolean hasActiveVMSnapshotTasks(Long vmId); - } diff --git a/engine/network/pom.xml b/engine/network/pom.xml index 1c569ac0dfa5..80905a5ba23b 100644 --- a/engine/network/pom.xml +++ b/engine/network/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml diff --git a/engine/orchestration/pom.xml b/engine/orchestration/pom.xml index 37fba37844f2..4fa4709b42cf 100755 --- a/engine/orchestration/pom.xml +++ b/engine/orchestration/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml diff --git a/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml b/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml index b5c4254abaa3..fd5299c8f70f 100644 --- a/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml +++ b/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml @@ -20,11 +20,16 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" + xmlns:util="http://www.springframework.org/schema/util" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd - http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd + http://www.springframework.org/schema/aop + http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context - http://www.springframework.org/schema/context/spring-context-3.0.xsd" + http://www.springframework.org/schema/context/spring-context-3.0.xsd + http://www.springframework.org/schema/util + http://www.springframework.org/schema/util/spring-util-3.0.xsd" > - + + + + + + + + + + + + + + + + + + + diff --git a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java index 488caf572b5d..4d925fd188ca 100755 --- a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -820,7 +820,7 @@ protected boolean handleDisconnectWithInvestigation(AgentAttache attache, Status HostPodVO podVO = _podDao.findById(host.getPodId()); String hostDesc = "name: " + host.getName() + " (id:" + host.getId() + "), availability zone: " + dcVO.getName() + ", pod: " + podVO.getName(); if ((host.getType() != Host.Type.SecondaryStorage) && (host.getType() != Host.Type.ConsoleProxy)) { - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "Host disconnected, " + hostDesc, + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "Host disconnected, " + hostDesc, "If the agent for host [" + hostDesc + "] is not restarted within " + AlertWait + " seconds, HA will begin on the VMs"); } event = Status.Event.AgentDisconnected; @@ -830,7 +830,7 @@ protected boolean handleDisconnectWithInvestigation(AgentAttache attache, Status DataCenterVO dcVO = _dcDao.findById(host.getDataCenterId()); HostPodVO podVO = _podDao.findById(host.getPodId()); String hostDesc = "name: " + host.getName() + " (id:" + host.getId() + "), availability zone: " + dcVO.getName() + ", pod: " + podVO.getName(); - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "Host in ALERT state, " + hostDesc, "In availability zone " + host.getDataCenterId() + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "Host in ALERT state, " + hostDesc, "In availability zone " + host.getDataCenterId() + ", host is in alert state: " + host.getId() + "-" + host.getName()); } } else { @@ -1199,10 +1199,10 @@ protected void processRequest(final Link link, final Request request) { HostPodVO podVO = _podDao.findById(host.getPodId()); String hostDesc = "name: " + host.getName() + " (id:" + host.getId() + "), availability zone: " + dcVO.getName() + ", pod: " + podVO.getName(); - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_ROUTING, host.getDataCenterId(), host.getPodId(), "Host lost connection to gateway, " + hostDesc, "Host [" + hostDesc + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_ROUTING, host.getDataCenterId(), host.getPodId(), "Host lost connection to gateway, " + hostDesc, "Host [" + hostDesc + "] lost connection to gateway (default route) and is possibly having network connection issues."); } else { - _alertMgr.clearAlert(AlertManager.ALERT_TYPE_ROUTING, host.getDataCenterId(), host.getPodId()); + _alertMgr.clearAlert(AlertManager.AlertType.ALERT_TYPE_ROUTING, host.getDataCenterId(), host.getPodId()); } } else { s_logger.debug("Not processing " + PingRoutingCommand.class.getSimpleName() + @@ -1473,20 +1473,12 @@ protected void runInContext() { List hosts = sc.list(); for (HostVO host : hosts) { - long hostId = host.getId(); - DataCenterVO dcVO = _dcDao.findById(host.getDataCenterId()); - HostPodVO podVO = _podDao.findById(host.getPodId()); - String hostDesc = "name: " + host.getName() + " (id:" + hostId + "), availability zone: " + dcVO.getName() + ", pod: " + podVO.getName(); - - if (host.getType() != Host.Type.Storage) { -// List vos = _vmDao.listByHostId(hostId); -// List vosMigrating = _vmDao.listVmsMigratingFromHost(hostId); -// if (vos.isEmpty() && vosMigrating.isEmpty()) { -// _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "Migration Complete for host " + hostDesc, "Host [" -// + hostDesc -// + "] is ready for maintenance"); -// _resourceMgr.resourceStateTransitTo(host, ResourceState.Event.InternalEnterMaintenance, _msId); -// } + if (_resourceMgr.checkAndMaintain(host.getId())) { + DataCenterVO dcVO = _dcDao.findById(host.getDataCenterId()); + HostPodVO podVO = _podDao.findById(host.getPodId()); + String hostDesc = "name: " + host.getName() + " (id:" + host.getId() + "), availability zone: " + dcVO.getName() + ", pod: " + podVO.getName(); + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "Migration Complete for host " + hostDesc, "Host [" + + hostDesc + "] is ready for maintenance"); } } } catch (Throwable th) { diff --git a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java index 8681263347e9..2fd1caf2f6c8 100755 --- a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java @@ -106,7 +106,6 @@ public class ClusteredAgentManagerImpl extends AgentManagerImpl implements Clust protected HashMap _peers; protected HashMap _sslEngines; private final Timer _timer = new Timer("ClusteredAgentManager Timer"); - private final Timer _agentLbTimer = new Timer("ClusteredAgentManager AgentRebalancing Timer"); boolean _agentLbHappened = false; @Inject @@ -133,8 +132,7 @@ protected ClusteredAgentManagerImpl() { protected final ConfigKey LoadSize = new ConfigKey(Integer.class, "direct.agent.load.size", "Advanced", "16", "How many agents to connect to in each round", true); protected final ConfigKey ScanInterval = new ConfigKey(Integer.class, "direct.agent.scan.interval", "Advanced", "90", - "Interval between scans to load agents", false, ConfigKey.Scope.Global, 1000); - + "Interval between scans to load agents", false, ConfigKey.Scope.Global, 1000); @Override public boolean configure(String name, Map xmlParams) throws ConfigurationException { @@ -277,9 +275,9 @@ protected AgentAttache createAttacheForConnect(HostVO host, Link link) { @Override protected AgentAttache createAttacheForDirectConnect(Host host, ServerResource resource) { -// if (resource instanceof DummySecondaryStorageResource) { -// return new DummyAttache(this, host.getId(), false); -// } +// if (resource instanceof DummySecondaryStorageResource) { +// return new DummyAttache(this, host.getId(), false); +// } s_logger.debug("create ClusteredDirectAgentAttache for " + host.getId()); final DirectAgentAttache attache = new ClusteredDirectAgentAttache(this, host.getId(), host.getName(), _nodeId, resource, host.isInMaintenanceStates(), this); AgentAttache old = null; @@ -329,23 +327,24 @@ public boolean executeUserRequest(long hostId, Event event) throws AgentUnavaila } AgentAttache attache = findAttache(hostId); if (attache != null) { - //don't process disconnect if the host is being rebalanced + // don't process disconnect if the host is being rebalanced if (isAgentRebalanceEnabled()) { HostTransferMapVO transferVO = _hostTransferDao.findById(hostId); if (transferVO != null) { if (transferVO.getFutureOwner() == _nodeId && transferVO.getState() == HostTransferState.TransferStarted) { - s_logger.debug("Not processing " + Event.AgentDisconnected + " event for the host id=" - + hostId +" as the host is being connected to " + _nodeId); + + s_logger.debug("Not processing " + Event.AgentDisconnected + " event for the host id=" + hostId + " as the host is being connected to " + + _nodeId); return true; } } } - //don't process disconnect if the disconnect came for the host via delayed cluster notification, - //but the host has already reconnected to the current management server + // don't process disconnect if the disconnect came for the host via delayed cluster notification, + // but the host has already reconnected to the current management server if (!attache.forForward()) { - s_logger.debug("Not processing " + Event.AgentDisconnected + " event for the host id=" - + hostId +" as the host is directly connected to the current management server " + _nodeId); + s_logger.debug("Not processing " + Event.AgentDisconnected + " event for the host id=" + hostId + + " as the host is directly connected to the current management server " + _nodeId); return true; } @@ -390,18 +389,18 @@ public void notifyNodesInClusterToScheduleHostScanTask() { } protected static void logT(byte[] bytes, final String msg) { - s_logger.trace("Seq " + Request.getAgentId(bytes) + "-" + Request.getSequence(bytes) + ": MgmtId " + Request.getManagementServerId(bytes) + ": " - + (Request.isRequest(bytes) ? "Req: " : "Resp: ") + msg); + s_logger.trace("Seq " + Request.getAgentId(bytes) + "-" + Request.getSequence(bytes) + ": MgmtId " + Request.getManagementServerId(bytes) + ": " + + (Request.isRequest(bytes) ? "Req: " : "Resp: ") + msg); } protected static void logD(byte[] bytes, final String msg) { - s_logger.debug("Seq " + Request.getAgentId(bytes) + "-" + Request.getSequence(bytes) + ": MgmtId " + Request.getManagementServerId(bytes) + ": " - + (Request.isRequest(bytes) ? "Req: " : "Resp: ") + msg); + s_logger.debug("Seq " + Request.getAgentId(bytes) + "-" + Request.getSequence(bytes) + ": MgmtId " + Request.getManagementServerId(bytes) + ": " + + (Request.isRequest(bytes) ? "Req: " : "Resp: ") + msg); } protected static void logI(byte[] bytes, final String msg) { - s_logger.info("Seq " + Request.getAgentId(bytes) + "-" + Request.getSequence(bytes) + ": MgmtId " + Request.getManagementServerId(bytes) + ": " - + (Request.isRequest(bytes) ? "Req: " : "Resp: ") + msg); + s_logger.info("Seq " + Request.getAgentId(bytes) + "-" + Request.getSequence(bytes) + ": MgmtId " + Request.getManagementServerId(bytes) + ": " + + (Request.isRequest(bytes) ? "Req: " : "Resp: ") + msg); } public boolean routeToPeer(String peer, byte[] bytes) { @@ -568,9 +567,8 @@ public boolean stop() { } } _timer.cancel(); - _agentLbTimer.cancel(); - //cancel all transfer tasks + // cancel all transfer tasks s_transferExecutor.shutdownNow(); cleanupTransferMap(_nodeId); @@ -626,8 +624,9 @@ protected void doTask(final Task task) throws Exception { } agent.cancel(cancel.getSequence()); final Long current = agent._currentSequence; - //if the request is the current request, always have to trigger sending next request in sequence, - //otherwise the agent queue will be blocked + // if the request is the current request, always have to trigger sending next request in +// sequence, + // otherwise the agent queue will be blocked if (req.executeInSequence() && (current != null && current == Request.getSequence(data))) { agent.sendNext(Request.getSequence(data)); } @@ -726,8 +725,9 @@ public void removeAgent(AgentAttache attache, Status nextState) { } @Override - public boolean executeRebalanceRequest(long agentId, long currentOwnerId, long futureOwnerId, Event event) throws AgentUnavailableException, OperationTimedoutException { - boolean result = false; + public boolean executeRebalanceRequest(long agentId, long currentOwnerId, long futureOwnerId, Event event) throws AgentUnavailableException, + OperationTimedoutException { + boolean result = false; if (event == Event.RequestAgentRebalance) { return setToWaitForRebalance(agentId, currentOwnerId, futureOwnerId); } else if (event == Event.StartAgentRebalance) { @@ -792,7 +792,8 @@ public void startRebalanceAgents() { avLoad = allManagedAgents.size() / allMS.size(); } else { if (s_logger.isDebugEnabled()) { - s_logger.debug("There are no hosts to rebalance in the system. Current number of active management server nodes in the system is " + allMS.size() + "; number of managed agents is " + allManagedAgents.size()); + s_logger.debug("There are no hosts to rebalance in the system. Current number of active management server nodes in the system is " + allMS.size() + + "; number of managed agents is " + allManagedAgents.size()); } return; } @@ -848,7 +849,8 @@ public void startRebalanceAgents() { if (s_logger.isDebugEnabled()) { s_logger.debug("Removing mapping from op_host_transfer as it failed to be set to transfer mode"); } - //just remove the mapping (if exists) as nothing was done on the peer management server yet + // just remove the mapping (if exists) as nothing was done on the peer management +// server yet _hostTransferDao.remove(transfer.getId()); } } @@ -934,7 +936,7 @@ protected void runInContext() { synchronized (_agentToTransferIds) { if (_agentToTransferIds.size() > 0) { s_logger.debug("Found " + _agentToTransferIds.size() + " agents to transfer"); - //for (Long hostId : _agentToTransferIds) { + // for (Long hostId : _agentToTransferIds) { for (Iterator iterator = _agentToTransferIds.iterator(); iterator.hasNext();) { Long hostId = iterator.next(); AgentAttache attache = findAttache(hostId); @@ -946,7 +948,8 @@ protected void runInContext() { // remove the host from re-balance list and delete from op_host_transfer DB // no need to do anything with the real attache as we haven't modified it yet Date cutTime = DateUtil.currentGMTTime(); - HostTransferMapVO transferMap = _hostTransferDao.findActiveHostTransferMapByHostId(hostId, new Date(cutTime.getTime() - rebalanceTimeOut)); + HostTransferMapVO transferMap = + _hostTransferDao.findActiveHostTransferMapByHostId(hostId, new Date(cutTime.getTime() - rebalanceTimeOut)); if (transferMap == null) { s_logger.debug("Timed out waiting for the host id=" + hostId + " to be ready to transfer, skipping rebalance for the host"); @@ -964,7 +967,8 @@ protected void runInContext() { ManagementServerHostVO ms = _mshostDao.findByMsid(transferMap.getFutureOwner()); if (ms != null && ms.getState() != ManagementServerHost.State.Up) { - s_logger.debug("Can't transfer host " + hostId + " as it's future owner is not in UP state: " + ms + ", skipping rebalance for the host"); + s_logger.debug("Can't transfer host " + hostId + " as it's future owner is not in UP state: " + ms + + ", skipping rebalance for the host"); iterator.remove(); _hostTransferDao.completeAgentTransfer(hostId); continue; @@ -980,7 +984,8 @@ protected void runInContext() { } } else { - s_logger.debug("Agent " + hostId + " can't be transfered yet as its request queue size is " + attache.getQueueSize() + " and listener queue size is " + attache.getNonRecurringListenersSize()); + s_logger.debug("Agent " + hostId + " can't be transfered yet as its request queue size is " + attache.getQueueSize() + + " and listener queue size is " + attache.getNonRecurringListenersSize()); } } } else { @@ -1048,7 +1053,8 @@ protected boolean rebalanceHost(final long hostId, long currentOwnerId, long fut if (result) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Loading directly connected host " + host.getId() + "(" + host.getName() + ") to the management server " + _nodeId + " as a part of rebalance process"); + s_logger.debug("Loading directly connected host " + host.getId() + "(" + host.getName() + ") to the management server " + _nodeId + + " as a part of rebalance process"); } result = loadDirectlyConnectedHost(host, true); } else { @@ -1057,14 +1063,17 @@ protected boolean rebalanceHost(final long hostId, long currentOwnerId, long fut } } catch (Exception ex) { - s_logger.warn("Failed to load directly connected host " + host.getId() + "(" + host.getName() + ") to the management server " + _nodeId + " as a part of rebalance process due to:", ex); + s_logger.warn("Failed to load directly connected host " + host.getId() + "(" + host.getName() + ") to the management server " + _nodeId + + " as a part of rebalance process due to:", ex); result = false; } if (result) { - s_logger.debug("Successfully loaded directly connected host " + host.getId() + "(" + host.getName() + ") to the management server " + _nodeId + " as a part of rebalance process"); + s_logger.debug("Successfully loaded directly connected host " + host.getId() + "(" + host.getName() + ") to the management server " + _nodeId + + " as a part of rebalance process"); } else { - s_logger.warn("Failed to load directly connected host " + host.getId() + "(" + host.getName() + ") to the management server " + _nodeId + " as a part of rebalance process"); + s_logger.warn("Failed to load directly connected host " + host.getId() + "(" + host.getName() + ") to the management server " + _nodeId + + " as a part of rebalance process"); } } @@ -1086,17 +1095,18 @@ protected void finishRebalance(final long hostId, long futureOwnerId, Event even return; } - ClusteredAgentAttache forwardAttache = (ClusteredAgentAttache)attache; + ClusteredAgentAttache forwardAttache = (ClusteredAgentAttache) attache; if (success) { - //1) Set transfer mode to false - so the agent can start processing requests normally + // 1) Set transfer mode to false - so the agent can start processing requests normally forwardAttache.setTransferMode(false); - //2) Get all transfer requests and route them to peer + // 2) Get all transfer requests and route them to peer Request requestToTransfer = forwardAttache.getRequestToTransfer(); while (requestToTransfer != null) { - s_logger.debug("Forwarding request " + requestToTransfer.getSequence() + " held in transfer attache " + hostId + " from the management server " + _nodeId + " to " + futureOwnerId); + s_logger.debug("Forwarding request " + requestToTransfer.getSequence() + " held in transfer attache " + hostId + " from the management server " + + _nodeId + " to " + futureOwnerId); boolean routeResult = routeToPeer(Long.toString(futureOwnerId), requestToTransfer.getBytes()); if (!routeResult) { logD(requestToTransfer.getBytes(), "Failed to route request to peer"); @@ -1134,10 +1144,10 @@ protected boolean startRebalance(final long hostId) { } synchronized (_agents) { - ClusteredDirectAgentAttache attache = (ClusteredDirectAgentAttache)_agents.get(hostId); + ClusteredDirectAgentAttache attache = (ClusteredDirectAgentAttache) _agents.get(hostId); if (attache != null && attache.getQueueSize() == 0 && attache.getNonRecurringListenersSize() == 0) { - handleDisconnectWithoutInvestigation(attache, Event.StartAgentRebalance, true, true); - ClusteredAgentAttache forwardAttache = (ClusteredAgentAttache)createAttache(hostId); + handleDisconnectWithoutInvestigation(attache, Event.StartAgentRebalance, true, true); + ClusteredAgentAttache forwardAttache = (ClusteredAgentAttache) createAttache(hostId); if (forwardAttache == null) { s_logger.warn("Unable to create a forward attache for the host " + hostId + " as a part of rebalance process"); return false; @@ -1149,7 +1159,8 @@ protected boolean startRebalance(final long hostId) { if (attache == null) { s_logger.warn("Attache for the agent " + hostId + " no longer exists on management server " + _nodeId + ", can't start host rebalancing"); } else { - s_logger.warn("Attache for the agent " + hostId + " has request queue size= " + attache.getQueueSize() + " and listener queue size " + attache.getNonRecurringListenersSize() + ", can't start host rebalancing"); + s_logger.warn("Attache for the agent " + hostId + " has request queue size= " + attache.getQueueSize() + " and listener queue size " + + attache.getNonRecurringListenersSize() + ", can't start host rebalancing"); } return false; } @@ -1207,8 +1218,8 @@ private String handleScheduleHostScanTaskCommand(ScheduleHostScanTaskCommand cmd } catch (Exception e) { // Scheduling host scan task in peer MS is a best effort operation during host add, regular host scan // happens at fixed intervals anyways. So handling any exceptions that may be thrown - s_logger.warn("Exception happened while trying to schedule host scan task on mgmt server " + _clusterMgr.getSelfPeerName() - + ", ignoring as regular host scan happens at fixed interval anyways", e); + s_logger.warn("Exception happened while trying to schedule host scan task on mgmt server " + _clusterMgr.getSelfPeerName() + + ", ignoring as regular host scan happens at fixed interval anyways", e); return null; } @@ -1247,8 +1258,8 @@ public String dispatch(ClusterServicePdu pdu) { s_logger.error("Excection in gson decoding : ", e); } - if (cmds.length == 1 && cmds[0] instanceof ChangeAgentCommand) { //intercepted - ChangeAgentCommand cmd = (ChangeAgentCommand)cmds[0]; + if (cmds.length == 1 && cmds[0] instanceof ChangeAgentCommand) { // intercepted + ChangeAgentCommand cmd = (ChangeAgentCommand) cmds[0]; if (s_logger.isDebugEnabled()) { s_logger.debug("Intercepting command for agent change: agent " + cmd.getAgentId() + " event: " + cmd.getEvent()); @@ -1269,7 +1280,7 @@ public String dispatch(ClusterServicePdu pdu) { answers[0] = new ChangeAgentAnswer(cmd, result); return _gson.toJson(answers); } else if (cmds.length == 1 && cmds[0] instanceof TransferAgentCommand) { - TransferAgentCommand cmd = (TransferAgentCommand)cmds[0]; + TransferAgentCommand cmd = (TransferAgentCommand) cmds[0]; if (s_logger.isDebugEnabled()) { s_logger.debug("Intercepting command for agent rebalancing: agent " + cmd.getAgentId() + " event: " + cmd.getEvent()); @@ -1292,7 +1303,7 @@ public String dispatch(ClusterServicePdu pdu) { answers[0] = new Answer(cmd, result, null); return _gson.toJson(answers); } else if (cmds.length == 1 && cmds[0] instanceof PropagateResourceEventCommand) { - PropagateResourceEventCommand cmd = (PropagateResourceEventCommand)cmds[0]; + PropagateResourceEventCommand cmd = (PropagateResourceEventCommand) cmds[0]; s_logger.debug("Intercepting command to propagate event " + cmd.getEvent().name() + " for host " + cmd.getHostId()); @@ -1309,7 +1320,7 @@ public String dispatch(ClusterServicePdu pdu) { answers[0] = new Answer(cmd, result, null); return _gson.toJson(answers); } else if (cmds.length == 1 && cmds[0] instanceof ScheduleHostScanTaskCommand) { - ScheduleHostScanTaskCommand cmd = (ScheduleHostScanTaskCommand)cmds[0]; + ScheduleHostScanTaskCommand cmd = (ScheduleHostScanTaskCommand) cmds[0]; String response = handleScheduleHostScanTaskCommand(cmd); return response; } @@ -1325,15 +1336,15 @@ public String dispatch(ClusterServicePdu pdu) { String jsonReturn = _gson.toJson(answers); if (s_logger.isDebugEnabled()) { - s_logger.debug("Completed dispatching -> " + pdu.getAgentId() + ", json: " + pdu.getJsonPackage() + - " in " + (System.currentTimeMillis() - startTick) + " ms, return result: " + jsonReturn); + s_logger.debug("Completed dispatching -> " + pdu.getAgentId() + ", json: " + pdu.getJsonPackage() + " in " + + (System.currentTimeMillis() - startTick) + " ms, return result: " + jsonReturn); } return jsonReturn; } else { if (s_logger.isDebugEnabled()) { - s_logger.debug("Completed dispatching -> " + pdu.getAgentId() + ", json: " + pdu.getJsonPackage() + - " in " + (System.currentTimeMillis() - startTick) + " ms, return null result"); + s_logger.debug("Completed dispatching -> " + pdu.getAgentId() + ", json: " + pdu.getJsonPackage() + " in " + + (System.currentTimeMillis() - startTick) + " ms, return null result"); } } } catch (AgentUnavailableException e) { @@ -1362,38 +1373,41 @@ public boolean isAgentRebalanceEnabled() { private Runnable getAgentRebalanceScanTask() { return new ManagedContextRunnable() { - @Override - protected void runInContext() { - try { - if (s_logger.isTraceEnabled()) { - s_logger.trace("Agent rebalance task check, management server id:" + _nodeId); + @Override + protected void runInContext() { + try { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Agent rebalance task check, management server id:" + _nodeId); + } + // initiate agent lb task will be scheduled and executed only once, and only when number of agents +// loaded exceeds _connectedAgentsThreshold + if (!_agentLbHappened) { + QueryBuilder sc = QueryBuilder.create(HostVO.class); + sc.and(sc.entity().getManagementServerId(), Op.NNULL); + sc.and(sc.entity().getType(), Op.EQ, Host.Type.Routing); + List allManagedRoutingAgents = sc.list(); + + sc = QueryBuilder.create(HostVO.class); + sc.and(sc.entity().getType(), Op.EQ, Host.Type.Routing); + List allAgents = sc.list(); + double allHostsCount = allAgents.size(); + double managedHostsCount = allManagedRoutingAgents.size(); + if (allHostsCount > 0.0) { + double load = managedHostsCount / allHostsCount; + if (load >= ConnectedAgentThreshold.value()) { + s_logger.debug("Scheduling agent rebalancing task as the average agent load " + load + " is more than the threshold " + + ConnectedAgentThreshold.value()); + scheduleRebalanceAgents(); + _agentLbHappened = true; + } else { + s_logger.debug("Not scheduling agent rebalancing task as the averages load " + load + " is less than the threshold " + + ConnectedAgentThreshold.value()); + } + } + } + } catch (Throwable e) { + s_logger.error("Problem with the clustered agent transfer scan check!", e); } - //initiate agent lb task will be scheduled and executed only once, and only when number of agents loaded exceeds _connectedAgentsThreshold - if (!_agentLbHappened) { - QueryBuilder sc = QueryBuilder.create(HostVO.class); - sc.and(sc.entity().getManagementServerId(), Op.NNULL); - sc.and(sc.entity().getType(), Op.EQ, Host.Type.Routing); - List allManagedRoutingAgents = sc.list(); - - sc = QueryBuilder.create(HostVO.class); - sc.and(sc.entity().getType(), Op.EQ, Host.Type.Routing); - List allAgents = sc.list(); - double allHostsCount = allAgents.size(); - double managedHostsCount = allManagedRoutingAgents.size(); - if (allHostsCount > 0.0) { - double load = managedHostsCount / allHostsCount; - if (load >= ConnectedAgentThreshold.value()) { - s_logger.debug("Scheduling agent rebalancing task as the average agent load " + load + " is more than the threshold " + ConnectedAgentThreshold.value()); - scheduleRebalanceAgents(); - _agentLbHappened = true; - } else { - s_logger.debug("Not scheduling agent rebalancing task as the averages load " + load + " is less than the threshold " + ConnectedAgentThreshold.value()); - } - } - } - } catch (Throwable e) { - s_logger.error("Problem with the clustered agent transfer scan check!", e); - } } }; } diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java index 555a58faaa94..b30fc16c6469 100755 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -18,6 +18,10 @@ package com.cloud.vm; import java.net.URI; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -26,6 +30,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -35,22 +40,36 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.log4j.Logger; + import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; 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.AsyncJob; +import org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext; +import org.apache.cloudstack.framework.jobs.AsyncJobManager; +import org.apache.cloudstack.framework.jobs.Outcome; +import org.apache.cloudstack.framework.jobs.dao.VmWorkJobDao; +import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; +import org.apache.cloudstack.framework.jobs.impl.OutcomeImpl; +import org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO; +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.framework.messagebus.MessageDispatcher; +import org.apache.cloudstack.framework.messagebus.MessageHandler; +import org.apache.cloudstack.jobs.JobInfo; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.cloudstack.utils.identity.ManagementServerNode; -import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; @@ -100,6 +119,7 @@ import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; +import com.cloud.deploy.DeploymentPlanner; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.deploy.DeploymentPlanningManager; import com.cloud.domain.dao.DomainDao; @@ -152,8 +172,10 @@ import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.user.User; +import com.cloud.utils.DateUtil; import com.cloud.utils.Journal; import com.cloud.utils.Pair; +import com.cloud.utils.Predicate; import com.cloud.utils.StringUtils; import com.cloud.utils.Ternary; import com.cloud.utils.component.ManagerBase; @@ -162,8 +184,10 @@ import com.cloud.utils.db.EntityManager; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; import com.cloud.utils.db.TransactionCallbackWithException; import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn; +import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExecutionException; @@ -171,6 +195,7 @@ import com.cloud.utils.fsm.StateMachine2; import com.cloud.vm.ItWorkVO.Step; import com.cloud.vm.VirtualMachine.Event; +import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; @@ -182,9 +207,13 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Local(value = VirtualMachineManager.class) -public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, Listener, Configurable { +public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, VmWorkJobHandler, Listener, Configurable { private static final Logger s_logger = Logger.getLogger(VirtualMachineManagerImpl.class); + public static final String VM_WORK_JOB_HANDLER = VirtualMachineManagerImpl.class.getSimpleName(); + + private static final String VM_SYNC_ALERT_SUBJECT = "VM state sync alert"; + @Inject DataStoreManager dataStoreMgr; @Inject @@ -245,6 +274,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac protected AffinityGroupVMMapDao _affinityGroupVMMapDao; @Inject protected EntityManager _entityMgr; + @Inject ConfigDepot _configDepot; @@ -278,6 +308,13 @@ public void setHostAllocators(List _hostAllocators) { @Inject DeploymentPlanningManager _dpMgr; + @Inject protected MessageBus _messageBus; + @Inject protected VirtualMachinePowerStateSync _syncMgr; + @Inject protected VmWorkJobDao _workJobDao; + @Inject protected AsyncJobManager _jobMgr; + + VmWorkJobHandlerProxy _jobHandlerProxy = new VmWorkJobHandlerProxy(this); + Map _vmGurus = new HashMap(); protected StateMachine2 _stateMachine; @@ -298,6 +335,21 @@ public void setHostAllocators(List _hostAllocators) { static final ConfigKey ClusterDeltaSyncInterval = new ConfigKey("Advanced", Integer.class, "sync.interval", "60", "Cluster Delta sync interval in seconds", false); + // TODO, remove it after transient period is over + static final ConfigKey VmJobEnabled = new ConfigKey("Advanced", + Boolean.class, "vm.job.enabled", "false", + "True to enable new VM sync model. false to use the old way", false); + + static final ConfigKey VmJobCheckInterval = new ConfigKey("Advanced", + Long.class, "vm.job.check.interval", "3000", + "Interval in milliseconds to check if the job is complete", false); + static final ConfigKey VmJobTimeout = new ConfigKey("Advanced", + Long.class, "vm.job.timeout", "600000", + "Time in milliseconds to wait before attempting to cancel a job", false); + static final ConfigKey VmJobStateReportInterval = new ConfigKey("Advanced", + Integer.class, "vm.job.report.interval", "60", + "Interval to send application level pings to make sure the connection is still working", false); + ScheduledExecutorService _executor = null; protected long _nodeId; @@ -312,7 +364,7 @@ public void registerGuru(VirtualMachine.Type type, VirtualMachineGuru guru) { @Override @DB public void allocate(String vmInstanceName, final VirtualMachineTemplate template, ServiceOffering serviceOffering, final Pair rootDiskOffering, - LinkedHashMap dataDiskOfferings, final LinkedHashMap auxiliaryNetworks, DeploymentPlan plan, + LinkedHashMap dataDiskOfferings, final LinkedHashMap> auxiliaryNetworks, DeploymentPlan plan, HypervisorType hyperType) throws InsufficientCapacityException { VMInstanceVO vm = _vmDao.findVMByInstanceName(vmInstanceName); @@ -328,7 +380,7 @@ public void allocate(String vmInstanceName, final VirtualMachineTemplate templat } assert (plan.getClusterId() == null && plan.getPoolId() == null) : "We currently don't support cluster and pool preset yet"; final VMInstanceVO vmFinal = _vmDao.persist(vm); - final LinkedHashMap dataDiskOfferingsFinal = dataDiskOfferings == null ? + final LinkedHashMap dataDiskOfferingsFinal = dataDiskOfferings == null ? new LinkedHashMap() : dataDiskOfferings; @@ -340,25 +392,25 @@ public void doInTransactionWithoutResult(TransactionStatus status) throws Insuff if (s_logger.isDebugEnabled()) { s_logger.debug("Allocating nics for " + vmFinal); } - + try { _networkMgr.allocate(vmProfile, auxiliaryNetworks); } catch (ConcurrentOperationException e) { throw new CloudRuntimeException("Concurrent operation while trying to allocate resources for the VM", e); } - + if (s_logger.isDebugEnabled()) { s_logger.debug("Allocating disks for " + vmFinal); } - + if (template.getFormat() == ImageFormat.ISO) { volumeMgr.allocateRawVolume(Type.ROOT, "ROOT-" + vmFinal.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vmFinal, template, owner); } else if (template.getFormat() == ImageFormat.BAREMETAL) { // Do nothing } else { - volumeMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vmFinal.getId(), rootDiskOffering.first(), rootDiskOffering.second(), template, vmFinal, owner); + volumeMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vmFinal.getId(), rootDiskOffering.first(), template, vmFinal, owner); } - + for (Map.Entry offering : dataDiskOfferingsFinal.entrySet()) { volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + vmFinal.getId(), offering.getKey(), offering.getValue(), vmFinal, template, owner); } @@ -371,7 +423,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) throws Insuff } @Override - public void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering, LinkedHashMap networks, + public void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering, LinkedHashMap> networks, DeploymentPlan plan, HypervisorType hyperType) throws InsufficientCapacityException { allocate(vmInstanceName, template, serviceOffering, new Pair(serviceOffering, null), null, networks, plan, hyperType); } @@ -405,7 +457,8 @@ protected void advanceExpunge(VMInstanceVO vm) throws ResourceUnavailableExcepti return; } - advanceStop(vm, false); + advanceStop(vm.getUuid(), false); + vm = _vmDao.findByUuid(vm.getUuid()); try { if (!stateTransitTo(vm, VirtualMachine.Event.ExpungeOperation, vm.getHostId())) { @@ -430,6 +483,36 @@ protected void advanceExpunge(VMInstanceVO vm) throws ResourceUnavailableExcepti List nicExpungeCommands = hvGuru.finalizeExpungeNics(vm, profile.getNics()); _networkMgr.cleanupNics(profile); + s_logger.debug("Cleaning up hypervisor data structures (ex. SRs in XenServer) for managed storage"); + + List volumeExpungeCommands = hvGuru.finalizeExpungeVolumes(vm); + + Long hostId = vm.getHostId() != null ? vm.getHostId() : vm.getLastHostId(); + + if (volumeExpungeCommands != null && volumeExpungeCommands.size() > 0 && hostId != null) { + Commands cmds = new Commands(Command.OnError.Stop); + + for (Command volumeExpungeCommand : volumeExpungeCommands) { + cmds.addCommand(volumeExpungeCommand); + } + + _agentMgr.send(hostId, cmds); + + if (!cmds.isSuccessful()) { + for (Answer answer : cmds.getAnswers()) { + if (!answer.getResult()) { + s_logger.warn("Failed to expunge vm due to: " + answer.getDetails()); + + throw new CloudRuntimeException("Unable to expunge " + vm + " due to " + answer.getDetails()); + } + } + } + } + + if (hostId != null) { + volumeMgr.disconnectVolumesFromHost(vm.getId(), hostId); + } + // Clean up volumes based on the vm's instance id volumeMgr.cleanupVolumes(vm.getId()); @@ -441,7 +524,6 @@ protected void advanceExpunge(VMInstanceVO vm) throws ResourceUnavailableExcepti // send hypervisor-dependent commands before removing List finalizeExpungeCommands = hvGuru.finalizeExpunge(vm); if (finalizeExpungeCommands != null && finalizeExpungeCommands.size() > 0) { - Long hostId = vm.getHostId() != null ? vm.getHostId() : vm.getLastHostId(); if (hostId != null) { Commands cmds = new Commands(Command.OnError.Stop); for (Command command : finalizeExpungeCommands) { @@ -472,8 +554,13 @@ protected void advanceExpunge(VMInstanceVO vm) throws ResourceUnavailableExcepti @Override public boolean start() { + // TODO, initial delay is hardcoded + _executor.scheduleAtFixedRate(new TransitionTask(), 5000, VmJobStateReportInterval.value(), TimeUnit.SECONDS); _executor.scheduleAtFixedRate(new CleanupTask(), VmOpCleanupInterval.value(), VmOpCleanupInterval.value(), TimeUnit.SECONDS); cancelWorkItems(_nodeId); + + // cleanup left over place holder works + _workJobDao.expungeLeftoverWorkJobs(ManagementServerNode.getManagementServerId()); return true; } @@ -492,6 +579,10 @@ public boolean configure(String name, Map xmlParams) throws Conf _agentMgr.registerForHostEvents(this, true, true, true); + if (VmJobEnabled.value()) { + _messageBus.subscribe(VirtualMachineManager.Topics.VM_POWER_STATE, MessageDispatcher.getDispatcher(this)); + } + return true; } @@ -507,7 +598,7 @@ public void start(String vmUuid, Map params @Override public void start(String vmUuid, Map params, DeploymentPlan planToDeploy) { try { - advanceStart(vmUuid, params, planToDeploy); + advanceStart(vmUuid, params, planToDeploy, null); } catch (ConcurrentOperationException e) { throw new CloudRuntimeException("Unable to start a VM due to concurrent operation", e).add(VirtualMachine.class, vmUuid); } catch (InsufficientCapacityException e) { @@ -560,7 +651,7 @@ protected Ternary changeToStartState while (retry-- != 0) { try { final ItWorkVO workFinal = work; - Ternary result = + Ternary result = Transaction.execute(new TransactionCallbackWithException, NoTransitionException>() { @Override public Ternary doInTransaction(TransactionStatus status) throws NoTransitionException { @@ -578,7 +669,7 @@ public Ternary doInTransaction(Trans return new Ternary(null, null, work); } }); - + work = result.third(); if (result.first() != null) return result; @@ -648,14 +739,56 @@ protected boolean areAffinityGroupsAssociated(VirtualMachineProfile vmProfile) { } @Override - public void advanceStart(String vmUuid, Map params) throws InsufficientCapacityException, ConcurrentOperationException, - ResourceUnavailableException { - advanceStart(vmUuid, params, null); + public void advanceStart(String vmUuid, Map params, DeploymentPlanner planner) + throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { + + advanceStart(vmUuid, params, null, planner); + } + + @Override + public void advanceStart(String vmUuid, Map params, DeploymentPlan planToDeploy, DeploymentPlanner planner) throws InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException { + + AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); + if (!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { + // avoid re-entrance + VmWorkJobVO placeHolder = null; + if (VmJobEnabled.value()) { + VirtualMachine vm = _vmDao.findByUuid(vmUuid); + placeHolder = createPlaceHolderWork(vm.getId()); + } + try { + orchestrateStart(vmUuid, params, planToDeploy, planner); + } finally { + if (VmJobEnabled.value()) + _workJobDao.expunge(placeHolder.getId()); + } + } else { + Outcome outcome = startVmThroughJobQueue(vmUuid, params, planToDeploy); + + try { + VirtualMachine vm = outcome.get(); + } catch (InterruptedException e) { + throw new RuntimeException("Operation is interrupted", e); + } catch (java.util.concurrent.ExecutionException e) { + throw new RuntimeException("Execution excetion", e); + } + + Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob()); + if (jobResult != null) { + if (jobResult instanceof ConcurrentOperationException) + throw (ConcurrentOperationException)jobResult; + else if (jobResult instanceof ResourceUnavailableException) + throw (ResourceUnavailableException)jobResult; + } + } } + @Override - public void advanceStart(String vmUuid, Map params, DeploymentPlan planToDeploy) throws InsufficientCapacityException, - ConcurrentOperationException, ResourceUnavailableException { + public void orchestrateStart(String vmUuid, Map params, DeploymentPlan planToDeploy, DeploymentPlanner planner) + throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { + CallContext cctxt = CallContext.current(); Account account = cctxt.getCallingAccount(); User caller = cctxt.getCallingUser(); @@ -766,10 +899,11 @@ public void advanceStart(String vmUuid, Map } } - VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, offering, account, params); + Account owner = _entityMgr.findById(Account.class, vm.getAccountId()); + VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, offering, owner, params); DeployDestination dest = null; try { - dest = _dpMgr.planDeployment(vmProfile, plan, avoids); + dest = _dpMgr.planDeployment(vmProfile, plan, avoids, planner); } catch (AffinityConflictException e2) { s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2); throw new CloudRuntimeException("Unable to create deployment, affinity rules associted to the VM conflict"); @@ -840,7 +974,7 @@ public void advanceStart(String vmUuid, Map handlePath(vmTO.getDisks(), vm.getHypervisorType()); cmds = new Commands(Command.OnError.Stop); - cmds.addCommand(new StartCommand(vmTO, dest.getHost(), getExecuteInSequence())); + cmds.addCommand(new StartCommand(vmTO, dest.getHost(), getExecuteInSequence(vm.getHypervisorType()))); vmGuru.finalizeDeployment(cmds, vmProfile, dest, ctx); @@ -883,15 +1017,15 @@ public void advanceStart(String vmUuid, Map s_logger.info("The guru did not like the answers so stopping " + vm); } - StopCommand cmd = new StopCommand(vm, getExecuteInSequence()); - StopAnswer answer = (StopAnswer)_agentMgr.easySend(destHostId, cmd); + StopCommand cmd = new StopCommand(vm, getExecuteInSequence(vm.getHypervisorType())); + StopAnswer answer = (StopAnswer) _agentMgr.easySend(destHostId, cmd); if ( answer != null ) { - String hypervisortoolsversion = answer.getHypervisorToolsVersion(); - if (hypervisortoolsversion != null) { - if (vm.getType() == VirtualMachine.Type.User) { + if (vm.getType() == VirtualMachine.Type.User) { + String platform = answer.getPlatform(); + if (platform != null) { UserVmVO userVm = _userVmDao.findById(vm.getId()); _userVmDao.loadDetails(userVm); - userVm.setDetail("hypervisortoolsversion", hypervisortoolsversion); + userVm.setDetail("platform", platform); _userVmDao.saveDetails(userVm); } } @@ -987,6 +1121,13 @@ private void handlePath(DiskTO[] disks, HypervisorType hypervisorType) { VolumeVO volume = _volsDao.findById(volumeId); disk.setPath(volume.get_iScsiName()); + + if (disk.getData() instanceof VolumeObjectTO) { + VolumeObjectTO volTo = (VolumeObjectTO)disk.getData(); + + volTo.setPath(volume.get_iScsiName()); + } + volume.setPath(volume.get_iScsiName()); _volsDao.update(volumeId, volume); @@ -997,20 +1138,22 @@ private void handlePath(DiskTO[] disks, HypervisorType hypervisorType) { // for managed storage on XenServer and VMware, need to update the DB with a path if the VDI/VMDK file was newly created private void handlePath(DiskTO[] disks, Map iqnToPath) { - if (disks != null) { + if (disks != null && iqnToPath != null) { for (DiskTO disk : disks) { Map details = disk.getDetails(); boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - if (isManaged && disk.getPath() == null) { + if (isManaged) { Long volumeId = disk.getData().getId(); VolumeVO volume = _volsDao.findById(volumeId); String iScsiName = volume.get_iScsiName(); String path = iqnToPath.get(iScsiName); - volume.setPath(path); + if (path != null) { + volume.setPath(path); - _volsDao.update(volumeId, volume); + _volsDao.update(volumeId, volume); + } } } } @@ -1043,22 +1186,26 @@ public void stop(String vmUuid) throws ResourceUnavailableException { } } - protected boolean getExecuteInSequence() { - return false; + protected boolean getExecuteInSequence(HypervisorType hypervisorType) { + if (HypervisorType.KVM == hypervisorType) { + return false; + } else { + return ExecuteInSequence.value(); + } } protected boolean sendStop(VirtualMachineGuru guru, VirtualMachineProfile profile, boolean force) { VirtualMachine vm = profile.getVirtualMachine(); - StopCommand stop = new StopCommand(vm, getExecuteInSequence()); + StopCommand stop = new StopCommand(vm, getExecuteInSequence(vm.getHypervisorType())); try { StopAnswer answer = (StopAnswer) _agentMgr.send(vm.getHostId(), stop); if ( answer != null ) { - String hypervisortoolsversion = answer.getHypervisorToolsVersion(); - if (hypervisortoolsversion != null) { - if (vm.getType() == VirtualMachine.Type.User) { + if (vm.getType() == VirtualMachine.Type.User) { + String platform = answer.getPlatform(); + if (platform != null) { UserVmVO userVm = _userVmDao.findById(vm.getId()); _userVmDao.loadDetails(userVm); - userVm.setDetail("hypervisortoolsversion", hypervisortoolsversion); + userVm.setDetail("platform", platform); _userVmDao.saveDetails(userVm); } } @@ -1086,67 +1233,112 @@ protected boolean cleanup(VirtualMachineGuru guru, VirtualMachineProfile profile VirtualMachine vm = profile.getVirtualMachine(); State state = vm.getState(); s_logger.debug("Cleaning up resources for the vm " + vm + " in " + state + " state"); - if (state == State.Starting) { - Step step = work.getStep(); - if (step == Step.Starting && !cleanUpEvenIfUnableToStop) { - s_logger.warn("Unable to cleanup vm " + vm + "; work state is incorrect: " + step); - return false; - } + try { + if (state == State.Starting) { + Step step = work.getStep(); + if (step == Step.Starting && !cleanUpEvenIfUnableToStop) { + s_logger.warn("Unable to cleanup vm " + vm + "; work state is incorrect: " + step); + return false; + } + + if (step == Step.Started || step == Step.Starting || step == Step.Release) { + if (vm.getHostId() != null) { + if (!sendStop(guru, profile, cleanUpEvenIfUnableToStop)) { + s_logger.warn("Failed to stop vm " + vm + " in " + State.Starting + " state as a part of cleanup process"); + return false; + } + } + } - if (step == Step.Started || step == Step.Starting || step == Step.Release) { + if (step != Step.Release && step != Step.Prepare && step != Step.Started && step != Step.Starting) { + s_logger.debug("Cleanup is not needed for vm " + vm + "; work state is incorrect: " + step); + return true; + } + } else if (state == State.Stopping) { if (vm.getHostId() != null) { if (!sendStop(guru, profile, cleanUpEvenIfUnableToStop)) { - s_logger.warn("Failed to stop vm " + vm + " in " + State.Starting + " state as a part of cleanup process"); + s_logger.warn("Failed to stop vm " + vm + " in " + State.Stopping + " state as a part of cleanup process"); return false; } } - } - - if (step != Step.Release && step != Step.Prepare && step != Step.Started && step != Step.Starting) { - s_logger.debug("Cleanup is not needed for vm " + vm + "; work state is incorrect: " + step); - return true; - } - } else if (state == State.Stopping) { - if (vm.getHostId() != null) { - if (!sendStop(guru, profile, cleanUpEvenIfUnableToStop)) { - s_logger.warn("Failed to stop vm " + vm + " in " + State.Stopping + " state as a part of cleanup process"); - return false; + } else if (state == State.Migrating) { + if (vm.getHostId() != null) { + if (!sendStop(guru, profile, cleanUpEvenIfUnableToStop)) { + s_logger.warn("Failed to stop vm " + vm + " in " + State.Migrating + " state as a part of cleanup process"); + return false; + } } - } - } else if (state == State.Migrating) { - if (vm.getHostId() != null) { - if (!sendStop(guru, profile, cleanUpEvenIfUnableToStop)) { - s_logger.warn("Failed to stop vm " + vm + " in " + State.Migrating + " state as a part of cleanup process"); - return false; + if (vm.getLastHostId() != null) { + if (!sendStop(guru, profile, cleanUpEvenIfUnableToStop)) { + s_logger.warn("Failed to stop vm " + vm + " in " + State.Migrating + " state as a part of cleanup process"); + return false; + } } - } - if (vm.getLastHostId() != null) { + } else if (state == State.Running) { if (!sendStop(guru, profile, cleanUpEvenIfUnableToStop)) { - s_logger.warn("Failed to stop vm " + vm + " in " + State.Migrating + " state as a part of cleanup process"); + s_logger.warn("Failed to stop vm " + vm + " in " + State.Running + " state as a part of cleanup process"); return false; } } - } else if (state == State.Running) { - if (!sendStop(guru, profile, cleanUpEvenIfUnableToStop)) { - s_logger.warn("Failed to stop vm " + vm + " in " + State.Running + " state as a part of cleanup process"); - return false; + } finally { + try { + _networkMgr.release(profile, cleanUpEvenIfUnableToStop); + s_logger.debug("Successfully released network resources for the vm " + vm); + } catch (Exception e) { + s_logger.warn("Unable to release some network resources.", e); } - } - try { - _networkMgr.release(profile, cleanUpEvenIfUnableToStop); - s_logger.debug("Successfully released network resources for the vm " + vm); - } catch (Exception e) { - s_logger.warn("Unable to release some network resources.", e); + volumeMgr.release(profile); + s_logger.debug("Successfully cleanued up resources for the vm " + vm + " in " + state + " state"); } - volumeMgr.release(profile); - s_logger.debug("Successfully cleanued up resources for the vm " + vm + " in " + state + " state"); return true; } @Override - public void advanceStop(String vmUuid, boolean cleanUpEvenIfUnableToStop) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException { + public void advanceStop(String vmUuid, boolean cleanUpEvenIfUnableToStop) + throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException { + + AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); + if (!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { + // avoid re-entrance + + VmWorkJobVO placeHolder = null; + if (VmJobEnabled.value()) { + VirtualMachine vm = _vmDao.findByUuid(vmUuid); + placeHolder = createPlaceHolderWork(vm.getId()); + } + try { + orchestrateStop(vmUuid, cleanUpEvenIfUnableToStop); + } finally { + if (VmJobEnabled.value()) + _workJobDao.expunge(placeHolder.getId()); + } + + } else { + Outcome outcome = stopVmThroughJobQueue(vmUuid, cleanUpEvenIfUnableToStop); + + try { + VirtualMachine vm = outcome.get(); + } catch (InterruptedException e) { + throw new RuntimeException("Operation is interrupted", e); + } catch (java.util.concurrent.ExecutionException e) { + throw new RuntimeException("Execution excetion", e); + } + + Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob()); + if (jobResult != null) { + if (jobResult instanceof AgentUnavailableException) + throw (AgentUnavailableException)jobResult; + else if (jobResult instanceof ConcurrentOperationException) + throw (ConcurrentOperationException)jobResult; + else if (jobResult instanceof OperationTimedoutException) + throw (OperationTimedoutException)jobResult; + } + } + } + + private void orchestrateStop(String vmUuid, boolean cleanUpEvenIfUnableToStop) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException { VMInstanceVO vm = _vmDao.findByUuid(vmUuid); advanceStop(vm, cleanUpEvenIfUnableToStop); @@ -1253,19 +1445,19 @@ private void advanceStop(VMInstanceVO vm, boolean cleanUpEvenIfUnableToStop) thr } vmGuru.prepareStop(profile); - StopCommand stop = new StopCommand(vm, getExecuteInSequence()); + StopCommand stop = new StopCommand(vm, getExecuteInSequence(vm.getHypervisorType())); boolean stopped = false; StopAnswer answer = null; try { answer = (StopAnswer)_agentMgr.send(vm.getHostId(), stop); if ( answer != null ) { - String hypervisortoolsversion = answer.getHypervisorToolsVersion(); - if (hypervisortoolsversion != null) { - if (vm.getType() == VirtualMachine.Type.User) { + if (vm.getType() == VirtualMachine.Type.User) { + String platform = answer.getPlatform(); + if ( platform != null) { UserVmVO userVm = _userVmDao.findById(vm.getId()); _userVmDao.loadDetails(userVm); - userVm.setDetail("hypervisortoolsversion", hypervisortoolsversion); + userVm.setDetail("platform", platform); _userVmDao.saveDetails(userVm); } } @@ -1273,16 +1465,6 @@ private void advanceStop(VMInstanceVO vm, boolean cleanUpEvenIfUnableToStop) thr stopped = answer.getResult(); if (!stopped) { throw new CloudRuntimeException("Unable to stop the virtual machine due to " + answer.getDetails()); - } else { - Integer timeoffset = answer.getTimeOffset(); - if (timeoffset != null) { - if (vm.getType() == VirtualMachine.Type.User) { - UserVmVO userVm = _userVmDao.findById(vm.getId()); - _userVmDao.loadDetails(userVm); - userVm.setDetail("timeoffset", timeoffset.toString()); - _userVmDao.saveDetails(userVm); - } - } } vmGuru.finalizeStop(profile, answer); @@ -1350,6 +1532,11 @@ private void setStateMachine() { } protected boolean stateTransitTo(VMInstanceVO vm, VirtualMachine.Event e, Long hostId, String reservationId) throws NoTransitionException { + // if there are active vm snapshots task, state change is not allowed + if (_vmSnapshotMgr.hasActiveVMSnapshotTasks(vm.getId())) { + s_logger.error("State transit with event: " + e + " failed due to: " + vm.getInstanceName() + " has active VM snapshots tasks"); + return false; + } vm.setReservationId(reservationId); return _stateMachine.transitTo(vm, e, new Pair(vm.getHostId(), hostId), _vmDao); } @@ -1390,13 +1577,15 @@ public void destroy(String vmUuid) throws AgentUnavailableException, OperationTi s_logger.debug("Destroying vm " + vm); } - advanceStop(vm, VmDestroyForcestop.value()); + advanceStop(vmUuid, VmDestroyForcestop.value()); if (!_vmSnapshotMgr.deleteAllVMSnapshots(vm.getId(), null)) { s_logger.debug("Unable to delete all snapshots for " + vm); throw new CloudRuntimeException("Unable to delete vm snapshots for " + vm); } + // reload the vm object from db + vm = _vmDao.findByUuid(vmUuid); try { if (!stateTransitTo(vm, VirtualMachine.Event.DestroyRequested, vm.getHostId())) { s_logger.debug("Unable to destroy the vm because it is not in the correct state: " + vm); @@ -1419,6 +1608,40 @@ protected boolean checkVmOnHost(VirtualMachine vm, long hostId) throws AgentUnav @Override public void storageMigration(String vmUuid, StoragePool destPool) { + AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); + if (!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { + // avoid re-entrance + VmWorkJobVO placeHolder = null; + if (VmJobEnabled.value()) { + VirtualMachine vm = _vmDao.findByUuid(vmUuid); + placeHolder = createPlaceHolderWork(vm.getId()); + } + try { + orchestrateStorageMigration(vmUuid, destPool); + } finally { + if (VmJobEnabled.value()) + _workJobDao.expunge(placeHolder.getId()); + } + } else { + Outcome outcome = migrateVmStorageThroughJobQueue(vmUuid, destPool); + + try { + VirtualMachine vm = outcome.get(); + } catch (InterruptedException e) { + throw new RuntimeException("Operation is interrupted", e); + } catch (java.util.concurrent.ExecutionException e) { + throw new RuntimeException("Execution excetion", e); + } + + Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob()); + if (jobResult != null) { + if (jobResult instanceof RuntimeException) + throw (RuntimeException)jobResult; + } + } + } + + private void orchestrateStorageMigration(String vmUuid, StoragePool destPool) { VMInstanceVO vm = _vmDao.findByUuid(vmUuid); try { @@ -1474,7 +1697,47 @@ public void storageMigration(String vmUuid, StoragePool destPool) { } @Override - public void migrate(String vmUuid, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException { + public void migrate(String vmUuid, long srcHostId, DeployDestination dest) + throws ResourceUnavailableException, ConcurrentOperationException { + + AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); + if (!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { + // avoid re-entrance + VmWorkJobVO placeHolder = null; + if (VmJobEnabled.value()) { + VirtualMachine vm = _vmDao.findByUuid(vmUuid); + placeHolder = createPlaceHolderWork(vm.getId()); + } + try { + orchestrateMigrate(vmUuid, srcHostId, dest); + } finally { + if (VmJobEnabled.value()) + _workJobDao.expunge(placeHolder.getId()); + } + } else { + Outcome outcome = migrateVmThroughJobQueue(vmUuid, srcHostId, dest); + + try { + VirtualMachine vm = outcome.get(); + } catch (InterruptedException e) { + throw new RuntimeException("Operation is interrupted", e); + } catch (java.util.concurrent.ExecutionException e) { + throw new RuntimeException("Execution excetion", e); + } + + Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob()); + if (jobResult != null) { + if (jobResult instanceof ResourceUnavailableException) + throw (ResourceUnavailableException)jobResult; + else if (jobResult instanceof ConcurrentOperationException) + throw (ConcurrentOperationException)jobResult; + else if (jobResult instanceof RuntimeException) + throw (RuntimeException)jobResult; + } + } + } + + private void orchestrateMigrate(String vmUuid, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException { VMInstanceVO vm = _vmDao.findByUuid(vmUuid); if (vm == null) { if (s_logger.isDebugEnabled()) { @@ -1509,11 +1772,11 @@ protected void migrate(VMInstanceVO vm, long srcHostId, DeployDestination dest) throw new CloudRuntimeException("VM is not Running, unable to migrate the vm currently " + vm + " , current state: " + vm.getState().toString()); } - short alertType = AlertManager.ALERT_TYPE_USERVM_MIGRATE; + AlertManager.AlertType alertType = AlertManager.AlertType.ALERT_TYPE_USERVM_MIGRATE; if (VirtualMachine.Type.DomainRouter.equals(vm.getType())) { - alertType = AlertManager.ALERT_TYPE_DOMAIN_ROUTER_MIGRATE; + alertType = AlertManager.AlertType.ALERT_TYPE_DOMAIN_ROUTER_MIGRATE; } else if (VirtualMachine.Type.ConsoleProxy.equals(vm.getType())) { - alertType = AlertManager.ALERT_TYPE_CONSOLE_PROXY_MIGRATE; + alertType = AlertManager.AlertType.ALERT_TYPE_CONSOLE_PROXY_MIGRATE; } VirtualMachineProfile vmSrc = new VirtualMachineProfileImpl(vm); @@ -1715,8 +1978,49 @@ private void moveVmOutofMigratingStateOnSuccess(T vm, L } @Override - public void migrateWithStorage(String vmUuid, long srcHostId, long destHostId, Map volumeToPool) throws ResourceUnavailableException, - ConcurrentOperationException { + public void migrateWithStorage(String vmUuid, long srcHostId, long destHostId, Map volumeToPool) + throws ResourceUnavailableException, ConcurrentOperationException { + + AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); + if (!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { + // avoid re-entrance + + VmWorkJobVO placeHolder = null; + if (VmJobEnabled.value()) { + VirtualMachine vm = _vmDao.findByUuid(vmUuid); + placeHolder = createPlaceHolderWork(vm.getId()); + } + try { + orchestrateMigrateWithStorage(vmUuid, srcHostId, destHostId, volumeToPool); + } finally { + if (VmJobEnabled.value()) + _workJobDao.expunge(placeHolder.getId()); + } + + } else { + Outcome outcome = migrateVmWithStorageThroughJobQueue(vmUuid, srcHostId, destHostId, volumeToPool); + + try { + VirtualMachine vm = outcome.get(); + } catch (InterruptedException e) { + throw new RuntimeException("Operation is interrupted", e); + } catch (java.util.concurrent.ExecutionException e) { + throw new RuntimeException("Execution excetion", e); + } + + Object jobException = _jobMgr.unmarshallResultObject(outcome.getJob()); + if (jobException != null) { + if (jobException instanceof ResourceUnavailableException) + throw (ResourceUnavailableException)jobException; + else if (jobException instanceof ConcurrentOperationException) + throw (ConcurrentOperationException)jobException; + } + } + } + + private void orchestrateMigrateWithStorage(String vmUuid, long srcHostId, long destHostId, Map volumeToPool) throws ResourceUnavailableException, + ConcurrentOperationException { + VMInstanceVO vm = _vmDao.findByUuid(vmUuid); HostVO srcHost = _hostDao.findById(srcHostId); @@ -1739,11 +2043,11 @@ public void migrateWithStorage(String vmUuid, long srcHostId, long destHostId, M " doesn't involve migrating the volumes."); } - short alertType = AlertManager.ALERT_TYPE_USERVM_MIGRATE; + AlertManager.AlertType alertType = AlertManager.AlertType.ALERT_TYPE_USERVM_MIGRATE; if (VirtualMachine.Type.DomainRouter.equals(vm.getType())) { - alertType = AlertManager.ALERT_TYPE_DOMAIN_ROUTER_MIGRATE; + alertType = AlertManager.AlertType.ALERT_TYPE_DOMAIN_ROUTER_MIGRATE; } else if (VirtualMachine.Type.ConsoleProxy.equals(vm.getType())) { - alertType = AlertManager.ALERT_TYPE_CONSOLE_PROXY_MIGRATE; + alertType = AlertManager.AlertType.ALERT_TYPE_CONSOLE_PROXY_MIGRATE; } _networkMgr.prepareNicForMigration(profile, destination); @@ -1828,10 +2132,12 @@ protected void cancelWorkItems(long nodeId) { if (work.getType() == State.Starting) { _haMgr.scheduleRestart(vm, true); work.setManagementServerId(_nodeId); + work.setStep(Step.Done); _workDao.update(work.getId(), work); } else if (work.getType() == State.Stopping) { _haMgr.scheduleStop(vm, vm.getHostId(), WorkType.CheckStop); work.setManagementServerId(_nodeId); + work.setStep(Step.Done); _workDao.update(work.getId(), work); } else if (work.getType() == State.Migrating) { _haMgr.scheduleMigration(vm); @@ -1853,7 +2159,7 @@ protected void cancelWorkItems(long nodeId) { } @Override - public void migrateAway(String vmUuid, long srcHostId) throws InsufficientServerCapacityException { + public void migrateAway(String vmUuid, long srcHostId, DeploymentPlanner planner) throws InsufficientServerCapacityException { VMInstanceVO vm = _vmDao.findByUuid(vmUuid); if (vm == null) { s_logger.debug("Unable to find a VM for " + vmUuid); @@ -1869,8 +2175,16 @@ public void migrateAway(String vmUuid, long srcHostId) throws InsufficientServer } Host host = _hostDao.findById(hostId); + Long poolId = null; + List vols = _volsDao.findReadyRootVolumesByInstance(vm.getId()); + for (VolumeVO rootVolumeOfVm : vols) { + StoragePoolVO rootDiskPool = _storagePoolDao.findById(rootVolumeOfVm.getPoolId()); + if (rootDiskPool != null) { + poolId = rootDiskPool.getId(); + } + } - DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), null, null, null); + DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), null, poolId, null); ExcludeList excludes = new ExcludeList(); excludes.addHost(hostId); @@ -1878,7 +2192,7 @@ public void migrateAway(String vmUuid, long srcHostId) throws InsufficientServer while (true) { try { - dest = _dpMgr.planDeployment(profile, plan, excludes); + dest = _dpMgr.planDeployment(profile, plan, excludes, planner); } catch (AffinityConflictException e2) { s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2); throw new CloudRuntimeException("Unable to create deployment, affinity rules associted to the VM conflict"); @@ -1906,7 +2220,7 @@ public void migrateAway(String vmUuid, long srcHostId) throws InsufficientServer } try { - advanceStop(vm, true); + advanceStop(vmUuid, true); throw new CloudRuntimeException("Unable to migrate " + vm); } catch (ResourceUnavailableException e) { s_logger.debug("Unable to stop VM due to " + e.getMessage()); @@ -1927,6 +2241,10 @@ protected void runInContext() { s_logger.trace("VM Operation Thread Running"); try { _workDao.cleanup(VmOpCleanupWait.value()); + + // TODO. hard-coded to one hour after job has been completed + Date cutDate = new Date(new Date().getTime() - 3600000); + _workJobDao.expungeCompletedWorkJobs(cutDate); } catch (Exception e) { s_logger.error("VM Operations failed due to ", e); } @@ -1957,7 +2275,47 @@ public void reboot(String vmUuid, Map param } @Override - public void advanceReboot(String vmUuid, Map params) throws InsufficientCapacityException, ConcurrentOperationException, + public void advanceReboot(String vmUuid, Map params) + throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { + + AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); + if (!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { + // avoid re-entrance + VmWorkJobVO placeHolder = null; + if (VmJobEnabled.value()) { + VirtualMachine vm = _vmDao.findByUuid(vmUuid); + placeHolder = createPlaceHolderWork(vm.getId()); + } + try { + orchestrateReboot(vmUuid, params); + } finally { + if (VmJobEnabled.value()) + _workJobDao.expunge(placeHolder.getId()); + } + } else { + Outcome outcome = rebootVmThroughJobQueue(vmUuid, params); + + try { + VirtualMachine vm = outcome.get(); + } catch (InterruptedException e) { + throw new RuntimeException("Operation is interrupted", e); + } catch (java.util.concurrent.ExecutionException e) { + throw new RuntimeException("Execution excetion", e); + } + + Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob()); + if (jobResult != null) { + if (jobResult instanceof ResourceUnavailableException) + throw (ResourceUnavailableException)jobResult; + else if (jobResult instanceof ConcurrentOperationException) + throw (ConcurrentOperationException)jobResult; + else if (jobResult instanceof InsufficientCapacityException) + throw (InsufficientCapacityException)jobResult; + } + } + } + + private void orchestrateReboot(String vmUuid, Map params) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { VMInstanceVO vm = _vmDao.findByUuid(vmUuid); @@ -1988,11 +2346,11 @@ public void advanceReboot(String vmUuid, Map newStates) { return commands; } - - public void deltaSync(Map> newStates) { Map states = convertToInfos(newStates); @@ -2332,13 +2688,13 @@ protected Command compareState(long hostId, VMInstanceVO vm, final AgentVmInfo i if (agentState == State.Error) { agentState = State.Stopped; - short alertType = AlertManager.ALERT_TYPE_USERVM; + AlertManager.AlertType alertType = AlertManager.AlertType.ALERT_TYPE_USERVM; if (VirtualMachine.Type.DomainRouter.equals(vm.getType())) { - alertType = AlertManager.ALERT_TYPE_DOMAIN_ROUTER; + alertType = AlertManager.AlertType.ALERT_TYPE_DOMAIN_ROUTER; } else if (VirtualMachine.Type.ConsoleProxy.equals(vm.getType())) { - alertType = AlertManager.ALERT_TYPE_CONSOLE_PROXY; + alertType = AlertManager.AlertType.ALERT_TYPE_CONSOLE_PROXY; } else if (VirtualMachine.Type.SecondaryStorageVm.equals(vm.getType())) { - alertType = AlertManager.ALERT_TYPE_SSVM; + alertType = AlertManager.AlertType.ALERT_TYPE_SSVM; } HostPodVO podVO = _podDao.findById(vm.getPodIdToDeployIn()); @@ -2350,21 +2706,12 @@ protected Command compareState(long hostId, VMInstanceVO vm, final AgentVmInfo i hostDesc + " due to storage failure", "Virtual Machine " + vm.getInstanceName() + " (id: " + vm.getId() + ") running on host [" + vm.getHostId() + "] stopped due to storage failure."); } - // track hypervsion tools version - if( info.hvtoolsversion != null && !info.hvtoolsversion.isEmpty() ) { - if (vm.getType() == VirtualMachine.Type.User) { - UserVmVO userVm = _userVmDao.findById(vm.getId()); - _userVmDao.loadDetails(userVm); - userVm.setDetail("hypervisortoolsversion", info.hvtoolsversion); - _userVmDao.saveDetails(userVm); - } - } - // track hypervsion tools version - if( info.hvtoolsversion != null && !info.hvtoolsversion.isEmpty() ) { + // track platform info + if( info.platform != null && !info.platform.isEmpty() ) { if (vm.getType() == VirtualMachine.Type.User) { UserVmVO userVm = _userVmDao.findById(vm.getId()); _userVmDao.loadDetails(userVm); - userVm.setDetail("hypervisortoolsversion", info.hvtoolsversion); + userVm.setDetail("platform", info.platform); _userVmDao.saveDetails(userVm); } } @@ -2448,7 +2795,7 @@ protected Command compareState(long hostId, VMInstanceVO vm, final AgentVmInfo i if (agentState == State.Shutdowned) { if (serverState == State.Running || serverState == State.Starting || serverState == State.Stopping) { try { - advanceStop(vm, true); + advanceStop(vm.getUuid(), true); } catch (AgentUnavailableException e) { assert (false) : "How do we hit this with forced on?"; return null; @@ -2498,7 +2845,7 @@ protected Command compareState(long hostId, VMInstanceVO vm, final AgentVmInfo i s_logger.warn(e.getMessage()); } } - } else if (serverState == State.Stopping) { + } else if (serverState == State.Stopped) { s_logger.debug("Scheduling a stop command for " + vm); _haMgr.scheduleStop(vm, hostId, WorkType.Stop); } else { @@ -2607,15 +2954,27 @@ public boolean processCommands(long agentId, long seq, Command[] cmds) { if (cmd instanceof PingRoutingCommand) { PingRoutingCommand ping = (PingRoutingCommand)cmd; if (ping.getNewStates() != null && ping.getNewStates().size() > 0) { - Commands commands = deltaHostSync(agentId, ping.getNewStates()); - if (commands.size() > 0) { - try { - _agentMgr.send(agentId, commands, this); - } catch (final AgentUnavailableException e) { - s_logger.warn("Agent is now unavailable", e); + if (!VmJobEnabled.value()) { + Commands commands = deltaHostSync(agentId, ping.getNewStates()); + if (commands.size() > 0) { + try { + _agentMgr.send(agentId, commands, this); + } catch (final AgentUnavailableException e) { + s_logger.warn("Agent is now unavailable", e); + } } } } + + if(VmJobEnabled.value()) { + if (ping.getHostVmStateReport() != null && ping.getHostVmStateReport().size() > 0) { + _syncMgr.processHostVmStatePingReport(agentId, ping.getHostVmStateReport()); + } + } + + // take the chance to scan VMs that are stuck in transitional states + // and are missing from the report + scanStalledVMInTransitionStateOnUpHost(agentId); processed = true; } } @@ -2638,6 +2997,13 @@ public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) return; } + if(s_logger.isDebugEnabled()) + s_logger.debug("Received startup command from hypervisor host. host id: " + agent.getId()); + + if(VmJobEnabled.value()) { + _syncMgr.resetHostSyncState(agent.getId()); + } + if (forRebalance) { s_logger.debug("Not processing listener " + this + " as connect happens on rebalance process"); return; @@ -2711,7 +3077,8 @@ protected void runInContext() { return; } try { - lock.addRef(); + scanStalledVMInTransitionStateOnDisconnectedHosts(); + List instances = _vmDao.findVMInTransition(new Date(new Date().getTime() - (AgentManager.Wait.value() * 1000)), State.Starting, State.Stopping); for (VMInstanceVO instance : instances) { State state = instance.getState(); @@ -2733,17 +3100,17 @@ protected class AgentVmInfo { public String name; public State state; public String hostUuid; - public String hvtoolsversion; public VMInstanceVO vm; + public String platform; @SuppressWarnings("unchecked") - public AgentVmInfo(String name, VMInstanceVO vm, State state, String host, String hvtoolsversion) { + public AgentVmInfo(String name, VMInstanceVO vm, State state, String host, String platform) { this.name = name; this.state = state; this.vm = vm; - this.hostUuid = host; - this.hvtoolsversion= hvtoolsversion; + hostUuid = host; + this.platform = platform; } @@ -2759,8 +3126,8 @@ public String getHostUuid() { return hostUuid; } - public String getHvtoolsversion() { - return hvtoolsversion; + public String getPlatform() { + return platform; } } @@ -2770,10 +3137,9 @@ public VMInstanceVO findById(long vmId) { } @Override - public void checkIfCanUpgrade(VirtualMachine vmInstance, long newServiceOfferingId) { - ServiceOfferingVO newServiceOffering = _offeringDao.findById(vmInstance.getId(), newServiceOfferingId); + public void checkIfCanUpgrade(VirtualMachine vmInstance, ServiceOffering newServiceOffering) { if (newServiceOffering == null) { - throw new InvalidParameterValueException("Unable to find a service offering with id " + newServiceOfferingId); + throw new InvalidParameterValueException("Unable to find a service offering with id " + newServiceOffering.getId()); } // Check that the VM is stopped / running @@ -2784,7 +3150,7 @@ public void checkIfCanUpgrade(VirtualMachine vmInstance, long newServiceOffering } // Check if the service offering being upgraded to is what the VM is already running with - if (vmInstance.getServiceOfferingId() == newServiceOffering.getId()) { + if (!newServiceOffering.isDynamic() && vmInstance.getServiceOfferingId() == newServiceOffering.getId()) { if (s_logger.isInfoEnabled()) { s_logger.info("Not upgrading vm " + vmInstance.toString() + " since it already has the requested " + "service offering (" + newServiceOffering.getName() + ")"); } @@ -2845,7 +3211,52 @@ public boolean upgradeVmDb(long vmId, long serviceOfferingId) { } @Override - public NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException, ResourceUnavailableException, + public NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) + throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + + AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); + if (!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { + // avoid re-entrance + VmWorkJobVO placeHolder = null; + if (VmJobEnabled.value()) { + placeHolder = createPlaceHolderWork(vm.getId()); + } + try { + return orchestrateAddVmToNetwork(vm, network, requested); + } finally { + if (VmJobEnabled.value()) + _workJobDao.expunge(placeHolder.getId()); + } + } else { + Outcome outcome = addVmToNetworkThroughJobQueue(vm, network, requested); + + try { + outcome.get(); + } catch (InterruptedException e) { + throw new RuntimeException("Operation is interrupted", e); + } catch (java.util.concurrent.ExecutionException e) { + throw new RuntimeException("Execution excetion", e); + } + + Object jobException = _jobMgr.unmarshallResultObject(outcome.getJob()); + if (jobException != null) { + if (jobException instanceof ResourceUnavailableException) + throw (ResourceUnavailableException)jobException; + else if (jobException instanceof ConcurrentOperationException) + throw (ConcurrentOperationException)jobException; + else if (jobException instanceof InsufficientCapacityException) + throw (InsufficientCapacityException)jobException; + else if (jobException instanceof RuntimeException) + throw (RuntimeException)jobException; + else if (jobException instanceof Long) + return requested; + } + + throw new RuntimeException("Unexpected job execution result"); + } + } + + private NicProfile orchestrateAddVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { CallContext cctx = CallContext.current(); @@ -2912,7 +3323,51 @@ public NicTO toNicTO(NicProfile nic, HypervisorType hypervisorType) { } @Override - public boolean removeNicFromVm(VirtualMachine vm, Nic nic) throws ConcurrentOperationException, ResourceUnavailableException { + public boolean removeNicFromVm(VirtualMachine vm, Nic nic) + throws ConcurrentOperationException, ResourceUnavailableException { + + AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); + if (!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { + // avoid re-entrance + VmWorkJobVO placeHolder = null; + if (VmJobEnabled.value()) { + placeHolder = createPlaceHolderWork(vm.getId()); + } + try { + return orchestrateRemoveNicFromVm(vm, nic); + } finally { + if (VmJobEnabled.value()) + _workJobDao.expunge(placeHolder.getId()); + } + + } else { + Outcome outcome = removeNicFromVmThroughJobQueue(vm, nic); + + try { + outcome.get(); + } catch (InterruptedException e) { + throw new RuntimeException("Operation is interrupted", e); + } catch (java.util.concurrent.ExecutionException e) { + throw new RuntimeException("Execution excetion", e); + } + + Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob()); + if (jobResult != null) { + if (jobResult instanceof ResourceUnavailableException) + throw (ResourceUnavailableException)jobResult; + else if (jobResult instanceof ConcurrentOperationException) + throw (ConcurrentOperationException)jobResult; + else if (jobResult instanceof RuntimeException) + throw (RuntimeException)jobResult; + else if (jobResult instanceof Boolean) + return (Boolean)jobResult; + } + + throw new RuntimeException("Job failed with un-handled exception"); + } + } + + private boolean orchestrateRemoveNicFromVm(VirtualMachine vm, Nic nic) throws ConcurrentOperationException, ResourceUnavailableException { CallContext cctx = CallContext.current(); VMInstanceVO vmVO = _vmDao.findById(vm.getId()); NetworkVO network = _networkDao.findById(nic.getNetworkId()); @@ -2972,6 +3427,12 @@ public boolean removeNicFromVm(VirtualMachine vm, Nic nic) throws ConcurrentOper @Override @DB public boolean removeVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException { + // TODO will serialize on the VM object later to resolve operation conflicts + return orchestrateRemoveVmFromNetwork(vm, network, broadcastUri); + } + + @DB + private boolean orchestrateRemoveVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException { CallContext cctx = CallContext.current(); VMInstanceVO vmVO = _vmDao.findById(vm.getId()); ReservationContext context = new ReservationContextImpl(null, null, cctx.getCallingUser(), cctx.getCallingAccount()); @@ -3080,7 +3541,7 @@ public void findHostAndMigrate(String vmUuid, Long newSvcOfferingId, ExcludeList DeployDestination dest = null; try { - dest = _dpMgr.planDeployment(profile, plan, excludes); + dest = _dpMgr.planDeployment(profile, plan, excludes, null); } catch (AffinityConflictException e2) { s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2); throw new CloudRuntimeException("Unable to create deployment, affinity rules associted to the VM conflict"); @@ -3109,7 +3570,46 @@ public void findHostAndMigrate(String vmUuid, Long newSvcOfferingId, ExcludeList } @Override - public void migrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long oldSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException { + public void migrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long oldSvcOfferingId) + throws ResourceUnavailableException, ConcurrentOperationException { + AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); + if (!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { + // avoid re-entrance + VmWorkJobVO placeHolder = null; + if (VmJobEnabled.value()) { + VirtualMachine vm = _vmDao.findByUuid(vmUuid); + placeHolder = createPlaceHolderWork(vm.getId()); + } + try { + orchestrateMigrateForScale(vmUuid, srcHostId, dest, oldSvcOfferingId); + } finally { + if (VmJobEnabled.value()) + _workJobDao.expunge(placeHolder.getId()); + } + } else { + Outcome outcome = migrateVmForScaleThroughJobQueue(vmUuid, srcHostId, dest, oldSvcOfferingId); + + try { + VirtualMachine vm = outcome.get(); + } catch (InterruptedException e) { + throw new RuntimeException("Operation is interrupted", e); + } catch (java.util.concurrent.ExecutionException e) { + throw new RuntimeException("Execution excetion", e); + } + + Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob()); + if (jobResult != null) { + if (jobResult instanceof ResourceUnavailableException) + throw (ResourceUnavailableException)jobResult; + else if (jobResult instanceof ConcurrentOperationException) + throw (ConcurrentOperationException)jobResult; + } + } + } + + private void orchestrateMigrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long oldSvcOfferingId) + throws ResourceUnavailableException, ConcurrentOperationException { + VMInstanceVO vm = _vmDao.findByUuid(vmUuid); s_logger.info("Migrating " + vm + " to " + dest); @@ -3144,11 +3644,11 @@ public void migrateForScale(String vmUuid, long srcHostId, DeployDestination des throw new CloudRuntimeException("VM is not Running, unable to migrate the vm currently " + vm + " , current state: " + vm.getState().toString()); } - short alertType = AlertManager.ALERT_TYPE_USERVM_MIGRATE; + AlertManager.AlertType alertType = AlertManager.AlertType.ALERT_TYPE_USERVM_MIGRATE; if (VirtualMachine.Type.DomainRouter.equals(vm.getType())) { - alertType = AlertManager.ALERT_TYPE_DOMAIN_ROUTER_MIGRATE; + alertType = AlertManager.AlertType.ALERT_TYPE_DOMAIN_ROUTER_MIGRATE; } else if (VirtualMachine.Type.ConsoleProxy.equals(vm.getType())) { - alertType = AlertManager.ALERT_TYPE_CONSOLE_PROXY_MIGRATE; + alertType = AlertManager.AlertType.ALERT_TYPE_CONSOLE_PROXY_MIGRATE; } VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); @@ -3294,7 +3794,7 @@ public boolean plugNic(Network network, NicTO nic, VirtualMachineTO vm, Reservat } public boolean unplugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, - ResourceUnavailableException { + ResourceUnavailableException { boolean result = true; VMInstanceVO router = _vmDao.findById(vm.getId()); @@ -3327,12 +3827,60 @@ public boolean unplugNic(Network network, NicTO nic, VirtualMachineTO vm, Reserv } @Override - public VMInstanceVO reConfigureVm(String vmUuid, ServiceOffering oldServiceOffering, boolean reconfiguringOnExistingHost) throws ResourceUnavailableException, + public VMInstanceVO reConfigureVm(String vmUuid, ServiceOffering oldServiceOffering, + boolean reconfiguringOnExistingHost) + throws ResourceUnavailableException, InsufficientServerCapacityException, ConcurrentOperationException { + + AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); + if (!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { + // avoid re-entrance + VmWorkJobVO placeHolder = null; + if (VmJobEnabled.value()) { + VirtualMachine vm = _vmDao.findByUuid(vmUuid); + placeHolder = createPlaceHolderWork(vm.getId()); + } + try { + return orchestrateReConfigureVm(vmUuid, oldServiceOffering, reconfiguringOnExistingHost); + } finally { + if (VmJobEnabled.value()) + _workJobDao.expunge(placeHolder.getId()); + } + } else { + Outcome outcome = reconfigureVmThroughJobQueue(vmUuid, oldServiceOffering, reconfiguringOnExistingHost); + + VirtualMachine vm = null; + try { + vm = outcome.get(); + } catch (InterruptedException e) { + throw new RuntimeException("Operation is interrupted", e); + } catch (java.util.concurrent.ExecutionException e) { + throw new RuntimeException("Execution excetion", e); + } + + Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob()); + if (jobResult != null) { + if (jobResult instanceof ResourceUnavailableException) + throw (ResourceUnavailableException)jobResult; + else if (jobResult instanceof ConcurrentOperationException) + throw (ConcurrentOperationException)jobResult; + else if (jobResult instanceof InsufficientServerCapacityException) + throw (InsufficientServerCapacityException)jobResult; + else if (jobResult instanceof Throwable) { + s_logger.error("Unhandled exception", (Throwable)jobResult); + throw new RuntimeException("Unhandled exception", (Throwable)jobResult); + } + } + + return (VMInstanceVO)vm; + } + } + + private VMInstanceVO orchestrateReConfigureVm(String vmUuid, ServiceOffering oldServiceOffering, boolean reconfiguringOnExistingHost) throws ResourceUnavailableException, ConcurrentOperationException { VMInstanceVO vm = _vmDao.findByUuid(vmUuid); long newServiceofferingId = vm.getServiceOfferingId(); - ServiceOffering newServiceOffering = _entityMgr.findById(ServiceOffering.class, newServiceofferingId); + ServiceOffering newServiceOffering = _offeringDao.findById(vm.getId(), newServiceofferingId); HostVO hostVo = _hostDao.findById(vm.getHostId()); Float memoryOvercommitRatio = CapacityManager.MemOverprovisioningFactor.valueIn(hostVo.getClusterId()); @@ -3389,7 +3937,7 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { return new ConfigKey[] {ClusterDeltaSyncInterval, StartRetry, VmDestroyForcestop, VmOpCancelInterval, VmOpCleanupInterval, VmOpCleanupWait, VmOpLockStateRetry, - VmOpWaitInterval}; + VmOpWaitInterval, VmJobCheckInterval, VmJobTimeout, VmJobStateReportInterval, ExecuteInSequence}; } public List getStoragePoolAllocators() { @@ -3398,7 +3946,1098 @@ public List getStoragePoolAllocators() { @Inject public void setStoragePoolAllocators(List storagePoolAllocators) { - this._storagePoolAllocators = storagePoolAllocators; + _storagePoolAllocators = storagePoolAllocators; + } + + + // + // PowerState report handling for out-of-band changes and handling of left-over transitional VM states + // + + @MessageHandler(topic = Topics.VM_POWER_STATE) + private void HandlePowerStateReport(String subject, String senderAddress, Object args) { + assert (args != null); + Long vmId = (Long)args; + + List pendingWorkJobs = _workJobDao.listPendingWorkJobs( + VirtualMachine.Type.Instance, vmId); + if (pendingWorkJobs.size() == 0) { + // there is no pending operation job + VMInstanceVO vm = _vmDao.findById(vmId); + if (vm != null) { + switch (vm.getPowerState()) { + case PowerOn: + handlePowerOnReportWithNoPendingJobsOnVM(vm); + break; + + case PowerOff: + handlePowerOffReportWithNoPendingJobsOnVM(vm); + break; + + // PowerUnknown shouldn't be reported, it is a derived + // VM power state from host state (host un-reachable) + case PowerUnknown: + default: + assert (false); + break; + } + } else { + s_logger.warn("VM " + vmId + " no longer exists when processing VM state report"); + } + } else { + s_logger.info("There is pending job working on the VM. vm id: " + vmId + ", postpone power-change report by resetting power-change counters"); + + // reset VM power state tracking so that we won't lost signal when VM has + // been translated to + _vmDao.resetVmPowerStateTracking(vmId); + } + } + + private void handlePowerOnReportWithNoPendingJobsOnVM(VMInstanceVO vm) { + // + // 1) handle left-over transitional VM states + // 2) handle out of band VM live migration + // 3) handle out of sync stationary states, marking VM from Stopped to Running with + // alert messages + // + switch (vm.getState()) { + case Starting: + s_logger.info("VM " + vm.getInstanceName() + " is at " + vm.getState() + " and we received a power-on report while there is no pending jobs on it"); + + try { + stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOnReport, vm.getPowerHostId()); + } catch (NoTransitionException e) { + s_logger.warn("Unexpected VM state transition exception, race-condition?", e); + } + + s_logger.info("VM " + vm.getInstanceName() + " is sync-ed to at Running state according to power-on report from hypervisor"); + + // we need to alert admin or user about this risky state transition + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_SYNC, vm.getDataCenterId(), vm.getPodIdToDeployIn(), + VM_SYNC_ALERT_SUBJECT, "VM " + vm.getHostName() + "(" + vm.getInstanceName() + + ") state is sync-ed (Starting -> Running) from out-of-context transition. VM network environment may need to be reset"); + break; + + case Running: + try { + if (vm.getHostId() != null && vm.getHostId().longValue() != vm.getPowerHostId().longValue()) + s_logger.info("Detected out of band VM migration from host " + vm.getHostId() + " to host " + vm.getPowerHostId()); + stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOnReport, vm.getPowerHostId()); + } catch (NoTransitionException e) { + s_logger.warn("Unexpected VM state transition exception, race-condition?", e); + } + + break; + + case Stopping: + case Stopped: + s_logger.info("VM " + vm.getInstanceName() + " is at " + vm.getState() + " and we received a power-on report while there is no pending jobs on it"); + + try { + stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOnReport, vm.getPowerHostId()); + } catch (NoTransitionException e) { + s_logger.warn("Unexpected VM state transition exception, race-condition?", e); + } + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_SYNC, vm.getDataCenterId(), vm.getPodIdToDeployIn(), + VM_SYNC_ALERT_SUBJECT, "VM " + vm.getHostName() + "(" + vm.getInstanceName() + ") state is sync-ed (" + vm.getState() + + " -> Running) from out-of-context transition. VM network environment may need to be reset"); + + s_logger.info("VM " + vm.getInstanceName() + " is sync-ed to at Running state according to power-on report from hypervisor"); + break; + + case Destroyed: + case Expunging: + s_logger.info("Receive power on report when VM is in destroyed or expunging state. vm: " + + vm.getId() + ", state: " + vm.getState()); + break; + + case Migrating: + s_logger.info("VM " + vm.getInstanceName() + " is at " + vm.getState() + " and we received a power-on report while there is no pending jobs on it"); + try { + stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOnReport, vm.getPowerHostId()); + } catch (NoTransitionException e) { + s_logger.warn("Unexpected VM state transition exception, race-condition?", e); + } + s_logger.info("VM " + vm.getInstanceName() + " is sync-ed to at Running state according to power-on report from hypervisor"); + break; + + case Error: + default: + s_logger.info("Receive power on report when VM is in error or unexpected state. vm: " + + vm.getId() + ", state: " + vm.getState()); + break; + } + } + + private void handlePowerOffReportWithNoPendingJobsOnVM(VMInstanceVO vm) { + + // 1) handle left-over transitional VM states + // 2) handle out of sync stationary states, schedule force-stop to release resources + // + switch (vm.getState()) { + case Starting: + case Stopping: + case Running: + case Stopped: + case Migrating: + s_logger.info("VM " + vm.getInstanceName() + " is at " + vm.getState() + " and we received a power-off report while there is no pending jobs on it"); + try { + stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOffReport, vm.getPowerHostId()); + } catch (NoTransitionException e) { + s_logger.warn("Unexpected VM state transition exception, race-condition?", e); + } + + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_SYNC, vm.getDataCenterId(), vm.getPodIdToDeployIn(), + VM_SYNC_ALERT_SUBJECT, "VM " + vm.getHostName() + "(" + vm.getInstanceName() + ") state is sync-ed (" + vm.getState() + + " -> Stopped) from out-of-context transition."); + + s_logger.info("VM " + vm.getInstanceName() + " is sync-ed to at Stopped state according to power-on report from hypervisor"); + + // TODO: we need to forcely release all resource allocation + break; + + case Destroyed: + case Expunging: + break; + + case Error: + default: + break; + } + } + + private void scanStalledVMInTransitionStateOnUpHost(long hostId) { + // + // Check VM that is stuck in Starting, Stopping, Migrating states, we won't check + // VMs in expunging state (this need to be handled specially) + // + // checking condition + // 1) no pending VmWork job + // 2) on hostId host and host is UP + // + // When host is UP, soon or later we will get a report from the host about the VM, + // however, if VM is missing from the host report (it may happen in out of band changes + // or from designed behave of XS/KVM), the VM may not get a chance to run the state-sync logic + // + // Therefore, we will scan thoses VMs on UP host based on last update timestamp, if the host is UP + // and a VM stalls for status update, we will consider them to be powered off + // (which is relatively safe to do so) + + long stallThresholdInMs = VmJobStateReportInterval.value() + (VmJobStateReportInterval.value() >> 1); + Date cutTime = new Date(DateUtil.currentGMTTime().getTime() - stallThresholdInMs); + List mostlikelyStoppedVMs = listStalledVMInTransitionStateOnUpHost(hostId, cutTime); + for (Long vmId : mostlikelyStoppedVMs) { + VMInstanceVO vm = _vmDao.findById(vmId); + assert (vm != null); + handlePowerOffReportWithNoPendingJobsOnVM(vm); + } + + List vmsWithRecentReport = listVMInTransitionStateWithRecentReportOnUpHost(hostId, cutTime); + for (Long vmId : vmsWithRecentReport) { + VMInstanceVO vm = _vmDao.findById(vmId); + assert (vm != null); + if (vm.getPowerState() == PowerState.PowerOn) + handlePowerOnReportWithNoPendingJobsOnVM(vm); + else + handlePowerOffReportWithNoPendingJobsOnVM(vm); + } + } + + private void scanStalledVMInTransitionStateOnDisconnectedHosts() { + Date cutTime = new Date(DateUtil.currentGMTTime().getTime() - VmOpWaitInterval.value() * 1000); + List stuckAndUncontrollableVMs = listStalledVMInTransitionStateOnDisconnectedHosts(cutTime); + for (Long vmId : stuckAndUncontrollableVMs) { + VMInstanceVO vm = _vmDao.findById(vmId); + + // We now only alert administrator about this situation + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_SYNC, vm.getDataCenterId(), vm.getPodIdToDeployIn(), + VM_SYNC_ALERT_SUBJECT, "VM " + vm.getHostName() + "(" + vm.getInstanceName() + ") is stuck in " + vm.getState() + + " state and its host is unreachable for too long"); + } + } + + // VMs that in transitional state without recent power state report + private List listStalledVMInTransitionStateOnUpHost(long hostId, Date cutTime) { + String sql = "SELECT i.* FROM vm_instance as i, host as h WHERE h.status = 'UP' " + + "AND h.id = ? AND i.power_state_update_time < ? AND i.host_id = h.id " + + "AND (i.state ='Starting' OR i.state='Stopping' OR i.state='Migrating') " + + "AND i.id NOT IN (SELECT w.vm_instance_id FROM vm_work_job AS w JOIN async_job AS j ON w.id = j.id WHERE j.job_status = ?)"; + + List l = new ArrayList(); + TransactionLegacy txn = null; + try { + txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB); + + PreparedStatement pstmt = null; + try { + pstmt = txn.prepareAutoCloseStatement(sql); + + pstmt.setLong(1, hostId); + pstmt.setString(2, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutTime)); + pstmt.setInt(3, JobInfo.Status.IN_PROGRESS.ordinal()); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + l.add(rs.getLong(1)); + } + } catch (SQLException e) { + } catch (Throwable e) { + } + + } finally { + if (txn != null) + txn.close(); + } + return l; + } + + // VMs that in transitional state and recently have power state update + private List listVMInTransitionStateWithRecentReportOnUpHost(long hostId, Date cutTime) { + String sql = "SELECT i.* FROM vm_instance as i, host as h WHERE h.status = 'UP' " + + "AND h.id = ? AND i.power_state_update_time > ? AND i.host_id = h.id " + + "AND (i.state ='Starting' OR i.state='Stopping' OR i.state='Migrating') " + + "AND i.id NOT IN (SELECT w.vm_instance_id FROM vm_work_job AS w JOIN async_job AS j ON w.id = j.id WHERE j.job_status = ?)"; + + List l = new ArrayList(); + TransactionLegacy txn = null; + try { + txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB); + PreparedStatement pstmt = null; + try { + pstmt = txn.prepareAutoCloseStatement(sql); + + pstmt.setLong(1, hostId); + pstmt.setString(2, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutTime)); + pstmt.setInt(3, JobInfo.Status.IN_PROGRESS.ordinal()); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + l.add(rs.getLong(1)); + } + } catch (SQLException e) { + } catch (Throwable e) { + } + return l; + } finally { + if (txn != null) + txn.close(); + } + } + + private List listStalledVMInTransitionStateOnDisconnectedHosts(Date cutTime) { + String sql = "SELECT i.* FROM vm_instance as i, host as h WHERE h.status != 'UP' " + + "AND i.power_state_update_time < ? AND i.host_id = h.id " + + "AND (i.state ='Starting' OR i.state='Stopping' OR i.state='Migrating') " + + "AND i.id NOT IN (SELECT w.vm_instance_id FROM vm_work_job AS w JOIN async_job AS j ON w.id = j.id WHERE j.job_status = ?)"; + + List l = new ArrayList(); + TransactionLegacy txn = null; + try { + txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB); + PreparedStatement pstmt = null; + try { + pstmt = txn.prepareAutoCloseStatement(sql); + + pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutTime)); + pstmt.setInt(2, JobInfo.Status.IN_PROGRESS.ordinal()); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + l.add(rs.getLong(1)); + } + } catch (SQLException e) { + } catch (Throwable e) { + } + return l; + } finally { + if (txn != null) + txn.close(); + } + } + + // + // VM operation based on new sync model + // + + public class VmStateSyncOutcome extends OutcomeImpl { + private long _vmId; + + public VmStateSyncOutcome(final AsyncJob job, final PowerState desiredPowerState, final long vmId, final Long srcHostIdForMigration) { + super(VirtualMachine.class, job, VmJobCheckInterval.value(), new Predicate() { + @Override + public boolean checkCondition() { + VMInstanceVO instance = _vmDao.findById(vmId); + if (instance.getPowerState() == desiredPowerState && (srcHostIdForMigration != null && instance.getPowerHostId() != srcHostIdForMigration)) + return true; + return false; + } + }, Topics.VM_POWER_STATE, AsyncJob.Topics.JOB_STATE); + _vmId = vmId; + } + + @Override + protected VirtualMachine retrieve() { + return _vmDao.findById(_vmId); + } + } + + public class VmJobVirtualMachineOutcome extends OutcomeImpl { + private long _vmId; + + public VmJobVirtualMachineOutcome(final AsyncJob job, final long vmId) { + super(VirtualMachine.class, job, VmJobCheckInterval.value(), new Predicate() { + @Override + public boolean checkCondition() { + AsyncJobVO jobVo = _entityMgr.findById(AsyncJobVO.class, job.getId()); + assert (jobVo != null); + if (jobVo == null || jobVo.getStatus() != JobInfo.Status.IN_PROGRESS) + return true; + + return false; + } + }, AsyncJob.Topics.JOB_STATE); + _vmId = vmId; + } + + @Override + protected VirtualMachine retrieve() { + return _vmDao.findById(_vmId); + } + } + + // + // TODO build a common pattern to reduce code duplication in following methods + // no time for this at current iteration + // + public Outcome startVmThroughJobQueue(final String vmUuid, + final Map params, + final DeploymentPlan planToDeploy) { + + final CallContext context = CallContext.current(); + final User callingUser = context.getCallingUser(); + final Account callingAccount = context.getCallingAccount(); + + final VMInstanceVO vm = _vmDao.findByUuid(vmUuid); + + Object[] result = Transaction.execute(new TransactionCallback() { + @Override + public Object[] doInTransaction(TransactionStatus status) { + VmWorkJobVO workJob = null; + + _vmDao.lockRow(vm.getId(), true); + List pendingWorkJobs = _workJobDao.listPendingWorkJobs(VirtualMachine.Type.Instance, + vm.getId(), VmWorkStart.class.getName()); + + if (pendingWorkJobs.size() > 0) { + assert (pendingWorkJobs.size() == 1); + workJob = pendingWorkJobs.get(0); + } else { + workJob = new VmWorkJobVO(context.getContextId()); + + workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER); + workJob.setCmd(VmWorkStart.class.getName()); + + workJob.setAccountId(callingAccount.getId()); + workJob.setUserId(callingUser.getId()); + workJob.setStep(VmWorkJobVO.Step.Starting); + workJob.setVmType(VirtualMachine.Type.Instance); + workJob.setVmInstanceId(vm.getId()); + workJob.setRelated(AsyncJobExecutionContext.getOriginJobContextId()); + + // save work context info (there are some duplications) + VmWorkStart workInfo = new VmWorkStart(callingUser.getId(), callingAccount.getId(), vm.getId(), VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER); + workInfo.setPlan(planToDeploy); + workInfo.setParams(params); + workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); + + _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); + } + + return new Object[] {workJob, new Long(workJob.getId())}; + } + }); + + final long jobId = (Long)result[1]; + AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId); + + return new VmStateSyncOutcome((VmWorkJobVO)result[0], + VirtualMachine.PowerState.PowerOn, vm.getId(), null); + } + + public Outcome stopVmThroughJobQueue(final String vmUuid, final boolean cleanup) { + final CallContext context = CallContext.current(); + final Account account = context.getCallingAccount(); + final User user = context.getCallingUser(); + + final VMInstanceVO vm = _vmDao.findByUuid(vmUuid); + + Object[] result = Transaction.execute(new TransactionCallback() { + @Override + public Object[] doInTransaction(TransactionStatus status) { + _vmDao.lockRow(vm.getId(), true); + + List pendingWorkJobs = _workJobDao.listPendingWorkJobs( + vm.getType(), vm.getId(), + VmWorkStop.class.getName()); + + VmWorkJobVO workJob = null; + if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) { + assert (pendingWorkJobs.size() == 1); + workJob = pendingWorkJobs.get(0); + } else { + workJob = new VmWorkJobVO(context.getContextId()); + + workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER); + workJob.setCmd(VmWorkStop.class.getName()); + + workJob.setAccountId(account.getId()); + workJob.setUserId(user.getId()); + workJob.setStep(VmWorkJobVO.Step.Prepare); + workJob.setVmType(VirtualMachine.Type.Instance); + workJob.setVmInstanceId(vm.getId()); + workJob.setRelated(AsyncJobExecutionContext.getOriginJobContextId()); + + // save work context info (there are some duplications) + VmWorkStop workInfo = new VmWorkStop(user.getId(), account.getId(), vm.getId(), VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, cleanup); + workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); + + _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); + } + + return new Object[] {workJob, new Long(workJob.getId())}; + } + }); + + final long jobId = (Long)result[1]; + AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId); + + return new VmStateSyncOutcome((VmWorkJobVO)result[0], + VirtualMachine.PowerState.PowerOff, vm.getId(), null); + } + + public Outcome rebootVmThroughJobQueue(final String vmUuid, + final Map params) { + + final CallContext context = CallContext.current(); + final Account account = context.getCallingAccount(); + final User user = context.getCallingUser(); + + final VMInstanceVO vm = _vmDao.findByUuid(vmUuid); + + Object[] result = Transaction.execute(new TransactionCallback() { + @Override + public Object[] doInTransaction(TransactionStatus status) { + _vmDao.lockRow(vm.getId(), true); + + List pendingWorkJobs = _workJobDao.listPendingWorkJobs( + VirtualMachine.Type.Instance, vm.getId(), + VmWorkReboot.class.getName()); + + VmWorkJobVO workJob = null; + if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) { + assert (pendingWorkJobs.size() == 1); + workJob = pendingWorkJobs.get(0); + } else { + workJob = new VmWorkJobVO(context.getContextId()); + + workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER); + workJob.setCmd(VmWorkReboot.class.getName()); + + workJob.setAccountId(account.getId()); + workJob.setUserId(user.getId()); + workJob.setStep(VmWorkJobVO.Step.Prepare); + workJob.setVmType(VirtualMachine.Type.Instance); + workJob.setVmInstanceId(vm.getId()); + workJob.setRelated(AsyncJobExecutionContext.getOriginJobContextId()); + + // save work context info (there are some duplications) + VmWorkReboot workInfo = new VmWorkReboot(user.getId(), account.getId(), vm.getId(), VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, params); + workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); + + _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); + } + + return new Object[] {workJob, new Long(workJob.getId())}; + } + }); + + final long jobId = (Long)result[1]; + AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId); + + return new VmJobVirtualMachineOutcome((VmWorkJobVO)result[0], + vm.getId()); + } + + public Outcome migrateVmThroughJobQueue(final String vmUuid, final long srcHostId, final DeployDestination dest) { + final CallContext context = CallContext.current(); + final User user = context.getCallingUser(); + final Account account = context.getCallingAccount(); + + final VMInstanceVO vm = _vmDao.findByUuid(vmUuid); + + Object[] result = Transaction.execute(new TransactionCallback() { + @Override + public Object[] doInTransaction(TransactionStatus status) { + + _vmDao.lockRow(vm.getId(), true); + + List pendingWorkJobs = _workJobDao.listPendingWorkJobs( + VirtualMachine.Type.Instance, vm.getId(), + VmWorkMigrate.class.getName()); + + VmWorkJobVO workJob = null; + if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) { + assert (pendingWorkJobs.size() == 1); + workJob = pendingWorkJobs.get(0); + } else { + + workJob = new VmWorkJobVO(context.getContextId()); + + workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER); + workJob.setCmd(VmWorkMigrate.class.getName()); + + workJob.setAccountId(account.getId()); + workJob.setUserId(user.getId()); + workJob.setVmType(VirtualMachine.Type.Instance); + workJob.setVmInstanceId(vm.getId()); + workJob.setRelated(AsyncJobExecutionContext.getOriginJobContextId()); + + // save work context info (there are some duplications) + VmWorkMigrate workInfo = new VmWorkMigrate(user.getId(), account.getId(), vm.getId(), VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, srcHostId, dest); + workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); + + _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); + } + return new Object[] {workJob, new Long(workJob.getId())}; + } + }); + + final long jobId = (Long)result[1]; + AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId); + + return new VmStateSyncOutcome((VmWorkJobVO)result[0], + VirtualMachine.PowerState.PowerOn, vm.getId(), vm.getPowerHostId()); + } + + public Outcome migrateVmWithStorageThroughJobQueue( + final String vmUuid, final long srcHostId, final long destHostId, + final Map volumeToPool) { + + final CallContext context = CallContext.current(); + final User user = context.getCallingUser(); + final Account account = context.getCallingAccount(); + + final VMInstanceVO vm = _vmDao.findByUuid(vmUuid); + + Object[] result = Transaction.execute(new TransactionCallback() { + @Override + public Object[] doInTransaction(TransactionStatus status) { + + _vmDao.lockRow(vm.getId(), true); + + List pendingWorkJobs = _workJobDao.listPendingWorkJobs( + VirtualMachine.Type.Instance, vm.getId(), + VmWorkMigrateWithStorage.class.getName()); + + VmWorkJobVO workJob = null; + if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) { + assert (pendingWorkJobs.size() == 1); + workJob = pendingWorkJobs.get(0); + } else { + + workJob = new VmWorkJobVO(context.getContextId()); + + workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER); + workJob.setCmd(VmWorkMigrate.class.getName()); + + workJob.setAccountId(account.getId()); + workJob.setUserId(user.getId()); + workJob.setVmType(VirtualMachine.Type.Instance); + workJob.setVmInstanceId(vm.getId()); + workJob.setRelated(AsyncJobExecutionContext.getOriginJobContextId()); + + // save work context info (there are some duplications) + VmWorkMigrateWithStorage workInfo = new VmWorkMigrateWithStorage(user.getId(), account.getId(), vm.getId(), + VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, srcHostId, destHostId, volumeToPool); + workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); + + _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); + } + return new Object[] {workJob, new Long(workJob.getId())}; + } + }); + + final long jobId = (Long)result[1]; + AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId); + + return new VmStateSyncOutcome((VmWorkJobVO)result[0], + VirtualMachine.PowerState.PowerOn, vm.getId(), destHostId); + } + + public Outcome migrateVmForScaleThroughJobQueue( + final String vmUuid, final long srcHostId, final DeployDestination dest, final Long newSvcOfferingId) { + + final CallContext context = CallContext.current(); + final User user = context.getCallingUser(); + final Account account = context.getCallingAccount(); + + final VMInstanceVO vm = _vmDao.findByUuid(vmUuid); + + Object[] result = Transaction.execute(new TransactionCallback() { + @Override + public Object[] doInTransaction(TransactionStatus status) { + + _vmDao.lockRow(vm.getId(), true); + + List pendingWorkJobs = _workJobDao.listPendingWorkJobs( + VirtualMachine.Type.Instance, vm.getId(), + VmWorkMigrateForScale.class.getName()); + + VmWorkJobVO workJob = null; + if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) { + assert (pendingWorkJobs.size() == 1); + workJob = pendingWorkJobs.get(0); + } else { + + workJob = new VmWorkJobVO(context.getContextId()); + + workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER); + workJob.setCmd(VmWorkMigrate.class.getName()); + + workJob.setAccountId(account.getId()); + workJob.setUserId(user.getId()); + workJob.setVmType(VirtualMachine.Type.Instance); + workJob.setVmInstanceId(vm.getId()); + workJob.setRelated(AsyncJobExecutionContext.getOriginJobContextId()); + + // save work context info (there are some duplications) + VmWorkMigrateForScale workInfo = new VmWorkMigrateForScale(user.getId(), account.getId(), vm.getId(), + VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, srcHostId, dest, newSvcOfferingId); + workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); + + _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); + } + + return new Object[] {workJob, new Long(workJob.getId())}; + } + }); + + final long jobId = (Long)result[1]; + AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId); + + return new VmJobVirtualMachineOutcome((VmWorkJobVO)result[0], vm.getId()); + } + + public Outcome migrateVmStorageThroughJobQueue( + final String vmUuid, final StoragePool destPool) { + + final CallContext context = CallContext.current(); + final User user = context.getCallingUser(); + final Account account = context.getCallingAccount(); + + final VMInstanceVO vm = _vmDao.findByUuid(vmUuid); + + Object[] result = Transaction.execute(new TransactionCallback() { + @Override + public Object[] doInTransaction(TransactionStatus status) { + + _vmDao.lockRow(vm.getId(), true); + + List pendingWorkJobs = _workJobDao.listPendingWorkJobs( + VirtualMachine.Type.Instance, vm.getId(), + VmWorkStorageMigration.class.getName()); + + VmWorkJobVO workJob = null; + if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) { + assert (pendingWorkJobs.size() == 1); + workJob = pendingWorkJobs.get(0); + } else { + + workJob = new VmWorkJobVO(context.getContextId()); + + workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER); + workJob.setCmd(VmWorkStorageMigration.class.getName()); + + workJob.setAccountId(account.getId()); + workJob.setUserId(user.getId()); + workJob.setVmType(VirtualMachine.Type.Instance); + workJob.setVmInstanceId(vm.getId()); + workJob.setRelated(AsyncJobExecutionContext.getOriginJobContextId()); + + // save work context info (there are some duplications) + VmWorkStorageMigration workInfo = new VmWorkStorageMigration(user.getId(), account.getId(), vm.getId(), + VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, destPool.getId()); + workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); + + _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); + } + + return new Object[] {workJob, new Long(workJob.getId())}; + } + }); + + final long jobId = (Long)result[1]; + AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId); + + return new VmJobVirtualMachineOutcome((VmWorkJobVO)result[0], vm.getId()); + } + + public Outcome addVmToNetworkThroughJobQueue( + final VirtualMachine vm, final Network network, final NicProfile requested) { + + final CallContext context = CallContext.current(); + final User user = context.getCallingUser(); + final Account account = context.getCallingAccount(); + + Object[] result = Transaction.execute(new TransactionCallback() { + @Override + public Object[] doInTransaction(TransactionStatus status) { + + _vmDao.lockRow(vm.getId(), true); + + List pendingWorkJobs = _workJobDao.listPendingWorkJobs( + VirtualMachine.Type.Instance, vm.getId(), + VmWorkAddVmToNetwork.class.getName()); + + VmWorkJobVO workJob = null; + if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) { + assert (pendingWorkJobs.size() == 1); + workJob = pendingWorkJobs.get(0); + } else { + + workJob = new VmWorkJobVO(context.getContextId()); + + workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER); + workJob.setCmd(VmWorkAddVmToNetwork.class.getName()); + + workJob.setAccountId(account.getId()); + workJob.setUserId(user.getId()); + workJob.setVmType(VirtualMachine.Type.Instance); + workJob.setVmInstanceId(vm.getId()); + workJob.setRelated(AsyncJobExecutionContext.getOriginJobContextId()); + + // save work context info (there are some duplications) + VmWorkAddVmToNetwork workInfo = new VmWorkAddVmToNetwork(user.getId(), account.getId(), vm.getId(), + VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, network.getId(), requested); + workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); + + _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); + } + return new Object[] {workJob, new Long(workJob.getId())}; + } + }); + + final long jobId = (Long)result[1]; + AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId); + + return new VmJobVirtualMachineOutcome((VmWorkJobVO)result[0], vm.getId()); + } + + public Outcome removeNicFromVmThroughJobQueue( + final VirtualMachine vm, final Nic nic) { + + final CallContext context = CallContext.current(); + final User user = context.getCallingUser(); + final Account account = context.getCallingAccount(); + + Object[] result = Transaction.execute(new TransactionCallback() { + @Override + public Object[] doInTransaction(TransactionStatus status) { + + _vmDao.lockRow(vm.getId(), true); + + List pendingWorkJobs = _workJobDao.listPendingWorkJobs( + VirtualMachine.Type.Instance, vm.getId(), + VmWorkRemoveNicFromVm.class.getName()); + + VmWorkJobVO workJob = null; + if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) { + assert (pendingWorkJobs.size() == 1); + workJob = pendingWorkJobs.get(0); + } else { + + workJob = new VmWorkJobVO(context.getContextId()); + + workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER); + workJob.setCmd(VmWorkRemoveNicFromVm.class.getName()); + + workJob.setAccountId(account.getId()); + workJob.setUserId(user.getId()); + workJob.setVmType(VirtualMachine.Type.Instance); + workJob.setVmInstanceId(vm.getId()); + workJob.setRelated(AsyncJobExecutionContext.getOriginJobContextId()); + + // save work context info (there are some duplications) + VmWorkRemoveNicFromVm workInfo = new VmWorkRemoveNicFromVm(user.getId(), account.getId(), vm.getId(), + VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, nic.getId()); + workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); + + _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); + } + return new Object[] {workJob, new Long(workJob.getId())}; + } + }); + + final long jobId = (Long)result[1]; + AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId); + + return new VmJobVirtualMachineOutcome((VmWorkJobVO)result[0], vm.getId()); + } + + public Outcome removeVmFromNetworkThroughJobQueue( + final VirtualMachine vm, final Network network, final URI broadcastUri) { + + final CallContext context = CallContext.current(); + final User user = context.getCallingUser(); + final Account account = context.getCallingAccount(); + + Object[] result = Transaction.execute(new TransactionCallback() { + @Override + public Object[] doInTransaction(TransactionStatus status) { + + _vmDao.lockRow(vm.getId(), true); + + List pendingWorkJobs = _workJobDao.listPendingWorkJobs( + VirtualMachine.Type.Instance, vm.getId(), + VmWorkRemoveVmFromNetwork.class.getName()); + + VmWorkJobVO workJob = null; + if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) { + assert (pendingWorkJobs.size() == 1); + workJob = pendingWorkJobs.get(0); + } else { + + workJob = new VmWorkJobVO(context.getContextId()); + + workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER); + workJob.setCmd(VmWorkRemoveVmFromNetwork.class.getName()); + + workJob.setAccountId(account.getId()); + workJob.setUserId(user.getId()); + workJob.setVmType(VirtualMachine.Type.Instance); + workJob.setVmInstanceId(vm.getId()); + workJob.setRelated(AsyncJobExecutionContext.getOriginJobContextId()); + + // save work context info (there are some duplications) + VmWorkRemoveVmFromNetwork workInfo = new VmWorkRemoveVmFromNetwork(user.getId(), account.getId(), vm.getId(), + VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, network, broadcastUri); + workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); + + _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); + } + return new Object[] {workJob, new Long(workJob.getId())}; + } + }); + + final long jobId = (Long)result[1]; + AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId); + + return new VmJobVirtualMachineOutcome((VmWorkJobVO)result[0], vm.getId()); + } + + public Outcome reconfigureVmThroughJobQueue( + final String vmUuid, final ServiceOffering newServiceOffering, final boolean reconfiguringOnExistingHost) { + + final CallContext context = CallContext.current(); + final User user = context.getCallingUser(); + final Account account = context.getCallingAccount(); + + final VMInstanceVO vm = _vmDao.findByUuid(vmUuid); + + Object[] result = Transaction.execute(new TransactionCallback() { + @Override + public Object[] doInTransaction(TransactionStatus status) { + + _vmDao.lockRow(vm.getId(), true); + + List pendingWorkJobs = _workJobDao.listPendingWorkJobs( + VirtualMachine.Type.Instance, vm.getId(), + VmWorkReconfigure.class.getName()); + + VmWorkJobVO workJob = null; + if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) { + assert (pendingWorkJobs.size() == 1); + workJob = pendingWorkJobs.get(0); + } else { + + workJob = new VmWorkJobVO(context.getContextId()); + + workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER); + workJob.setCmd(VmWorkReconfigure.class.getName()); + + workJob.setAccountId(account.getId()); + workJob.setUserId(user.getId()); + workJob.setVmType(VirtualMachine.Type.Instance); + workJob.setVmInstanceId(vm.getId()); + workJob.setRelated(AsyncJobExecutionContext.getOriginJobContextId()); + + // save work context info (there are some duplications) + VmWorkReconfigure workInfo = new VmWorkReconfigure(user.getId(), account.getId(), vm.getId(), + VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, newServiceOffering.getId(), reconfiguringOnExistingHost); + workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); + + _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); + } + return new Object[] {workJob, new Long(workJob.getId())}; + } + }); + + final long jobId = (Long)result[1]; + AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId); + + return new VmJobVirtualMachineOutcome((VmWorkJobVO)result[0], vm.getId()); + } + + private Pair orchestrateStart(VmWorkStart work) throws Exception { + VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId()); + if (vm == null) { + s_logger.info("Unable to find vm " + work.getVmId()); + } + assert (vm != null); + + orchestrateStart(vm.getUuid(), work.getParams(), work.getPlan(), null); + return new Pair(JobInfo.Status.SUCCEEDED, null); + } + + private Pair orchestrateStop(VmWorkStop work) throws Exception { + VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId()); + if (vm == null) { + s_logger.info("Unable to find vm " + work.getVmId()); + } + assert (vm != null); + + orchestrateStop(vm.getUuid(), work.isCleanup()); + return new Pair(JobInfo.Status.SUCCEEDED, null); + } + + private Pair orchestrateMigrate(VmWorkMigrate work) throws Exception { + VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId()); + if (vm == null) { + s_logger.info("Unable to find vm " + work.getVmId()); + } + assert (vm != null); + + orchestrateMigrate(vm.getUuid(), work.getSrcHostId(), work.getDeployDestination()); + return new Pair(JobInfo.Status.SUCCEEDED, null); + } + + private Pair orchestrateMigrateWithStorage(VmWorkMigrateWithStorage work) throws Exception { + VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId()); + if (vm == null) { + s_logger.info("Unable to find vm " + work.getVmId()); + } + assert (vm != null); + orchestrateMigrateWithStorage(vm.getUuid(), + work.getSrcHostId(), + work.getDestHostId(), + work.getVolumeToPool()); + return new Pair(JobInfo.Status.SUCCEEDED, null); + } + + private Pair orchestrateMigrateForScale(VmWorkMigrateForScale work) throws Exception { + VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId()); + if (vm == null) { + s_logger.info("Unable to find vm " + work.getVmId()); + } + assert (vm != null); + orchestrateMigrateForScale(vm.getUuid(), + work.getSrcHostId(), + work.getDeployDestination(), + work.getNewServiceOfferringId()); + return new Pair(JobInfo.Status.SUCCEEDED, null); } + private Pair orchestrateReboot(VmWorkReboot work) throws Exception { + VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId()); + if (vm == null) { + s_logger.info("Unable to find vm " + work.getVmId()); + } + assert (vm != null); + orchestrateReboot(vm.getUuid(), work.getParams()); + return new Pair(JobInfo.Status.SUCCEEDED, null); + } + + private Pair orchestrateAddVmToNetwork(VmWorkAddVmToNetwork work) throws Exception { + VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId()); + if (vm == null) { + s_logger.info("Unable to find vm " + work.getVmId()); + } + assert (vm != null); + + Network network = _networkDao.findById(work.getNetworkId()); + NicProfile nic = orchestrateAddVmToNetwork(vm, network, + work.getRequestedNicProfile()); + + return new Pair(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(new Long(nic.getId()))); + } + + private Pair orchestrateRemoveNicFromVm(VmWorkRemoveNicFromVm work) throws Exception { + VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId()); + if (vm == null) { + s_logger.info("Unable to find vm " + work.getVmId()); + } + assert (vm != null); + NicVO nic = _entityMgr.findById(NicVO.class, work.getNicId()); + boolean result = orchestrateRemoveNicFromVm(vm, nic); + return new Pair(JobInfo.Status.SUCCEEDED, + _jobMgr.marshallResultObject(new Boolean(result))); + } + + private Pair orchestrateRemoveVmFromNetwork(VmWorkRemoveVmFromNetwork work) throws Exception { + VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId()); + if (vm == null) { + s_logger.info("Unable to find vm " + work.getVmId()); + } + assert (vm != null); + boolean result = orchestrateRemoveVmFromNetwork(vm, + work.getNetwork(), work.getBroadcastUri()); + return new Pair(JobInfo.Status.SUCCEEDED, + _jobMgr.marshallResultObject(new Boolean(result))); + } + + private Pair orchestrateReconfigure(VmWorkReconfigure work) throws Exception { + VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId()); + if (vm == null) { + s_logger.info("Unable to find vm " + work.getVmId()); + } + assert (vm != null); + + ServiceOffering newServiceOffering = _offeringDao.findById(vm.getId(), work.getNewServiceOfferingId()); + + reConfigureVm(vm.getUuid(), newServiceOffering, + work.isSameHost()); + return new Pair(JobInfo.Status.SUCCEEDED, null); + } + + private Pair orchestrateStorageMigration(VmWorkStorageMigration work) throws Exception { + VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId()); + if (vm == null) { + s_logger.info("Unable to find vm " + work.getVmId()); + } + assert (vm != null); + StoragePool pool = (PrimaryDataStoreInfo)dataStoreMgr.getPrimaryDataStore(work.getDestStoragePoolId()); + orchestrateStorageMigration(vm.getUuid(), pool); + return new Pair(JobInfo.Status.SUCCEEDED, null); + } + + @Override + public Pair handleVmWorkJob(VmWork work) throws Exception { + return _jobHandlerProxy.handleVmWorkJob(work); + } + + private VmWorkJobVO createPlaceHolderWork(long instanceId) { + VmWorkJobVO workJob = new VmWorkJobVO(""); + + workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_PLACEHOLDER); + workJob.setCmd(""); + workJob.setCmdInfo(""); + + workJob.setAccountId(0); + workJob.setUserId(0); + workJob.setStep(VmWorkJobVO.Step.Starting); + workJob.setVmType(VirtualMachine.Type.Instance); + workJob.setVmInstanceId(instanceId); + workJob.setInitMsid(ManagementServerNode.getManagementServerId()); + + _workJobDao.persist(workJob); + + return workJob; + } } diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java index 7a23ddd81e9f..d7aef72aea21 100644 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java @@ -5,7 +5,7 @@ // 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, @@ -19,14 +19,15 @@ import java.util.Map; import com.cloud.agent.api.HostVmStateReportEntry; -import com.cloud.vm.VirtualMachine.PowerState; public interface VirtualMachinePowerStateSync { - + void resetHostSyncState(long hostId); - + void processHostVmStateReport(long hostId, Map report); - + // to adapt legacy ping report - void processHostVmStatePingReport(long hostId, Map report); + void processHostVmStatePingReport(long hostId, Map report); + + Map convertVmStateReport(Map states); } diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java index 9c47727ed515..9a0119ca41fb 100644 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java @@ -27,7 +27,6 @@ import org.apache.cloudstack.framework.messagebus.PublishScope; import com.cloud.agent.api.HostVmStateReportEntry; -import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.dao.VMInstanceDao; public class VirtualMachinePowerStateSyncImpl implements VirtualMachinePowerStateSync { @@ -36,81 +35,64 @@ public class VirtualMachinePowerStateSyncImpl implements VirtualMachinePowerStat @Inject MessageBus _messageBus; @Inject VMInstanceDao _instanceDao; @Inject VirtualMachineManager _vmMgr; - + public VirtualMachinePowerStateSyncImpl() { } - + @Override public void resetHostSyncState(long hostId) { s_logger.info("Reset VM power state sync for host: " + hostId); _instanceDao.resetHostPowerStateTracking(hostId); } - + @Override public void processHostVmStateReport(long hostId, Map report) { if(s_logger.isDebugEnabled()) s_logger.debug("Process host VM state report from ping process. host: " + hostId); - - Map translatedInfo = convertToInfos(report); + + Map translatedInfo = convertVmStateReport(report); processReport(hostId, translatedInfo); } @Override - public void processHostVmStatePingReport(long hostId, Map report) { + public void processHostVmStatePingReport(long hostId, Map report) { if(s_logger.isDebugEnabled()) s_logger.debug("Process host VM state report from ping process. host: " + hostId); - - Map translatedInfo = convertHostPingInfos(report); + + Map translatedInfo = convertVmStateReport(report); processReport(hostId, translatedInfo); } - + private void processReport(long hostId, Map translatedInfo) { - + for(Map.Entry entry : translatedInfo.entrySet()) { - + if(s_logger.isDebugEnabled()) s_logger.debug("VM state report. host: " + hostId + ", vm id: " + entry.getKey() + ", power state: " + entry.getValue()); if(_instanceDao.updatePowerState(entry.getKey(), hostId, entry.getValue())) { - if(s_logger.isDebugEnabled()) s_logger.debug("VM state report is updated. host: " + hostId + ", vm id: " + entry.getKey() + ", power state: " + entry.getValue()); - + _messageBus.publish(null, VirtualMachineManager.Topics.VM_POWER_STATE, PublishScope.GLOBAL, entry.getKey()); + } else { + if (s_logger.isDebugEnabled()) + s_logger.debug("VM power state does not change, skip DB writing. vm id: " + entry.getKey()); } } } - - private Map convertHostPingInfos(Map states) { - final HashMap map = new HashMap(); - if (states == null) { - return map; - } - - for (Map.Entry entry : states.entrySet()) { - VMInstanceVO vm = findVM(entry.getKey()); - if(vm != null) { - map.put(vm.getId(), entry.getValue()); - break; - } else { - s_logger.info("Unable to find matched VM in CloudStack DB. name: " + entry.getKey()); - } - } - return map; - } - - private Map convertToInfos(Map states) { + @Override + public Map convertVmStateReport(Map states) { final HashMap map = new HashMap(); if (states == null) { return map; } - + for (Map.Entry entry : states.entrySet()) { VMInstanceVO vm = findVM(entry.getKey()); if(vm != null) { map.put(vm.getId(), entry.getValue().getState()); - break; } else { s_logger.info("Unable to find matched VM in CloudStack DB. name: " + entry.getKey()); } @@ -118,7 +100,7 @@ private Map convertToInfos(Map _handlers; + + public VmWorkJobDispatcher() { + } + + public Map getHandlers() { + return _handlers; + } + + public void setHandlers(Map handlers) { + _handlers = handlers; + } + + @Override + public void runJob(AsyncJob job) { + VmWork work = null; + try { + String cmd = job.getCmd(); + assert(cmd != null); + + Class workClz = null; + try { + workClz = Class.forName(job.getCmd()); + } catch(ClassNotFoundException e) { + s_logger.error("VM work class " + cmd + " is not found" + ", job origin: " + job.getRelated(), e); + _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.FAILED, 0, e.getMessage()); + return; + } + + work = VmWorkSerializer.deserialize(workClz, job.getCmdInfo()); + assert(work != null); + if(work == null) { + s_logger.error("Unable to deserialize VM work " + job.getCmd() + ", job info: " + job.getCmdInfo() + ", job origin: " + job.getRelated()); + _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.FAILED, 0, "Unable to deserialize VM work"); + return; + } + + if (s_logger.isDebugEnabled()) + s_logger.debug("Run VM work job: " + cmd + " for VM " + work.getVmId() + ", job origin: " + job.getRelated()); + try { + if (_handlers == null || _handlers.isEmpty()) { + s_logger.error("Invalid startup configuration, no work job handler is found. cmd: " + job.getCmd() + ", job info: " + job.getCmdInfo() + + ", job origin: " + job.getRelated()); + _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.FAILED, 0, "Invalid startup configuration. no job handler is found"); + return; + } + + VmWorkJobHandler handler = _handlers.get(work.getHandlerName()); + + if (handler == null) { + s_logger.error("Unable to find work job handler. handler name: " + work.getHandlerName() + ", job cmd: " + job.getCmd() + + ", job info: " + job.getCmdInfo() + ", job origin: " + job.getRelated()); + _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.FAILED, 0, "Unable to find work job handler"); + return; + } + + CallContext.register(work.getUserId(), work.getAccountId(), job.getRelated()); + + Pair result = handler.handleVmWorkJob(work); + _asyncJobMgr.completeAsyncJob(job.getId(), result.first(), 0, result.second()); + } finally { + if (s_logger.isDebugEnabled()) + s_logger.debug("Done with run of VM work job: " + cmd + " for VM " + work.getVmId() + ", job origin: " + job.getRelated()); + } + } catch(Throwable e) { + s_logger.error("Unable to complete " + job + ", job origin:" + job.getRelated(), e); + + RuntimeException ex = new RuntimeException("Job failed due to exception " + e.getMessage()); + _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.FAILED, 0, _asyncJobMgr.marshallResultObject(ex)); + } finally { + CallContext.unregister(); + } + } +} diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkJobWakeupDispatcher.java b/engine/orchestration/src/com/cloud/vm/VmWorkJobWakeupDispatcher.java new file mode 100644 index 000000000000..520a55042e3d --- /dev/null +++ b/engine/orchestration/src/com/cloud/vm/VmWorkJobWakeupDispatcher.java @@ -0,0 +1,147 @@ +// 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.vm; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.framework.jobs.AsyncJob; +import org.apache.cloudstack.framework.jobs.AsyncJobDispatcher; +import org.apache.cloudstack.framework.jobs.AsyncJobManager; +import org.apache.cloudstack.framework.jobs.dao.AsyncJobJoinMapDao; +import org.apache.cloudstack.framework.jobs.dao.VmWorkJobDao; +import org.apache.cloudstack.framework.jobs.impl.AsyncJobJoinMapVO; +import org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO; + +import com.cloud.user.AccountVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.component.AdapterBase; +import com.cloud.vm.dao.VMInstanceDao; + +/** + * Please note: VmWorkJobWakeupDispatcher is not currently in use. It is designed for event-driven based + * job processing model. + * + * Current code base uses blocking calls to wait for job completion + */ +public class VmWorkJobWakeupDispatcher extends AdapterBase implements AsyncJobDispatcher { + private static final Logger s_logger = Logger.getLogger(VmWorkJobWakeupDispatcher.class); + + @Inject + private VmWorkJobDao _workjobDao; + @Inject + private AsyncJobJoinMapDao _joinMapDao; + @Inject + private AccountDao _accountDao; + @Inject + private VMInstanceDao _instanceDao; + @Inject + private VirtualMachineManager _vmMgr; + @Inject + private AsyncJobManager _asyncJobMgr; + + private final Map _handlerMap = new HashMap(); + + @Override + public void runJob(AsyncJob job) { + try { + List joinRecords = _joinMapDao.listJoinRecords(job.getId()); + if (joinRecords.size() != 1) { + s_logger.warn("AsyncJob-" + job.getId() + + " received wakeup call with un-supported joining job number: " + joinRecords.size()); + + // if we fail wakeup-execution for any reason, avoid release sync-source if there is any + job.setSyncSource(null); + return; + } + + AsyncJobJoinMapVO joinRecord = joinRecords.get(0); + VmWorkJobVO joinedJob = _workjobDao.findById(joinRecord.getJoinJobId()); + + Class workClz = null; + try { + workClz = Class.forName(job.getCmd()); + } catch (ClassNotFoundException e) { + s_logger.error("VM work class " + job.getCmd() + " is not found", e); + return; + } + + // get original work context information from joined job + VmWork work = VmWorkSerializer.deserialize(workClz, joinedJob.getCmdInfo()); + assert (work != null); + + AccountVO account = _accountDao.findById(work.getAccountId()); + assert (account != null); + + VMInstanceVO vm = _instanceDao.findById(work.getVmId()); + assert (vm != null); + + CallContext.register(work.getUserId(), work.getAccountId(), job.getRelated()); + try { + Method handler = getHandler(joinRecord.getWakeupHandler()); + if (handler != null) { + handler.invoke(_vmMgr); + } else { + assert (false); + s_logger.error("Unable to find wakeup handler " + joinRecord.getWakeupHandler() + + " when waking up job-" + job.getId()); + } + } finally { + CallContext.unregister(); + } + } catch (Throwable e) { + s_logger.warn("Unexpected exception in waking up job-" + job.getId()); + + // if we fail wakeup-execution for any reason, avoid release sync-source if there is any + job.setSyncSource(null); + } + } + + private Method getHandler(String wakeupHandler) { + + synchronized (_handlerMap) { + Class clz = _vmMgr.getClass(); + Method method = _handlerMap.get(wakeupHandler); + if (method != null) + return method; + + try { + method = clz.getMethod(wakeupHandler); + method.setAccessible(true); + } catch (SecurityException e) { + assert (false); + s_logger.error("Unexpected exception", e); + return null; + } catch (NoSuchMethodException e) { + assert (false); + s_logger.error("Unexpected exception", e); + return null; + } + + _handlerMap.put(wakeupHandler, method); + return method; + } + } +} \ No newline at end of file diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkMigrate.java b/engine/orchestration/src/com/cloud/vm/VmWorkMigrate.java new file mode 100644 index 000000000000..51ee52c609fb --- /dev/null +++ b/engine/orchestration/src/com/cloud/vm/VmWorkMigrate.java @@ -0,0 +1,87 @@ +// 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.vm; + +import java.util.HashMap; +import java.util.Map; + +import com.cloud.dc.DataCenter; +import com.cloud.dc.Pod; +import com.cloud.deploy.DeployDestination; +import com.cloud.host.Host; +import com.cloud.org.Cluster; +import com.cloud.storage.StoragePool; +import com.cloud.storage.Volume; +import com.cloud.utils.db.EntityManager; + +public class VmWorkMigrate extends VmWork { + private static final long serialVersionUID = 1689203333114836522L; + + Long zoneId; + Long podId; + Long clusterId; + Long hostId; + private Map storage; + long srcHostId; + + public VmWorkMigrate(long userId, long accountId, long vmId, String handlerName, + long srcHostId, DeployDestination dst) { + super(userId, accountId, vmId, handlerName); + this.srcHostId = srcHostId; + zoneId = dst.getDataCenter() != null ? dst.getDataCenter().getId() : null; + podId = dst.getPod() != null ? dst.getPod().getId() : null; + clusterId = dst.getCluster() != null ? dst.getCluster().getId() : null; + hostId = dst.getHost() != null ? dst.getHost().getId() : null; + if (dst.getStorageForDisks() != null) { + storage = new HashMap(dst.getStorageForDisks().size()); + for (Map.Entry entry : dst.getStorageForDisks().entrySet()) { + storage.put(entry.getKey().getUuid(), entry.getValue().getUuid()); + } + } else { + storage = null; + } + } + + public DeployDestination getDeployDestination() { + DataCenter zone = zoneId != null ? s_entityMgr.findById(DataCenter.class, zoneId) : null; + Pod pod = podId != null ? s_entityMgr.findById(Pod.class, podId) : null; + Cluster cluster = clusterId != null ? s_entityMgr.findById(Cluster.class, clusterId) : null; + Host host = hostId != null ? s_entityMgr.findById(Host.class, hostId) : null; + + Map vols = null; + + if (storage != null) { + vols = new HashMap(storage.size()); + for (Map.Entry entry : storage.entrySet()) { + vols.put(s_entityMgr.findByUuid(Volume.class, entry.getKey()), s_entityMgr.findByUuid(StoragePool.class, entry.getValue())); + } + } + + DeployDestination dest = new DeployDestination(zone, pod, cluster, host, vols); + return dest; + } + + public long getSrcHostId() { + return srcHostId; + } + + static private EntityManager s_entityMgr; + + static public void init(EntityManager entityMgr) { + s_entityMgr = entityMgr; + } +} diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkMigrateForScale.java b/engine/orchestration/src/com/cloud/vm/VmWorkMigrateForScale.java new file mode 100644 index 000000000000..9b59f676d018 --- /dev/null +++ b/engine/orchestration/src/com/cloud/vm/VmWorkMigrateForScale.java @@ -0,0 +1,48 @@ +// 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.vm; + +import com.cloud.deploy.DeployDestination; + +public class VmWorkMigrateForScale extends VmWork { + private static final long serialVersionUID = 6854870395568389613L; + + long srcHostId; + DeployDestination deployDestination; + Long newSvcOfferingId; + + public VmWorkMigrateForScale(long userId, long accountId, long vmId, String handlerName, long srcHostId, + DeployDestination dest, Long newSvcOfferingId) { + + super(userId, accountId, vmId, handlerName); + this.srcHostId = srcHostId; + deployDestination = dest; + this.newSvcOfferingId = newSvcOfferingId; + } + + public long getSrcHostId() { + return srcHostId; + } + + public DeployDestination getDeployDestination() { + return deployDestination; + } + + public Long getNewServiceOfferringId() { + return newSvcOfferingId; + } +} diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkMigrateWithStorage.java b/engine/orchestration/src/com/cloud/vm/VmWorkMigrateWithStorage.java new file mode 100644 index 000000000000..37a6ba40d8d6 --- /dev/null +++ b/engine/orchestration/src/com/cloud/vm/VmWorkMigrateWithStorage.java @@ -0,0 +1,52 @@ +// 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.vm; + +import java.util.Map; + +import com.cloud.storage.StoragePool; +import com.cloud.storage.Volume; + +public class VmWorkMigrateWithStorage extends VmWork { + private static final long serialVersionUID = -5626053872453569165L; + + long srcHostId; + long destHostId; + Map volumeToPool; + + public VmWorkMigrateWithStorage(long userId, long accountId, long vmId, String handlerName, long srcHostId, + long destHostId, Map volumeToPool) { + + super(userId, accountId, vmId, handlerName); + + this.srcHostId = srcHostId; + this.destHostId = destHostId; + this.volumeToPool = volumeToPool; + } + + public long getSrcHostId() { + return srcHostId; + } + + public long getDestHostId() { + return destHostId; + } + + public Map getVolumeToPool() { + return volumeToPool; + } +} diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkReboot.java b/engine/orchestration/src/com/cloud/vm/VmWorkReboot.java new file mode 100644 index 000000000000..8e69f893abb5 --- /dev/null +++ b/engine/orchestration/src/com/cloud/vm/VmWorkReboot.java @@ -0,0 +1,68 @@ +// 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.vm; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper; + +public class VmWorkReboot extends VmWork { + private static final long serialVersionUID = 195907627459759933L; + + // use serialization friendly map + private Map rawParams; + + public VmWorkReboot(long userId, long accountId, long vmId, String handlerName, Map params) { + super(userId, accountId, vmId, handlerName); + + setParams(params); + } + + public Map getRawParams() { + return rawParams; + } + + public void setRawParams(Map params) { + rawParams = params; + } + + public Map getParams() { + Map map = new HashMap(); + + if(rawParams != null) { + for(Map.Entry entry : rawParams.entrySet()) { + VirtualMachineProfile.Param key = new VirtualMachineProfile.Param(entry.getKey()); + Object val = JobSerializerHelper.fromObjectSerializedString(entry.getValue()); + map.put(key, val); + } + } + + return map; + } + + public void setParams(Map params) { + if(params != null) { + rawParams = new HashMap(); + for(Map.Entry entry : params.entrySet()) { + rawParams.put(entry.getKey().getName(), JobSerializerHelper.toObjectSerializedString( + entry.getValue() instanceof Serializable ? (Serializable)entry.getValue() : entry.getValue().toString())); + } + } + } +} diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkReconfigure.java b/engine/orchestration/src/com/cloud/vm/VmWorkReconfigure.java new file mode 100644 index 000000000000..11415775fe34 --- /dev/null +++ b/engine/orchestration/src/com/cloud/vm/VmWorkReconfigure.java @@ -0,0 +1,42 @@ +// 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.vm; + + +public class VmWorkReconfigure extends VmWork { + private static final long serialVersionUID = -4517030323758086615L; + + Long newServiceOfferingId; + boolean sameHost; + + public VmWorkReconfigure(long userId, long accountId, long vmId, String handlerName, + Long newServiceOfferingId, boolean sameHost) { + + super(userId, accountId, vmId, handlerName); + + this.newServiceOfferingId = newServiceOfferingId; + this.sameHost = sameHost; + } + + public Long getNewServiceOfferingId() { + return newServiceOfferingId; + } + + public boolean isSameHost() { + return sameHost; + } +} diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkRemoveNicFromVm.java b/engine/orchestration/src/com/cloud/vm/VmWorkRemoveNicFromVm.java new file mode 100644 index 000000000000..67f5ad420560 --- /dev/null +++ b/engine/orchestration/src/com/cloud/vm/VmWorkRemoveNicFromVm.java @@ -0,0 +1,33 @@ +// 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.vm; + +public class VmWorkRemoveNicFromVm extends VmWork { + private static final long serialVersionUID = -4265657031064437923L; + + Long nicId; + + public VmWorkRemoveNicFromVm(long userId, long accountId, long vmId, String handlerName, Long nicId) { + super(userId, accountId, vmId, handlerName); + + this.nicId = nicId; + } + + public Long getNicId() { + return nicId; + } +} diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkRemoveVmFromNetwork.java b/engine/orchestration/src/com/cloud/vm/VmWorkRemoveVmFromNetwork.java new file mode 100644 index 000000000000..0cb02b28f602 --- /dev/null +++ b/engine/orchestration/src/com/cloud/vm/VmWorkRemoveVmFromNetwork.java @@ -0,0 +1,43 @@ +// 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.vm; + +import java.net.URI; + +import com.cloud.network.Network; + +public class VmWorkRemoveVmFromNetwork extends VmWork { + private static final long serialVersionUID = -5070392905642149925L; + + Network network; + URI broadcastUri; + + public VmWorkRemoveVmFromNetwork(long userId, long accountId, long vmId, String handlerName, Network network, URI broadcastUri) { + super(userId, accountId, vmId, handlerName); + + this.network = network; + this.broadcastUri = broadcastUri; + } + + public Network getNetwork() { + return network; + } + + public URI getBroadcastUri() { + return broadcastUri; + } +} diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkStart.java b/engine/orchestration/src/com/cloud/vm/VmWorkStart.java new file mode 100644 index 000000000000..caa4cfbe7064 --- /dev/null +++ b/engine/orchestration/src/com/cloud/vm/VmWorkStart.java @@ -0,0 +1,125 @@ +// 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.vm; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper; + +import com.cloud.deploy.DataCenterDeployment; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.utils.Journal; + +public class VmWorkStart extends VmWork { + private static final long serialVersionUID = 9038937399817468894L; + + private static final Logger s_logger = Logger.getLogger(VmWorkStart.class); + + long dcId; + Long podId; + Long clusterId; + Long hostId; + Long poolId; + ExcludeList avoids; + Long physicalNetworkId; + + String reservationId; + String journalName; + + // use serialization friendly map + private Map rawParams; + + public VmWorkStart(long userId, long accountId, long vmId, String handlerName) { + super(userId, accountId, vmId, handlerName); + } + + public DeploymentPlan getPlan() { + + if(podId != null || clusterId != null || hostId != null || poolId != null || physicalNetworkId != null) { + // this is ugly, to work with legacy code, we need to re-construct the DeploymentPlan hard-codely + // this has to be refactored together with migrating legacy code into the new way + ReservationContext context = null; + if(reservationId != null) { + Journal journal = new Journal.LogJournal("VmWorkStart", s_logger); + context = new ReservationContextImpl(reservationId, journal, + CallContext.current().getCallingUser(), + CallContext.current().getCallingAccount()); + } + + DeploymentPlan plan = new DataCenterDeployment( + dcId, podId, clusterId, hostId, poolId, physicalNetworkId, + context); + return plan; + } + + return null; + } + + public void setPlan(DeploymentPlan plan) { + if(plan != null) { + dcId = plan.getDataCenterId(); + podId = plan.getPodId(); + clusterId = plan.getClusterId(); + hostId = plan.getHostId(); + poolId = plan.getPoolId(); + physicalNetworkId = plan.getPhysicalNetworkId(); + avoids = plan.getAvoids(); + + if(plan.getReservationContext() != null) + reservationId = plan.getReservationContext().getReservationId(); + } + } + + public Map getRawParams() { + return rawParams; + } + + public void setRawParams(Map params) { + rawParams = params; + } + + public Map getParams() { + Map map = new HashMap(); + + if(rawParams != null) { + for(Map.Entry entry : rawParams.entrySet()) { + VirtualMachineProfile.Param key = new VirtualMachineProfile.Param(entry.getKey()); + Object val = JobSerializerHelper.fromObjectSerializedString(entry.getValue()); + map.put(key, val); + } + } + + return map; + } + + public void setParams(Map params) { + if(params != null) { + rawParams = new HashMap(); + for(Map.Entry entry : params.entrySet()) { + rawParams.put(entry.getKey().getName(), JobSerializerHelper.toObjectSerializedString( + entry.getValue() instanceof Serializable ? (Serializable)entry.getValue() : entry.getValue().toString())); + } + } + } +} diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkStop.java b/engine/orchestration/src/com/cloud/vm/VmWorkStop.java new file mode 100644 index 000000000000..4b2c00ca6dd7 --- /dev/null +++ b/engine/orchestration/src/com/cloud/vm/VmWorkStop.java @@ -0,0 +1,32 @@ +// 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.vm; + +public class VmWorkStop extends VmWork { + private static final long serialVersionUID = 202908740486785251L; + + private final boolean cleanup; + + public VmWorkStop(long userId, long accountId, long vmId, String handlerName, boolean cleanup) { + super(userId, accountId, vmId, handlerName); + this.cleanup = cleanup; + } + + public boolean isCleanup() { + return cleanup; + } +} diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkStorageMigration.java b/engine/orchestration/src/com/cloud/vm/VmWorkStorageMigration.java new file mode 100644 index 000000000000..a5b0a0aa8010 --- /dev/null +++ b/engine/orchestration/src/com/cloud/vm/VmWorkStorageMigration.java @@ -0,0 +1,33 @@ +// 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.vm; + +public class VmWorkStorageMigration extends VmWork { + private static final long serialVersionUID = -8677979691741157474L; + + Long destPoolId; + + public VmWorkStorageMigration(long userId, long accountId, long vmId, String handlerName, Long destPoolId) { + super(userId, accountId, vmId, handlerName); + + this.destPoolId = destPoolId; + } + + public Long getDestStoragePoolId() { + return destPoolId; + } +} diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java index e784295b1d3c..bdb7323dc8bc 100755 --- a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java @@ -147,6 +147,7 @@ public String reserveVirtualMachine(VMEntityVO vmEntityVO, String plannerToUse, //FIXME: profile should work on VirtualMachineEntity VMInstanceVO vm = _vmDao.findByUuid(vmEntityVO.getUuid()); VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm); + vmProfile.setServiceOffering(_serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId())); DataCenterDeployment plan = new DataCenterDeployment(vm.getDataCenterId(), vm.getPodIdToDeployIn(), null, null, null, null); if(planToDeploy != null && planToDeploy.getDataCenterId() != 0){ plan = new DataCenterDeployment(planToDeploy.getDataCenterId(), planToDeploy.getPodId(), planToDeploy.getClusterId(), planToDeploy.getHostId(), planToDeploy.getPoolId(), planToDeploy.getPhysicalNetworkId()); @@ -184,7 +185,7 @@ public String reserveVirtualMachine(VMEntityVO vmEntityVO, String plannerToUse, while (true) { DeployDestination dest = null; try { - dest = _dpMgr.planDeployment(vmProfile, plan, exclude); + dest = _dpMgr.planDeployment(vmProfile, plan, exclude, null); } catch (AffinityConflictException e) { throw new CloudRuntimeException( "Unable to create deployment, affinity rules associted to the VM conflict"); diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VirtualMachineEntityImpl.java b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VirtualMachineEntityImpl.java index dd57f9a03f4a..1e50d146f9be 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VirtualMachineEntityImpl.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VirtualMachineEntityImpl.java @@ -54,7 +54,6 @@ public void init(String vmId, String owner, String hostName, String displayName, this.vmEntityVO.setOwner(owner); this.vmEntityVO.setHostname(hostName); this.vmEntityVO.setDisplayname(displayName); - this.vmEntityVO.setSpeed(speed); this.vmEntityVO.setComputeTags(computeTags); this.vmEntityVO.setRootDiskTags(rootDiskTags); this.vmEntityVO.setNetworkIds(networks); @@ -72,7 +71,6 @@ public VirtualMachineEntityImpl(String vmId, String owner, String hostName, Stri this.vmEntityVO.setOwner(owner); this.vmEntityVO.setHostname(hostName); this.vmEntityVO.setDisplayname(displayName); - this.vmEntityVO.setSpeed(speed); this.vmEntityVO.setComputeTags(computeTags); this.vmEntityVO.setRootDiskTags(rootDiskTags); this.vmEntityVO.setNetworkIds(networks); diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java index 5dd15ce0bb48..af75b35b34da 100755 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java @@ -20,14 +20,13 @@ import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.cloud.entity.api.NetworkEntity; import org.apache.cloudstack.engine.cloud.entity.api.TemplateEntity; import org.apache.cloudstack.engine.cloud.entity.api.VMEntityManager; @@ -36,6 +35,7 @@ import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.engine.service.api.OrchestrationService; +import org.springframework.stereotype.Component; import com.cloud.deploy.DeploymentPlan; import com.cloud.exception.InsufficientCapacityException; @@ -164,15 +164,15 @@ public VirtualMachineEntity createVirtualMachine( Long diskSize, List computeTags, List rootDiskTags, - Map networkNicMap, DeploymentPlan plan, Long rootDiskSize) throws InsufficientCapacityException { + Map networkNicMap, DeploymentPlan plan) throws InsufficientCapacityException { // VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks, vmEntityManager); - LinkedHashMap networkIpMap = new LinkedHashMap(); + LinkedHashMap> networkIpMap = new LinkedHashMap>(); for (String uuid : networkNicMap.keySet()) { NetworkVO network = _networkDao.findByUuid(uuid); if(network != null){ - networkIpMap.put(network, networkNicMap.get(uuid)); + networkIpMap.put(network, new ArrayList(Arrays.asList(networkNicMap.get(uuid)))); } } @@ -193,7 +193,6 @@ public VirtualMachineEntity createVirtualMachine( ServiceOfferingVO offering = _serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId()); rootDiskOffering.first(offering); - rootDiskOffering.second(rootDiskSize); if(vm.getDiskOfferingId() != null){ DiskOfferingVO diskOffering = _diskOfferingDao.findById(vm.getDiskOfferingId()); @@ -264,11 +263,11 @@ public VirtualMachineEntity createVirtualMachineFromScratch(String id, String ow rootDiskOffering.first(diskOffering); rootDiskOffering.second(size); - LinkedHashMap networkIpMap = new LinkedHashMap(); + LinkedHashMap> networkIpMap = new LinkedHashMap>(); for (String uuid : networkNicMap.keySet()) { NetworkVO network = _networkDao.findByUuid(uuid); if(network != null){ - networkIpMap.put(network, networkNicMap.get(uuid)); + networkIpMap.put(network, new ArrayList(Arrays.asList(networkNicMap.get(uuid)))); } } diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index ddec9fcd7e44..9e869c436c4b 100755 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -36,7 +36,6 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.log4j.Logger; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; @@ -46,6 +45,7 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.region.PortableIpDao; +import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; @@ -146,6 +146,7 @@ import com.cloud.network.rules.StaticNatRuleImpl; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.NetworkACLManager; +import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.dao.PrivateIpDao; import com.cloud.network.vpn.RemoteAccessVpnService; @@ -167,14 +168,14 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.EntityManager; import com.cloud.utils.db.GlobalLock; -import com.cloud.utils.db.TransactionCallback; -import com.cloud.utils.db.TransactionCallbackNoReturn; -import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn; -import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.db.JoinBuilder.JoinType; import com.cloud.utils.db.SearchBuilder; 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.TransactionCallbackWithExceptionNoReturn; +import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.fsm.StateMachine2; @@ -684,67 +685,84 @@ public void doInTransactionWithoutResult(TransactionStatus status) { @Override @DB - public void allocate(final VirtualMachineProfile vm, final LinkedHashMap networks) throws InsufficientCapacityException, + public void allocate(final VirtualMachineProfile vm, final LinkedHashMap> networks) throws InsufficientCapacityException, ConcurrentOperationException { Transaction.execute(new TransactionCallbackWithExceptionNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) throws InsufficientCapacityException { int deviceId = 0; - - boolean[] deviceIds = new boolean[networks.size()]; + + int size = 0; + for (Network ntwk : networks.keySet()) { + List profiles = networks.get(ntwk); + if (profiles != null && !profiles.isEmpty()) { + size = size + profiles.size(); + } else { + size = size + 1; + } + } + + boolean[] deviceIds = new boolean[size]; Arrays.fill(deviceIds, false); - List nics = new ArrayList(networks.size()); + List nics = new ArrayList(size); NicProfile defaultNic = null; - for (Map.Entry network : networks.entrySet()) { + for (Map.Entry> network : networks.entrySet()) { Network config = network.getKey(); - NicProfile requested = network.getValue(); - - Boolean isDefaultNic = false; - if (vm != null && (requested != null && requested.isDefaultNic())) { - isDefaultNic = true; + List requestedProfiles = network.getValue(); + if (requestedProfiles == null) { + requestedProfiles = new ArrayList(); } - - while (deviceIds[deviceId] && deviceId < deviceIds.length) { - deviceId++; + if (requestedProfiles.isEmpty()) { + requestedProfiles.add(null); } - - Pair vmNicPair = allocateNic(requested, config, isDefaultNic, deviceId, vm); - - NicProfile vmNic = vmNicPair.first(); - if (vmNic == null) { - continue; - } - - deviceId = vmNicPair.second(); - - int devId = vmNic.getDeviceId(); - if (devId > deviceIds.length) { - throw new IllegalArgumentException("Device id for nic is too large: " + vmNic); - } - if (deviceIds[devId]) { - throw new IllegalArgumentException("Conflicting device id for two different nics: " + vmNic); - } - - deviceIds[devId] = true; - - if (vmNic.isDefaultNic()) { - if (defaultNic != null) { - throw new IllegalArgumentException("You cannot specify two nics as default nics: nic 1 = " + defaultNic + "; nic 2 = " + vmNic); + + for (NicProfile requested : requestedProfiles) { + Boolean isDefaultNic = false; + if (vm != null && (requested != null && requested.isDefaultNic())) { + isDefaultNic = true; + } + + while (deviceIds[deviceId] && deviceId < deviceIds.length) { + deviceId++; + } + + Pair vmNicPair = allocateNic(requested, config, isDefaultNic, deviceId, vm); + + NicProfile vmNic = vmNicPair.first(); + if (vmNic == null) { + continue; + } + + deviceId = vmNicPair.second(); + + int devId = vmNic.getDeviceId(); + if (devId > deviceIds.length) { + throw new IllegalArgumentException("Device id for nic is too large: " + vmNic); + } + if (deviceIds[devId]) { + throw new IllegalArgumentException("Conflicting device id for two different nics: " + vmNic); + } + + deviceIds[devId] = true; + + if (vmNic.isDefaultNic()) { + if (defaultNic != null) { + throw new IllegalArgumentException("You cannot specify two nics as default nics: nic 1 = " + defaultNic + "; nic 2 = " + vmNic); + } + defaultNic = vmNic; } - defaultNic = vmNic; + + nics.add(vmNic); + vm.addNic(vmNic); } - - nics.add(vmNic); - vm.addNic(vmNic); - } - if (nics.size() != networks.size()) { - s_logger.warn("Number of nics " + nics.size() + " doesn't match number of requested networks " + networks.size()); - throw new CloudRuntimeException("Number of nics " + nics.size() + " doesn't match number of requested networks " + networks.size()); + if (nics.size() != size) { + s_logger.warn("Number of nics " + nics.size() + " doesn't match number of requested nics " + size); + throw new CloudRuntimeException("Number of nics " + nics.size() + " doesn't match number of requested networks " + size); } if (nics.size() == 1) { @@ -767,14 +785,14 @@ public Pair allocateNic(NicProfile requested, Network netwo requested.setMode(network.getMode()); } NicProfile profile = guru.allocate(network, requested, vm); - if (isDefaultNic != null) { - profile.setDefaultNic(isDefaultNic); - } - if (profile == null) { return null; } + if (isDefaultNic != null) { + profile.setDefaultNic(isDefaultNic); + } + if (requested != null && requested.getMode() == null) { profile.setMode(requested.getMode()); } else { @@ -1013,25 +1031,25 @@ public void implementNetworkElementsAndResources(DeployDestination dest, Reserva DataCenter zone = _dcDao.findById(network.getDataCenterId()); if (!sharedSourceNat && _networkModel.areServicesSupportedInNetwork(network.getId(), Service.SourceNat) && - (network.getGuestType() == Network.GuestType.Isolated || (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced))) { + (network.getGuestType() == Network.GuestType.Isolated || (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced))) { List ips = null; + Account owner = _entityMgr.findById(Account.class, network.getAccountId()); if (network.getVpcId() != null) { ips = _ipAddressDao.listByAssociatedVpc(network.getVpcId(), true); if (ips.isEmpty()) { - throw new CloudRuntimeException("Vpc is not implemented; there is no source nat ip"); + Vpc vpc = _vpcMgr.getActiveVpc(network.getVpcId()); + s_logger.debug("Creating a source nat ip for vpc " + vpc); + _vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc); } } else { ips = _ipAddressDao.listByAssociatedNetwork(network.getId(), true); - } - - if (ips.isEmpty()) { - s_logger.debug("Creating a source nat ip for network " + network); - Account owner = _entityMgr.findById(Account.class, network.getAccountId()); - _ipAddrMgr.assignSourceNatIpAddressToGuestNetwork(owner, network); + if (ips.isEmpty()) { + s_logger.debug("Creating a source nat ip for network " + network); + _ipAddrMgr.assignSourceNatIpAddressToGuestNetwork(owner, network); + } } } - // get providers to implement List providersToImplement = getNetworkProviders(network.getId()); for (NetworkElement element : _networkElements) { @@ -1092,21 +1110,20 @@ protected boolean reprogramNetworkRules(long networkId, Account caller, Network } List firewallEgressRulesToApply = _firewallDao.listByNetworkPurposeTrafficType(networkId, Purpose.Firewall, FirewallRule.TrafficType.Egress); - if (firewallEgressRulesToApply.size() == 0) { + NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); //there are no egress rules then apply the default egress rule DataCenter zone = _dcDao.findById(network.getDataCenterId()); - if (offering.getEgressDefaultPolicy() && _networkModel.areServicesSupportedInNetwork(network.getId(), Service.Firewall) && + if ( _networkModel.areServicesSupportedInNetwork(network.getId(), Service.Firewall) && (network.getGuestType() == Network.GuestType.Isolated || (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced))) { // add default egress rule to accept the traffic - _firewallMgr.applyDefaultEgressFirewallRule(network.getId(), true); + _firewallMgr.applyDefaultEgressFirewallRule(network.getId(), offering.getEgressDefaultPolicy(), true); } - } else { + if (!_firewallMgr.applyFirewallRules(firewallEgressRulesToApply, false, caller)) { s_logger.warn("Failed to reapply firewall Egress rule(s) as a part of network id=" + networkId + " restart"); success = false; } - } // apply port forwarding rules if (!_rulesMgr.applyPortForwardingRulesForNetwork(networkId, false, caller)) { @@ -1497,6 +1514,17 @@ public void removeNic(VirtualMachineProfile vm, Nic nic) { } protected void removeNic(VirtualMachineProfile vm, NicVO nic) { + + if (nic.getReservationStrategy() == Nic.ReservationStrategy.Start && nic.getState() != Nic.State.Allocated) { + // Nics with reservation strategy 'Start' should go through release phase in the Nic life cycle. + // Ensure that release is performed before Nic is to be removed to avoid resource leaks. + try { + releaseNic(vm, nic.getId()); + } catch (Exception ex) { + s_logger.warn("Failed to release nic: " + nic.toString() + " as part of remove operation due to", ex ); + } + } + nic.setState(Nic.State.Deallocating); _nicDao.update(nic.getId(), nic); NetworkVO network = _networksDao.findById(nic.getNetworkId()); @@ -2059,7 +2087,7 @@ public boolean shutdownNetworkElementsAndResources(ReservationContext context, b @Override @DB - public boolean destroyNetwork(long networkId, final ReservationContext context) { + public boolean destroyNetwork(long networkId, final ReservationContext context, boolean forced) { final Account callerAccount = context.getAccount(); NetworkVO network = _networksDao.findById(networkId); @@ -2102,7 +2130,7 @@ public boolean destroyNetwork(long networkId, final ReservationContext context) // get updated state for the network network = _networksDao.findById(networkId); - if (network.getState() != Network.State.Allocated && network.getState() != Network.State.Setup) { + if (network.getState() != Network.State.Allocated && network.getState() != Network.State.Setup && !forced) { s_logger.debug("Network is not not in the correct state to be destroyed: " + network.getState()); return false; } @@ -2465,8 +2493,8 @@ public boolean reallocate(final VirtualMachineProfile vm, DataCenterDeployment d if (dc.getNetworkType() == NetworkType.Basic) { List nics = _nicDao.listByVmId(vmInstance.getId()); NetworkVO network = _networksDao.findById(nics.get(0).getNetworkId()); - final LinkedHashMap profiles = new LinkedHashMap(); - profiles.put(network, null); + final LinkedHashMap> profiles = new LinkedHashMap>(); + profiles.put(network, new ArrayList()); Transaction.execute(new TransactionCallbackWithExceptionNoReturn() { @Override @@ -2667,6 +2695,21 @@ private boolean shutdownNetworkResources(long networkId, Account caller, long ca s_logger.debug("Releasing " + firewallEgressRules.size() + " firewall egress rules for network id=" + networkId + " as a part of shutdownNetworkRules"); } + try { + // delete default egress rule + DataCenter zone = _dcDao.findById(network.getDataCenterId()); + if ( _networkModel.areServicesSupportedInNetwork(network.getId(), Service.Firewall) && + (network.getGuestType() == Network.GuestType.Isolated || (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced))) { + // add default egress rule to accept the traffic + _firewallMgr.applyDefaultEgressFirewallRule(network.getId(), _networkModel.getNetworkEgressDefaultPolicy(networkId), false); + } + + } catch (ResourceUnavailableException ex) { + s_logger.warn("Failed to cleanup firewall default egress rule as a part of shutdownNetworkRules due to ", ex); + success = false; + } + + for (FirewallRuleVO firewallRule : firewallEgressRules) { s_logger.trace("Marking firewall egress rule " + firewallRule + " with Revoke state"); firewallRule.setState(FirewallRule.State.Revoke); @@ -2813,7 +2856,7 @@ public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) if (!answer.getResult()) { s_logger.warn("Unable to setup agent " + hostId + " due to " + ((answer != null) ? answer.getDetails() : "return null")); String msg = "Incorrect Network setup on agent, Reinitialize agent after network names are setup, details : " + answer.getDetails(); - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, host.getPodId(), msg, msg); + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, dcId, host.getPodId(), msg, msg); throw new ConnectionException(true, msg); } else { if (answer.needReconnect()) { 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 f839d6cf343c..2f181ab0640d 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -31,12 +31,14 @@ import javax.naming.ConfigurationException; 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.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService; import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; @@ -71,6 +73,8 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.StorageUnavailableException; import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.offering.DiskOffering; import com.cloud.offering.ServiceOffering; @@ -140,6 +144,10 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati SnapshotDataFactory snapshotFactory; @Inject ConfigDepot _configDepot; + @Inject + HostDao _hostDao; + @Inject + SnapshotService _snapshotSrv; private final StateMachine2 _volStateMachine; protected List _storagePoolAllocators; @@ -265,7 +273,8 @@ public Pair findPod(VirtualMachineTemplate template, ServiceOffering @DB @Override - public VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot) throws StorageUnavailableException { + public VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot, UserVm vm) + throws StorageUnavailableException { Account account = _entityMgr.findById(Account.class, volume.getAccountId()); final HashSet poolsToAvoid = new HashSet(); @@ -278,17 +287,68 @@ public VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot) thr DataCenter dc = _entityMgr.findById(DataCenter.class, volume.getDataCenterId()); DiskProfile dskCh = new DiskProfile(volume, diskOffering, snapshot.getHypervisorType()); - // Determine what pod to store the volume in - while ((pod = findPod(null, null, dc, account.getId(), podsToAvoid)) != null) { - podsToAvoid.add(pod.first().getId()); + String msg = "There are no available storage pools to store the volume in"; + + if(vm != null){ + Pod podofVM = _entityMgr.findById(Pod.class, vm.getPodIdToDeployIn()); + if(podofVM != null){ + pod = new Pair(podofVM, podofVM.getId()); + } + } + + if(vm != null && pod != null){ + //if VM is running use the hostId to find the clusterID. If it is stopped, refer the cluster where the ROOT volume of the VM exists. + Long hostId = null; + Long clusterId = null; + if(vm.getState() == State.Running){ + hostId = vm.getHostId(); + if(hostId != null){ + Host vmHost = _entityMgr.findById(Host.class, hostId); + clusterId = vmHost.getClusterId(); + } + }else{ + List rootVolumesOfVm = _volsDao.findByInstanceAndType(vm.getId(), Volume.Type.ROOT); + if (rootVolumesOfVm.size() != 1) { + throw new CloudRuntimeException("The VM " + vm.getHostName() + " has more than one ROOT volume and is in an invalid state. Please contact Cloud Support."); + } else { + VolumeVO rootVolumeOfVm = rootVolumesOfVm.get(0); + StoragePoolVO rootDiskPool = _storagePoolDao.findById(rootVolumeOfVm.getPoolId()); + clusterId = (rootDiskPool == null ? null : rootDiskPool.getClusterId()); + } + } // Determine what storage pool to store the volume in - while ((pool = findStoragePool(dskCh, dc, pod.first(), null, null, null, poolsToAvoid)) != null) { + while ((pool = findStoragePool(dskCh, dc, pod.first(), clusterId, hostId, vm, poolsToAvoid)) != null) { break; } + + if (pool == null) { + //pool could not be found in the VM's pod/cluster. + if(s_logger.isDebugEnabled()){ + s_logger.debug("Could not find any storage pool to create Volume in the pod/cluster of the provided VM "+vm.getUuid()); + } + StringBuilder addDetails = new StringBuilder(msg); + addDetails.append(", Could not find any storage pool to create Volume in the pod/cluster of the VM "); + addDetails.append(vm.getUuid()); + msg = addDetails.toString(); + } + }else{ + // Determine what pod to store the volume in + while ((pod = findPod(null, null, dc, account.getId(), podsToAvoid)) != null) { + podsToAvoid.add(pod.first().getId()); + // Determine what storage pool to store the volume in + while ((pool = findStoragePool(dskCh, dc, pod.first(), null, null, null, poolsToAvoid)) != null) { + break; + } + if (pool != null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Found a suitable pool for create volume: " + pool.getId()); + } + break; + } + } } if (pool == null) { - String msg = "There are no available storage pools to store the volume in"; s_logger.info(msg); throw new StorageUnavailableException(msg, -1); } @@ -296,6 +356,16 @@ public VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot) thr VolumeInfo vol = volFactory.getVolume(volume.getId()); DataStore store = dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary); SnapshotInfo snapInfo = snapshotFactory.getSnapshot(snapshot.getId(), DataStoreRole.Image); + // sync snapshot to region store if necessary + DataStore snapStore = snapInfo.getDataStore(); + long snapVolId = snapInfo.getVolumeId(); + try { + _snapshotSrv.syncVolumeSnapshotsToRegionStore(snapVolId, snapStore); + } catch (Exception ex) { + // log but ignore the sync error to avoid any potential S3 down issue, it should be sync next time + s_logger.warn(ex.getMessage(), ex); + } + // create volume on primary from snapshot AsyncCallFuture future = volService.createVolumeFromSnapshot(vol, store, snapInfo); try { VolumeApiResult result = future.get(); @@ -374,11 +444,10 @@ public VolumeInfo copyVolumeFromSecToPrimary(VolumeInfo volume, VirtualMachine v @DB public VolumeInfo createVolume(VolumeInfo volume, VirtualMachine vm, VirtualMachineTemplate template, DataCenter dc, Pod pod, Long clusterId, ServiceOffering offering, DiskOffering diskOffering, List avoids, long size, HypervisorType hyperType) { - StoragePool pool = null; + // update the volume's hypervisor_ss_reserve from its disk offering (used for managed storage) + volume = updateHypervisorSnapshotReserveForVolume(diskOffering, volume, hyperType); - if (diskOffering != null && diskOffering.isCustomized()) { - diskOffering.setDiskSize(size); - } + StoragePool pool = null; DiskProfile dskCh = null; if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) { @@ -387,14 +456,18 @@ public VolumeInfo createVolume(VolumeInfo volume, VirtualMachine vm, VirtualMach dskCh = createDiskCharacteristics(volume, template, dc, diskOffering); } + if (diskOffering != null && diskOffering.isCustomized()) { + dskCh.setSize(size); + } + dskCh.setHyperType(hyperType); final HashSet avoidPools = new HashSet(avoids); pool = findStoragePool(dskCh, dc, pod, clusterId, vm.getHostId(), vm, avoidPools); if (pool == null) { - s_logger.warn("Unable to find storage pool when create volume " + volume.getName()); - throw new CloudRuntimeException("Unable to find storage pool when create volume" + volume.getName()); + s_logger.warn("Unable to find suitable primary storage when creating volume " + volume.getName()); + throw new CloudRuntimeException("Unable to find suitable primary storage when creating volume " + volume.getName()); } if (s_logger.isDebugEnabled()) { @@ -406,7 +479,6 @@ public VolumeInfo createVolume(VolumeInfo volume, VirtualMachine vm, VirtualMach AsyncCallFuture future = null; boolean isNotCreatedFromTemplate = volume.getTemplateId() == null ? true : false; if (isNotCreatedFromTemplate) { - volume = updateHypervisorSnapshotReserveForVolume(diskOffering, volume, hyperType); future = volService.createVolumeAsync(volume, store); } else { TemplateInfo templ = tmplFactory.getTemplate(template.getId(), DataStoreRole.Image); @@ -566,8 +638,7 @@ public DiskProfile allocateRawVolume(Type type, String name, DiskOffering offeri vol = _volsDao.persist(vol); // Save usage event and update resource count for user vm volumes - if (vm instanceof UserVm) { - + if (vm.getType() == VirtualMachine.Type.User) { UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), vol.getDataCenterId(), @@ -586,13 +657,10 @@ public DiskProfile allocateRawVolume(Type type, String name, DiskOffering offeri } @Override - public DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, VirtualMachineTemplate template, VirtualMachine vm, Account owner) { + public DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, VirtualMachineTemplate template, VirtualMachine vm, Account owner) { assert (template.getFormat() != ImageFormat.ISO) : "ISO is not a template really...."; Long size = _tmpltMgr.getTemplateSize(template.getId(), vm.getDataCenterId()); - if (rootDisksize != null) { - size = (rootDisksize * 1024 * 1024 * 1024); - } VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), @@ -621,7 +689,7 @@ public DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering vol = _volsDao.persist(vol); // Create event and update resource count for volumes if vm is a user vm - if (vm instanceof UserVm) { + if (vm.getType() == VirtualMachine.Type.User) { Long offeringId = null; @@ -653,6 +721,8 @@ private ImageFormat getSupportedImageFormatForCluster(HypervisorType hyperType) return ImageFormat.OVA; } else if (hyperType == HypervisorType.Ovm) { return ImageFormat.RAW; + } else if (hyperType == HypervisorType.Hyperv) { + return ImageFormat.VHD; } else { return null; } @@ -722,7 +792,7 @@ protected VolumeVO switchVolume(final VolumeVO existingVolume, final VirtualMach templateIdToUse = vmTemplateId; } - final Long templateIdToUseFinal = templateIdToUse; + final Long templateIdToUseFinal = templateIdToUse; return Transaction.execute(new TransactionCallback() { @Override public VolumeVO doInTransaction(TransactionStatus status) { @@ -738,7 +808,16 @@ public VolumeVO doInTransaction(TransactionStatus status) { } 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; } }); @@ -794,6 +873,22 @@ public void doInTransactionWithoutResult(TransactionStatus status) { } } + @Override + public void disconnectVolumesFromHost(long vmId, long hostId) { + HostVO host = _hostDao.findById(hostId); + + List volumesForVm = _volsDao.findByInstance(vmId); + + if (volumesForVm != null) { + for (VolumeVO volumeForVm : volumesForVm) { + VolumeInfo volumeInfo = volFactory.getVolume(volumeForVm.getId()); + DataStore dataStore = dataStoreMgr.getDataStore(volumeForVm.getPoolId(), DataStoreRole.Primary); + + volService.disconnectVolumeFromHost(volumeInfo, host, dataStore); + } + } + } + @Override @DB public Volume migrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException { @@ -922,10 +1017,12 @@ public void prepareForMigration(VirtualMachineProfile vm, DeployDestination dest vm.addDisk(disk); } - if (vm.getType() == VirtualMachine.Type.User && vm.getTemplate().getFormat() == ImageFormat.ISO) { - DataTO dataTO = tmplFactory.getTemplate(vm.getTemplate().getId(), DataStoreRole.Image, vm.getVirtualMachine().getDataCenterId()).getTO(); - DiskTO iso = new DiskTO(dataTO, 3L, null, Volume.Type.ISO); - vm.addDisk(iso); + //if (vm.getType() == VirtualMachine.Type.User && vm.getTemplate().getFormat() == ImageFormat.ISO) { + if (vm.getType() == VirtualMachine.Type.User) { + _tmpltMgr.prepareIsoForVmProfile(vm); + //DataTO dataTO = tmplFactory.getTemplate(vm.getTemplate().getId(), DataStoreRole.Image, vm.getVirtualMachine().getDataCenterId()).getTO(); + //DiskTO iso = new DiskTO(dataTO, 3L, null, Volume.Type.ISO); + //vm.addDisk(iso); } } @@ -1077,9 +1174,21 @@ private Pair recreateVolume(VolumeVO vol, VirtualMachinePro // retry one more time in case of template reload is required for Vmware case AsyncCallFuture future = null; if (templateId == null) { + DiskOffering diskOffering = _entityMgr.findById(DiskOffering.class, volume.getDiskOfferingId()); + HypervisorType hyperType = vm.getVirtualMachine().getHypervisorType(); + + // update the volume's hypervisor_ss_reserve from its disk offering (used for managed storage) + updateHypervisorSnapshotReserveForVolume(diskOffering, volume, hyperType); + + volume = volFactory.getVolume(newVol.getId(), destPool); + future = volService.createVolumeAsync(volume, destPool); } else { - TemplateInfo templ = tmplFactory.getTemplate(templateId, DataStoreRole.Image); + TemplateInfo templ = tmplFactory.getReadyTemplateOnImageStore(templateId, dest.getDataCenter().getId()); + if (templ == null) { + s_logger.debug("can't find ready template: " + templateId + " for data center " + dest.getDataCenter().getId()); + throw new CloudRuntimeException("can't find ready template: " + templateId + " for data center " + dest.getDataCenter().getId()); + } future = volService.createVolumeFromTemplateAsync(volume, destPool.getId(), templ); } VolumeApiResult result = null; @@ -1095,6 +1204,16 @@ private Pair recreateVolume(VolumeVO vol, VirtualMachinePro throw new StorageUnavailableException("Unable to create " + newVol + ":" + result.getResult(), destPool.getId()); } } + + StoragePoolVO storagePool = _storagePoolDao.findById(destPool.getId()); + + if (newVol.getVolumeType() == Type.DATADISK && storagePool.isManaged()) { + long hostId = vm.getVirtualMachine().getHostId(); + Host host = _hostDao.findById(hostId); + + volService.connectVolumeToHost(volFactory.getVolume(newVol.getId()), host, destPool); + } + newVol = _volsDao.findById(newVol.getId()); break; //break out of template-redeploy retry loop } catch (InterruptedException e) { @@ -1164,7 +1283,7 @@ public boolean canVmRestartOnAnotherServer(long vmId) { } return true; } - + public static final ConfigKey MaxVolumeSize = new ConfigKey(Long.class, "storage.max.volume.size", "Storage", @@ -1188,7 +1307,7 @@ public boolean canVmRestartOnAnotherServer(long vmId) { @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {RecreatableSystemVmEnabled, MaxVolumeSize, StorageHAMigrationEnabled}; + return new ConfigKey[] {RecreatableSystemVmEnabled, MaxVolumeSize, StorageHAMigrationEnabled, CustomDiskOfferingMaxSize, CustomDiskOfferingMinSize}; } @Override @@ -1243,7 +1362,7 @@ public String getStoragePoolOfVolume(long volumeId) { VolumeVO vol = _volsDao.findById(volumeId); return dataStoreMgr.getPrimaryDataStore(vol.getPoolId()).getUuid(); } - + @Override public void updateVolumeDiskChain(long volumeId, String path, String chainInfo) { VolumeVO vol = _volsDao.findById(volumeId); @@ -1253,10 +1372,10 @@ public void updateVolumeDiskChain(long volumeId, String path, String chainInfo) return; if(!vol.getPath().equalsIgnoreCase(path)) needUpdate = true; - + if(chainInfo != null && (vol.getChainInfo() == null || !chainInfo.equalsIgnoreCase(vol.getChainInfo()))) needUpdate = true; - + if(needUpdate) { s_logger.info("Update volume disk chain info. vol: " + vol.getId() + ", " + vol.getPath() + " -> " + path + ", " + vol.getChainInfo() + " -> " + chainInfo); diff --git a/engine/pom.xml b/engine/pom.xml index 27254d5b6c9b..d0b1ba2d8d85 100644 --- a/engine/pom.xml +++ b/engine/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml diff --git a/engine/schema/pom.xml b/engine/schema/pom.xml index 8860b9b79206..cd74caaea078 100644 --- a/engine/schema/pom.xml +++ b/engine/schema/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml 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 0a5ae5028b4d..699fd6bd63fc 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 @@ -222,6 +222,7 @@ + @@ -251,6 +252,7 @@ + @@ -258,7 +260,6 @@ - @@ -322,8 +323,14 @@ - - + + + + + + + + diff --git a/engine/schema/src/com/cloud/alert/AlertVO.java b/engine/schema/src/com/cloud/alert/AlertVO.java index 3f014aa2b1f9..05c4ac4f0b50 100755 --- a/engine/schema/src/com/cloud/alert/AlertVO.java +++ b/engine/schema/src/com/cloud/alert/AlertVO.java @@ -72,14 +72,14 @@ public class AlertVO implements Alert { @Column(name="archived") private boolean archived; + + @Column(name="name") + private String name; public AlertVO() { this.uuid = UUID.randomUUID().toString(); } - public AlertVO(Long id) { - this.id = id; - this.uuid = UUID.randomUUID().toString(); - } + @Override public long getId() { @@ -180,4 +180,14 @@ public boolean getArchived() { public void setArchived(Boolean archived) { this.archived = archived; } + + @Override + public String getName() { + return name; + } + + + public void setName(String name) { + this.name = name; + } } diff --git a/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java b/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java index 04466f4adb2e..7c5d42066061 100755 --- a/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java +++ b/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java @@ -42,4 +42,6 @@ List findCapacityBy(Integer capacityType, Long zoneId, void updateCapacityState(Long dcId, Long podId, Long clusterId, Long hostId, String capacityState); List listClustersCrossingThreshold(short capacityType, Long zoneId, String ConfigName, long computeRequested); + + float findClusterConsumption(Long clusterId, short capacityType, long computeRequested); } diff --git a/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java b/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java index 64a1660a9666..cf0d4919f505 100755 --- a/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -28,7 +28,6 @@ import javax.inject.Inject; import com.cloud.dc.ClusterDetailsDao; -import com.cloud.dc.ClusterDetailsVO; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; @@ -38,7 +37,6 @@ import com.cloud.capacity.CapacityVO; import com.cloud.storage.Storage; import com.cloud.utils.Pair; -import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.JoinBuilder.JoinType; @@ -159,6 +157,8 @@ public class CapacityDaoImpl extends GenericDaoBase implements "GROUP BY cluster.cluster_id) clusterList " + "WHERE clusterList.ratio > clusterList.value; "; + private static final String FIND_CLUSTER_CONSUMPTION_RATIO = "select ( (sum(capacity.used_capacity) + sum(capacity.reserved_capacity) + ?)/sum(capacity.total_capacity) ) " + + "from op_host_capacity capacity where cluster_id = ? and capacity_type = ?;"; public CapacityDaoImpl() { @@ -873,4 +873,26 @@ public void updateCapacityState(Long dcId, Long podId, Long clusterId, Long host s_logger.warn("Error updating CapacityVO", e); } } + + @Override + public float findClusterConsumption(Long clusterId, short capacityType, long computeRequested){ + TransactionLegacy txn = TransactionLegacy.currentTxn(); + StringBuilder sql = new StringBuilder(FIND_CLUSTER_CONSUMPTION_RATIO); + PreparedStatement pstmt = null; + try { + pstmt = txn.prepareAutoCloseStatement(sql.toString()); + + pstmt.setLong(1, computeRequested); + pstmt.setLong(2, clusterId); + pstmt.setShort(3, capacityType); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + return rs.getFloat(1); + } + } catch (Exception e) { + s_logger.warn("Error checking cluster threshold", e); + } + return 0; + } + } diff --git a/engine/schema/src/com/cloud/event/UsageEventVO.java b/engine/schema/src/com/cloud/event/UsageEventVO.java index 6fad8c9cb1a3..8c3d3fb7d663 100644 --- a/engine/schema/src/com/cloud/event/UsageEventVO.java +++ b/engine/schema/src/com/cloud/event/UsageEventVO.java @@ -31,7 +31,11 @@ @Entity @Table(name="usage_event") public class UsageEventVO implements UsageEvent { - @Id + public enum DynamicParameters { + cpuSpeed, cpuNumber, memory + }; + + @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="id") private long id = -1; diff --git a/engine/schema/src/com/cloud/event/dao/UsageEventDaoImpl.java b/engine/schema/src/com/cloud/event/dao/UsageEventDaoImpl.java index 370afbafa4b2..df8124afaadf 100644 --- a/engine/schema/src/com/cloud/event/dao/UsageEventDaoImpl.java +++ b/engine/schema/src/com/cloud/event/dao/UsageEventDaoImpl.java @@ -53,6 +53,10 @@ public class UsageEventDaoImpl extends GenericDaoBase implem private static final String COPY_ALL_EVENTS = "INSERT INTO cloud_usage.usage_event (id, type, account_id, created, zone_id, resource_id, resource_name, offering_id, template_id, size, resource_type, virtual_size) " + "SELECT id, type, account_id, created, zone_id, resource_id, resource_name, offering_id, template_id, size, resource_type, virtual_size FROM cloud.usage_event vmevt WHERE vmevt.id <= ?"; private static final String MAX_EVENT = "select max(id) from cloud.usage_event where created <= ?"; + private static final String COPY_EVENT_DETAILS = "INSERT INTO cloud_usage.usage_event_details (id, usage_event_id, name, value) " + + "SELECT id, usage_event_id, name, value FROM cloud.usage_event_details vmevtDetails WHERE vmevtDetails.usage_event_id > ? and vmevtDetails.usage_event_id <= ? "; + private static final String COPY_ALL_EVENT_DETAILS = "INSERT INTO cloud_usage.usage_event_details (id, usage_event_id, name, value) " + + "SELECT id, usage_event_id, name, value FROM cloud.usage_event_details vmevtDetails WHERE vmevtDetails.usage_event_id <= ?"; @Inject protected UsageEventDetailsDao usageEventDetailsDao; public UsageEventDaoImpl () { @@ -93,6 +97,7 @@ public synchronized List getRecentEvents(Date endDate) { long recentEventId = getMostRecentEventId(); long maxEventId = getMaxEventId(endDate); TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + // Copy events from cloud db to usage db String sql = COPY_EVENTS; if (recentEventId == 0) { if (s_logger.isDebugEnabled()) { @@ -112,12 +117,39 @@ public synchronized List getRecentEvents(Date endDate) { pstmt.setLong(i++, maxEventId); pstmt.executeUpdate(); txn.commit(); - return findRecentEvents(endDate); } catch (Exception ex) { txn.rollback(); s_logger.error("error copying events from cloud db to usage db", ex); throw new CloudRuntimeException(ex.getMessage()); } + + // Copy event details from cloud db to usage db + sql = COPY_EVENT_DETAILS; + if (recentEventId == 0) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("no recent event date, copying all event detailss"); + } + sql = COPY_ALL_EVENT_DETAILS; + } + + pstmt = null; + try { + txn.start(); + pstmt = txn.prepareAutoCloseStatement(sql); + int i = 1; + if (recentEventId != 0) { + pstmt.setLong(i++, recentEventId); + } + pstmt.setLong(i++, maxEventId); + pstmt.executeUpdate(); + txn.commit(); + } catch (Exception ex) { + txn.rollback(); + s_logger.error("error copying event details from cloud db to usage db", ex); + throw new CloudRuntimeException(ex.getMessage()); + } + + return findRecentEvents(endDate); } @DB diff --git a/engine/schema/src/com/cloud/event/dao/UsageEventDetailsDao.java b/engine/schema/src/com/cloud/event/dao/UsageEventDetailsDao.java index fb9c0e27b093..240553e81320 100644 --- a/engine/schema/src/com/cloud/event/dao/UsageEventDetailsDao.java +++ b/engine/schema/src/com/cloud/event/dao/UsageEventDetailsDao.java @@ -23,7 +23,6 @@ public interface UsageEventDetailsDao extends GenericDao { - Map findDetails(long eventId); void persist(long eventId, Map details); diff --git a/engine/schema/src/com/cloud/event/dao/UsageEventDetailsDaoImpl.java b/engine/schema/src/com/cloud/event/dao/UsageEventDetailsDaoImpl.java index a4382c47a3c0..5512f07701b4 100644 --- a/engine/schema/src/com/cloud/event/dao/UsageEventDetailsDaoImpl.java +++ b/engine/schema/src/com/cloud/event/dao/UsageEventDetailsDaoImpl.java @@ -21,10 +21,15 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.TransactionLegacy; +import com.cloud.utils.exception.CloudRuntimeException; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import javax.ejb.Local; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -71,20 +76,6 @@ public UsageEventDetailsVO findDetail(long eventId, String key) { return findOneBy(sc); } - @Override - public Map findDetails(long eventId) { - SearchCriteria sc = EventDetailsSearch.create(); - sc.setParameters("eventId", eventId); - - List results = search(sc, null); - Map details = new HashMap(results.size()); - for (UsageEventDetailsVO result : results) { - details.put(result.getKey(), result.getValue()); - } - - return details; - } - @Override public void persist(long eventId, Map details) { TransactionLegacy txn = TransactionLegacy.currentTxn(); diff --git a/engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDaoImpl.java b/engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDaoImpl.java index e8ef0d22420c..9e0cfc42f872 100644 --- a/engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDaoImpl.java +++ b/engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDaoImpl.java @@ -54,6 +54,7 @@ public ExternalLoadBalancerDeviceDaoImpl() { allocationStateSearch.and("physicalNetworkId", allocationStateSearch.entity().getPhysicalNetworkId(), Op.EQ); allocationStateSearch.and("providerName", allocationStateSearch.entity().getProviderName(), Op.EQ); allocationStateSearch.and("allocationState", allocationStateSearch.entity().getAllocationState(), Op.EQ); + allocationStateSearch.and("exclusiveGslbProvider", allocationStateSearch.entity().getExclusiveGslbProvider(), Op.EQ); allocationStateSearch.done(); deviceStatusSearch = createSearchBuilder(); @@ -95,6 +96,7 @@ public List listByProviderAndDeviceAllocationState sc.setParameters("physicalNetworkId", physicalNetworkId); sc.setParameters("providerName", provider_name); sc.setParameters("allocationState", state); + sc.setParameters("exclusiveGslbProvider", false); return search(sc, null); } diff --git a/engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceVO.java b/engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceVO.java index c1c983489a3d..072d294b34ce 100644 --- a/engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceVO.java +++ b/engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceVO.java @@ -68,7 +68,10 @@ public class ExternalLoadBalancerDeviceVO implements InternalIdentity, Identity @Column(name="is_gslb_provider") private boolean gslbProvider; - @Column(name="gslb_site_publicip") + @Column(name = "is_exclusive_gslb_provider") + private boolean exclusiveGslbProvider; + + @Column(name = "gslb_site_publicip") private String gslbSitePublicIP; @Column(name="gslb_site_privateip") @@ -201,6 +204,14 @@ public void setGslbProvider(boolean gslbProvider) { this.gslbProvider = gslbProvider; } + public boolean getExclusiveGslbProvider() { + return exclusiveGslbProvider; + } + + public void setExclusiveGslbProvider(boolean exclusiveGslbProvider) { + this.exclusiveGslbProvider = exclusiveGslbProvider; + } + public void setGslbSitePublicIP(String gslbSitePublicIP) { this.gslbSitePublicIP = gslbSitePublicIP; } diff --git a/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsDao.java b/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsDao.java index d020ea72eac7..99255c6ba0be 100644 --- a/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsDao.java +++ b/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsDao.java @@ -18,6 +18,7 @@ import java.util.List; +import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDao; public interface FirewallRulesCidrsDao extends GenericDao { @@ -25,5 +26,7 @@ public interface FirewallRulesCidrsDao extends GenericDao sourceCidrs); List getSourceCidrs(long firewallRuleId); - + + @DB + List listByFirewallRuleId(long firewallRuleId); } diff --git a/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsDaoImpl.java b/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsDaoImpl.java index 26f399d12464..aa3b82e580b0 100644 --- a/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsDaoImpl.java +++ b/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsDaoImpl.java @@ -39,7 +39,7 @@ public class FirewallRulesCidrsDaoImpl extends GenericDaoBase getSourceCidrs(long firewallRuleId) { return cidrs; } - + + @Override @DB + public List listByFirewallRuleId(long firewallRuleId) { + SearchCriteria sc = CidrsSearch.create(); + sc.setParameters("firewallRuleId", firewallRuleId); + + List results = search(sc, null); + + return results; + } @Override @DB public void persist(long firewallRuleId, List sourceCidrs) { TransactionLegacy txn = TransactionLegacy.currentTxn(); diff --git a/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsVO.java b/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsVO.java index 75b8919d645b..fc595a7bd2b0 100644 --- a/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsVO.java +++ b/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsVO.java @@ -61,5 +61,10 @@ public String getCidr() { public String getSourceCidrList() { return sourceCidrList; } - + + public void setSourceCidrList(String sourceCidrList) { + this.sourceCidrList = sourceCidrList; + } + + } diff --git a/engine/schema/src/com/cloud/network/dao/Site2SiteCustomerGatewayVO.java b/engine/schema/src/com/cloud/network/dao/Site2SiteCustomerGatewayVO.java index fe0a4032819c..c5227e2678b2 100644 --- a/engine/schema/src/com/cloud/network/dao/Site2SiteCustomerGatewayVO.java +++ b/engine/schema/src/com/cloud/network/dao/Site2SiteCustomerGatewayVO.java @@ -29,7 +29,6 @@ import com.cloud.network.Site2SiteCustomerGateway; import com.cloud.utils.db.Encrypt; import com.cloud.utils.db.GenericDao; -import org.apache.cloudstack.api.InternalIdentity; @Entity @Table(name=("s2s_customer_gateway")) diff --git a/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java b/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java index af0d9705d3f9..5fd6cfb93894 100644 --- a/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java +++ b/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java @@ -34,7 +34,7 @@ public SslCertDaoImpl() { listByAccountId = createSearchBuilder(); listByAccountId.and("accountId", listByAccountId.entity().getAccountId(), SearchCriteria.Op.EQ); listByAccountId.done(); - } + } @Override public List listByAccountId(Long accountId) { diff --git a/engine/schema/src/com/cloud/network/vpc/NetworkACLItemVO.java b/engine/schema/src/com/cloud/network/vpc/NetworkACLItemVO.java index 46f84c9f617a..f4b65b530857 100644 --- a/engine/schema/src/com/cloud/network/vpc/NetworkACLItemVO.java +++ b/engine/schema/src/com/cloud/network/vpc/NetworkACLItemVO.java @@ -61,7 +61,7 @@ public class NetworkACLItemVO implements NetworkACLItem { @Enumerated(value=EnumType.STRING) TrafficType trafficType; - @Column(name="cidr") + @Column(name = "cidr", length = 2048) String sourceCidrs; @Column(name="uuid") @@ -75,7 +75,7 @@ public class NetworkACLItemVO implements NetworkACLItem { Action action; public NetworkACLItemVO() { - this.uuid = UUID.randomUUID().toString(); + uuid = UUID.randomUUID().toString(); } public NetworkACLItemVO(Integer portStart, Integer portEnd, String protocol, @@ -85,11 +85,11 @@ public NetworkACLItemVO(Integer portStart, Integer portEnd, String protocol, this.sourcePortEnd = portEnd; this.protocol = protocol; this.aclId = aclId; - this.state = State.Staged; + state = State.Staged; this.icmpCode = icmpCode; this.icmpType = icmpType; setSourceCidrList(sourceCidrs); - this.uuid = UUID.randomUUID().toString(); + uuid = UUID.randomUUID().toString(); this.trafficType = trafficType; this.action = action; this.number = number; @@ -181,7 +181,7 @@ public Integer getIcmpType() { @Override public String getUuid() { - return this.uuid; + return uuid; } @Override diff --git a/engine/schema/src/com/cloud/service/ServiceOfferingDetailsVO.java b/engine/schema/src/com/cloud/service/ServiceOfferingDetailsVO.java index 4ab313438f22..e04473826ef5 100644 --- a/engine/schema/src/com/cloud/service/ServiceOfferingDetailsVO.java +++ b/engine/schema/src/com/cloud/service/ServiceOfferingDetailsVO.java @@ -43,7 +43,7 @@ public class ServiceOfferingDetailsVO implements ResourceDetail { private String value; @Column(name="display") - boolean display; + boolean display = true; protected ServiceOfferingDetailsVO() { } diff --git a/engine/schema/src/com/cloud/service/ServiceOfferingVO.java b/engine/schema/src/com/cloud/service/ServiceOfferingVO.java index 1e89addb5194..fd8473497721 100755 --- a/engine/schema/src/com/cloud/service/ServiceOfferingVO.java +++ b/engine/schema/src/com/cloud/service/ServiceOfferingVO.java @@ -18,7 +18,12 @@ import java.util.Map; -import javax.persistence.*; +import javax.persistence.Column; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.Table; +import javax.persistence.Transient; import com.cloud.offering.ServiceOffering; import com.cloud.storage.DiskOfferingVO; @@ -29,9 +34,6 @@ @DiscriminatorValue(value="Service") @PrimaryKeyJoinColumn(name="id") public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering { - public enum DynamicParameters { - cpuSpeed, cpuNumber, memory - }; @Column(name="cpu") private Integer cpu; @@ -78,6 +80,11 @@ public enum DynamicParameters { @Transient Map details; + // This flag is required to tell if the offering is dynamic once the cpu, memory and speed are set. + // In some cases cpu, memory and speed are set to non-null values even if the offering is dynamic. + @Transient + boolean isDynamic; + protected ServiceOfferingVO() { super(); } @@ -91,9 +98,9 @@ public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer spee this.rateMbps = rateMbps; this.multicastRateMbps = multicastRateMbps; this.offerHA = offerHA; - this.limitCpuUse = false; - this.volatileVm = false; - this.default_use = defaultUse; + limitCpuUse = false; + volatileVm = false; + default_use = defaultUse; this.vm_type = vm_type == null ? null : vm_type.toString().toLowerCase(); } @@ -127,6 +134,20 @@ public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer spee this.deploymentPlanner = deploymentPlanner; } + public ServiceOfferingVO(ServiceOfferingVO offering) { + super(offering.getId(), offering.getName(), offering.getDisplayText(), false, offering.getTags(), offering.isRecreatable(), offering.getUseLocalStorage(), offering.getSystemUse(), true, offering.getDomainId()); + cpu = offering.getCpu(); + ramSize = offering.getRamSize(); + speed = offering.getSpeed(); + rateMbps = offering.getRateMbps(); + multicastRateMbps = offering.getMulticastRateMbps(); + offerHA = offering.getOfferHA(); + limitCpuUse = offering.getLimitCpuUse(); + volatileVm = offering.getVolatileVm(); + hostTag = offering.getHostTag(); + vm_type = offering.getSystemVmType(); + } + @Override public boolean getOfferHA() { return offerHA; @@ -210,19 +231,23 @@ public void setHostTag(String hostTag) { this.hostTag = hostTag; } - public String getHostTag() { + @Override + public String getHostTag() { return hostTag; } - public String getSystemVmType(){ + @Override + public String getSystemVmType(){ return vm_type; } - public void setSortKey(int key) { + @Override + public void setSortKey(int key) { sortKey = key; } - public int getSortKey() { + @Override + public int getSortKey() { return sortKey; } @@ -256,9 +281,12 @@ public void setDetails(Map details) { this.details = details; } + @Override public boolean isDynamic() { - return cpu == null || speed == null || ramSize == null; + return cpu == null || speed == null || ramSize == null || isDynamic; } - + public void setDynamicFlag(boolean isdynamic) { + isDynamic = isdynamic; + } } diff --git a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDao.java b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDao.java index c5c4cff62c01..6e11e96eebc4 100644 --- a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDao.java +++ b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDao.java @@ -36,6 +36,6 @@ public interface ServiceOfferingDao extends GenericDao void saveDetails(ServiceOfferingVO serviceOffering); ServiceOfferingVO findById(Long vmId, long serviceOfferingId); ServiceOfferingVO findByIdIncludingRemoved(Long vmId, long serviceOfferingId); - boolean isDynamic(long serviceOfferingId); - ServiceOfferingVO getcomputeOffering(long serviceOfferingId, Integer cpuCores, Integer cpuSpeed, Integer memory); + boolean isDynamic(long serviceOfferingId); + ServiceOfferingVO getcomputeOffering(ServiceOfferingVO serviceOffering, Map customParameters); } diff --git a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java index 917eaefb445d..f4abd15e51d0 100644 --- a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java +++ b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java @@ -25,6 +25,7 @@ import javax.inject.Inject; import javax.persistence.EntityExistsException; +import com.cloud.event.UsageEventVO; import com.cloud.exception.InvalidParameterValueException; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.dao.UserVmDetailsDao; @@ -188,14 +189,12 @@ public void saveDetails(ServiceOfferingVO serviceOffering) { public ServiceOfferingVO findById(Long vmId, long serviceOfferingId) { ServiceOfferingVO offering = super.findById(serviceOfferingId); if (offering.isDynamic()) { + offering.setDynamicFlag(true); if (vmId == null) { throw new CloudRuntimeException("missing argument vmId"); } Map dynamicOffering = userVmDetailsDao.listDetailsKeyPairs(vmId); - offering.setCpu(Integer.parseInt(dynamicOffering.get(ServiceOfferingVO.DynamicParameters.cpuNumber.name()))); - offering.setSpeed(Integer.parseInt(dynamicOffering.get(ServiceOfferingVO.DynamicParameters.cpuSpeed.name()))); - offering.setRamSize(Integer.parseInt(dynamicOffering.get(ServiceOfferingVO.DynamicParameters.memory.name()))); - return offering; + return getcomputeOffering(offering, dynamicOffering); } return offering; } @@ -203,15 +202,12 @@ public ServiceOfferingVO findById(Long vmId, long serviceOfferingId) { public ServiceOfferingVO findByIdIncludingRemoved(Long vmId, long serviceOfferingId) { ServiceOfferingVO offering = super.findByIdIncludingRemoved(serviceOfferingId); if (offering.isDynamic()) { + offering.setDynamicFlag(true); if (vmId == null) { throw new CloudRuntimeException("missing argument vmId"); } Map dynamicOffering = userVmDetailsDao.listDetailsKeyPairs(vmId); - offering.setCpu(Integer.parseInt(dynamicOffering.get(ServiceOfferingVO.DynamicParameters.cpuNumber.name()))); - offering.setSpeed(Integer.parseInt(dynamicOffering.get(ServiceOfferingVO.DynamicParameters.cpuSpeed.name()))); - offering.setRamSize(Integer.parseInt(dynamicOffering.get(ServiceOfferingVO.DynamicParameters.memory.name()))); - return offering; - + return getcomputeOffering(offering, dynamicOffering); } return offering; } @@ -228,4 +224,19 @@ public ServiceOfferingVO getcomputeOffering(long serviceOfferingId, Integer cpuC offering.setRamSize(memory); return offering; } + + public ServiceOfferingVO getcomputeOffering(ServiceOfferingVO serviceOffering, Map customParameters) { + ServiceOfferingVO dummyoffering = new ServiceOfferingVO(serviceOffering); + dummyoffering.setDynamicFlag(true); + if (customParameters.containsKey(UsageEventVO.DynamicParameters.cpuNumber.name())) { + dummyoffering.setCpu(Integer.parseInt(customParameters.get(UsageEventVO.DynamicParameters.cpuNumber.name()))); + } + if (customParameters.containsKey(UsageEventVO.DynamicParameters.cpuSpeed.name())) { + dummyoffering.setSpeed(Integer.parseInt(customParameters.get(UsageEventVO.DynamicParameters.cpuSpeed.name()))); + } + if (customParameters.containsKey(UsageEventVO.DynamicParameters.memory.name())) { + dummyoffering.setRamSize(Integer.parseInt(customParameters.get(UsageEventVO.DynamicParameters.memory.name()))); + } + return dummyoffering; + } } diff --git a/engine/schema/src/com/cloud/storage/DiskOfferingVO.java b/engine/schema/src/com/cloud/storage/DiskOfferingVO.java index b5b345191021..3321cb481eb0 100755 --- a/engine/schema/src/com/cloud/storage/DiskOfferingVO.java +++ b/engine/schema/src/com/cloud/storage/DiskOfferingVO.java @@ -184,6 +184,22 @@ public DiskOfferingVO(String name, String displayText, boolean mirrored, String state = State.Active; } + public DiskOfferingVO(long id, String name, String displayText, boolean mirrored, String tags, boolean recreatable, + boolean useLocalStorage, boolean systemUse, boolean customized, Long domainId) { + this.id = id; + type = Type.Service; + this.name = name; + this.displayText = displayText; + this.tags = tags; + this.recreatable = recreatable; + this.useLocalStorage = useLocalStorage; + this.systemUse = systemUse; + this.customized = customized; + this.domainId = domainId; + uuid = UUID.randomUUID().toString(); + state = State.Active; + } + @Override public State getState() { return state; diff --git a/engine/schema/src/com/cloud/storage/VolumeVO.java b/engine/schema/src/com/cloud/storage/VolumeVO.java index a130d89a86d3..e3516a356814 100755 --- a/engine/schema/src/com/cloud/storage/VolumeVO.java +++ b/engine/schema/src/com/cloud/storage/VolumeVO.java @@ -587,6 +587,7 @@ public void setHypervisorSnapshotReserve(Integer hypervisorSnapshotReserve) { this.hypervisorSnapshotReserve = hypervisorSnapshotReserve; } + @Override public Integer getHypervisorSnapshotReserve() { return hypervisorSnapshotReserve; } diff --git a/engine/schema/src/com/cloud/storage/dao/SnapshotDao.java b/engine/schema/src/com/cloud/storage/dao/SnapshotDao.java index a58902121cc7..0868ac401f02 100644 --- a/engine/schema/src/com/cloud/storage/dao/SnapshotDao.java +++ b/engine/schema/src/com/cloud/storage/dao/SnapshotDao.java @@ -56,14 +56,4 @@ public interface SnapshotDao extends GenericDao, StateDao listByStatus(long volumeId, Snapshot.State... status); List listAllByStatus(Snapshot.State... status); - - /** - * Gets the Total Secondary Storage space (in bytes) used by snapshots - * allocated for an account - * - * @param account - * @return total Secondary Storage space allocated - */ - long secondaryStorageUsedForAccount(long accountId); - } diff --git a/engine/schema/src/com/cloud/storage/dao/SnapshotDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/SnapshotDaoImpl.java index c56a3cf43b80..3810ee41c36e 100644 --- a/engine/schema/src/com/cloud/storage/dao/SnapshotDaoImpl.java +++ b/engine/schema/src/com/cloud/storage/dao/SnapshotDaoImpl.java @@ -36,7 +36,6 @@ import com.cloud.storage.SnapshotVO; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; -import com.cloud.storage.dao.VolumeDaoImpl.SumCount; import com.cloud.tags.dao.ResourceTagDao; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; @@ -46,7 +45,6 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; -import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.TransactionLegacy; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.dao.VMInstanceDao; @@ -70,7 +68,6 @@ public class SnapshotDaoImpl extends GenericDaoBase implements private SearchBuilder InstanceIdSearch; private SearchBuilder StatusSearch; private GenericSearchBuilder CountSnapshotsByAccount; - private GenericSearchBuilder secondaryStorageSearch; @Inject ResourceTagDao _tagsDao; @Inject @@ -176,6 +173,7 @@ protected void init() { CountSnapshotsByAccount = createSearchBuilder(Long.class); CountSnapshotsByAccount.select(null, Func.COUNT, null); CountSnapshotsByAccount.and("account", CountSnapshotsByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); + CountSnapshotsByAccount.and("status", CountSnapshotsByAccount.entity().getState(), SearchCriteria.Op.NIN); CountSnapshotsByAccount.and("removed", CountSnapshotsByAccount.entity().getRemoved(), SearchCriteria.Op.NULL); CountSnapshotsByAccount.done(); @@ -193,12 +191,6 @@ protected void init() { InstanceIdSearch.join("instanceSnapshots", volumeSearch, volumeSearch.entity().getId(), InstanceIdSearch .entity().getVolumeId(), JoinType.INNER); InstanceIdSearch.done(); - - secondaryStorageSearch = createSearchBuilder(SumCount.class); - secondaryStorageSearch.select("sum", Func.SUM, secondaryStorageSearch.entity().getSize()); - secondaryStorageSearch.and("accountId", secondaryStorageSearch.entity().getAccountId(), Op.EQ); - secondaryStorageSearch.and("isRemoved", secondaryStorageSearch.entity().getRemoved(), Op.NULL); - secondaryStorageSearch.done(); } @Override @@ -277,6 +269,7 @@ public long updateSnapshotSecHost(long dcId, long secHostId) { public Long countSnapshotsForAccount(long accountId) { SearchCriteria sc = CountSnapshotsByAccount.create(); sc.setParameters("account", accountId); + sc.setParameters("status", State.Error, State.Destroyed); return customSearch(sc, null).get(0); } @@ -333,15 +326,4 @@ public boolean updateState(State currentState, Event event, State nextState, Sna return true; } - @Override - public long secondaryStorageUsedForAccount(long accountId) { - SearchCriteria sc = secondaryStorageSearch.create(); - sc.setParameters("accountId", accountId); - List storageSpace = customSearch(sc, null); - if (storageSpace != null) { - return storageSpace.get(0).sum; - } else { - return 0; - } - } } 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 000000000000..b216de6ed6a6 --- /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 000000000000..f8d3813d64d3 --- /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 000000000000..5b91c820154a --- /dev/null +++ b/engine/schema/src/com/cloud/storage/dao/SnapshotDetailsVO.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 + * 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 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 = "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() { + + } + + 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 1f5083a8e14b..24ade51c3b43 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 54b6465642e6..2fb9dbae07d9 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 VolumeDaoImpl() { 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 Pair getNonDestroyedCountAndTotalByPool(long poolId) { 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/com/cloud/upgrade/dao/Upgrade410to420.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java index c2630b068f09..1ed1e3c1a9c9 100755 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -27,11 +27,9 @@ import java.sql.Types; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.UUID; import org.apache.log4j.Logger; @@ -83,7 +81,6 @@ public void performDataMigration(Connection conn) { persistVswitchConfiguration(conn); createPlaceHolderNics(conn); updateRemoteAccessVpn(conn); - updateSystemVmTemplates(conn); updateOverCommitRatioClusterDetails(conn); updatePrimaryStore(conn); addEgressFwRulesForSRXGuestNw(conn); @@ -629,162 +626,6 @@ private void dropUploadTable(Connection conn) { } - private void updateSystemVmTemplates(Connection conn) { - // TODO: system vm template migration after storage refactoring - PreparedStatement pstmt = null; - ResultSet rs = null; - s_logger.debug("Updating System Vm template IDs"); - try{ - //Get all hypervisors in use - Set hypervisorsListInUse = new HashSet(); - try { - pstmt = conn.prepareStatement("select distinct(hypervisor_type) from `cloud`.`cluster` where removed is null"); - rs = pstmt.executeQuery(); - while(rs.next()){ - switch (HypervisorType.getType(rs.getString(1))) { - case XenServer: hypervisorsListInUse.add(HypervisorType.XenServer); - break; - case KVM: hypervisorsListInUse.add(HypervisorType.KVM); - break; - case VMware: hypervisorsListInUse.add(HypervisorType.VMware); - break; - case Hyperv: hypervisorsListInUse.add(HypervisorType.Hyperv); - break; - case LXC: hypervisorsListInUse.add(HypervisorType.LXC); - break; - } - } - } catch (SQLException e) { - throw new CloudRuntimeException("Error while listing hypervisors in use", e); - } - - Map NewTemplateNameList = new HashMap(){ - { put(HypervisorType.XenServer, "systemvm-xenserver-4.2"); - put(HypervisorType.VMware, "systemvm-vmware-4.2"); - put(HypervisorType.KVM, "systemvm-kvm-4.2"); - put(HypervisorType.LXC, "systemvm-lxc-4.2"); - put(HypervisorType.Hyperv, "systemvm-hyperv-4.2"); - } - }; - - Map routerTemplateConfigurationNames = new HashMap(){ - { put(HypervisorType.XenServer, "router.template.xen"); - put(HypervisorType.VMware, "router.template.vmware"); - put(HypervisorType.KVM, "router.template.kvm"); - put(HypervisorType.LXC, "router.template.lxc"); - put(HypervisorType.Hyperv, "router.template.hyperv"); - } - }; - - Map newTemplateUrl = new HashMap(){ - { put(HypervisorType.XenServer, "http://download.cloud.com/templates/4.2/systemvmtemplate-2013-07-12-master-xen.vhd.bz2"); - put(HypervisorType.VMware, "http://download.cloud.com/templates/4.2/systemvmtemplate-4.2-vh7.ova"); - put(HypervisorType.KVM, "http://download.cloud.com/templates/4.2/systemvmtemplate-2013-06-12-master-kvm.qcow2.bz2"); - put(HypervisorType.LXC, "http://download.cloud.com/templates/acton/acton-systemvm-02062012.qcow2.bz2"); - put(HypervisorType.Hyperv, "http://download.cloud.com/templates/4.2/systemvmtemplate-2013-06-12-master-xen.vhd.bz2"); - } - }; - - Map newTemplateChecksum = new HashMap(){ - { put(HypervisorType.XenServer, "fb1b6e032a160d86f2c28feb5add6d83"); - put(HypervisorType.VMware, "8fde62b1089e5844a9cd3b9b953f9596"); - put(HypervisorType.KVM, "6cea42b2633841648040becb588bd8f0"); - put(HypervisorType.LXC, "2755de1f9ef2ce4d6f2bee2efbb4da92"); - put(HypervisorType.Hyperv, "fb1b6e032a160d86f2c28feb5add6d83"); - } - }; - - for (Map.Entry hypervisorAndTemplateName : NewTemplateNameList.entrySet()){ - s_logger.debug("Updating " + hypervisorAndTemplateName.getKey() + " System Vms"); - try { - //Get 4.2.0 system Vm template Id for corresponding hypervisor - pstmt = conn.prepareStatement("select id from `cloud`.`vm_template` where name = ? and removed is null order by id desc limit 1"); - pstmt.setString(1, hypervisorAndTemplateName.getValue()); - rs = pstmt.executeQuery(); - if(rs.next()){ - long templateId = rs.getLong(1); - rs.close(); - pstmt.close(); - // Mark the old system templates as removed - pstmt = conn.prepareStatement("UPDATE `cloud`.`vm_template` SET removed = now() WHERE hypervisor_type = ? AND type = 'SYSTEM' AND removed is null"); - pstmt.setString(1, hypervisorAndTemplateName.getKey().toString()); - pstmt.executeUpdate(); - pstmt.close(); - // change template type to SYSTEM - pstmt = conn.prepareStatement("update `cloud`.`vm_template` set type='SYSTEM' where id = ?"); - pstmt.setLong(1, templateId); - pstmt.executeUpdate(); - pstmt.close(); - // update templete ID of system Vms - pstmt = conn.prepareStatement("update `cloud`.`vm_instance` set vm_template_id = ? where type <> 'User' and hypervisor_type = ?"); - pstmt.setLong(1, templateId); - pstmt.setString(2, hypervisorAndTemplateName.getKey().toString()); - pstmt.executeUpdate(); - pstmt.close(); - // Change value of global configuration parameter router.template.* for the corresponding hypervisor - pstmt = conn.prepareStatement("UPDATE `cloud`.`configuration` SET value = ? WHERE name = ?"); - pstmt.setString(1, hypervisorAndTemplateName.getValue()); - pstmt.setString(2, routerTemplateConfigurationNames.get(hypervisorAndTemplateName.getKey())); - pstmt.executeUpdate(); - pstmt.close(); - } else { - if (hypervisorsListInUse.contains(hypervisorAndTemplateName.getKey())){ - // throw new CloudRuntimeException("4.2.0 " + hypervisorAndTemplateName.getKey() + " SystemVm template not found. Cannot upgrade system Vms"); - } else { - s_logger.warn("4.2.0 " + hypervisorAndTemplateName.getKey() + " SystemVm template not found. " + hypervisorAndTemplateName.getKey() + " hypervisor is not used, so not failing upgrade"); - // Update the latest template URLs for corresponding hypervisor - pstmt = conn.prepareStatement("UPDATE `cloud`.`vm_template` SET url = ? , checksum = ? WHERE hypervisor_type = ? AND type = 'SYSTEM' AND removed is null order by id desc limit 1"); - pstmt.setString(1, newTemplateUrl.get(hypervisorAndTemplateName.getKey())); - pstmt.setString(2, newTemplateChecksum.get(hypervisorAndTemplateName.getKey())); - pstmt.setString(3, hypervisorAndTemplateName.getKey().toString()); - pstmt.executeUpdate(); - pstmt.close(); - } - } - } catch (SQLException e) { - throw new CloudRuntimeException("Error while updating "+ hypervisorAndTemplateName.getKey() +" systemVm template", e); - } - } - try { - pstmt = conn.prepareStatement("UPDATE `cloud`.`vm_template` set dynamically_scalable = 1 where name = ? and type = 'SYSTEM'"); - pstmt.setString(1, NewTemplateNameList.get(HypervisorType.VMware)); - pstmt.executeUpdate(); - pstmt.close(); - } catch (SQLException e) { - throw new CloudRuntimeException("Error while updating dynamically_scalable flag to 1 for SYSTEM template systemvm-vmware-4.2"); - } - s_logger.debug("Updating System Vm Template IDs Complete"); - } - finally { - try { - if (rs != null) { - rs.close(); - } - - if (pstmt != null) { - pstmt.close(); - } - } catch (SQLException e) { - } - } - /* - pstmt = null; - try { - pstmt = conn.prepareStatement("update vm_template set image_data_store_id = 1 where type = 'SYSTEM' or type = 'BUILTIN'"); - pstmt.executeUpdate(); - } catch (SQLException e) { - throw new CloudRuntimeException("Failed to upgrade vm template data store uuid: " + e.toString()); - } finally { - if (pstmt != null) { - try { - pstmt.close(); - } catch (SQLException e) { - } - } - } - */ - } - //KVM snapshot flag: only turn on if Customers is using snapshot; private void setKVMSnapshotFlag(Connection conn) { s_logger.debug("Verify and set the KVM snapshot flag if snapshot was used. "); @@ -893,7 +734,7 @@ private void updateOverCommitRatioClusterDetails(Connection conn) { }else { //update cluster_details table with the default overcommit ratios. pstmt1.setLong(1,id); - pstmt1.setString(2,"1"); + pstmt1.setString(2,global_cpu_overprovisioning_factor); pstmt1.execute(); pstmt2.setLong(1,id); pstmt2.setString(2,"1"); diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade420to421.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade420to421.java index d7eccc15efc9..eb2327af39a9 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade420to421.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade420to421.java @@ -23,6 +23,7 @@ import java.sql.ResultSet; import java.sql.SQLException; +import com.cloud.hypervisor.Hypervisor; import org.apache.log4j.Logger; import com.cloud.utils.exception.CloudRuntimeException; @@ -68,6 +69,8 @@ public void performDataMigration(Connection conn) { updateCpuOverprovisioning(conn); } + + private void updateCpuOverprovisioning(Connection conn) { PreparedStatement pstmt1 = null; PreparedStatement pstmt2 = null; @@ -80,27 +83,49 @@ private void updateCpuOverprovisioning(Connection conn) { try { pstmt1 = conn.prepareStatement("select value from `cloud`.`configuration` where name='cpu.overprovisioning.factor'"); result1 = pstmt1.executeQuery(); - String overprov = "1"; + String cpuoverprov = "1"; + if(result1.next()){ + cpuoverprov = result1.getString(1); + } + pstmt1 = conn.prepareStatement("select value from `cloud`.`configuration` where name='mem.overprovisioning.factor'"); + result1 = pstmt1.executeQuery(); + String memoverprov = "1"; if(result1.next()){ - overprov = result1.getString(1); + memoverprov = result1.getString(1); } + // Need to populate only when overprovisioning factor doesn't pre exist. s_logger.debug("Starting updating user_vm_details with cpu/memory overprovisioning factors"); - pstmt2 = conn.prepareStatement("select id from `cloud`.`vm_instance` where removed is null and id not in (select vm_id from `cloud`.`user_vm_details` where name='cpuOvercommitRatio')"); + pstmt2 = conn.prepareStatement("select id, hypervisor_type from `cloud`.`vm_instance` where removed is null and id not in (select vm_id from `cloud`.`user_vm_details` where name='cpuOvercommitRatio')"); pstmt3 = conn.prepareStatement("INSERT IGNORE INTO cloud.user_vm_details (vm_id, name, value) VALUES (?, ?, ?)"); result2 = pstmt2.executeQuery(); while (result2.next()) { - //For cpu - pstmt3.setLong(1, result2.getLong(1)); - pstmt3.setString(2, "cpuOvercommitRatio"); - pstmt3.setString(3, overprov); - pstmt3.executeUpdate(); + String hypervisor_type = result2.getString(2); + if (hypervisor_type.equalsIgnoreCase(Hypervisor.HypervisorType.VMware.name())) { + //For cpu + pstmt3.setLong(1, result2.getLong(1)); + pstmt3.setString(2, "cpuOvercommitRatio"); + pstmt3.setString(3, cpuoverprov); + pstmt3.executeUpdate(); + + // For memory + pstmt3.setLong(1, result2.getLong(1)); + pstmt3.setString(2, "memoryOvercommitRatio"); + pstmt3.setString(3, memoverprov); // memory overprovisioning was used to reserve memory in case of VMware. + pstmt3.executeUpdate(); + } else { + //For cpu + pstmt3.setLong(1, result2.getLong(1)); + pstmt3.setString(2, "cpuOvercommitRatio"); + pstmt3.setString(3, cpuoverprov); + pstmt3.executeUpdate(); - // For memory - pstmt3.setLong(1, result2.getLong(1)); - pstmt3.setString(2, "memoryOvercommitRatio"); - pstmt3.setString(3, "1"); // memory overprovisioning didn't exist earlier. - pstmt3.executeUpdate(); + // For memory + pstmt3.setLong(1, result2.getLong(1)); + pstmt3.setString(2, "memoryOvercommitRatio"); + pstmt3.setString(3, "1"); // memory overprovisioning didn't exist earlier. + pstmt3.executeUpdate(); + } } s_logger.debug("Done updating user_vm_details with cpu/memory overprovisioning factors"); @@ -109,13 +134,23 @@ private void updateCpuOverprovisioning(Connection conn) { throw new CloudRuntimeException("Unable to update cpu/memory overprovisioning factors", e); } finally { try { - if (pstmt1 != null) + if (pstmt1 != null && !pstmt1.isClosed()) { pstmt1.close(); - if (pstmt2 != null) + } + if (pstmt2 != null && !pstmt2.isClosed()) { pstmt2.close(); - if (pstmt3 != null) + } + if (pstmt3 != null && !pstmt3.isClosed()) { pstmt3.close(); - } catch (SQLException e) { + } + if (result1 != null) { + result1.close(); + } + if (result2 != null) { + result2.close(); + } + }catch (SQLException e){ + } } diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade421to430.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade421to430.java index 5647289f489c..7e26132d9e08 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade421to430.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade421to430.java @@ -18,10 +18,22 @@ package com.cloud.upgrade.dao; import java.io.File; +import java.io.UnsupportedEncodingException; import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import com.cloud.hypervisor.Hypervisor; +import com.cloud.utils.crypt.DBEncryptionUtil; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; @@ -50,11 +62,300 @@ public File[] getPrepareScripts() { throw new CloudRuntimeException("Unable to find db/schema-421to430.sql"); } - return new File[] { new File(script) }; + return new File[] {new File(script)}; } @Override public void performDataMigration(Connection conn) { + encryptLdapConfigParams(conn); + encryptImageStoreDetails(conn); + upgradeMemoryOfSsvmOffering(conn); + updateSystemVmTemplates(conn); + } + + private void upgradeMemoryOfSsvmOffering(Connection conn) { + PreparedStatement updatePstmt = null; + PreparedStatement selectPstmt = null; + ResultSet selectResultSet = null; + int newRamSize = 512; //512MB + long serviceOfferingId = 0; + + /** + * Pick first row in service_offering table which has system vm type as secondary storage vm. User added offerings would start from 2nd row onwards. + * We should not update/modify any user-defined offering. + */ + + try { + selectPstmt = conn.prepareStatement("SELECT id FROM `cloud`.`service_offering` WHERE vm_type='secondarystoragevm'"); + updatePstmt = conn.prepareStatement("UPDATE `cloud`.`service_offering` SET ram_size=? WHERE id=?"); + selectResultSet = selectPstmt.executeQuery(); + if(selectResultSet.next()) { + serviceOfferingId = selectResultSet.getLong("id"); + } + + updatePstmt.setInt(1, newRamSize); + updatePstmt.setLong(2, serviceOfferingId); + updatePstmt.executeUpdate(); + } catch (SQLException e) { + throw new CloudRuntimeException("Unable to upgrade ram_size of service offering for secondary storage vm. ", e); + } finally { + try { + if (selectPstmt != null) { + selectPstmt.close(); + } + if (selectResultSet != null) { + selectResultSet.close(); + } + if (updatePstmt != null) { + updatePstmt.close(); + } + } catch (SQLException e) { + } + } + s_logger.debug("Done upgrading RAM for service offering of Secondary Storage VM to " + newRamSize); + } + + private void encryptLdapConfigParams(Connection conn) { + PreparedStatement pstmt = null; + + String[][] ldapParams = { {"ldap.user.object", "inetOrgPerson", "Sets the object type of users within LDAP"}, + {"ldap.username.attribute", "uid", "Sets the username attribute used within LDAP"}, {"ldap.email.attribute", "mail", "Sets the email attribute used within LDAP"}, + {"ldap.firstname.attribute", "givenname", "Sets the firstname attribute used within LDAP"}, + {"ldap.lastname.attribute", "sn", "Sets the lastname attribute used within LDAP"}, + {"ldap.group.object", "groupOfUniqueNames", "Sets the object type of groups within LDAP"}, + {"ldap.group.user.uniquemember", "uniquemember", "Sets the attribute for uniquemembers within a group"}}; + + String insertSql = "INSERT INTO `cloud`.`configuration`(category, instance, component, name, value, description) VALUES ('Secure', 'DEFAULT', 'management-server', ?, ?, " + + "?) ON DUPLICATE KEY UPDATE category='Secure';"; + + try { + + for (String[] ldapParam : ldapParams) { + String name = ldapParam[0]; + String value = ldapParam[1]; + String desc = ldapParam[2]; + String encryptedValue = DBEncryptionUtil.encrypt(value); + pstmt = conn.prepareStatement(insertSql); + pstmt.setString(1, name); + pstmt.setBytes(2, encryptedValue.getBytes("UTF-8")); + pstmt.setString(3, desc); + pstmt.executeUpdate(); + } + + /** + * if encrypted, decrypt the ldap hostname and port and then update as they are not encrypted now. + */ + pstmt = conn.prepareStatement("SELECT conf.value FROM `cloud`.`configuration` conf WHERE conf.name='ldap.hostname'"); + ResultSet resultSet = pstmt.executeQuery(); + String hostname = null; + String port; + int portNumber = 0; + if (resultSet.next()) { + hostname = DBEncryptionUtil.decrypt(resultSet.getString(1)); + } + + pstmt = conn.prepareStatement("SELECT conf.value FROM `cloud`.`configuration` conf WHERE conf.name='ldap.port'"); + resultSet = pstmt.executeQuery(); + if (resultSet.next()) { + port = DBEncryptionUtil.decrypt(resultSet.getString(1)); + if (StringUtils.isNotBlank(port)) { + portNumber = Integer.valueOf(port); + } + } + + if (StringUtils.isNotBlank(hostname)) { + pstmt = conn.prepareStatement("INSERT INTO `cloud`.`ldap_configuration`(hostname, port) VALUES(?,?)"); + pstmt.setString(1, hostname); + if (portNumber != 0) { + pstmt.setInt(2, portNumber); + } else { + pstmt.setNull(2, Types.INTEGER); + } + pstmt.executeUpdate(); + } + + } catch (SQLException e) { + throw new CloudRuntimeException("Unable to insert ldap configuration values ", e); + } catch (UnsupportedEncodingException e) { + throw new CloudRuntimeException("Unable to insert ldap configuration values ", e); + } finally { + try { + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException e) { + } + } + s_logger.debug("Done encrypting ldap Config values"); + + } + + private void updateSystemVmTemplates(Connection conn) { + PreparedStatement pstmt = null; + ResultSet rs = null; + s_logger.debug("Updating System Vm template IDs"); + try{ + //Get all hypervisors in use + Set hypervisorsListInUse = new HashSet(); + try { + pstmt = conn.prepareStatement("select distinct(hypervisor_type) from `cloud`.`cluster` where removed is null"); + rs = pstmt.executeQuery(); + while(rs.next()){ + switch (Hypervisor.HypervisorType.getType(rs.getString(1))) { + case XenServer: hypervisorsListInUse.add(Hypervisor.HypervisorType.XenServer); + break; + case KVM: hypervisorsListInUse.add(Hypervisor.HypervisorType.KVM); + break; + case VMware: hypervisorsListInUse.add(Hypervisor.HypervisorType.VMware); + break; + case Hyperv: hypervisorsListInUse.add(Hypervisor.HypervisorType.Hyperv); + break; + case LXC: hypervisorsListInUse.add(Hypervisor.HypervisorType.LXC); + break; + } + } + } catch (SQLException e) { + throw new CloudRuntimeException("Error while listing hypervisors in use", e); + } + + Map NewTemplateNameList = new HashMap(){ + { put(Hypervisor.HypervisorType.XenServer, "systemvm-xenserver-4.3"); + put(Hypervisor.HypervisorType.VMware, "systemvm-vmware-4.3"); + put(Hypervisor.HypervisorType.KVM, "systemvm-kvm-4.3"); + put(Hypervisor.HypervisorType.LXC, "systemvm-lxc-4.3"); + put(Hypervisor.HypervisorType.Hyperv, "systemvm-hyperv-4.3"); + } + }; + + Map routerTemplateConfigurationNames = new HashMap(){ + { put(Hypervisor.HypervisorType.XenServer, "router.template.xen"); + put(Hypervisor.HypervisorType.VMware, "router.template.vmware"); + put(Hypervisor.HypervisorType.KVM, "router.template.kvm"); + put(Hypervisor.HypervisorType.LXC, "router.template.lxc"); + put(Hypervisor.HypervisorType.Hyperv, "router.template.hyperv"); + } + }; + + Map newTemplateUrl = new HashMap(){ + { put(Hypervisor.HypervisorType.XenServer, "http://download.cloud.com/templates/4.3/systemvm64template-2014-01-14-master-xen.vhd.bz2"); + put(Hypervisor.HypervisorType.VMware, "http://download.cloud.com/templates/4.3/systemvm64template-2014-01-14-master-vmware.ova"); + put(Hypervisor.HypervisorType.KVM, "http://download.cloud.com/templates/4.3/systemvm64template-2014-01-14-master-kvm.qcow2.bz2"); + put(Hypervisor.HypervisorType.LXC, "http://download.cloud.com/templates/4.3/systemvm64template-2014-01-14-master-kvm.qcow2.bz2"); + put(Hypervisor.HypervisorType.Hyperv, "http://download.cloud.com/templates/4.3/systemvm64template-2013-12-23-hyperv.vhd.bz2"); + } + }; + + Map newTemplateChecksum = new HashMap(){ + { put(Hypervisor.HypervisorType.XenServer, "74b92f031cc5c2089ee89efb81344dcf"); + put(Hypervisor.HypervisorType.VMware, "ef593a061f3b7594ab0bfd9b0ed0a0d4"); + put(Hypervisor.HypervisorType.KVM, "85a1bed07bf43cbf022451cb2ecae4ff"); + put(Hypervisor.HypervisorType.LXC, "85a1bed07bf43cbf022451cb2ecae4ff"); + put(Hypervisor.HypervisorType.Hyperv, "5df45ee6ebe1b703a8805f4e1f4d0818"); + } + }; + + for (Map.Entry hypervisorAndTemplateName : NewTemplateNameList.entrySet()){ + s_logger.debug("Updating " + hypervisorAndTemplateName.getKey() + " System Vms"); + try { + //Get 4.3.0 system Vm template Id for corresponding hypervisor + pstmt = conn.prepareStatement("select id from `cloud`.`vm_template` where name = ? and removed is null order by id desc limit 1"); + pstmt.setString(1, hypervisorAndTemplateName.getValue()); + rs = pstmt.executeQuery(); + if(rs.next()){ + long templateId = rs.getLong(1); + rs.close(); + pstmt.close(); +// // Mark the old system templates as removed +// pstmt = conn.prepareStatement("UPDATE `cloud`.`vm_template` SET removed = now() WHERE hypervisor_type = ? AND type = 'SYSTEM' AND removed is null"); +// pstmt.setString(1, hypervisorAndTemplateName.getKey().toString()); +// pstmt.executeUpdate(); +// pstmt.close(); + // change template type to SYSTEM + pstmt = conn.prepareStatement("update `cloud`.`vm_template` set type='SYSTEM' where id = ?"); + pstmt.setLong(1, templateId); + pstmt.executeUpdate(); + pstmt.close(); + // update templete ID of system Vms + pstmt = conn.prepareStatement("update `cloud`.`vm_instance` set vm_template_id = ? where type <> 'User' and hypervisor_type = ?"); + pstmt.setLong(1, templateId); + pstmt.setString(2, hypervisorAndTemplateName.getKey().toString()); + pstmt.executeUpdate(); + pstmt.close(); + // Change value of global configuration parameter router.template.* for the corresponding hypervisor + pstmt = conn.prepareStatement("UPDATE `cloud`.`configuration` SET value = ? WHERE name = ?"); + pstmt.setString(1, hypervisorAndTemplateName.getValue()); + pstmt.setString(2, routerTemplateConfigurationNames.get(hypervisorAndTemplateName.getKey())); + pstmt.executeUpdate(); + pstmt.close(); + } else { + if (hypervisorsListInUse.contains(hypervisorAndTemplateName.getKey())){ + throw new CloudRuntimeException("4.3.0 " + hypervisorAndTemplateName.getKey() + " SystemVm template not found. Cannot upgrade system Vms"); + } else { + s_logger.warn("4.3.0 " + hypervisorAndTemplateName.getKey() + " SystemVm template not found. " + hypervisorAndTemplateName.getKey() + " hypervisor is not used, so not failing upgrade"); + // Update the latest template URLs for corresponding hypervisor + pstmt = conn.prepareStatement("UPDATE `cloud`.`vm_template` SET url = ? , checksum = ? WHERE hypervisor_type = ? AND type = 'SYSTEM' AND removed is null order by id desc limit 1"); + pstmt.setString(1, newTemplateUrl.get(hypervisorAndTemplateName.getKey())); + pstmt.setString(2, newTemplateChecksum.get(hypervisorAndTemplateName.getKey())); + pstmt.setString(3, hypervisorAndTemplateName.getKey().toString()); + pstmt.executeUpdate(); + pstmt.close(); + } + } + } catch (SQLException e) { + throw new CloudRuntimeException("Error while updating "+ hypervisorAndTemplateName.getKey() +" systemVm template", e); + } + } + s_logger.debug("Updating System Vm Template IDs Complete"); + } finally { + try { + if (rs != null) { + rs.close(); + } + + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException e) { + } + } + } + + private void encryptImageStoreDetails(Connection conn) { + s_logger.debug("Encrypting image store details"); + PreparedStatement pstmt = null; + ResultSet rs = null; + try { + pstmt = conn.prepareStatement("select id, value from `cloud`.`image_store_details` where name = 'key' or name = 'secretkey'"); + rs = pstmt.executeQuery(); + while (rs.next()) { + long id = rs.getLong(1); + String value = rs.getString(2); + if (value == null) { + continue; + } + String encryptedValue = DBEncryptionUtil.encrypt(value); + pstmt = conn.prepareStatement("update `cloud`.`image_store_details` set value=? where id=?"); + pstmt.setBytes(1, encryptedValue.getBytes("UTF-8")); + pstmt.setLong(2, id); + pstmt.executeUpdate(); + } + } catch (SQLException e) { + throw new CloudRuntimeException("Unable encrypt image_store_details values ", e); + } catch (UnsupportedEncodingException e) { + throw new CloudRuntimeException("Unable encrypt image_store_details values ", e); + } finally { + try { + if (rs != null) { + rs.close(); + } + + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException e) { + } + } + s_logger.debug("Done encrypting image_store_details"); } @Override @@ -64,7 +365,7 @@ public File[] getCleanupScripts() { throw new CloudRuntimeException("Unable to find db/schema-421to430-cleanup.sql"); } - return new File[] { new File(script) }; + return new File[] {new File(script)}; } } diff --git a/engine/schema/src/com/cloud/usage/UsageVMInstanceVO.java b/engine/schema/src/com/cloud/usage/UsageVMInstanceVO.java index 2fe346ea06c9..34175217663b 100644 --- a/engine/schema/src/com/cloud/usage/UsageVMInstanceVO.java +++ b/engine/schema/src/com/cloud/usage/UsageVMInstanceVO.java @@ -27,6 +27,7 @@ @Entity @Table(name="usage_vm_instance") public class UsageVMInstanceVO { + @Column(name="usage_type") private int usageType; @@ -45,6 +46,15 @@ public class UsageVMInstanceVO { @Column(name="service_offering_id") private long serviceOfferingId; + @Column(name="cpu_cores") + private Long cpuCores; + + @Column(name="memory") + private Long memory; + + @Column(name="cpu_speed") + private Long cpuSpeed; + @Column(name="template_id") private long templateId; @@ -126,4 +136,28 @@ public Date getEndDate() { public void setEndDate(Date endDate) { this.endDate = endDate; } + + public Long getMemory() { + return memory; + } + + public void setMemory(Long memory) { + this.memory = memory; + } + + public Long getCpuCores() { + return cpuCores; + } + + public void setCpuCores(Long cpuCores) { + this.cpuCores = cpuCores; + } + + public Long getCpuSpeed() { + return cpuSpeed; + } + + public void setCpuSpeed(Long cpuSpeed) { + this.cpuSpeed = cpuSpeed; + } } diff --git a/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java index c4d8ec4d6d40..937bd3fadd48 100644 --- a/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java +++ b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java @@ -18,7 +18,6 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; -import java.sql.Timestamp; import java.sql.Types; import java.util.ArrayList; import java.util.Date; @@ -428,8 +427,8 @@ public void saveUsageRecords(List usageRecords) { } else { pstmt.setNull(15, Types.BIGINT); } - pstmt.setTimestamp(16, new Timestamp(usageRecord.getStartDate().getTime())); - pstmt.setTimestamp(17, new Timestamp(usageRecord.getEndDate().getTime())); + pstmt.setString(16, DateUtil.getDateDisplayString(s_gmtTimeZone, usageRecord.getStartDate())); + pstmt.setString(17, DateUtil.getDateDisplayString(s_gmtTimeZone, usageRecord.getEndDate())); if(usageRecord.getVirtualSize() != null){ pstmt.setLong(18, usageRecord.getSize()); } else { diff --git a/engine/schema/src/com/cloud/vm/UserVmDetailVO.java b/engine/schema/src/com/cloud/vm/UserVmDetailVO.java index 82bf32d49a64..84a11f68687d 100644 --- a/engine/schema/src/com/cloud/vm/UserVmDetailVO.java +++ b/engine/schema/src/com/cloud/vm/UserVmDetailVO.java @@ -43,7 +43,7 @@ public class UserVmDetailVO implements ResourceDetail { private String value; @Column(name="display") - private boolean display; + private boolean display = true; public UserVmDetailVO() {} diff --git a/engine/schema/src/com/cloud/vm/VMInstanceVO.java b/engine/schema/src/com/cloud/vm/VMInstanceVO.java index 96f534a4aacc..f9dad74aae7c 100644 --- a/engine/schema/src/com/cloud/vm/VMInstanceVO.java +++ b/engine/schema/src/com/cloud/vm/VMInstanceVO.java @@ -425,7 +425,7 @@ public Long getPodIdToDeployIn() { return podIdToDeployIn; } - public void setPodId(long podId) { + public void setPodId(Long podId) { this.podIdToDeployIn = podId; } diff --git a/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java b/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java index f1912b5d06ea..474ac050f42c 100755 --- a/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java +++ b/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java @@ -68,7 +68,7 @@ public interface DomainRouterDao extends GenericDao { * @param podId id of the pod. null if to get all. * @return list of DomainRouterVO */ - public List listByPodId(Long podId); + public List listRunningByPodId(Long podId); /** * list virtual machine routers by pod id. pass in null to get all @@ -93,7 +93,7 @@ public interface DomainRouterDao extends GenericDao { * @param id * @return */ - public List listByDomain(Long id); + public List listRunningByDomain(Long id); List findBy(long accountId, long dcId, Role role); @@ -146,5 +146,9 @@ public interface DomainRouterDao extends GenericDao { */ void removeRouterFromGuestNetwork(long routerId, long guestNetworkId); - List listByClusterId(Long clusterId); + List listRunningByClusterId(Long clusterId); + + List listRunningByAccountId(long accountId); + + List listRunningByDataCenter(long dcId); } diff --git a/engine/schema/src/com/cloud/vm/dao/DomainRouterDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/DomainRouterDaoImpl.java index 5158e9857cdb..c6d0dc20b055 100755 --- a/engine/schema/src/com/cloud/vm/dao/DomainRouterDaoImpl.java +++ b/engine/schema/src/com/cloud/vm/dao/DomainRouterDaoImpl.java @@ -27,19 +27,15 @@ import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; -import com.cloud.host.dao.HostDaoImpl; import com.cloud.network.Network; import com.cloud.network.dao.RouterNetworkDao; -import com.cloud.network.dao.RouterNetworkDaoImpl; import com.cloud.network.dao.RouterNetworkVO; import com.cloud.network.router.VirtualRouter; import com.cloud.network.router.VirtualRouter.Role; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; -import com.cloud.offerings.dao.NetworkOfferingDaoImpl; import com.cloud.user.UserStatisticsVO; import com.cloud.user.dao.UserStatisticsDao; -import com.cloud.user.dao.UserStatisticsDaoImpl; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.JoinBuilder.JoinType; @@ -50,7 +46,6 @@ import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.db.UpdateBuilder; import com.cloud.vm.DomainRouterVO; -import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; @Component @@ -59,10 +54,12 @@ public class DomainRouterDaoImpl extends GenericDaoBase implements DomainRouterDao { protected SearchBuilder AllFieldsSearch; + protected SearchBuilder RunningSearch; protected SearchBuilder IdNetworkIdStatesSearch; protected SearchBuilder HostUpSearch; protected SearchBuilder StateNetworkTypeSearch; protected SearchBuilder OutsidePodSearch; + protected SearchBuilder clusterSearch; @Inject HostDao _hostsDao; @Inject RouterNetworkDao _routerNetworkDao; @Inject UserStatisticsDao _userStatsDao; @@ -117,7 +114,7 @@ protected void init() { StateNetworkTypeSearch = createSearchBuilder(); StateNetworkTypeSearch.select(null, Func.DISTINCT, StateNetworkTypeSearch.entity().getId()); StateNetworkTypeSearch.and("state", StateNetworkTypeSearch.entity().getState(), Op.EQ); - SearchBuilder joinRouterNetwork4 = _routerNetworkDao.createSearchBuilder(); + SearchBuilder joinRouterNetwork4 =_routerNetworkDao.createSearchBuilder(); joinRouterNetwork4.and("networkId", joinRouterNetwork4.entity().getNetworkId(), Op.EQ); joinRouterNetwork4.and("type", joinRouterNetwork4.entity().getGuestType(), Op.EQ); StateNetworkTypeSearch.join("networkRouter", joinRouterNetwork4, joinRouterNetwork4.entity().getRouterId(), StateNetworkTypeSearch.entity().getId(), JoinType.INNER); @@ -139,6 +136,20 @@ protected void init() { OutsidePodSearch.and("role", OutsidePodSearch.entity().getRole(), Op.EQ); OutsidePodSearch.done(); + clusterSearch = createSearchBuilder(); + clusterSearch.and("state", clusterSearch.entity().getState(), Op.EQ); + SearchBuilder clusterHost = _hostsDao.createSearchBuilder(); + clusterHost.and("clusterId", clusterHost.entity().getClusterId(), Op.EQ); + clusterSearch.join("host", clusterHost, clusterSearch.entity().getHostId(), clusterHost.entity().getId(),JoinType.INNER); + clusterSearch.done(); + + RunningSearch = createSearchBuilder(); + RunningSearch.and("dc", RunningSearch.entity().getDataCenterId(), Op.EQ); + RunningSearch.and("account", RunningSearch.entity().getAccountId(), Op.EQ); + RunningSearch.and("domainId", RunningSearch.entity().getDomainId(), Op.EQ); + RunningSearch.and("state", RunningSearch.entity().getState(), Op.EQ); + RunningSearch.and("podId", RunningSearch.entity().getPodIdToDeployIn(), Op.EQ); + RunningSearch.done(); } @Override @@ -197,16 +208,18 @@ public List listByHostId(Long hostId) { } @Override - public List listByPodId(Long podId) { - SearchCriteria sc = AllFieldsSearch.create(); + public List listRunningByPodId(Long podId) { + SearchCriteria sc = RunningSearch.create(); + sc.setParameters("state", State.Running); sc.setParameters("podId", podId); return listBy(sc); } @Override - public List listByClusterId(Long clusterId) { - SearchCriteria sc = AllFieldsSearch.create(); - //ToDo: Add cluster criteria + public List listRunningByClusterId(Long clusterId) { + SearchCriteria sc = clusterSearch.create(); + sc.setParameters("state", State.Running); + sc.setJoinParameters("host", "clusterId", clusterId); return listBy(sc); } @@ -234,8 +247,9 @@ public List listIsolatedByHostId(Long hostId) { } @Override - public List listByDomain(Long domainId) { - SearchCriteria sc = AllFieldsSearch.create(); + public List listRunningByDomain(Long domainId) { + SearchCriteria sc = RunningSearch.create(); + sc.setParameters("state", State.Running); sc.setParameters("domainId", domainId); return listBy(sc); } @@ -376,4 +390,19 @@ public List listByVpcId(long vpcId) { return listBy(sc); } + @Override + public List listRunningByAccountId(long accountId) { + SearchCriteria sc = RunningSearch.create(); + sc.setParameters("state", State.Running); + sc.setParameters("account", accountId); + return listBy(sc); + } + + @Override + public List listRunningByDataCenter(long dcId) { + SearchCriteria sc = RunningSearch.create(); + sc.setParameters("state", State.Running); + sc.setParameters("dc", dcId); + return listBy(sc); + } } diff --git a/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java b/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java index 830dea8aac72..78c6e8c9f61c 100644 --- a/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java +++ b/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java @@ -70,6 +70,8 @@ public interface VMInstanceDao extends GenericDao, StateDao< List findVMInTransition(Date time, State... states); + List listByHostAndState(long hostId, State... states); + List listByTypes(VirtualMachine.Type... types); VMInstanceVO findByIdTypes(long id, VirtualMachine.Type... types); @@ -123,8 +125,8 @@ public interface VMInstanceDao extends GenericDao, StateDao< List listStartingWithNoHostId(); boolean updatePowerState(long instanceId, long powerHostId, VirtualMachine.PowerState powerState); - + void resetVmPowerStateTracking(long instanceId); - + void resetHostPowerStateTracking(long hostId); } diff --git a/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java index e7f907e6545b..cc747bc56119 100644 --- a/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java +++ b/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java @@ -49,7 +49,11 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; 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.TransactionLegacy; +import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.db.UpdateBuilder; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.NicVO; @@ -65,7 +69,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem public static final Logger s_logger = Logger.getLogger(VMInstanceDaoImpl.class); private static final int MAX_CONSECUTIVE_SAME_STATE_UPDATE_COUNT = 3; - + protected SearchBuilder VMClusterSearch; protected SearchBuilder LHVMClusterSearch; protected SearchBuilder IdStatesSearch; @@ -77,6 +81,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem protected SearchBuilder TypesSearch; protected SearchBuilder IdTypesSearch; protected SearchBuilder HostIdTypesSearch; + protected SearchBuilder HostIdStatesSearch; protected SearchBuilder HostIdUpTypesSearch; protected SearchBuilder HostUpSearch; protected SearchBuilder InstanceNameSearch; @@ -180,6 +185,11 @@ protected void init() { HostIdTypesSearch.and("types", HostIdTypesSearch.entity().getType(), Op.IN); HostIdTypesSearch.done(); + HostIdStatesSearch = createSearchBuilder(); + HostIdStatesSearch.and("hostId", HostIdStatesSearch.entity().getHostId(), Op.EQ); + HostIdStatesSearch.and("states", HostIdStatesSearch.entity().getState(), Op.IN); + HostIdStatesSearch.done(); + HostIdUpTypesSearch = createSearchBuilder(); HostIdUpTypesSearch.and("hostid", HostIdUpTypesSearch.entity().getHostId(), Op.EQ); HostIdUpTypesSearch.and("types", HostIdUpTypesSearch.entity().getType(), Op.IN); @@ -230,7 +240,7 @@ protected void init() { _updateTimeAttr = _allAttributes.get("updateTime"); assert _updateTimeAttr != null : "Couldn't get this updateTime attribute"; - + SearchBuilder nicSearch = _nicDao.createSearchBuilder(); nicSearch.and("networkId", nicSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); @@ -242,7 +252,7 @@ protected void init() { DistinctHostNameSearch.join("nicSearch", nicSearch, DistinctHostNameSearch.entity().getId(), nicSearch.entity().getInstanceId(), JoinBuilder.JoinType.INNER); DistinctHostNameSearch.done(); - + } @Override @@ -334,6 +344,15 @@ public List listByHostIdTypes(long hostid, Type... types) { return listBy(sc); } + @Override + public List listByHostAndState(long hostId, State... states) { + SearchCriteria sc = HostIdStatesSearch.create(); + sc.setParameters("hostId", hostId); + sc.setParameters("states", (Object[])states); + + return listBy(sc); + } + @Override public List listUpByHostIdTypes(long hostid, Type... types) { SearchCriteria sc = HostIdUpTypesSearch.create(); @@ -679,63 +698,68 @@ public List listStartingWithNoHostId() { sc.setParameters("state", State.Starting); return listBy(sc); } - - @Override - public boolean updatePowerState(long instanceId, long powerHostId, VirtualMachine.PowerState powerState) { - boolean needToUpdate = false; - TransactionLegacy txn = TransactionLegacy.currentTxn(); - txn.start(); - - VMInstanceVO instance = findById(instanceId); - if(instance != null) { - Long savedPowerHostId = instance.getPowerHostId(); - if(instance.getPowerState() != powerState || savedPowerHostId == null - || savedPowerHostId.longValue() != powerHostId) { - instance.setPowerState(powerState); - instance.setPowerHostId(powerHostId); - instance.setPowerStateUpdateCount(1); - instance.setPowerStateUpdateTime(DateUtil.currentGMTTime()); - needToUpdate = true; - update(instanceId, instance); - } else { - // to reduce DB updates, consecutive same state update for more than 3 times - if(instance.getPowerStateUpdateCount() < MAX_CONSECUTIVE_SAME_STATE_UPDATE_COUNT) { - instance.setPowerStateUpdateCount(instance.getPowerStateUpdateCount() + 1); - instance.setPowerStateUpdateTime(DateUtil.currentGMTTime()); - needToUpdate = true; - update(instanceId, instance); - } - } - } - - txn.commit(); - return needToUpdate; - } - + @Override - public void resetVmPowerStateTracking(long instanceId) { - TransactionLegacy txn = TransactionLegacy.currentTxn(); - txn.start(); - VMInstanceVO instance = findById(instanceId); - if(instance != null) { - instance.setPowerStateUpdateCount(0); - instance.setPowerStateUpdateTime(DateUtil.currentGMTTime()); - update(instanceId, instance); - } - - txn.commit(); + public boolean updatePowerState(final long instanceId, final long powerHostId, final VirtualMachine.PowerState powerState) { + return Transaction.execute(new TransactionCallback() { + @Override + public Boolean doInTransaction(TransactionStatus status) { + boolean needToUpdate = false; + VMInstanceVO instance = findById(instanceId); + if(instance != null) { + Long savedPowerHostId = instance.getPowerHostId(); + if(instance.getPowerState() != powerState || savedPowerHostId == null + || savedPowerHostId.longValue() != powerHostId) { + instance.setPowerState(powerState); + instance.setPowerHostId(powerHostId); + instance.setPowerStateUpdateCount(1); + instance.setPowerStateUpdateTime(DateUtil.currentGMTTime()); + needToUpdate = true; + update(instanceId, instance); + } else { + // to reduce DB updates, consecutive same state update for more than 3 times + if(instance.getPowerStateUpdateCount() < MAX_CONSECUTIVE_SAME_STATE_UPDATE_COUNT) { + instance.setPowerStateUpdateCount(instance.getPowerStateUpdateCount() + 1); + instance.setPowerStateUpdateTime(DateUtil.currentGMTTime()); + needToUpdate = true; + update(instanceId, instance); + } + } + } + return needToUpdate; + } + }); + } + + @Override + public void resetVmPowerStateTracking(final long instanceId) { + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + VMInstanceVO instance = findById(instanceId); + if (instance != null) { + instance.setPowerStateUpdateCount(0); + instance.setPowerStateUpdateTime(DateUtil.currentGMTTime()); + update(instanceId, instance); + } + } + }); } - - + @Override @DB - public void resetHostPowerStateTracking(long hostId) { - SearchCriteria sc = createSearchCriteria(); - sc.addAnd("powerHostId", SearchCriteria.Op.EQ, hostId); - - VMInstanceVO instance = this.createForUpdate(); - instance.setPowerStateUpdateCount(0); - instance.setPowerStateUpdateTime(DateUtil.currentGMTTime()); - - this.update(instance, sc); + public void resetHostPowerStateTracking(final long hostId) { + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("powerHostId", SearchCriteria.Op.EQ, hostId); + + VMInstanceVO instance = createForUpdate(); + instance.setPowerStateUpdateCount(0); + instance.setPowerStateUpdateTime(DateUtil.currentGMTTime()); + + update(instance, sc); + } + }); } } diff --git a/engine/schema/src/org/apache/cloudstack/engine/cloud/entity/api/db/VMEntityVO.java b/engine/schema/src/org/apache/cloudstack/engine/cloud/entity/api/db/VMEntityVO.java index b1df96758944..21556059463d 100644 --- a/engine/schema/src/org/apache/cloudstack/engine/cloud/entity/api/db/VMEntityVO.java +++ b/engine/schema/src/org/apache/cloudstack/engine/cloud/entity/api/db/VMEntityVO.java @@ -145,12 +145,6 @@ public class VMEntityVO implements VirtualMachine, FiniteStateObject details; @@ -161,9 +155,6 @@ public class VMEntityVO implements VirtualMachine, FiniteStateObject computeTags; @@ -513,14 +504,6 @@ public void setOwner(String owner) { this.owner = owner; } - public int getSpeed() { - return speed; - } - - public void setSpeed(int speed) { - this.speed = speed; - } - public List getComputeTags() { return computeTags; } diff --git a/engine/schema/src/org/apache/cloudstack/lb/ApplicationLoadBalancerRuleVO.java b/engine/schema/src/org/apache/cloudstack/lb/ApplicationLoadBalancerRuleVO.java index 37a747e42722..7bb7293ec509 100644 --- a/engine/schema/src/org/apache/cloudstack/lb/ApplicationLoadBalancerRuleVO.java +++ b/engine/schema/src/org/apache/cloudstack/lb/ApplicationLoadBalancerRuleVO.java @@ -58,6 +58,10 @@ public class ApplicationLoadBalancerRuleVO extends FirewallRuleVO implements App @Column(name="source_ip_address_network_id") Long sourceIpNetworkId; + + @Column(name="lb_protocol") + String lbProtocol; + @Column(name="source_ip_address") @Enumerated(value=EnumType.STRING) @@ -111,6 +115,11 @@ public String getAlgorithm() { return algorithm; } + @Override + public String getLbProtocol() { + return lbProtocol; + } + @Override public int getDefaultPortStart() { return defaultPortStart; @@ -130,4 +139,6 @@ public Scheme getScheme() { public int getInstancePort() { return defaultPortStart; } + + } diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/FirewallRuleDetailVO.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/FirewallRuleDetailVO.java index a2ec6ff0bb49..9b431f2f1b8e 100644 --- a/engine/schema/src/org/apache/cloudstack/resourcedetail/FirewallRuleDetailVO.java +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/FirewallRuleDetailVO.java @@ -47,8 +47,8 @@ public class FirewallRuleDetailVO implements ResourceDetail{ public FirewallRuleDetailVO() {} - public FirewallRuleDetailVO(long networkId, String name, String value) { - this.resourceId = networkId; + public FirewallRuleDetailVO(long id, String name, String value) { + this.resourceId = id; this.name = name; this.value = value; } diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/NetworkACLItemDetailVO.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/NetworkACLItemDetailVO.java new file mode 100644 index 000000000000..fb27d374a947 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/NetworkACLItemDetailVO.java @@ -0,0 +1,82 @@ +// 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 = "network_acl_item_details") +public class NetworkACLItemDetailVO implements ResourceDetail { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "network_acl_item_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 NetworkACLItemDetailVO() { + } + + public NetworkACLItemDetailVO(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/NetworkACLListDetailVO.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/NetworkACLListDetailVO.java new file mode 100644 index 000000000000..71cf563478ac --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/NetworkACLListDetailVO.java @@ -0,0 +1,82 @@ +// 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 = "network_acl_details") +public class NetworkACLListDetailVO implements ResourceDetail { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "network_acl_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 NetworkACLListDetailVO() { + } + + public NetworkACLListDetailVO(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/RemoteAccessVpnDetailVO.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/RemoteAccessVpnDetailVO.java new file mode 100644 index 000000000000..625feb5d5809 --- /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/ResourceDetailsDaoBase.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java index 4ecebf85f036..2d086444213d 100644 --- a/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java @@ -27,10 +27,9 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.TransactionLegacy; - -public abstract class ResourceDetailsDaoBase extends GenericDaoBase{ +public abstract class ResourceDetailsDaoBase extends GenericDaoBase { private SearchBuilder AllFieldsSearch; - + public ResourceDetailsDaoBase() { AllFieldsSearch = createSearchBuilder(); AllFieldsSearch.and("resourceId", AllFieldsSearch.entity().getResourceId(), SearchCriteria.Op.EQ); @@ -43,15 +42,14 @@ public R findDetail(long resourceId, String name) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("resourceId", resourceId); sc.setParameters("name", name); - + return findOneBy(sc); } - public Map listDetailsKeyPairs(long resourceId) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("resourceId", resourceId); - + List results = search(sc, null); Map details = new HashMap(results.size()); for (R result : results) { @@ -68,23 +66,21 @@ public List listDetails(long resourceId) { return results; } - public void removeDetails(long resourceId) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("resourceId", resourceId); remove(sc); } - public void removeDetail(long resourceId, String key) { - if (key != null){ + if (key != null) { SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("resourceId", resourceId); sc.setParameters("name", key); remove(sc); } } - public void saveDetails(List details) { if (details.isEmpty()) { return; @@ -94,14 +90,13 @@ public void saveDetails(List details) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("resourceId", details.get(0).getResourceId()); expunge(sc); - + for (R detail : details) { persist(detail); } - + txn.commit(); } - protected void addDetail(R detail) { if (detail == null) { @@ -113,12 +108,12 @@ protected void addDetail(R detail) { } persist(detail); } - + public Map listDetailsKeyPairs(long resourceId, boolean forDisplay) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("resourceId", resourceId); sc.setParameters("display", forDisplay); - + List results = search(sc, null); Map details = new HashMap(results.size()); for (R result : results) { @@ -126,7 +121,6 @@ public Map listDetailsKeyPairs(long resourceId, boolean forDispl } return details; } - public List listDetails(long resourceId, boolean forDisplay) { SearchCriteria sc = AllFieldsSearch.create(); diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/Site2SiteCustomerGatewayDetailVO.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/Site2SiteCustomerGatewayDetailVO.java new file mode 100644 index 000000000000..1a2743cab816 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/Site2SiteCustomerGatewayDetailVO.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 +// 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 = "s2s_customer_gateway_details") +public class Site2SiteCustomerGatewayDetailVO implements ResourceDetail { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "s2s_customer_gateway_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 Site2SiteCustomerGatewayDetailVO() { + } + + public Site2SiteCustomerGatewayDetailVO(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/Site2SiteVpnConnectionDetailVO.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/Site2SiteVpnConnectionDetailVO.java new file mode 100644 index 000000000000..9a4b616624b9 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/Site2SiteVpnConnectionDetailVO.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 +// 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 = "s2s_vpn_connection_details") +public class Site2SiteVpnConnectionDetailVO implements ResourceDetail { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "s2s_vpn_connection_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 Site2SiteVpnConnectionDetailVO() { + } + + public Site2SiteVpnConnectionDetailVO(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/Site2SiteVpnGatewayDetailVO.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/Site2SiteVpnGatewayDetailVO.java new file mode 100644 index 000000000000..244e218218a4 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/Site2SiteVpnGatewayDetailVO.java @@ -0,0 +1,84 @@ +// 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 = "s2s_vpn_gateway_details") +public class Site2SiteVpnGatewayDetailVO implements ResourceDetail { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "s2s_vpn_gateway_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 Site2SiteVpnGatewayDetailVO() { + } + + public Site2SiteVpnGatewayDetailVO(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 index 56a47c2226f4..2b2f5e172b8a 100644 --- a/engine/schema/src/org/apache/cloudstack/resourcedetail/UserIpAddressDetailVO.java +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/UserIpAddressDetailVO.java @@ -47,8 +47,8 @@ public class UserIpAddressDetailVO implements ResourceDetail{ public UserIpAddressDetailVO() {} - public UserIpAddressDetailVO(long networkId, String name, String value) { - this.resourceId = networkId; + public UserIpAddressDetailVO(long id, String name, String value) { + this.resourceId = id; this.name = name; this.value = value; } diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/VpcDetailVO.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/VpcDetailVO.java new file mode 100644 index 000000000000..beb38b50d1bf --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/VpcDetailVO.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 +// 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 = "vpc_details") +public class VpcDetailVO implements ResourceDetail { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "vpc_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 VpcDetailVO() { + } + + public VpcDetailVO(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/VpcGatewayDetailVO.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/VpcGatewayDetailVO.java new file mode 100644 index 000000000000..b78bfa8b5dbb --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/VpcGatewayDetailVO.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 +// 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 = "vpc_gateway_details") +public class VpcGatewayDetailVO implements ResourceDetail { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "vpc_gateway_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 VpcGatewayDetailVO() { + } + + public VpcGatewayDetailVO(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/NetworkACLItemDetailsDao.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/NetworkACLItemDetailsDao.java new file mode 100644 index 000000000000..db820ac51231 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/NetworkACLItemDetailsDao.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.NetworkACLItemDetailVO; +import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; + +import com.cloud.utils.db.GenericDao; + +public interface NetworkACLItemDetailsDao extends GenericDao, ResourceDetailsDao { + +} \ No newline at end of file diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/NetworkACLItemDetailsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/NetworkACLItemDetailsDaoImpl.java new file mode 100644 index 000000000000..930c77a45008 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/NetworkACLItemDetailsDaoImpl.java @@ -0,0 +1,33 @@ +// 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.NetworkACLItemDetailVO; +import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; +import org.springframework.stereotype.Component; + +@Component +@Local(value = { NetworkACLItemDetailsDao.class }) +public class NetworkACLItemDetailsDaoImpl extends ResourceDetailsDaoBase implements NetworkACLItemDetailsDao { + + @Override + public void addDetail(long resourceId, String key, String value) { + super.addDetail(new NetworkACLItemDetailVO(resourceId, key, value)); + } +} \ No newline at end of file diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/NetworkACLListDetailsDao.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/NetworkACLListDetailsDao.java new file mode 100644 index 000000000000..1c8524505ddf --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/NetworkACLListDetailsDao.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.NetworkACLListDetailVO; +import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; + +import com.cloud.utils.db.GenericDao; + +public interface NetworkACLListDetailsDao extends GenericDao, ResourceDetailsDao { + +} \ No newline at end of file diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/NetworkACLListDetailsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/NetworkACLListDetailsDaoImpl.java new file mode 100644 index 000000000000..0b7037f7975e --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/NetworkACLListDetailsDaoImpl.java @@ -0,0 +1,33 @@ +// 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.NetworkACLListDetailVO; +import org.springframework.stereotype.Component; + +@Component +@Local(value = { NetworkACLListDetailsDao.class }) +public class NetworkACLListDetailsDaoImpl extends ResourceDetailsDaoBase implements NetworkACLListDetailsDao { + + @Override + public void addDetail(long resourceId, String key, String value) { + super.addDetail(new NetworkACLListDetailVO(resourceId, key, value)); + } +} 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 000000000000..697c91b87899 --- /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 000000000000..46e6be994a77 --- /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/Site2SiteCustomerGatewayDetailsDao.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteCustomerGatewayDetailsDao.java new file mode 100644 index 000000000000..0689b1c25c36 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteCustomerGatewayDetailsDao.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.Site2SiteCustomerGatewayDetailVO; + +import com.cloud.utils.db.GenericDao; + +public interface Site2SiteCustomerGatewayDetailsDao extends GenericDao, ResourceDetailsDao { + +} \ No newline at end of file diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteCustomerGatewayDetailsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteCustomerGatewayDetailsDaoImpl.java new file mode 100644 index 000000000000..b07adcbd6530 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteCustomerGatewayDetailsDaoImpl.java @@ -0,0 +1,33 @@ +// 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.Site2SiteCustomerGatewayDetailVO; +import org.springframework.stereotype.Component; + +@Component +@Local(value = {Site2SiteCustomerGatewayDetailsDao.class}) +public class Site2SiteCustomerGatewayDetailsDaoImpl extends ResourceDetailsDaoBase implements Site2SiteCustomerGatewayDetailsDao { + + @Override + public void addDetail(long resourceId, String key, String value) { + super.addDetail(new Site2SiteCustomerGatewayDetailVO(resourceId, key, value)); + } +} diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteVpnConnectionDetailsDao.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteVpnConnectionDetailsDao.java new file mode 100644 index 000000000000..ceb5cf7211f8 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteVpnConnectionDetailsDao.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.Site2SiteVpnConnectionDetailVO; + +import com.cloud.utils.db.GenericDao; + +public interface Site2SiteVpnConnectionDetailsDao extends GenericDao, ResourceDetailsDao { + +} diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteVpnConnectionDetailsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteVpnConnectionDetailsDaoImpl.java new file mode 100644 index 000000000000..a737850d4bff --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteVpnConnectionDetailsDaoImpl.java @@ -0,0 +1,33 @@ +// 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.Site2SiteVpnConnectionDetailVO; +import org.springframework.stereotype.Component; + +@Component +@Local(value = {Site2SiteVpnConnectionDetailsDao.class}) +public class Site2SiteVpnConnectionDetailsDaoImpl extends ResourceDetailsDaoBase implements Site2SiteVpnConnectionDetailsDao { + + @Override + public void addDetail(long resourceId, String key, String value) { + super.addDetail(new Site2SiteVpnConnectionDetailVO(resourceId, key, value)); + } +} diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteVpnGatewayDetailsDao.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteVpnGatewayDetailsDao.java new file mode 100644 index 000000000000..12c181f93520 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteVpnGatewayDetailsDao.java @@ -0,0 +1,27 @@ +// 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.Site2SiteVpnGatewayDetailVO; + +import com.cloud.utils.db.GenericDao; + +public interface Site2SiteVpnGatewayDetailsDao extends GenericDao, ResourceDetailsDao { + +} + diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteVpnGatewayDetailsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteVpnGatewayDetailsDaoImpl.java new file mode 100644 index 000000000000..8349ea8bd2a1 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/Site2SiteVpnGatewayDetailsDaoImpl.java @@ -0,0 +1,33 @@ +// 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.Site2SiteVpnGatewayDetailVO; +import org.springframework.stereotype.Component; + +@Component +@Local(value = { Site2SiteVpnGatewayDetailsDao.class }) +public class Site2SiteVpnGatewayDetailsDaoImpl extends ResourceDetailsDaoBase implements Site2SiteVpnGatewayDetailsDao { + + @Override + public void addDetail(long resourceId, String key, String value) { + super.addDetail(new Site2SiteVpnGatewayDetailVO(resourceId, key, value)); + } +} diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/VpcDetailsDao.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/VpcDetailsDao.java new file mode 100644 index 000000000000..8ebd5005d614 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/VpcDetailsDao.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.VpcDetailVO; + +import com.cloud.utils.db.GenericDao; + +public interface VpcDetailsDao extends GenericDao, ResourceDetailsDao { + +} diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/VpcDetailsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/VpcDetailsDaoImpl.java new file mode 100644 index 000000000000..645972310098 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/VpcDetailsDaoImpl.java @@ -0,0 +1,33 @@ +// 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.VpcDetailVO; +import org.springframework.stereotype.Component; + +@Component +@Local(value = { VpcDetailsDao.class }) +public class VpcDetailsDaoImpl extends ResourceDetailsDaoBase implements VpcDetailsDao { + + @Override + public void addDetail(long resourceId, String key, String value) { + super.addDetail(new VpcDetailVO(resourceId, key, value)); + } +} diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/VpcGatewayDetailsDao.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/VpcGatewayDetailsDao.java new file mode 100644 index 000000000000..4f1691926a85 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/VpcGatewayDetailsDao.java @@ -0,0 +1,27 @@ +// 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.VpcGatewayDetailVO; + +import com.cloud.utils.db.GenericDao; + +public interface VpcGatewayDetailsDao extends GenericDao, ResourceDetailsDao { + +} + diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/VpcGatewayDetailsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/VpcGatewayDetailsDaoImpl.java new file mode 100644 index 000000000000..2b4c563a4cf8 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/dao/VpcGatewayDetailsDaoImpl.java @@ -0,0 +1,33 @@ +// 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.VpcGatewayDetailVO; +import org.springframework.stereotype.Component; + +@Component +@Local(value = { VpcGatewayDetailsDao.class }) +public class VpcGatewayDetailsDaoImpl extends ResourceDetailsDaoBase implements VpcGatewayDetailsDao { + + @Override + public void addDetail(long resourceId, String key, String value) { + super.addDetail(new VpcGatewayDetailVO(resourceId, key, value)); + } +} \ No newline at end of file diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreVO.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreVO.java index 5ed48a3781c8..387e096ff057 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreVO.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreVO.java @@ -31,6 +31,7 @@ import com.cloud.storage.DataStoreRole; import com.cloud.storage.ImageStore; import com.cloud.storage.ScopeType; +import com.cloud.utils.UriUtils; import com.cloud.utils.db.GenericDao; @Entity @@ -144,7 +145,11 @@ public String getUuid() { } public String getUrl() { - return url; + String updatedUrl = url; + if ("cifs".equalsIgnoreCase(this.protocol)) { + updatedUrl = UriUtils.getUpdateUri(updatedUrl, false); + } + return updatedUrl; } public void setUrl(String url) { diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java index 59c338e28036..a3cb76fe123e 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java @@ -114,4 +114,6 @@ List findPoolsByDetails(long dcId, long podId, Long clusterId, Ma List findZoneWideStoragePoolsByTags(long dcId, String[] tags); List findZoneWideStoragePoolsByHypervisor(long dataCenterId, HypervisorType hypervisorType); + + List findLocalStoragePoolsByHostAndTags(long hostId, String[] tags); } diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java index d35aa440f742..eea07628af88 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java @@ -24,19 +24,21 @@ import java.util.List; import java.util.Map; +import javax.annotation.PostConstruct; import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.springframework.stereotype.Component; - import com.cloud.host.Status; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.ScopeType; +import com.cloud.storage.StoragePoolHostVO; import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.QueryBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; @@ -45,7 +47,6 @@ import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.exception.CloudRuntimeException; - @Local(value = { PrimaryDataStoreDao.class }) @DB() public class PrimaryDataStoreDaoImpl extends GenericDaoBase implements PrimaryDataStoreDao { @@ -54,8 +55,12 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase protected final SearchBuilder DcPodAnyClusterSearch; protected final SearchBuilder DeleteLvmSearch; protected final GenericSearchBuilder StatusCountSearch; + protected SearchBuilder HostSearch; + protected SearchBuilder HostPoolSearch; + protected SearchBuilder TagPoolSearch; @Inject protected StoragePoolDetailsDao _detailsDao; + @Inject protected StoragePoolHostDao _hostDao; private final String DetailsSqlPrefix = "SELECT storage_pool.* from storage_pool LEFT JOIN storage_pool_details ON storage_pool.id = storage_pool_details.pool_id WHERE storage_pool.removed is null and storage_pool.status = 'Up' and storage_pool.data_center_id = ? and (storage_pool.pod_id = ? or storage_pool.pod_id is null) and storage_pool.scope = ? and ("; private final String DetailsSqlSuffix = ") GROUP BY storage_pool_details.pool_id HAVING COUNT(storage_pool_details.name) >= ?"; @@ -112,6 +117,26 @@ public PrimaryDataStoreDaoImpl() { } + @PostConstruct + void init() { + HostSearch = createSearchBuilder(); + TagPoolSearch = _detailsDao.createSearchBuilder(); + HostPoolSearch = _hostDao.createSearchBuilder(); + // Search for pools on the host + HostPoolSearch.and("hostId", HostPoolSearch.entity().getHostId(), Op.EQ); + // Set criteria for pools + HostSearch.and("scope", HostSearch.entity().getScope(), Op.EQ); + HostSearch.and("removed", HostSearch.entity().getRemoved(), Op.NULL); + HostSearch.and("status", HostSearch.entity().getStatus(), Op.EQ); + HostSearch.join("hostJoin", HostPoolSearch, HostSearch.entity().getId(), HostPoolSearch.entity().getPoolId(), JoinBuilder.JoinType.INNER); + // Set criteria for tags + TagPoolSearch.and("name", TagPoolSearch.entity().getName(), Op.EQ); + TagPoolSearch.and("value", TagPoolSearch.entity().getValue(), Op.EQ); + + HostSearch.join("tagJoin", TagPoolSearch, HostSearch.entity().getId(), TagPoolSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); + HostSearch.done(); + } + @Override public List findPoolByName(String name) { SearchCriteria sc = AllFieldSearch.create(); @@ -353,6 +378,23 @@ public List findZoneWideStoragePoolsByTags(long dcId, String[] ta } } + @Override + public List findLocalStoragePoolsByHostAndTags(long hostId, String[] tags) { + + SearchCriteria sc = HostSearch.create(); + sc.setJoinParameters("hostJoin", "hostId", hostId ); + sc.setParameters("scope", ScopeType.HOST.toString()); + sc.setParameters("status", Status.Up.toString()); + if (!(tags == null || tags.length == 0 )) { + Map details = tagsToDetails(tags); + for (Map.Entry detail : details.entrySet()) { + sc.setJoinParameters("tagJoin","name", detail.getKey()); + sc.setJoinParameters("tagJoin", "value", detail.getValue()); + } + } + return listBy(sc); + } + @Override @DB public List searchForStoragePoolDetails(long poolId, String value) { diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java index dfa03adf29b7..b995fbb20aa9 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java @@ -47,7 +47,11 @@ public interface SnapshotDataStoreDao extends GenericDao listOnCache(long snapshotId); void updateStoreRoleToCache(long storeId); + + SnapshotDataStoreVO findLatestSnapshotForVolume(Long volumeId, DataStoreRole role); } diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailVO.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailVO.java index 5968fd28539d..ee22d74d6aeb 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailVO.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailVO.java @@ -43,7 +43,7 @@ public class StoragePoolDetailVO implements ResourceDetail { String value; @Column(name="display") - private boolean display; + private boolean display = true; public StoragePoolDetailVO(long poolId, String name, String value) { this.resourceId = poolId; diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java index 557c96456ab1..0d1e43db1c23 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java @@ -30,10 +30,11 @@ import javax.persistence.TemporalType; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.ScopeType; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolStatus; +import com.cloud.utils.UriUtils; import com.cloud.utils.db.GenericDao; @Entity @@ -135,10 +136,10 @@ public StoragePoolVO(long poolId, String name, String uuid, StoragePoolType type this.usedBytes = availableBytes; this.capacityBytes = capacityBytes; this.hostAddress = hostAddress; - this.path = hostPath; this.port = port; this.podId = podId; this.setStatus(StoragePoolStatus.Initial); + this.setPath(hostPath); } public StoragePoolVO(StoragePoolVO that) { @@ -150,9 +151,9 @@ public StoragePoolVO(StoragePoolType type, String hostAddress, int port, String this.poolType = type; this.hostAddress = hostAddress; this.port = port; - this.path = path; this.setStatus(StoragePoolStatus.Initial); this.uuid = UUID.randomUUID().toString(); + this.setPath(path); } public String getName() { @@ -244,7 +245,12 @@ public void setHostAddress(String host) { } public String getPath() { - return path; + String updatedPath = path; + if (this.poolType == StoragePoolType.SMB) { + updatedPath = UriUtils.getUpdateUri(updatedPath, false); + } + + return updatedPath; } public String getUserInfo() { diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreDao.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreDao.java index 93adaaf5c8b5..3e5173128b10 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreDao.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreDao.java @@ -24,6 +24,7 @@ import com.cloud.storage.DataStoreRole; import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.utils.db.GenericDao; import com.cloud.utils.fsm.StateDao; @@ -53,16 +54,22 @@ List listByTemplateZoneDownloadStatus(long templateId, Long TemplateDataStoreVO findByTemplateZoneDownloadStatus(long templateId, Long zoneId, VMTemplateStorageResourceAssoc.Status... status); + TemplateDataStoreVO findByTemplateZoneStagingDownloadStatus(long templateId, Long zoneId, Status... status); + TemplateDataStoreVO findByStoreTemplate(long storeId, long templateId); TemplateDataStoreVO findByStoreTemplate(long storeId, long templateId, boolean lock); TemplateDataStoreVO findByTemplate(long templateId, DataStoreRole role); + TemplateDataStoreVO findReadyByTemplate(long templateId, DataStoreRole role); + TemplateDataStoreVO findByTemplateZone(long templateId, Long zoneId, DataStoreRole role); List listByTemplate(long templateId); + TemplateDataStoreVO findByTemplateZoneReady(long templateId, Long zoneId); + void duplicateCacheRecordsOnRegionStore(long storeId); TemplateDataStoreVO findReadyOnCache(long templateId); diff --git a/engine/service/pom.xml b/engine/service/pom.xml index 2a53844dff4f..9d9ae6e6f9ba 100644 --- a/engine/service/pom.xml +++ b/engine/service/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloud-engine - 4.3.0-SNAPSHOT + 4.3.0 cloud-engine-service war diff --git a/engine/storage/cache/pom.xml b/engine/storage/cache/pom.xml index acb279278f7a..b6d195f9e43a 100644 --- a/engine/storage/cache/pom.xml +++ b/engine/storage/cache/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloud-engine - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/allocator/StorageCacheAllocator.java b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/allocator/StorageCacheAllocator.java index 4259d9ed03f1..9f0052f659c0 100644 --- a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/allocator/StorageCacheAllocator.java +++ b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/allocator/StorageCacheAllocator.java @@ -18,9 +18,12 @@ */ package org.apache.cloudstack.storage.cache.allocator; +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.Scope; public interface StorageCacheAllocator { DataStore getCacheStore(Scope scope); + + DataStore getCacheStore(DataObject data, Scope scope); } diff --git a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/allocator/StorageCacheRandomAllocator.java b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/allocator/StorageCacheRandomAllocator.java index 3b434d175fdd..0054e3dcae13 100644 --- a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/allocator/StorageCacheRandomAllocator.java +++ b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/allocator/StorageCacheRandomAllocator.java @@ -23,9 +23,14 @@ import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.Scope; +import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; + import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -36,6 +41,8 @@ public class StorageCacheRandomAllocator implements StorageCacheAllocator { private static final Logger s_logger = Logger.getLogger(StorageCacheRandomAllocator.class); @Inject DataStoreManager dataStoreMgr; + @Inject + ObjectInDataStoreManager objectInStoreMgr; @Override public DataStore getCacheStore(Scope scope) { @@ -53,4 +60,36 @@ public DataStore getCacheStore(Scope scope) { Collections.shuffle(cacheStores); return cacheStores.get(0); } + + @Override + public DataStore getCacheStore(DataObject data, Scope scope) { + if (scope.getScopeType() != ScopeType.ZONE) { + s_logger.debug("Can only support zone wide cache storage"); + return null; + } + + List cacheStores = dataStoreMgr.getImageCacheStores(scope); + if (cacheStores.size() <= 0) { + s_logger.debug("Can't find staging storage in zone: " + scope.getScopeId()); + return null; + } + + // if there are multiple cache stores, we give priority to the one where data is already there + if (cacheStores.size() > 1) { + for (DataStore store : cacheStores) { + DataObjectInStore obj = objectInStoreMgr.findObject(data, store); + if (obj != null && obj.getState() == ObjectInDataStoreStateMachine.State.Ready) { + s_logger.debug("pick the cache store " + store.getId() + " where data is already there"); + return store; + } + } + + // otherwise, just random pick one + Collections.shuffle(cacheStores); + } + return cacheStores.get(0); + + } + + } diff --git a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java index bb8d67d321fe..7c74729bc287 100644 --- a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java +++ b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java @@ -90,6 +90,19 @@ public DataStore getCacheStorage(Scope scope) { return null; } + + @Override + public DataStore getCacheStorage(DataObject data, Scope scope) { + for (StorageCacheAllocator allocator : storageCacheAllocator) { + DataStore store = allocator.getCacheStore(data, scope); + if (store != null) { + return store; + } + } + return null; + } + + protected List getCacheStores() { QueryBuilder sc = QueryBuilder.create(ImageStoreVO.class); sc.and(sc.entity().getRole(), SearchCriteria.Op.EQ,DataStoreRole.ImageCache); diff --git a/engine/storage/datamotion/pom.xml b/engine/storage/datamotion/pom.xml index 5e4f7322fc9e..2a785b3dc0be 100644 --- a/engine/storage/datamotion/pom.xml +++ b/engine/storage/datamotion/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java index 67cc324bc5ca..d6759cb95375 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java @@ -18,6 +18,7 @@ */ package org.apache.cloudstack.storage.motion; +import java.util.HashMap; import java.util.Map; import javax.inject.Inject; @@ -37,6 +38,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.StorageAction; import org.apache.cloudstack.engine.subsystem.api.storage.StorageCacheManager; import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; @@ -65,6 +67,7 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.VirtualMachineManager; @Component public class @@ -162,7 +165,7 @@ protected Answer copyObject(DataObject srcData, DataObject destData) { srcForCopy = cacheData = cacheMgr.createCacheObject(srcData, destScope); } - CopyCommand cmd = new CopyCommand(srcForCopy.getTO(), destData.getTO(), _primaryStorageDownloadWait, _mgmtServer.getExecuteInSequence()); + CopyCommand cmd = new CopyCommand(srcForCopy.getTO(), destData.getTO(), _primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); EndPoint ep = selector.select(srcForCopy, destData); if (ep == null) { String errMsg = "No remote endpoint to send command, check if host or ssvm is down?"; @@ -196,9 +199,9 @@ protected Answer copyObject(DataObject srcData, DataObject destData) { } } - protected DataObject cacheSnapshotChain(SnapshotInfo snapshot) { + protected DataObject cacheSnapshotChain(SnapshotInfo snapshot, Scope scope) { DataObject leafData = null; - DataStore store = cacheMgr.getCacheStorage(snapshot.getDataStore().getScope()); + DataStore store = cacheMgr.getCacheStorage(snapshot, scope); while (snapshot != null) { DataObject cacheData = cacheMgr.createCacheObject(snapshot, store); if (leafData == null) { @@ -209,6 +212,7 @@ protected DataObject cacheSnapshotChain(SnapshotInfo snapshot) { return leafData; } + protected void deleteSnapshotCacheChain(SnapshotInfo snapshot) { while (snapshot != null) { cacheMgr.deleteCacheObject(snapshot); @@ -233,7 +237,8 @@ protected Answer copyVolumeFromSnapshot(DataObject snapObj, DataObject volObj) { DataObject srcData = snapObj; try { if (!(storTO instanceof NfsTO)) { - srcData = cacheSnapshotChain(snapshot); + // cache snapshot to zone-wide staging store for the volume to be created + srcData = cacheSnapshotChain(snapshot, new ZoneScope(pool.getDataCenterId())); } String value = configDao.getValue(Config.CreateVolumeFromSnapshotWait.toString()); @@ -244,10 +249,10 @@ protected Answer copyVolumeFromSnapshot(DataObject snapObj, DataObject volObj) { if (srcData.getDataStore().getRole() == DataStoreRole.Primary) { ep = selector.select(volObj); } else { - ep = selector.select(snapObj, volObj); + ep = selector.select(srcData, volObj); } - CopyCommand cmd = new CopyCommand(srcData.getTO(), volObj.getTO(), _createVolumeFromSnapshotWait, _mgmtServer.getExecuteInSequence()); + CopyCommand cmd = new CopyCommand(srcData.getTO(), volObj.getTO(), _createVolumeFromSnapshotWait, VirtualMachineManager.ExecuteInSequence.value()); Answer answer = null; if (ep == null) { String errMsg = "No remote endpoint to send command, check if host or ssvm is down?"; @@ -270,7 +275,7 @@ protected Answer copyVolumeFromSnapshot(DataObject snapObj, DataObject volObj) { } protected Answer cloneVolume(DataObject template, DataObject volume) { - CopyCommand cmd = new CopyCommand(template.getTO(), volume.getTO(), 0, _mgmtServer.getExecuteInSequence()); + CopyCommand cmd = new CopyCommand(template.getTO(), volume.getTO(), 0, VirtualMachineManager.ExecuteInSequence.value()); try { EndPoint ep = selector.select(volume.getDataStore()); Answer answer = null; @@ -320,7 +325,7 @@ protected Answer copyVolumeBetweenPools(DataObject srcData, DataObject destData) objOnImageStore.processEvent(Event.CopyingRequested); - CopyCommand cmd = new CopyCommand(objOnImageStore.getTO(), destData.getTO(), _copyvolumewait, _mgmtServer.getExecuteInSequence()); + CopyCommand cmd = new CopyCommand(objOnImageStore.getTO(), destData.getTO(), _copyvolumewait, VirtualMachineManager.ExecuteInSequence.value()); EndPoint ep = selector.select(objOnImageStore, destData); if (ep == null) { String errMsg = "No remote endpoint to send command, check if host or ssvm is down?"; @@ -344,7 +349,7 @@ protected Answer copyVolumeBetweenPools(DataObject srcData, DataObject destData) return answer; } else { DataObject cacheData = cacheMgr.createCacheObject(srcData, destScope); - CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _copyvolumewait, _mgmtServer.getExecuteInSequence()); + CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _copyvolumewait, VirtualMachineManager.ExecuteInSequence.value()); EndPoint ep = selector.select(cacheData, destData); Answer answer = null; if (ep == null) { @@ -366,7 +371,7 @@ protected Answer copyVolumeBetweenPools(DataObject srcData, DataObject destData) protected Answer migrateVolumeToPool(DataObject srcData, DataObject destData) { VolumeInfo volume = (VolumeInfo)srcData; StoragePool destPool = (StoragePool)dataStoreMgr.getDataStore(destData.getDataStore().getId(), DataStoreRole.Primary); - MigrateVolumeCommand command = new MigrateVolumeCommand(volume.getId(), volume.getPath(), destPool); + MigrateVolumeCommand command = new MigrateVolumeCommand(volume.getId(), volume.getPath(), destPool, volume.getAttachedVmName()); EndPoint ep = selector.select(volume.getDataStore()); Answer answer = null; if (ep == null) { @@ -447,7 +452,7 @@ protected Answer createTemplateFromSnapshot(DataObject srcData, DataObject destD if (needCacheStorage(srcData, destData)) { needCache = true; SnapshotInfo snapshot = (SnapshotInfo) srcData; - srcData = cacheSnapshotChain(snapshot); + srcData = cacheSnapshotChain(snapshot, snapshot.getDataStore().getScope()); } EndPoint ep = null; @@ -457,7 +462,7 @@ protected Answer createTemplateFromSnapshot(DataObject srcData, DataObject destD ep = selector.select(srcData, destData); } - CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _createprivatetemplatefromsnapshotwait, _mgmtServer.getExecuteInSequence()); + CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _createprivatetemplatefromsnapshotwait, VirtualMachineManager.ExecuteInSequence.value()); Answer answer = null; if (ep == null) { String errMsg = "No remote endpoint to send command, check if host or ssvm is down?"; @@ -480,14 +485,23 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) { Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue())); DataObject cacheData = null; + SnapshotInfo snapshotInfo = (SnapshotInfo)srcData; + Object payload = snapshotInfo.getPayload(); + Boolean fullSnapshot = true; + if (payload != null) { + fullSnapshot = (Boolean)payload; + } + Map options = new HashMap(); + options.put("fullSnapshot", fullSnapshot.toString()); Answer answer = null; try { if (needCacheStorage(srcData, destData)) { Scope selectedScope = pickCacheScopeForCopy(srcData, destData); cacheData = cacheMgr.getCacheObject(srcData, selectedScope); - CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait, _mgmtServer.getExecuteInSequence()); + CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait, VirtualMachineManager.ExecuteInSequence.value()); cmd.setCacheTO(cacheData.getTO()); + cmd.setOptions(options); EndPoint ep = selector.select(srcData, destData); if (ep == null) { String errMsg = "No remote endpoint to send command, check if host or ssvm is down?"; @@ -497,8 +511,9 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) { answer = ep.sendMessage(cmd); } } else { - CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait, _mgmtServer.getExecuteInSequence()); - EndPoint ep = selector.select(srcData, destData); + CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait, VirtualMachineManager.ExecuteInSequence.value()); + cmd.setOptions(options); + EndPoint ep = selector.select(srcData, destData, StorageAction.BACKUPSNAPSHOT); if (ep == null) { String errMsg = "No remote endpoint to send command, check if host or ssvm is down?"; s_logger.error(errMsg); @@ -506,12 +521,11 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) { } else { answer = ep.sendMessage(cmd); } + } - // clean up cache entry in case of failure - if (answer == null || !answer.getResult()) { - if (cacheData != null) { - cacheMgr.deleteCacheObject(cacheData); - } + // clean up cache entry + if (cacheData != null) { + cacheMgr.deleteCacheObject(cacheData); } return answer; } catch (Exception e) { diff --git a/engine/storage/image/pom.xml b/engine/storage/image/pom.xml index 6a30f189f271..1aa72f4e9db3 100644 --- a/engine/storage/image/pom.xml +++ b/engine/storage/image/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java index 63693112cac9..a3557d787884 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java @@ -23,6 +23,7 @@ import javax.inject.Inject; +import com.cloud.utils.exception.CloudRuntimeException; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -106,6 +107,17 @@ public TemplateInfo getTemplate(long templateId, DataStoreRole storeRole, Long z return this.getTemplate(templateId, store); } + @Override + public TemplateInfo getReadyTemplateOnImageStore(long templateId, Long zoneId) { + TemplateDataStoreVO tmplStore = templateStoreDao.findByTemplateZoneReady(templateId, zoneId); + if (tmplStore != null) { + DataStore store = storeMgr.getDataStore(tmplStore.getDataStoreId(), DataStoreRole.Image); + return this.getTemplate(templateId, store); + } else { + return null; + } + } + @Override public TemplateInfo getTemplate(DataObject obj, DataStore store) { TemplateObject tmpObj = (TemplateObject) this.getTemplate(obj.getId(), store); diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index 308347d8a389..1dd288185aa4 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -41,6 +41,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.StorageCacheManager; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory; @@ -74,9 +75,10 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.DataStoreRole; -import com.cloud.storage.ScopeType; +import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.StoragePool; +import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateZoneVO; @@ -281,7 +283,7 @@ public void handleTemplateSync(DataStore store) { GlobalLock syncLock = GlobalLock.getInternLock(lockString); try { if (syncLock.lock(3)) { - try{ + try { Long zoneId = store.getScope().getScopeId(); Map templateInfos = listTemplate(store); @@ -369,7 +371,7 @@ public void handleTemplateSync(DataStore store) { tmpltInfo.getSize() - UriUtils.getRemoteSize(tmplt.getUrl())); } catch (ResourceAllocationException e) { s_logger.warn(e.getMessage()); - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED, zoneId, null, + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED, zoneId, null, e.getMessage(), e.getMessage()); } finally { _resourceLimitMgr.recalculateResourceCount(accountId, _accountMgr.getAccount(accountId) @@ -393,14 +395,20 @@ public void handleTemplateSync(DataStore store) { _templateDao.update(tmplt.getId(), tmlpt); associateTemplateToZone(tmplt.getId(), zoneId); - } } else { s_logger.info("Template Sync did not find " + uniqueName + " on image store " + storeId + ", may request download based on available hypervisor types"); if (tmpltStore != null) { - s_logger.info("Removing leftover template " + uniqueName + " entry from template store table"); - // remove those leftover entries - _vmTemplateStoreDao.remove(tmpltStore.getId()); + if (_storeMgr.isRegionStore(store) && tmpltStore.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED + && tmpltStore.getState() == State.Ready + && tmpltStore.getInstallPath() == null) { + s_logger.info("Keep fake entry in template store table for migration of previous NFS to object store"); + } + else { + s_logger.info("Removing leftover template " + uniqueName + " entry from template store table"); + // remove those leftover entries + _vmTemplateStoreDao.remove(tmpltStore.getId()); + } } } } @@ -430,6 +438,17 @@ public void handleTemplateSync(DataStore store) { continue; } + // if this is a region store, and there is already an DOWNLOADED entry there without install_path information, which + // means that this is a duplicate entry from migration of previous NFS to staging. + if (_storeMgr.isRegionStore(store)) { + TemplateDataStoreVO tmpltStore = _vmTemplateStoreDao.findByStoreTemplate(storeId, tmplt.getId()); + if (tmpltStore != null && tmpltStore.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED && tmpltStore.getState() == State.Ready + && tmpltStore.getInstallPath() == null) { + s_logger.info("Skip sync template for migration of previous NFS to object store"); + continue; + } + } + if (availHypers.contains(tmplt.getHypervisorType())) { s_logger.info("Downloading template " + tmplt.getUniqueName() + " to image store " + store.getName()); @@ -474,8 +493,7 @@ public void handleTemplateSync(DataStore store) { } } - } - finally{ + } finally { syncLock.unlock(); } } @@ -682,18 +700,14 @@ protected Void syncTemplateCallBack(AsyncCallbackDispatcher copyTemplate(TemplateInfo srcTemplate, DataStore destStore) { + // for vmware template, we need to check if ova packing is needed, since template created from snapshot does not have .ova file + // we invoke createEntityExtractURL to trigger ova packing. Ideally, we can directly use extractURL to pass to following createTemplate. + // Need to understand what is the background to use two different urls for copy and extract. + if (srcTemplate.getFormat() == ImageFormat.OVA){ + ImageStoreEntity tmpltStore = (ImageStoreEntity)srcTemplate.getDataStore(); + tmpltStore.createEntityExtractUrl(srcTemplate.getInstallPath(), srcTemplate.getFormat(), srcTemplate); + } // generate a URL from source template ssvm to download to destination data store String url = generateCopyUrl(srcTemplate); if (url == null) { @@ -772,12 +793,21 @@ private String generateCopyUrl(String ipAddress, String dir, String path){ String scheme = "http"; boolean _sslCopy = false; String sslCfg = _configDao.getValue(Config.SecStorageEncryptCopy.toString()); + String _ssvmUrlDomain = _configDao.getValue("secstorage.ssl.cert.domain"); if ( sslCfg != null ){ _sslCopy = Boolean.parseBoolean(sslCfg); } + if(_sslCopy && (_ssvmUrlDomain == null || _ssvmUrlDomain.isEmpty())){ + s_logger.warn("Empty secondary storage url domain, ignoring SSL"); + _sslCopy = false; + } if (_sslCopy) { - hostname = ipAddress.replace(".", "-"); - hostname = hostname + ".realhostip.com"; + if(_ssvmUrlDomain.startsWith("*")) { + hostname = ipAddress.replace(".", "-"); + hostname = hostname + _ssvmUrlDomain.substring(1); + } else { + hostname = _ssvmUrlDomain; + } scheme = "https"; } return scheme + "://" + hostname + "/copy/SecStorage/" + dir + "/" + path; diff --git a/engine/storage/integration-test/pom.xml b/engine/storage/integration-test/pom.xml index 4e5fdeb7eb90..81dc863bb84d 100644 --- a/engine/storage/integration-test/pom.xml +++ b/engine/storage/integration-test/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java index de64b8f5ca2a..399d2d1dc60e 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java @@ -18,6 +18,8 @@ */ package org.apache.cloudstack.storage.test; +import java.util.List; +import java.util.Map; import java.util.UUID; import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; @@ -35,12 +37,32 @@ import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; +import com.cloud.host.Host; +import com.cloud.storage.StoragePool; +import com.cloud.storage.Volume; public class FakePrimaryDataStoreDriver implements PrimaryDataStoreDriver { boolean snapshotResult = true; + + @Override + public Map getCapabilities() { + return null; + } + @Override public ChapInfo getChapInfo(VolumeInfo volumeInfo) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; // To change body of implemented methods, use File | Settings | File Templates. + } + + @Override + public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { return false; } + + @Override + public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {} + + @Override + public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { + return volume.getSize(); } @Override diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java index 550a6bfc7b56..b1b614bcd246 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java @@ -276,8 +276,7 @@ protected void injectMockito() { resourceMgr.listAllUpAndEnabledHosts((Type) Matchers.any(), Matchers.anyLong(), Matchers.anyLong(), Matchers.anyLong())).thenReturn(hosts); - remoteEp = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host.getId(), this.host.getPrivateIpAddress(), - this.host.getPublicIpAddress()); + remoteEp = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host); Mockito.when(epSelector.select(Matchers.any(DataObject.class), Matchers.any(DataObject.class))).thenReturn( remoteEp); Mockito.when(epSelector.select(Matchers.any(DataObject.class))).thenReturn(remoteEp); diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java index cbfafc93333e..fcba047ab950 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java @@ -255,8 +255,7 @@ protected void injectMockito() { resourceMgr.listAllUpAndEnabledHosts((Type) Matchers.any(), Matchers.anyLong(), Matchers.anyLong(), Matchers.anyLong())).thenReturn(hosts); - RemoteHostEndPoint ep = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host.getId(), - this.host.getPrivateIpAddress(), this.host.getPublicIpAddress()); + RemoteHostEndPoint ep = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host); Mockito.when(epSelector.select(Matchers.any(DataObject.class), Matchers.any(DataObject.class))).thenReturn(ep); Mockito.when(epSelector.select(Matchers.any(DataObject.class))).thenReturn(ep); Mockito.when(epSelector.select(Matchers.any(DataStore.class))).thenReturn(ep); diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTestVmware.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTestVmware.java index be9dd19c6b0a..32805f4103e0 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTestVmware.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTestVmware.java @@ -257,8 +257,7 @@ protected void injectMockito() { resourceMgr.listAllUpAndEnabledHosts((Type) Matchers.any(), Matchers.anyLong(), Matchers.anyLong(), Matchers.anyLong())).thenReturn(hosts); - RemoteHostEndPoint ep = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host.getId(), - this.host.getPrivateIpAddress(), this.host.getPublicIpAddress()); + RemoteHostEndPoint ep = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host); Mockito.when(epSelector.select(Matchers.any(DataObject.class), Matchers.any(DataObject.class))).thenReturn(ep); Mockito.when(epSelector.select(Matchers.any(DataObject.class))).thenReturn(ep); Mockito.when(epSelector.select(Matchers.any(DataStore.class))).thenReturn(ep); diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java index 08de7f3a9419..4195d0511b62 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java @@ -194,8 +194,7 @@ protected void injectMockito() { Mockito.when(hostDao.findById(Matchers.anyLong())).thenReturn(host); Mockito.when(hostDao.findHypervisorHostInCluster(Matchers.anyLong())).thenReturn(results); List eps = new ArrayList(); - eps.add(RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(), host.getPrivateIpAddress(), - host.getPublicIpAddress())); + eps.add(RemoteHostEndPoint.getHypervisorHostEndPoint(host)); Mockito.when(selector.selectAll(Matchers.any(DataStore.class))).thenReturn(eps); Mockito.when(selector.select(Matchers.any(DataObject.class))).thenReturn(eps.get(0)); Mockito.when(selector.select(Matchers.any(DataObject.class), Matchers.any(DataObject.class))).thenReturn( diff --git a/engine/storage/pom.xml b/engine/storage/pom.xml index 91fc879e8891..a2c43a1cfeb3 100644 --- a/engine/storage/pom.xml +++ b/engine/storage/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml diff --git a/engine/storage/snapshot/pom.xml b/engine/storage/snapshot/pom.xml index 808d0c207a69..fb595cd303d7 100644 --- a/engine/storage/snapshot/pom.xml +++ b/engine/storage/snapshot/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java index 6205fe40deb8..16c14f3c36d7 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java @@ -79,6 +79,18 @@ public SnapshotInfo getSnapshot(long snapshotId, DataStoreRole role) { return so; } + @Override + public SnapshotInfo getReadySnapshotOnCache(long snapshotId) { + SnapshotDataStoreVO snapStore = snapshotStoreDao.findReadyOnCache(snapshotId); + if (snapStore != null) { + DataStore store = storeMgr.getDataStore(snapStore.getDataStoreId(), DataStoreRole.ImageCache); + return getSnapshot(snapshotId, store); + } else { + return null; + } + + } + @Override public List listSnapshotOnCache(long snapshotId) { List cacheSnapshots = snapshotStoreDao.listOnCache(snapshotId); diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java index ee02eed8f6c4..a69b2d77f02d 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java @@ -19,10 +19,11 @@ package org.apache.cloudstack.storage.snapshot; import java.util.Date; -import java.util.List; import javax.inject.Inject; +import org.apache.log4j.Logger; + import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; @@ -30,7 +31,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy.SnapshotOperation; -import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; import org.apache.cloudstack.engine.subsystem.api.storage.StorageStrategyFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; @@ -40,7 +40,6 @@ import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; import org.apache.cloudstack.storage.to.SnapshotObjectTO; -import org.apache.log4j.Logger; import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.DataObjectType; @@ -79,6 +78,7 @@ public class SnapshotObject implements SnapshotInfo { SnapshotDataStoreDao snapshotStoreDao; @Inject StorageStrategyFactory storageStrategyFactory; + private String installPath; // temporarily set installPath before passing to resource for entries with empty installPath for object store migration case public SnapshotObject() { @@ -200,6 +200,9 @@ public long getVolumeId() { @Override public String getPath() { + if (installPath != null) + return installPath; + DataObjectInStore objectInStore = objectInStoreMgr.findObject(this, getDataStore()); if (objectInStore != null) { return objectInStore.getInstallPath(); @@ -207,6 +210,10 @@ public String getPath() { return null; } + public void setPath(String installPath) { + this.installPath = installPath; + } + @Override public String getName() { return snapshot.getName(); @@ -281,6 +288,10 @@ public void processEvent(ObjectInDataStoreStateMachine.Event event, Answer answe } else if (answer instanceof CopyCmdAnswer) { SnapshotObjectTO snapshotTO = (SnapshotObjectTO) ((CopyCmdAnswer) answer).getNewData(); snapshotStore.setInstallPath(snapshotTO.getPath()); + if (snapshotTO.getPhysicalSize() != null) { + // For S3 delta snapshot, physical size is currently not set + snapshotStore.setSize(snapshotTO.getPhysicalSize()); + } if (snapshotTO.getParentSnapshotPath() == null) { snapshotStore.setParentSnapshotId(0L); } @@ -359,12 +370,12 @@ public ObjectInDataStoreStateMachine.State getStatus() { @Override public void addPayload(Object data) { - this.payload = data; + payload = data; } @Override public Object getPayload() { - return this.payload; + return payload; } @Override diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java index 9b73bea5211f..e967b06d20e6 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java @@ -17,10 +17,14 @@ package org.apache.cloudstack.storage.snapshot; -import com.cloud.storage.DataStoreRole; -import com.cloud.storage.Snapshot; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.fsm.NoTransitionException; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import javax.inject.Inject; + +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + 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.DataMotionService; @@ -28,11 +32,13 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotResult; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService; +import org.apache.cloudstack.engine.subsystem.api.storage.StorageCacheManager; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; @@ -40,26 +46,32 @@ import org.apache.cloudstack.framework.async.AsyncRpcContext; import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.command.CopyCmdAnswer; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; -import javax.inject.Inject; -import java.util.concurrent.ExecutionException; +import com.cloud.storage.DataStoreRole; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.template.TemplateConstants; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.NoTransitionException; @Component public class SnapshotServiceImpl implements SnapshotService { private static final Logger s_logger = Logger.getLogger(SnapshotServiceImpl.class); @Inject + protected SnapshotDao _snapshotDao; + @Inject protected SnapshotDataStoreDao _snapshotStoreDao; @Inject - SnapshotDataFactory snapshotfactory; + SnapshotDataFactory _snapshotFactory; @Inject DataStoreManager dataStoreMgr; @Inject DataMotionService motionSrv; + @Inject + StorageCacheManager _cacheMgr; static private class CreateSnapshotContext extends AsyncRpcContext { final SnapshotInfo snapshot; @@ -219,7 +231,12 @@ public SnapshotResult takeSnapshot(SnapshotInfo snap) { // the same store as its parent since // we are taking delta snapshot private DataStore findSnapshotImageStore(SnapshotInfo snapshot) { - if (snapshot.getParent() == null) { + Boolean fullSnapshot = true; + Object payload = snapshot.getPayload(); + if (payload != null) { + fullSnapshot = (Boolean)payload; + } + if (fullSnapshot) { return dataStoreMgr.getImageStore(snapshot.getDataCenterId()); } else { SnapshotInfo parentSnapshot = snapshot.getParent(); @@ -244,7 +261,7 @@ public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) { try { snapObj.processEvent(Snapshot.Event.BackupToSecondary); - DataStore imageStore = this.findSnapshotImageStore(snapshot); + DataStore imageStore = findSnapshotImageStore(snapshot); if (imageStore == null) { throw new CloudRuntimeException("can not find an image stores"); } @@ -257,7 +274,7 @@ public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) { AsyncCallbackDispatcher caller = AsyncCallbackDispatcher .create(this); caller.setCallback(caller.getTarget().copySnapshotAsyncCallback(null, null)).setContext(context); - this.motionSrv.copyAsync(snapshot, snapshotOnImageStore, caller); + motionSrv.copyAsync(snapshot, snapshotOnImageStore, caller); } catch (Exception e) { s_logger.debug("Failed to copy snapshot", e); result.setResult("Failed to copy snapshot:" + e.toString()); @@ -296,6 +313,10 @@ protected Void copySnapshotAsyncCallback(AsyncCallbackDispatcher future = new AsyncCallFuture(); @@ -424,4 +445,94 @@ public boolean revertSnapshot(Long snapshotId) { return false; } + + // This routine is used to push snapshots currently on cache store, but not in region store to region store. + // used in migrating existing NFS secondary storage to S3. We chose to push all volume related snapshots to handle delta snapshots smoothly. + @Override + public void syncVolumeSnapshotsToRegionStore(long volumeId, DataStore store) { + if (dataStoreMgr.isRegionStore(store)) { + // list all backed up snapshots for the given volume + List snapshots = _snapshotDao.listByStatus(volumeId, Snapshot.State.BackedUp); + if (snapshots != null ){ + for (SnapshotVO snapshot : snapshots){ + syncSnapshotToRegionStore(snapshot.getId(), store); + } + } + } + } + + // push one individual snapshots currently on cache store to region store if it is not there already + private void syncSnapshotToRegionStore(long snapshotId, DataStore store){ + // if snapshot is already on region wide object store, check if it is really downloaded there (by checking install_path). Sync snapshot to region + // wide store if it is not there physically. + SnapshotInfo snapOnStore = _snapshotFactory.getSnapshot(snapshotId, store); + if (snapOnStore == null) { + throw new CloudRuntimeException("Cannot find an entry in snapshot_store_ref for snapshot " + snapshotId + " on region store: " + store.getName()); + } + if (snapOnStore.getPath() == null || snapOnStore.getPath().length() == 0) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("sync snapshot " + snapshotId + " from cache to object store..."); + } + // snapshot is not on region store yet, sync to region store + SnapshotInfo srcSnapshot = _snapshotFactory.getReadySnapshotOnCache(snapshotId); + if (srcSnapshot == null) { + throw new CloudRuntimeException("Cannot find snapshot " + snapshotId + " on cache store"); + } + AsyncCallFuture future = syncToRegionStoreAsync(srcSnapshot, store); + try { + SnapshotResult result = future.get(); + if (result.isFailed()) { + throw new CloudRuntimeException("sync snapshot from cache to region wide store failed for image store " + store.getName() + ":" + + result.getResult()); + } + _cacheMgr.releaseCacheObject(srcSnapshot); // reduce reference count for template on cache, so it can recycled by schedule + } catch (Exception ex) { + throw new CloudRuntimeException("sync snapshot from cache to region wide store failed for image store " + store.getName()); + } + } + + } + + + private AsyncCallFuture syncToRegionStoreAsync(SnapshotInfo snapshot, DataStore store) { + AsyncCallFuture future = new AsyncCallFuture(); + // no need to create entry on snapshot_store_ref here, since entries are already created when updateCloudToUseObjectStore is invoked. + // But we need to set default install path so that sync can be done in the right s3 path + SnapshotInfo snapshotOnStore = _snapshotFactory.getSnapshot(snapshot, store); + String installPath = TemplateConstants.DEFAULT_SNAPSHOT_ROOT_DIR + "/" + + snapshot.getAccountId() + "/" + snapshot.getVolumeId(); + ((SnapshotObject)snapshotOnStore).setPath(installPath); + CopySnapshotContext context = new CopySnapshotContext(null, snapshot, + snapshotOnStore, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher + .create(this); + caller.setCallback(caller.getTarget().syncSnapshotCallBack(null, null)).setContext(context); + motionSrv.copyAsync(snapshot, snapshotOnStore, caller); + return future; + } + + protected Void syncSnapshotCallBack(AsyncCallbackDispatcher callback, + CopySnapshotContext context) { + CopyCommandResult result = callback.getResult(); + SnapshotInfo destSnapshot = context.destSnapshot; + SnapshotResult res = new SnapshotResult(destSnapshot, null); + + AsyncCallFuture future = context.future; + try { + if (result.isFailed()) { + res.setResult(result.getResult()); + // no change to existing snapshot_store_ref, will try to re-sync later if other call triggers this sync operation + } else { + // this will update install path properly, next time it will not sync anymore. + destSnapshot.processEvent(Event.OperationSuccessed, result.getAnswer()); + } + future.complete(res); + } catch (Exception e) { + s_logger.debug("Failed to process sync snapshot callback", e); + res.setResult(e.toString()); + future.complete(res); + } + + return null; + } } diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java index 555dcb8b3015..a70b0789ac4d 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java @@ -44,7 +44,7 @@ public SnapshotStateMachineManagerImpl() { stateMachine.addTransition(Snapshot.State.CreatedOnPrimary, Event.BackupToSecondary, Snapshot.State.BackingUp); stateMachine.addTransition(State.CreatedOnPrimary, Event.OperationNotPerformed, State.BackedUp); stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationSucceeded, Snapshot.State.BackedUp); - stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationFailed, Snapshot.State.CreatedOnPrimary); + stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationFailed, Snapshot.State.Error); stateMachine.addTransition(Snapshot.State.BackedUp, Event.DestroyRequested, Snapshot.State.Destroying); stateMachine.addTransition(Snapshot.State.BackedUp, Event.CopyingRequested, Snapshot.State.Copying); stateMachine.addTransition(Snapshot.State.Copying, Event.OperationSucceeded, Snapshot.State.BackedUp); 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 7eec5ffbb233..adb24bda90f5 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,9 +21,6 @@ import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; @@ -39,8 +36,13 @@ import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; import org.apache.cloudstack.storage.to.SnapshotObjectTO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.hypervisor.Hypervisor; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.CreateSnapshotPayload; import com.cloud.storage.DataStoreRole; import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotVO; @@ -106,21 +108,17 @@ public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) { // determine full snapshot backup or not - boolean fullBackup = false; - - if (parentSnapshot != null) { + boolean fullBackup = true; + SnapshotDataStoreVO parentSnapshotOnBackupStore = snapshotStoreDao.findLatestSnapshotForVolume(snapshot.getVolumeId(), DataStoreRole.Image); + HypervisorType hypervisorType = snapshot.getBaseVolume().getHypervisorType(); + if (parentSnapshotOnBackupStore != null && hypervisorType == Hypervisor.HypervisorType.XenServer) { // CS does incremental backup only for XenServer int _deltaSnapshotMax = NumbersUtil.parseInt(configDao.getValue("snapshot.delta.max"), SnapshotManager.DELTAMAX); int deltaSnap = _deltaSnapshotMax; int i; - SnapshotDataStoreVO parentSnapshotOnBackupStore = null; + for (i = 1; i < deltaSnap; i++) { - parentSnapshotOnBackupStore = snapshotStoreDao.findBySnapshot(parentSnapshot.getId(), - DataStoreRole.Image); - if (parentSnapshotOnBackupStore == null) { - break; - } Long prevBackupId = parentSnapshotOnBackupStore.getParentSnapshotId(); if (prevBackupId == 0) { @@ -128,9 +126,15 @@ public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) { } parentSnapshotOnBackupStore = snapshotStoreDao.findBySnapshot(prevBackupId, DataStoreRole.Image); + if (parentSnapshotOnBackupStore == null) { + break; + } } + if (i >= deltaSnap) { fullBackup = true; + } else { + fullBackup = false; } } @@ -205,7 +209,7 @@ public boolean deleteSnapshot(Long snapshotId) { return true; } - if (!Snapshot.State.BackedUp.equals(snapshotVO.getState())) { + if (!Snapshot.State.BackedUp.equals(snapshotVO.getState()) && !Snapshot.State.Error.equals(snapshotVO.getState())) { throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is in " + snapshotVO.getState() + " Status"); } @@ -260,6 +264,14 @@ public boolean revertSnapshot(Long snapshotId) { @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/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java b/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java index 3cae2b95f1d3..378827270577 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java +++ b/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java @@ -24,6 +24,8 @@ import javax.inject.Inject; +import com.cloud.vm.SecondaryStorageVmVO; +import com.cloud.vm.dao.SecondaryStorageVmDao; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.managed.context.ManagedContextRunnable; @@ -56,21 +58,30 @@ public class RemoteHostEndPoint implements EndPoint { AgentManager agentMgr; @Inject protected HypervisorGuruManager _hvGuruMgr; + @Inject + protected SecondaryStorageVmDao vmDao; private ScheduledExecutorService executor; public RemoteHostEndPoint() { executor = Executors.newScheduledThreadPool(10, new NamedThreadFactory("RemoteHostEndPoint")); } - private void configure(long hostId, String hostAddress, String publicAddress) { - this.hostId = hostId; - this.hostAddress = hostAddress; - this.publicAddress = publicAddress; + private void configure(Host host) { + this.hostId = host.getId(); + this.hostAddress = host.getPrivateIpAddress(); + this.publicAddress = host.getPublicIpAddress(); + if (Host.Type.SecondaryStorageVM == host.getType()) { + String vmName = host.getName(); + SecondaryStorageVmVO ssvm = vmDao.findByInstanceName(vmName); + if (ssvm != null) { + this.publicAddress = ssvm.getPublicIpAddress(); + } + } } - public static RemoteHostEndPoint getHypervisorHostEndPoint(long hostId, String hostAddress, String publicAddress) { + public static RemoteHostEndPoint getHypervisorHostEndPoint(Host host) { RemoteHostEndPoint ep = ComponentContext.inject(RemoteHostEndPoint.class); - ep.configure(hostId, hostAddress, publicAddress); + ep.configure(host); return ep; } diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/ClusterScopeStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/ClusterScopeStoragePoolAllocator.java index d48edd6eb801..6f8039911d6a 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/ClusterScopeStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/ClusterScopeStoragePoolAllocator.java @@ -79,14 +79,22 @@ protected List select(DiskProfile dskCh, VirtualMachineProfile vmPr } List pools = _storagePoolDao.findPoolsByTags(dcId, podId, clusterId, dskCh.getTags()); + s_logger.debug("Found pools matching tags: " + pools); // add remaining pools in cluster, that did not match tags, to avoid set List allPools = _storagePoolDao.findPoolsByTags(dcId, podId, clusterId, null); allPools.removeAll(pools); for (StoragePoolVO pool : allPools) { + s_logger.debug("Adding pool " + pool + " to avoid set since it did not match tags"); avoid.addPool(pool.getId()); } + // make sure our matching pool was not in avoid set + for (StoragePoolVO pool : pools) { + s_logger.debug("Removing pool " + pool + " from avoid set, must have been inserted when searching for another disk's tag"); + avoid.removePool(pool.getId()); + } + if (pools.size() == 0) { if (s_logger.isDebugEnabled()) { s_logger.debug("No storage pools available for " + ServiceOffering.StorageType.shared.toString() + " volume allocation, returning"); diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/LocalStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/LocalStoragePoolAllocator.java index 1f61e8b948d9..51ab0feb0477 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/LocalStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/LocalStoragePoolAllocator.java @@ -28,7 +28,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; - import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -73,14 +72,13 @@ protected List select(DiskProfile dskCh, VirtualMachineProfile vmPr if (!dskCh.useLocalStorage()) { return null; } - List suitablePools = new ArrayList(); // data disk and host identified from deploying vm (attach volume case) if (dskCh.getType() == Volume.Type.DATADISK && plan.getHostId() != null) { - List hostPools = _poolHostDao.listByHostId(plan.getHostId()); - for (StoragePoolHostVO hostPool : hostPools) { - StoragePoolVO pool = _storagePoolDao.findById(hostPool.getPoolId()); + List hostTagsPools = null; + hostTagsPools =_storagePoolDao.findLocalStoragePoolsByHostAndTags(plan.getHostId(), dskCh.getTags()); + for (StoragePoolVO pool : hostTagsPools) { if (pool != null && pool.isLocal()) { StoragePool storagePool = (StoragePool) this.dataStoreMgr.getPrimaryDataStore(pool.getId()); if (filter(avoid, storagePool, dskCh, plan)) { diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java index b58bcb53cb61..a95ceabb54e2 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java @@ -93,6 +93,12 @@ protected List select(DiskProfile dskCh, avoid.addPool(pool.getId()); } + // make sure our matching pool was not in avoid set + for (StoragePoolVO pool : storagePoolsByHypervisor) { + s_logger.debug("Removing pool " + pool + " from avoid set, must have been inserted when searching for another disk's tag"); + avoid.removePool(pool.getId()); + } + for (StoragePoolVO storage : storagePools) { if (suitablePools.size() == returnUpTo) { break; diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java index 88061aa5e121..d44fb42045c8 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java @@ -32,6 +32,7 @@ import org.apache.cloudstack.storage.image.datastore.ImageStoreProviderManager; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ScopeType; import com.cloud.utils.exception.CloudRuntimeException; @Component @@ -82,11 +83,24 @@ public DataStore getImageStore(long zoneId) { return stores.get(0); } + @Override + public boolean isRegionStore(DataStore store) { + if (store.getScope().getScopeType() == ScopeType.ZONE && store.getScope().getScopeId() == null) + return true; + else + return false; + } + @Override public DataStore getPrimaryDataStore(long storeId) { return primaryStoreMgr.getPrimaryDataStore(storeId); } + @Override + public DataStore getPrimaryDataStore(String storeUuid) { + return primaryStoreMgr.getPrimaryDataStore(storeUuid); + } + @Override public List getImageCacheStores(Scope scope) { return imageDataStoreMgr.listImageCacheStores(scope); 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 652df43c7852..9d47ce674c78 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); @@ -113,6 +114,7 @@ public DataObject create(DataObject obj, DataStore dataStore) { ss.setDataStoreId(dataStore.getId()); ss.setRole(dataStore.getRole()); ss.setVolumeId(snapshotInfo.getVolumeId()); + ss.setSize(snapshotInfo.getSize()); // this is the virtual size of snapshot in primary storage. SnapshotDataStoreVO snapshotDataStoreVO = snapshotDataStoreDao.findParent(dataStore.getRole(), dataStore.getId(),snapshotInfo.getVolumeId()); if (snapshotDataStoreVO != null) { ss.setParentSnapshotId(snapshotDataStoreVO.getSnapshotId()); @@ -256,13 +258,7 @@ public boolean deleteIfNotReady(DataObject dataObj) { // 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/endpoint/DefaultEndPointSelector.java b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java index ce83790a4f51..39bc8399b80b 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java +++ b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java @@ -35,7 +35,10 @@ 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.Scope; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.StorageAction; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.storage.LocalHostEndpoint; import org.apache.cloudstack.storage.RemoteHostEndPoint; @@ -43,6 +46,7 @@ import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor; import com.cloud.storage.DataStoreRole; import com.cloud.storage.ScopeType; import com.cloud.storage.Storage.TemplateType; @@ -51,6 +55,7 @@ import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.VirtualMachine; @Component public class DefaultEndPointSelector implements EndPointSelector { @@ -59,6 +64,7 @@ public class DefaultEndPointSelector implements EndPointSelector { HostDao hostDao; private final String findOneHostOnPrimaryStorage = "select h.id from host h, storage_pool_host_ref s where h.status = 'Up' and h.type = 'Routing' and h.resource_state = 'Enabled' and" + " h.id = s.host_id and s.pool_id = ? "; + private String findOneHypervisorHostInScope = "select h.id from host h where h.status = 'Up' and h.hypervisor_type is not null "; protected boolean moveBetweenPrimaryImage(DataStore srcStore, DataStore destStore) { DataStoreRole srcRole = srcStore.getRole(); @@ -141,8 +147,7 @@ protected EndPoint findEndPointInScope(Scope scope, String sqlBase, Long poolId) return null; } - return RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(), host.getPrivateIpAddress(), - host.getPublicIpAddress()); + return RemoteHostEndPoint.getHypervisorHostEndPoint(host); } protected EndPoint findEndPointForImageMove(DataStore srcStore, DataStore destStore) { @@ -162,10 +167,11 @@ protected EndPoint findEndPointForImageMove(DataStore srcStore, DataStore destSt poolId = destStore.getId(); } else { // if both are zone scope - selectedScope = srcScope; if (srcStore.getRole() == DataStoreRole.Primary) { + selectedScope = srcScope; poolId = srcStore.getId(); } else if (destStore.getRole() == DataStoreRole.Primary) { + selectedScope = destScope; poolId = destStore.getId(); } } @@ -206,6 +212,21 @@ public EndPoint select(DataObject srcData, DataObject destData) { return null; } + @Override + public EndPoint select(DataObject srcData, DataObject destData, StorageAction action) { + if (action == StorageAction.BACKUPSNAPSHOT && srcData.getDataStore().getRole() == DataStoreRole.Primary) { + SnapshotInfo srcSnapshot = (SnapshotInfo)srcData; + if (srcSnapshot.getHypervisorType() == Hypervisor.HypervisorType.KVM) { + VolumeInfo volumeInfo = srcSnapshot.getBaseVolume(); + VirtualMachine vm = volumeInfo.getAttachedVM(); + if (vm != null && vm.getState() == VirtualMachine.State.Running) { + return getEndPointFromHostId(vm.getHostId()); + } + } + } + return select(srcData, destData); + } + protected EndPoint findEndpointForPrimaryStorage(DataStore store) { return findEndPointInScope(store.getScope(), findOneHostOnPrimaryStorage, store.getId()); } @@ -225,8 +246,7 @@ protected EndPoint findEndpointForImageStorage(DataStore store) { } Collections.shuffle(ssAHosts); HostVO host = ssAHosts.get(0); - return RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(), host.getPrivateIpAddress(), - host.getPublicIpAddress()); + return RemoteHostEndPoint.getHypervisorHostEndPoint(host); } private List listUpAndConnectingSecondaryStorageVmHost(Long dcId) { @@ -269,6 +289,27 @@ public EndPoint select(DataStore store) { } } + private EndPoint getEndPointFromHostId(Long hostId) { + HostVO host = hostDao.findById(hostId); + return RemoteHostEndPoint.getHypervisorHostEndPoint(host); + } + + @Override + public EndPoint select(DataObject object, StorageAction action) { + if (action == StorageAction.TAKESNAPSHOT) { + SnapshotInfo snapshotInfo = (SnapshotInfo)object; + if (snapshotInfo.getHypervisorType() == Hypervisor.HypervisorType.KVM) { + VolumeInfo volumeInfo = snapshotInfo.getBaseVolume(); + VirtualMachine vm = volumeInfo.getAttachedVM(); + if ((vm != null) && (vm.getState() == VirtualMachine.State.Running)) { + Long hostId = vm.getHostId(); + return getEndPointFromHostId(hostId); + } + } + } + return select(object); + } + @Override public EndPoint select(Scope scope, Long storeId) { return findEndPointInScope(scope, findOneHostOnPrimaryStorage, storeId); @@ -279,16 +320,14 @@ public List selectAll(DataStore store) { List endPoints = new ArrayList(); if (store.getScope().getScopeType() == ScopeType.HOST) { HostVO host = hostDao.findById(store.getScope().getScopeId()); - endPoints.add(RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(), host.getPrivateIpAddress(), - host.getPublicIpAddress())); + endPoints.add(RemoteHostEndPoint.getHypervisorHostEndPoint(host)); } else if (store.getScope().getScopeType() == ScopeType.CLUSTER) { QueryBuilder sc = QueryBuilder.create(HostVO.class); sc.and(sc.entity().getClusterId(), Op.EQ, store.getScope().getScopeId()); sc.and(sc.entity().getStatus(), Op.EQ, Status.Up); List hosts = sc.list(); for (HostVO host : hosts) { - endPoints.add(RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(), host.getPrivateIpAddress(), - host.getPublicIpAddress())); + endPoints.add(RemoteHostEndPoint.getHypervisorHostEndPoint(host)); } } else { @@ -296,4 +335,51 @@ public List selectAll(DataStore store) { } return endPoints; } + + @Override + public EndPoint selectHypervisorHost(Scope scope) { + StringBuilder sbuilder = new StringBuilder(); + sbuilder.append(findOneHypervisorHostInScope); + if (scope.getScopeType() == ScopeType.ZONE) { + sbuilder.append(" and h.data_center_id = "); + sbuilder.append(scope.getScopeId()); + } else if (scope.getScopeType() == ScopeType.CLUSTER) { + sbuilder.append(" and h.cluster_id = "); + sbuilder.append(scope.getScopeId()); + } + sbuilder.append(" ORDER by rand() limit 1"); + + String sql = sbuilder.toString(); + PreparedStatement pstmt = null; + ResultSet rs = null; + HostVO host = null; + TransactionLegacy txn = TransactionLegacy.currentTxn(); + + try { + pstmt = txn.prepareStatement(sql); + rs = pstmt.executeQuery(); + while (rs.next()) { + long id = rs.getLong(1); + host = hostDao.findById(id); + } + } catch (SQLException e) { + s_logger.warn("can't find endpoint", e); + } finally { + try { + if (rs != null) { + rs.close(); + } + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException e) { + } + } + + if (host == null) { + return null; + } + + return RemoteHostEndPoint.getHypervisorHostEndPoint(host); + } } 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 eb29aa4d85be..e539a0ff6473 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/helper/HypervisorHelperImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/helper/HypervisorHelperImpl.java @@ -110,7 +110,7 @@ public VMSnapshotTO quiesceVm(VirtualMachine virtualMachine) { String value = configurationDao.getValue("vmsnapshot.create.wait"); 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, + VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(1L, UUID.randomUUID().toString(), VMSnapshot.Type.Disk, null, null, false, null, true); GuestOSVO guestOS = guestOSDao.findById(virtualMachine.getGuestOSId()); List volumeTOs = vmSnapshotHelper.getVolumeTOList(virtualMachine.getId()); 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 bd93e73e0efc..6a74c4540a57 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 @@ 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 @@ protected Proxy getHttpProxy() { } } + @Override + public Map getCapabilities() { + return null; + } + @Override public DataTO getTO(DataObject data) { return null; diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageStoreHelper.java b/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageStoreHelper.java index e2c48ea51e8f..187d6e4defd9 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageStoreHelper.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageStoreHelper.java @@ -18,6 +18,8 @@ */ package org.apache.cloudstack.storage.image.datastore; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.Iterator; import java.util.Map; import java.util.UUID; @@ -26,6 +28,7 @@ import org.springframework.stereotype.Component; +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailVO; @@ -33,8 +36,10 @@ import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.storage.DataStoreRole; import com.cloud.storage.ScopeType; +import com.cloud.utils.crypt.DBEncryptionUtil; import com.cloud.utils.exception.CloudRuntimeException; @Component @@ -94,6 +99,28 @@ public ImageStoreVO createImageStore(Map params, Map params, Map getDetails(long storeId) { List details = listBy(sc); Map detailsMap = new HashMap(); for (ImageStoreDetailVO detail : details) { - detailsMap.put(detail.getName(), detail.getValue()); + String name = detail.getName(); + String value = detail.getValue(); + if (name.equals(ApiConstants.KEY) || name.equals(ApiConstants.S3_SECRET_KEY)) { + value = DBEncryptionUtil.decrypt(value); + } + detailsMap.put(name, value); } return detailsMap; diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java index 7b9cf957a071..7d726d316f3c 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java @@ -58,7 +58,10 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase params) throws Configu storeSnapshotSearch.and("snapshot_id", storeSnapshotSearch.entity().getSnapshotId(), SearchCriteria.Op.EQ); storeSnapshotSearch.and("store_id", storeSnapshotSearch.entity().getDataStoreId(), SearchCriteria.Op.EQ); storeSnapshotSearch.and("store_role", storeSnapshotSearch.entity().getRole(), SearchCriteria.Op.EQ); + storeSnapshotSearch.and("state", storeSnapshotSearch.entity().getState(), SearchCriteria.Op.EQ); storeSnapshotSearch.done(); snapshotIdSearch = createSearchBuilder(); @@ -189,6 +193,33 @@ public SnapshotDataStoreVO findByStoreSnapshot(DataStoreRole role, long storeId, return findOneBy(sc); } + @Override + public SnapshotDataStoreVO findLatestSnapshotForVolume(Long volumeId, DataStoreRole role) { + TransactionLegacy txn = TransactionLegacy.currentTxn(); + PreparedStatement pstmt = null; + ResultSet rs = null; + try { + pstmt = txn.prepareStatement(findLatestSnapshot); + pstmt.setString(1, role.toString()); + pstmt.setLong(2, volumeId); + rs = pstmt.executeQuery(); + while (rs.next()) { + long sid = rs.getLong(1); + long snid = rs.getLong(3); + return findByStoreSnapshot(role, sid, snid); + } + } catch (SQLException e) { + s_logger.debug("Failed to find parent snapshot: " + e.toString()); + } finally { + try { + if (pstmt != null) + pstmt.close(); + } catch (SQLException e) { + } + } + return null; + } + @Override @DB public SnapshotDataStoreVO findParent(DataStoreRole role, Long storeId, Long volumeId) { @@ -288,6 +319,15 @@ public void duplicateCacheRecordsOnRegionStore(long storeId) { } + @Override + public SnapshotDataStoreVO findReadyOnCache(long snapshotId) { + SearchCriteria sc = storeSnapshotSearch.create(); + sc.setParameters("snapshot_id", snapshotId); + sc.setParameters("store_role", DataStoreRole.ImageCache); + sc.setParameters("state", ObjectInDataStoreStateMachine.State.Ready); + return findOneIncludingRemovedBy(sc); + } + @Override public List listOnCache(long snapshotId) { SearchCriteria sc = storeSnapshotSearch.create(); diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/TemplateDataStoreDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/TemplateDataStoreDaoImpl.java index ee7c4fcfd567..c5543ffbdee8 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/db/TemplateDataStoreDaoImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/db/TemplateDataStoreDaoImpl.java @@ -294,6 +294,23 @@ public TemplateDataStoreVO findByTemplateZoneDownloadStatus(long templateId, Lon return null; } + @Override + public TemplateDataStoreVO findByTemplateZoneStagingDownloadStatus(long templateId, Long zoneId, Status... status) { + // get all elgible image stores + List cacheStores = _storeMgr.getImageCacheStores(new ZoneScope(zoneId)); + if (cacheStores != null) { + for (DataStore store : cacheStores) { + List sRes = listByTemplateStoreDownloadStatus(templateId, store.getId(), + status); + if (sRes != null && sRes.size() > 0) { + Collections.shuffle(sRes); + return sRes.get(0); + } + } + } + return null; + } + @Override public TemplateDataStoreVO findByStoreTemplate(long storeId, long templateId) { SearchCriteria sc = storeTemplateSearch.create(); @@ -326,15 +343,20 @@ public TemplateDataStoreVO findByTemplate(long templateId, DataStoreRole role) { } @Override - public TemplateDataStoreVO findReadyOnCache(long templateId) { + public TemplateDataStoreVO findReadyByTemplate(long templateId, DataStoreRole role) { SearchCriteria sc = templateRoleSearch.create(); sc.setParameters("template_id", templateId); - sc.setParameters("store_role", DataStoreRole.ImageCache); + sc.setParameters("store_role", role); sc.setParameters("destroyed", false); sc.setParameters("state", ObjectInDataStoreStateMachine.State.Ready); return findOneIncludingRemovedBy(sc); } + @Override + public TemplateDataStoreVO findReadyOnCache(long templateId) { + return findReadyByTemplate(templateId, DataStoreRole.ImageCache); + } + @Override public List listOnCache(long templateId) { SearchCriteria sc = templateRoleSearch.create(); @@ -371,6 +393,22 @@ public TemplateDataStoreVO findByTemplateZone(long templateId, Long zoneId, Data return null; } + @Override + public TemplateDataStoreVO findByTemplateZoneReady(long templateId, Long zoneId) { + List imgStores = null; + imgStores = _storeMgr.getImageStoresByScope(new ZoneScope(zoneId)); + if (imgStores != null) { + Collections.shuffle(imgStores); + for (DataStore store : imgStores) { + List sRes = listByTemplateStoreStatus(templateId, store.getId(), State.Ready); + if (sRes != null && sRes.size() > 0) { + return sRes.get(0); + } + } + } + return null; + } + /** * Duplicate all image cache store entries */ diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java b/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java index 90ad17aa6d8b..c2bb31f532f5 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java @@ -18,6 +18,8 @@ */ package org.apache.cloudstack.storage.volume.datastore; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.List; import java.util.Map; @@ -36,13 +38,17 @@ import com.cloud.capacity.Capacity; import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.storage.DataStoreRole; import com.cloud.storage.ScopeType; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolHostVO; import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.utils.UriUtils; +import com.cloud.utils.crypt.DBEncryptionUtil; import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.exception.CloudRuntimeException; @@ -69,8 +75,8 @@ public DataStore createPrimaryDataStore(PrimaryDataStoreParameters params) { dataStoreVO = new StoragePoolVO(); dataStoreVO.setStorageProviderName(params.getProviderName()); dataStoreVO.setHostAddress(params.getHost()); - dataStoreVO.setPath(params.getPath()); dataStoreVO.setPoolType(params.getType()); + dataStoreVO.setPath(params.getPath()); dataStoreVO.setPort(params.getPort()); dataStoreVO.setName(params.getName()); dataStoreVO.setUuid(params.getUuid()); @@ -86,6 +92,29 @@ public DataStore createPrimaryDataStore(PrimaryDataStoreParameters params) { dataStoreVO.setHypervisor(params.getHypervisorType()); Map details = params.getDetails(); + if (params.getType() == StoragePoolType.SMB && details != null) { + String user = details.get("user"); + String password = details.get("password"); + String domain = details.get("domain"); + String updatedPath = params.getPath(); + + if (user == null || password == null) { + String errMsg = "Missing cifs user and password details. Add them as details parameter."; + s_logger.warn(errMsg); + throw new InvalidParameterValueException(errMsg); + } else { + try { + password = DBEncryptionUtil.encrypt(URLEncoder.encode(password, "UTF-8")); + details.put("password", password); + updatedPath += "?user=" + user + "&password=" + password + "&domain=" + domain; + } catch (UnsupportedEncodingException e) { + throw new CloudRuntimeException("Error while generating the cifs url. " + e.getMessage()); + } + } + + dataStoreVO.setPath(updatedPath); + } + String tags = params.getTags(); if (tags != null) { String[] tokens = tags.split(","); diff --git a/engine/storage/volume/pom.xml b/engine/storage/volume/pom.xml index 32426aa3b72c..3bf1c8907dc3 100644 --- a/engine/storage/volume/pom.xml +++ b/engine/storage/volume/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java index cb502e9e2601..f3651d4d7ff6 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java @@ -23,6 +23,7 @@ import javax.inject.Inject; +import com.cloud.hypervisor.Hypervisor; import org.apache.cloudstack.engine.subsystem.api.storage.*; import org.apache.log4j.Logger; @@ -360,6 +361,11 @@ public boolean isInMaintenance() { return getStatus() == StoragePoolStatus.PrepareForMaintenance || getStatus() == StoragePoolStatus.Maintenance || getStatus() == StoragePoolStatus.ErrorInMaintenance || getRemoved() != null; } + @Override + public HypervisorType getHypervisor() { + return pdsv.getHypervisor(); + } + @Override public String getStorageProviderName() { return pdsv.getStorageProviderName(); diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java index fa5e2167cc86..9d05bc342b6e 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java @@ -62,7 +62,7 @@ public boolean hostConnect(long hostId, long poolId) { if (!answer.getResult()) { String msg = "Unable to attach storage pool" + poolId + " to the host" + hostId; - alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, pool.getDataCenterId(), pool.getPodId(), msg, msg); + alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, pool.getDataCenterId(), pool.getPodId(), msg, msg); throw new CloudRuntimeException("Unable establish connection from storage head to storage pool " + pool.getId() + " due to " + answer.getDetails() + pool.getId()); } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java index f761a0c60ba6..df71bad4ff70 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java @@ -22,6 +22,7 @@ import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; @@ -98,6 +99,15 @@ public String getAttachedVmName() { return null; } + @Override + public VirtualMachine getAttachedVM() { + Long vmId = this.volumeVO.getInstanceId(); + if (vmId != null) { + VMInstanceVO vm = vmInstanceDao.findById(vmId); + return vm; + } + return null; + } @Override public String getUuid() { return volumeVO.getUuid(); @@ -141,7 +151,6 @@ public Long getMaxIops() { return volumeVO.getMaxIops(); } - @Override public void setHypervisorSnapshotReserve(Integer hypervisorSnapshotReserve) { volumeVO.setHypervisorSnapshotReserve(hypervisorSnapshotReserve); } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index 5818aa8d9243..d221fa970ce9 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -75,6 +75,7 @@ import com.cloud.host.Host; import com.cloud.storage.DataStoreRole; import com.cloud.storage.ScopeType; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePool; import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VMTemplateStorageResourceAssoc; @@ -159,6 +160,26 @@ public ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore) { return null; } + @Override + public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { + DataStoreDriver dataStoreDriver = dataStore != null ? dataStore.getDriver() : null; + + if (dataStoreDriver instanceof PrimaryDataStoreDriver) { + return ((PrimaryDataStoreDriver)dataStoreDriver).connectVolumeToHost(volumeInfo, host, dataStore); + } + + return false; + } + + @Override + public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { + DataStoreDriver dataStoreDriver = dataStore != null ? dataStore.getDriver() : null; + + if (dataStoreDriver instanceof PrimaryDataStoreDriver) { + ((PrimaryDataStoreDriver)dataStoreDriver).disconnectVolumeFromHost(volumeInfo, host, dataStore); + } + } + @Override public AsyncCallFuture createVolumeAsync(VolumeInfo volume, DataStore dataStore) { AsyncCallFuture future = new AsyncCallFuture(); @@ -659,9 +680,16 @@ protected Void createVolumeFromSnapshotCallback( protected VolumeVO duplicateVolumeOnAnotherStorage(Volume volume, StoragePool pool) { Long lastPoolId = volume.getPoolId(); + String folder = pool.getPath(); + // For SMB, pool credentials are also stored in the uri query string. We trim the query string + // part here to make sure the credentials do not get stored in the db unencrypted. + if (pool.getPoolType() == StoragePoolType.SMB && folder != null && folder.contains("?")) { + folder = folder.substring(0, folder.indexOf("?")); + } + VolumeVO newVol = new VolumeVO(volume); newVol.setPoolId(pool.getId()); - newVol.setFolder(pool.getPath()); + newVol.setFolder(folder); newVol.setPodId(pool.getPodId()); newVol.setPoolId(pool.getId()); newVol.setLastPoolId(lastPoolId); @@ -1238,7 +1266,7 @@ public void handleVolumeSync(DataStore store) { - volInfo.getPhysicalSize()); } catch (ResourceAllocationException e) { s_logger.warn(e.getMessage()); - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED, + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED, volume.getDataCenterId(), volume.getPodId(), e.getMessage(), e.getMessage()); } finally { _resourceLimitMgr.recalculateResourceCount(volume.getAccountId(), volume.getDomainId(), @@ -1263,6 +1291,17 @@ public void handleVolumeSync(DataStore store) { s_logger.info("Skip downloading volume " + volumeHost.getVolumeId() + " since no download url is specified."); continue; } + + // if this is a region store, and there is already an DOWNLOADED entry there without install_path information, which + // means that this is a duplicate entry from migration of previous NFS to staging. + if (store.getScope().getScopeType() == ScopeType.REGION) { + if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED + && volumeHost.getInstallPath() == null) { + s_logger.info("Skip sync volume for migration of previous NFS to object store"); + continue; + } + } + s_logger.debug("Volume " + volumeHost.getVolumeId() + " needs to be downloaded to " + store.getName()); // TODO: pass a callback later VolumeInfo vol = volFactory.getVolume(volumeHost.getVolumeId()); diff --git a/framework/cluster/pom.xml b/framework/cluster/pom.xml index fe8af4cdba14..8da287e0310a 100644 --- a/framework/cluster/pom.xml +++ b/framework/cluster/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-framework - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml diff --git a/framework/cluster/src/com/cloud/cluster/ClusterManagerImpl.java b/framework/cluster/src/com/cloud/cluster/ClusterManagerImpl.java index 1c10a95c328d..a8691df5c0a7 100644 --- a/framework/cluster/src/com/cloud/cluster/ClusterManagerImpl.java +++ b/framework/cluster/src/com/cloud/cluster/ClusterManagerImpl.java @@ -16,8 +16,6 @@ // under the License. package com.cloud.cluster; -import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.net.ConnectException; import java.net.InetSocketAddress; @@ -25,6 +23,7 @@ import java.rmi.RemoteException; import java.sql.Connection; import java.sql.SQLException; +import java.sql.SQLNonTransientException; import java.sql.SQLRecoverableException; import java.util.ArrayList; import java.util.Date; @@ -42,18 +41,17 @@ 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; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.utils.identity.ManagementServerNode; +import org.apache.log4j.Logger; import com.cloud.cluster.dao.ManagementServerHostDao; import com.cloud.cluster.dao.ManagementServerHostPeerDao; import com.cloud.utils.DateUtil; import com.cloud.utils.Profiler; -import com.cloud.utils.PropertiesUtil; import com.cloud.utils.component.ComponentLifecycle; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; @@ -585,21 +583,15 @@ protected void runInContext() { } if(isRootCauseConnectionRelated(e.getCause())) { - s_logger.error("DB communication problem detected, fence it"); - queueNotification(new ClusterManagerMessage(ClusterManagerMessage.MessageType.nodeIsolated)); + invalidHeartbeatConnection(); } - - invalidHeartbeatConnection(); } catch(ActiveFencingException e) { queueNotification(new ClusterManagerMessage(ClusterManagerMessage.MessageType.nodeIsolated)); } catch (Throwable e) { s_logger.error("Unexpected exception in cluster heartbeat", e); if(isRootCauseConnectionRelated(e.getCause())) { - s_logger.error("DB communication problem detected, fence it"); - queueNotification(new ClusterManagerMessage(ClusterManagerMessage.MessageType.nodeIsolated)); + invalidHeartbeatConnection(); } - - invalidHeartbeatConnection(); } finally { txn.transitToAutoManagedConnection(TransactionLegacy.CLOUD_DB); txn.close("ClusterHeartbeat"); @@ -610,8 +602,8 @@ protected void runInContext() { private boolean isRootCauseConnectionRelated(Throwable e) { while (e != null) { - if (e instanceof SQLRecoverableException) { - return true; + if (e instanceof SQLRecoverableException || e instanceof SQLNonTransientException) { + return true; } e = e.getCause(); @@ -634,6 +626,9 @@ private void invalidHeartbeatConnection() { Connection conn = TransactionLegacy.getStandaloneConnection(); if (conn != null) { _heartbeatConnection.reset(TransactionLegacy.getStandaloneConnection()); + } else { + s_logger.error("DB communication problem detected, fence it"); + queueNotification(new ClusterManagerMessage(ClusterManagerMessage.MessageType.nodeIsolated)); } } } diff --git a/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java b/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java index 246bfe6bcd42..d187199a6215 100644 --- a/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java +++ b/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java @@ -100,6 +100,7 @@ public void update(long id, long runid, String name, String version, String serv txn.commit(); } catch(Exception e) { s_logger.warn("Unexpected exception, ", e); + throw new RuntimeException(e.getMessage(), e); } } @@ -119,9 +120,8 @@ public boolean remove(Long id) { return true; } catch(Exception e) { s_logger.warn("Unexpected exception, ", e); + throw new RuntimeException(e.getMessage(), e); } - - return false; } @Override @@ -145,6 +145,7 @@ public void update(long id, long runid, Date lastUpdate) { } } catch(Exception e) { s_logger.warn("Unexpected exception, ", e); + throw new RuntimeException(e.getMessage(), e); } } @@ -180,7 +181,7 @@ public int increaseAlertCount(long id) { txn.commit(); } catch(Exception e) { s_logger.warn("Unexpected exception, ", e); - txn.rollback(); + throw new RuntimeException(e.getMessage(), e); } return changedRows; diff --git a/framework/config/pom.xml b/framework/config/pom.xml index 7c42201e4b20..b1c2b345ef80 100644 --- a/framework/config/pom.xml +++ b/framework/config/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-framework - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml 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 2fd6efbb5dac..6dd13603f5ae 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.Set; + /** * ConfigDepot is a repository of configurations. * @@ -23,4 +25,6 @@ public interface ConfigDepot { ConfigKey get(String paramName); + + Set> 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 254e6d20b06c..4cefdafb32d2 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 HashSet>()); + _scopeLevelConfigsMap.put(ConfigKey.Scope.Cluster, new HashSet>()); + _scopeLevelConfigsMap.put(ConfigKey.Scope.StoragePool, new HashSet>()); + _scopeLevelConfigsMap.put(ConfigKey.Scope.Account, new HashSet>()); } @Override @@ -108,7 +114,7 @@ protected void populateConfiguration(Date date, Configurable configurable) { ": " + 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); @@ -117,14 +123,20 @@ protected void populateConfiguration(Date date, Configurable configurable) { } else { if (vo.isDynamic() != key.isDynamic() || !ObjectUtils.equals(vo.getDescription(), key.description()) || - !ObjectUtils.equals(vo.getDefaultValue(), key.defaultValue())) { + !ObjectUtils.equals(vo.getDefaultValue(), key.defaultValue()) || + !ObjectUtils.equals(vo.getScope(), key.scope().toString())) { vo.setDynamic(key.isDynamic()); vo.setDescription(key.description()); vo.setDefaultValue(key.defaultValue()); + vo.setScope(key.scope().toString()); vo.setUpdated(date); _configDao.persist(vo); } } + if ((key.scope() != null) && (key.scope() != ConfigKey.Scope.Global)) { + Set> currentConfigs = _scopeLevelConfigsMap.get(key.scope()); + currentConfigs.add(key); + } } _configured.add(configurable); @@ -172,4 +184,9 @@ public void setConfigurables(List configurables) { this._configurables = configurables; } + @Override + public Set> getConfigListByScope(String scope) { + return _scopeLevelConfigsMap.get(ConfigKey.Scope.valueOf(scope)); + } + } diff --git a/framework/db/pom.xml b/framework/db/pom.xml index 5af00a00747f..7347115fe4d4 100644 --- a/framework/db/pom.xml +++ b/framework/db/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-framework - 4.3.0-SNAPSHOT + 4.3.0 ../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 000000000000..29e96dfc18ec --- /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 39893bd4eab7..d50118bdc8f5 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 static void initDataSource(Properties dbProps) { 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 static void initDataSource(Properties dbProps) { 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 static void initDataSource(Properties dbProps) { 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 static void initDataSource(Properties dbProps) { 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/events/pom.xml b/framework/events/pom.xml index 222e99fe8f66..61b8baa74e77 100644 --- a/framework/events/pom.xml +++ b/framework/events/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-framework - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml diff --git a/framework/ipc/pom.xml b/framework/ipc/pom.xml index 9d4ae8d172f8..b556a80d474b 100644 --- a/framework/ipc/pom.xml +++ b/framework/ipc/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-framework - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml diff --git a/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageDispatcher.java b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageDispatcher.java index ac75afb7c7d8..e83c5ee7685b 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageDispatcher.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageDispatcher.java @@ -20,25 +20,31 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import org.apache.log4j.Logger; public class MessageDispatcher implements MessageSubscriber { - private static Map, Method> s_handlerCache = new HashMap, Method>(); - + private static final Logger s_logger = Logger.getLogger(MessageDispatcher.class); + + private static Map, List> s_handlerCache = new HashMap, List>(); + private static Map s_targetMap = new HashMap(); private Object _targetObject; - + public MessageDispatcher(Object targetObject) { _targetObject = targetObject; + buildHandlerMethodCache(targetObject.getClass()); } - + @Override public void onPublishMessage(String senderAddress, String subject, Object args) { dispatch(_targetObject, subject, senderAddress, args); } - + public static MessageDispatcher getDispatcher(Object targetObject) { MessageDispatcher dispatcher; synchronized(s_targetMap) { @@ -50,55 +56,94 @@ public static MessageDispatcher getDispatcher(Object targetObject) { } return dispatcher; } - + public static void removeDispatcher(Object targetObject) { synchronized(s_targetMap) { s_targetMap.remove(targetObject); } } - + public static boolean dispatch(Object target, String subject, String senderAddress, Object args) { assert(subject != null); assert(target != null); - + Method handler = resolveHandler(target.getClass(), subject); if(handler == null) return false; - + try { handler.invoke(target, subject, senderAddress, args); } catch (IllegalArgumentException e) { + s_logger.error("Unexpected exception when calling " + target.getClass().getName() + "." + handler.getName(), e); throw new RuntimeException("IllegalArgumentException when invoking event handler for subject: " + subject); } catch (IllegalAccessException e) { + s_logger.error("Unexpected exception when calling " + target.getClass().getName() + "." + handler.getName(), e); throw new RuntimeException("IllegalAccessException when invoking event handler for subject: " + subject); } catch (InvocationTargetException e) { + s_logger.error("Unexpected exception when calling " + target.getClass().getName() + "." + handler.getName(), e); throw new RuntimeException("InvocationTargetException when invoking event handler for subject: " + subject); } - + return true; } - + public static Method resolveHandler(Class handlerClz, String subject) { synchronized(s_handlerCache) { - Method handler = s_handlerCache.get(handlerClz); - if(handler != null) - return handler; - - for(Method method : handlerClz.getMethods()) { - MessageHandler annotation = method.getAnnotation(MessageHandler.class); - if(annotation != null) { - if(match(annotation.topic(), subject)) { - s_handlerCache.put(handlerClz, method); - return method; - } - } - } + List handlerList = s_handlerCache.get(handlerClz); + if (handlerList != null) { + for (Method method : handlerList) { + MessageHandler annotation = method.getAnnotation(MessageHandler.class); + assert (annotation != null); + + if (match(annotation.topic(), subject)) { + return method; + } + } + } else { + s_logger.error("Handler class " + handlerClz.getName() + " is not registered"); + } } - + return null; } - + private static boolean match(String expression, String param) { return param.matches(expression); } + + private void buildHandlerMethodCache(Class handlerClz) { + if (s_logger.isInfoEnabled()) + s_logger.info("Build message handler cache for " + handlerClz.getName()); + + synchronized (s_handlerCache) { + List handlerList = s_handlerCache.get(handlerClz); + if (handlerList == null) { + handlerList = new ArrayList(); + s_handlerCache.put(handlerClz, handlerList); + + Class clz = handlerClz; + while (clz != null && clz != Object.class) { + for (Method method : clz.getDeclaredMethods()) { + MessageHandler annotation = method.getAnnotation(MessageHandler.class); + if (annotation != null) { + // allow private member access via reflection + method.setAccessible(true); + handlerList.add(method); + + if (s_logger.isInfoEnabled()) + s_logger.info("Add message handler " + handlerClz.getName() + "." + method.getName() + " to cache"); + } + } + + clz = clz.getSuperclass(); + } + } else { + if (s_logger.isInfoEnabled()) + s_logger.info("Message handler for class " + handlerClz.getName() + " is already in cache"); + } + } + + if (s_logger.isInfoEnabled()) + s_logger.info("Done building message handler cache for " + handlerClz.getName()); + } } diff --git a/framework/jobs/pom.xml b/framework/jobs/pom.xml index f491c60dc5df..8d4a0dd57c71 100644 --- a/framework/jobs/pom.xml +++ b/framework/jobs/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-framework - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml diff --git a/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml b/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml index 85cad0216c07..2d1eba0d9bed 100644 --- a/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml +++ b/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml @@ -43,6 +43,6 @@ class="org.apache.cloudstack.framework.jobs.dao.SyncQueueItemDaoImpl" /> - - + diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java index 595800d25241..4343a4d60a5a 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java @@ -17,6 +17,8 @@ package org.apache.cloudstack.framework.jobs; import org.apache.log4j.Logger; + +import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.jobs.dao.AsyncJobJoinMapDao; import org.apache.cloudstack.framework.jobs.impl.AsyncJobJoinMapVO; import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper; @@ -27,10 +29,14 @@ import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.user.User; public class AsyncJobExecutionContext { + private static final Logger s_logger = Logger.getLogger(AsyncJobExecutionContext.class); + private AsyncJob _job; - + static private AsyncJobManager _jobMgr; static private AsyncJobJoinMapDao _joinMapDao; @@ -38,47 +44,55 @@ public static void init(AsyncJobManager jobMgr, AsyncJobJoinMapDao joinMapDao) { _jobMgr = jobMgr; _joinMapDao = joinMapDao; } - + private static ManagedThreadLocal s_currentExectionContext = new ManagedThreadLocal(); public AsyncJobExecutionContext() { } - + public AsyncJobExecutionContext(AsyncJob job) { _job = job; } - + public SyncQueueItem getSyncSource() { return _job.getSyncSource(); } - + public void resetSyncSource() { _job.setSyncSource(null); } - + public AsyncJob getJob() { return _job; } - + public void setJob(AsyncJob job) { _job = job; } - + + public boolean isJobDispatchedBy(String jobDispatcherName) { + assert(jobDispatcherName != null); + if(_job != null && _job.getDispatcher() != null && _job.getDispatcher().equals(jobDispatcherName)) + return true; + + return false; + } + public void completeAsyncJob(JobInfo.Status jobStatus, int resultCode, String resultObject) { assert(_job != null); _jobMgr.completeAsyncJob(_job.getId(), jobStatus, resultCode, resultObject); } - + public void updateAsyncJobStatus(int processStatus, String resultObject) { assert(_job != null); _jobMgr.updateAsyncJobStatus(_job.getId(), processStatus, resultObject); } - + public void updateAsyncJobAttachment(String instanceType, Long instanceId) { assert(_job != null); _jobMgr.updateAsyncJobAttachment(_job.getId(), instanceType, instanceId); } - + public void logJobJournal(AsyncJob.JournalType journalType, String journalText, String journalObjJson) { assert(_job != null); _jobMgr.logJobJournal(_job.getId(), journalType, journalText, journalObjJson); @@ -93,45 +107,59 @@ public void joinJob(long joinJobId) { assert(_job != null); _jobMgr.joinJob(_job.getId(), joinJobId); } - + public void joinJob(long joinJobId, String wakeupHandler, String wakeupDispatcher, String[] wakeupTopcisOnMessageBus, long wakeupIntervalInMilliSeconds, long timeoutInMilliSeconds) { assert(_job != null); _jobMgr.joinJob(_job.getId(), joinJobId, wakeupHandler, wakeupDispatcher, wakeupTopcisOnMessageBus, wakeupIntervalInMilliSeconds, timeoutInMilliSeconds); } - + // - // check failure exception before we disjoin the worker job + // check failure exception before we disjoin the worker job, work job usually fails with exception + // this will help propogate exception between jobs // TODO : it is ugly and this will become unnecessary after we switch to full-async mode // public void disjoinJob(long joinedJobId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { assert(_job != null); - + AsyncJobJoinMapVO record = _joinMapDao.getJoinRecord(_job.getId(), joinedJobId); - if(record.getJoinStatus() == JobInfo.Status.FAILED && record.getJoinResult() != null) { - Object exception = JobSerializerHelper.fromObjectSerializedString(record.getJoinResult()); - if(exception != null && exception instanceof Exception) { - if(exception instanceof InsufficientCapacityException) - throw (InsufficientCapacityException)exception; - else if(exception instanceof ConcurrentOperationException) - throw (ConcurrentOperationException)exception; - else if(exception instanceof ResourceUnavailableException) - throw (ResourceUnavailableException)exception; - else - throw new RuntimeException((Exception)exception); - } + _jobMgr.disjoinJob(_job.getId(), joinedJobId); + + if (record.getJoinStatus() == JobInfo.Status.FAILED) { + if (record.getJoinResult() != null) { + Object exception = JobSerializerHelper.fromObjectSerializedString(record.getJoinResult()); + if (exception != null && exception instanceof Exception) { + if (exception instanceof InsufficientCapacityException) { + s_logger.error("Job " + joinedJobId + " failed with InsufficientCapacityException"); + throw (InsufficientCapacityException)exception; + } + else if (exception instanceof ConcurrentOperationException) { + s_logger.error("Job " + joinedJobId + " failed with ConcurrentOperationException"); + throw (ConcurrentOperationException)exception; + } + else if (exception instanceof ResourceUnavailableException) { + s_logger.error("Job " + joinedJobId + " failed with ResourceUnavailableException"); + throw (ResourceUnavailableException)exception; + } + else { + s_logger.error("Job " + joinedJobId + " failed with exception"); + throw new RuntimeException((Exception)exception); + } + } + } else { + s_logger.error("Job " + joinedJobId + " failed without providing an error object"); + throw new RuntimeException("Job " + joinedJobId + " failed without providing an error object"); + } } - - _jobMgr.disjoinJob(_job.getId(), joinedJobId); } - + public void completeJoin(JobInfo.Status joinStatus, String joinResult) { assert(_job != null); _jobMgr.completeJoin(_job.getId(), joinStatus, joinResult); } - + public void completeJobAndJoin(JobInfo.Status joinStatus, String joinResult) { assert(_job != null); _jobMgr.completeJoin(_job.getId(), joinStatus, joinResult); @@ -140,9 +168,20 @@ public void completeJobAndJoin(JobInfo.Status joinStatus, String joinResult) { public static AsyncJobExecutionContext getCurrentExecutionContext() { AsyncJobExecutionContext context = s_currentExectionContext.get(); + if (context == null) { + // TODO, this has security implications, operations carried from API layer should always + // set its context, otherwise, the fall-back here will use system security context + // + s_logger.warn("Job is executed without a context, setup psudo job for the executing thread"); + if (CallContext.current() != null) + context = registerPseudoExecutionContext(CallContext.current().getCallingAccountId(), + CallContext.current().getCallingUserId()); + else + context = registerPseudoExecutionContext(Account.ACCOUNT_ID_SYSTEM, User.UID_SYSTEM); + } return context; } - + public static AsyncJobExecutionContext registerPseudoExecutionContext(long accountId, long userId) { AsyncJobExecutionContext context = s_currentExectionContext.get(); if (context == null) { @@ -164,4 +203,8 @@ public static AsyncJobExecutionContext unregister() { public static void setCurrentExecutionContext(AsyncJobExecutionContext currentContext) { s_currentExectionContext.set(currentContext); } + + public static String getOriginJobContextId() { + return String.valueOf(CallContext.current().getContextId()); + } } diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobManager.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobManager.java index bc061018957a..6d5358e57725 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobManager.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobManager.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.framework.jobs; +import java.io.Serializable; import java.util.List; import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; @@ -25,13 +26,13 @@ import com.cloud.utils.component.Manager; public interface AsyncJobManager extends Manager { - + public static final String JOB_POOL_THREAD_PREFIX = "Job-Executor"; AsyncJobVO getAsyncJob(long jobId); - + List findInstancePendingAsyncJobs(String instanceType, Long accountId); - + long submitAsyncJob(AsyncJob job); long submitAsyncJob(AsyncJob job, String syncObjType, long syncObjId); @@ -41,11 +42,11 @@ public interface AsyncJobManager extends Manager { void updateAsyncJobAttachment(long jobId, String instanceType, Long instanceId); void logJobJournal(long jobId, AsyncJob.JournalType journalType, String journalText, String journalObjJson); - + /** * A running thread inside management server can have a 1:1 linked pseudo job. * This is to help make some legacy code work without too dramatic changes. - * + * * All pseudo jobs should be expunged upon management start event * * @return pseudo job for the thread @@ -56,21 +57,21 @@ void logJobJournal(long jobId, AsyncJob.JournalType journalType, String * Used by upper level job to wait for completion of a down-level job (usually VmWork jobs) * in synchronous way. Caller needs to use waitAndCheck() to check the completion status * of the down-level job - * + * * Due to the amount of legacy code that relies on synchronous-call semantics, this form of joinJob * is used mostly - * - * + * + * * @param jobId upper job that is going to wait the completion of a down-level job * @param joinJobId down-level job */ void joinJob(long jobId, long joinJobId); - + /** * Used by upper level job to wait for completion of a down-level job (usually VmWork jobs) * in asynchronous way, it will cause upper job to cease current execution, upper job will be * rescheduled to execute periodically or on wakeup events detected from message bus - * + * * @param jobId upper job that is going to wait the completion of a down-level job * @param joinJobId down-level job * @Param wakeupHandler wake-up handler @@ -81,18 +82,18 @@ void logJobJournal(long jobId, AsyncJob.JournalType journalType, String */ void joinJob(long jobId, long joinJobId, String wakeupHandler, String wakupDispatcher, String[] wakeupTopicsOnMessageBus, long wakeupIntervalInMilliSeconds, long timeoutInMilliSeconds); - + /** * Dis-join two related jobs - * + * * @param jobId * @param joinedJobId */ void disjoinJob(long jobId, long joinedJobId); - + /** * Used by down-level job to notify its completion to upper level jobs - * + * * @param joinJobId down-level job for upper level job to join with * @param joinStatus AsyncJobConstants status code to indicate success or failure of the * down-level job @@ -102,14 +103,14 @@ void joinJob(long jobId, long joinJobId, String wakeupHandler, String wakupDispa * object-stream based serialization instead of GSON */ void completeJoin(long joinJobId, JobInfo.Status joinStatus, String joinResult); - + void releaseSyncSource(); void syncAsyncJobExecution(AsyncJob job, String syncObjType, long syncObjId, long queueSizeLimit); - + /** * This method will be deprecated after all code has been migrated to fully-asynchronous mode * that uses async-feature of joinJob/disjoinJob - * + * * @param wakupTopicsOnMessageBus topic on message bus to wakeup the wait * @param checkIntervalInMilliSeconds time to break out wait for checking predicate condition * @param timeoutInMiliseconds time out to break out the whole wait process @@ -122,4 +123,7 @@ boolean waitAndCheck(AsyncJob job, String[] wakupTopicsOnMessageBus, long checkI AsyncJob queryJob(long jobId, boolean updatePollTime); + String marshallResultObject(Serializable obj); + + Object unmarshallResultObject(AsyncJob job); } diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/SyncQueueItemDao.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/SyncQueueItemDao.java index 61670bf70439..7b6eed75a008 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/SyncQueueItemDao.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/SyncQueueItemDao.java @@ -23,9 +23,14 @@ import com.cloud.utils.db.GenericDao; public interface SyncQueueItemDao extends GenericDao { - public SyncQueueItemVO getNextQueueItem(long queueId); - public List getNextQueueItems(int maxItems); - public List getActiveQueueItems(Long msid, boolean exclusive); - public List getBlockedQueueItems(long thresholdMs, boolean exclusive); - public Long getQueueItemIdByContentIdAndType(long contentId, String contentType); + public SyncQueueItemVO getNextQueueItem(long queueId); + public int getActiveQueueItemCount(long queueId); + + public List getNextQueueItems(int maxItems); + + public List getActiveQueueItems(Long msid, boolean exclusive); + + public List getBlockedQueueItems(long thresholdMs, boolean exclusive); + + public Long getQueueItemIdByContentIdAndType(long contentId, String contentType); } diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/SyncQueueItemDaoImpl.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/SyncQueueItemDaoImpl.java index 2f04a7cc8902..41f14190f36d 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/SyncQueueItemDaoImpl.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/SyncQueueItemDaoImpl.java @@ -36,6 +36,7 @@ import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Func; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.TransactionLegacy; @@ -43,7 +44,8 @@ public class SyncQueueItemDaoImpl extends GenericDaoBase implements SyncQueueItemDao { private static final Logger s_logger = Logger.getLogger(SyncQueueItemDaoImpl.class); final GenericSearchBuilder queueIdSearch; - + final GenericSearchBuilder queueActiveItemSearch; + public SyncQueueItemDaoImpl() { super(); queueIdSearch = createSearchBuilder(Long.class); @@ -51,37 +53,52 @@ public SyncQueueItemDaoImpl() { queueIdSearch.and("contentType", queueIdSearch.entity().getContentType(), Op.EQ); queueIdSearch.selectFields(queueIdSearch.entity().getId()); queueIdSearch.done(); + + queueActiveItemSearch = createSearchBuilder(Integer.class); + queueActiveItemSearch.and("queueId", queueActiveItemSearch.entity().getQueueId(), Op.EQ); + queueActiveItemSearch.and("processNumber", queueActiveItemSearch.entity().getLastProcessNumber(), Op.NNULL); + queueActiveItemSearch.select(null, Func.COUNT, queueActiveItemSearch.entity().getId()); + queueActiveItemSearch.done(); } - @Override - public SyncQueueItemVO getNextQueueItem(long queueId) { - - SearchBuilder sb = createSearchBuilder(); + @Override + public SyncQueueItemVO getNextQueueItem(long queueId) { + + SearchBuilder sb = createSearchBuilder(); sb.and("queueId", sb.entity().getQueueId(), SearchCriteria.Op.EQ); - sb.and("lastProcessNumber", sb.entity().getLastProcessNumber(), SearchCriteria.Op.NULL); + sb.and("lastProcessNumber", sb.entity().getLastProcessNumber(), SearchCriteria.Op.NULL); sb.done(); - - SearchCriteria sc = sb.create(); - sc.setParameters("queueId", queueId); - - Filter filter = new Filter(SyncQueueItemVO.class, "created", true, 0L, 1L); + + SearchCriteria sc = sb.create(); + sc.setParameters("queueId", queueId); + + Filter filter = new Filter(SyncQueueItemVO.class, "created", true, 0L, 1L); List l = listBy(sc, filter); if(l != null && l.size() > 0) - return l.get(0); - - return null; - } - - @Override - public List getNextQueueItems(int maxItems) { - List l = new ArrayList(); - - String sql = "SELECT i.id, i.queue_id, i.content_type, i.content_id, i.created " + - " FROM sync_queue AS q JOIN sync_queue_item AS i ON q.id = i.queue_id " + + return l.get(0); + + return null; + } + + @Override + public int getActiveQueueItemCount(long queueId) { + SearchCriteria sc = queueActiveItemSearch.create(); + sc.setParameters("queueId", queueId); + + List count = customSearch(sc, null); + return count.get(0); + } + + @Override + public List getNextQueueItems(int maxItems) { + List l = new ArrayList(); + + String sql = "SELECT i.id, i.queue_id, i.content_type, i.content_id, i.created " + + " FROM sync_queue AS q JOIN sync_queue_item AS i ON q.id = i.queue_id " + " WHERE i.queue_proc_number IS NULL " + - " GROUP BY q.id " + - " ORDER BY i.id " + - " LIMIT 0, ?"; + " GROUP BY q.id " + + " ORDER BY i.id " + + " LIMIT 0, ?"; TransactionLegacy txn = TransactionLegacy.currentTxn(); PreparedStatement pstmt = null; @@ -90,54 +107,54 @@ public List getNextQueueItems(int maxItems) { pstmt.setInt(1, maxItems); ResultSet rs = pstmt.executeQuery(); while(rs.next()) { - SyncQueueItemVO item = new SyncQueueItemVO(); - item.setId(rs.getLong(1)); - item.setQueueId(rs.getLong(2)); - item.setContentType(rs.getString(3)); - item.setContentId(rs.getLong(4)); - item.setCreated(DateUtil.parseDateString(TimeZone.getTimeZone("GMT"), rs.getString(5))); - l.add(item); + SyncQueueItemVO item = new SyncQueueItemVO(); + item.setId(rs.getLong(1)); + item.setQueueId(rs.getLong(2)); + item.setContentType(rs.getString(3)); + item.setContentId(rs.getLong(4)); + item.setCreated(DateUtil.parseDateString(TimeZone.getTimeZone("GMT"), rs.getString(5))); + l.add(item); } } catch (SQLException e) { - s_logger.error("Unexpected sql excetpion, ", e); + s_logger.error("Unexpected sql excetpion, ", e); } catch (Throwable e) { - s_logger.error("Unexpected excetpion, ", e); + s_logger.error("Unexpected excetpion, ", e); } - return l; - } - - @Override - public List getActiveQueueItems(Long msid, boolean exclusive) { - SearchBuilder sb = createSearchBuilder(); + return l; + } + + @Override + public List getActiveQueueItems(Long msid, boolean exclusive) { + SearchBuilder sb = createSearchBuilder(); sb.and("lastProcessMsid", sb.entity().getLastProcessMsid(), - SearchCriteria.Op.EQ); + SearchCriteria.Op.EQ); sb.done(); - - SearchCriteria sc = sb.create(); - sc.setParameters("lastProcessMsid", msid); - - Filter filter = new Filter(SyncQueueItemVO.class, "created", true, null, null); - - if(exclusive) - return lockRows(sc, filter, true); + + SearchCriteria sc = sb.create(); + sc.setParameters("lastProcessMsid", msid); + + Filter filter = new Filter(SyncQueueItemVO.class, "created", true, null, null); + + if (exclusive) + return lockRows(sc, filter, true); return listBy(sc, filter); - } + } @Override public List getBlockedQueueItems(long thresholdMs, boolean exclusive) { Date cutTime = DateUtil.currentGMTTime(); - + SearchBuilder sbItem = createSearchBuilder(); sbItem.and("lastProcessMsid", sbItem.entity().getLastProcessMsid(), SearchCriteria.Op.NNULL); sbItem.and("lastProcessNumber", sbItem.entity().getLastProcessNumber(), SearchCriteria.Op.NNULL); sbItem.and("lastProcessNumber", sbItem.entity().getLastProcessTime(), SearchCriteria.Op.NNULL); sbItem.and("lastProcessTime2", sbItem.entity().getLastProcessTime(), SearchCriteria.Op.LT); - + sbItem.done(); - + SearchCriteria sc = sbItem.create(); sc.setParameters("lastProcessTime2", new Date(cutTime.getTime() - thresholdMs)); - + if(exclusive) return lockRows(sc, null, true); return listBy(sc, null); diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/VmWorkJobDao.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/VmWorkJobDao.java index dfb063f21a6a..bd6289ec4ed5 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/VmWorkJobDao.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/VmWorkJobDao.java @@ -29,7 +29,9 @@ public interface VmWorkJobDao extends GenericDao { VmWorkJobVO findPendingWorkJob(VirtualMachine.Type type, long instanceId); List listPendingWorkJobs(VirtualMachine.Type type, long instanceId); List listPendingWorkJobs(VirtualMachine.Type type, long instanceId, String jobCmd); - + void updateStep(long workJobId, Step step); void expungeCompletedWorkJobs(Date cutDate); + + void expungeLeftoverWorkJobs(long msid); } diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/VmWorkJobDaoImpl.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/VmWorkJobDaoImpl.java index 77515a797fe4..1ee7b25c54c2 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/VmWorkJobDaoImpl.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/dao/VmWorkJobDaoImpl.java @@ -16,8 +16,11 @@ // under the License. package org.apache.cloudstack.framework.jobs.dao; +import java.sql.PreparedStatement; +import java.sql.SQLException; import java.util.Date; import java.util.List; +import java.util.TimeZone; import javax.annotation.PostConstruct; @@ -31,24 +34,26 @@ 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.TransactionLegacy; +import com.cloud.utils.db.TransactionStatus; import com.cloud.vm.VirtualMachine; public class VmWorkJobDaoImpl extends GenericDaoBase implements VmWorkJobDao { protected SearchBuilder PendingWorkJobSearch; protected SearchBuilder PendingWorkJobByCommandSearch; - protected SearchBuilder ExpungeWorkJobSearch; - + public VmWorkJobDaoImpl() { } - + @PostConstruct public void init() { PendingWorkJobSearch = createSearchBuilder(); PendingWorkJobSearch.and("jobStatus", PendingWorkJobSearch.entity().getStatus(), Op.EQ); PendingWorkJobSearch.and("vmType", PendingWorkJobSearch.entity().getVmType(), Op.EQ); PendingWorkJobSearch.and("vmInstanceId", PendingWorkJobSearch.entity().getVmInstanceId(), Op.EQ); - PendingWorkJobSearch.and("step", PendingWorkJobSearch.entity().getStep(), Op.NEQ); PendingWorkJobSearch.done(); PendingWorkJobByCommandSearch = createSearchBuilder(); @@ -58,54 +63,49 @@ public void init() { PendingWorkJobByCommandSearch.and("step", PendingWorkJobByCommandSearch.entity().getStep(), Op.NEQ); PendingWorkJobByCommandSearch.and("cmd", PendingWorkJobByCommandSearch.entity().getCmd(), Op.EQ); PendingWorkJobByCommandSearch.done(); - - ExpungeWorkJobSearch = createSearchBuilder(); - ExpungeWorkJobSearch.and("lastUpdated", ExpungeWorkJobSearch.entity().getLastUpdated(), Op.LT); - ExpungeWorkJobSearch.and("jobStatus", ExpungeWorkJobSearch.entity().getStatus(), Op.NEQ); - ExpungeWorkJobSearch.done(); } - + @Override public VmWorkJobVO findPendingWorkJob(VirtualMachine.Type type, long instanceId) { - + SearchCriteria sc = PendingWorkJobSearch.create(); sc.setParameters("jobStatus", JobInfo. Status.IN_PROGRESS); sc.setParameters("vmType", type); sc.setParameters("vmInstanceId", instanceId); - + Filter filter = new Filter(VmWorkJobVO.class, "created", true, null, null); List result = this.listBy(sc, filter); if(result != null && result.size() > 0) return result.get(0); - + return null; } - + @Override public List listPendingWorkJobs(VirtualMachine.Type type, long instanceId) { - + SearchCriteria sc = PendingWorkJobSearch.create(); sc.setParameters("jobStatus", JobInfo.Status.IN_PROGRESS); sc.setParameters("vmType", type); sc.setParameters("vmInstanceId", instanceId); - + Filter filter = new Filter(VmWorkJobVO.class, "created", true, null, null); return this.listBy(sc, filter); } @Override public List listPendingWorkJobs(VirtualMachine.Type type, long instanceId, String jobCmd) { - + SearchCriteria sc = PendingWorkJobByCommandSearch.create(); sc.setParameters("jobStatus", JobInfo.Status.IN_PROGRESS); sc.setParameters("vmType", type); sc.setParameters("vmInstanceId", instanceId); sc.setParameters("cmd", jobCmd); - + Filter filter = new Filter(VmWorkJobVO.class, "created", true, null, null); return this.listBy(sc, filter); } - + @Override public void updateStep(long workJobId, Step step) { VmWorkJobVO jobVo = findById(workJobId); @@ -113,13 +113,82 @@ public void updateStep(long workJobId, Step step) { jobVo.setLastUpdated(DateUtil.currentGMTTime()); update(workJobId, jobVo); } - + @Override - public void expungeCompletedWorkJobs(Date cutDate) { - SearchCriteria sc = ExpungeWorkJobSearch.create(); - sc.setParameters("lastUpdated",cutDate); - sc.setParameters("jobStatus", JobInfo.Status.IN_PROGRESS); - - expunge(sc); + public void expungeCompletedWorkJobs(final Date cutDate) { + // current DAO machenism does not support following usage + /* + SearchCriteria sc = ExpungeWorkJobSearch.create(); + sc.setParameters("lastUpdated",cutDate); + sc.setParameters("jobStatus", JobInfo.Status.IN_PROGRESS); + + expunge(sc); + */ + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + TransactionLegacy txn = TransactionLegacy.currentTxn(); + + PreparedStatement pstmt = null; + try { + pstmt = txn.prepareAutoCloseStatement( + "DELETE FROM vm_work_job WHERE id IN (SELECT id FROM async_job WHERE job_dispatcher='VmWorkJobDispatcher' AND job_status != 0 AND last_updated < ?)"); + pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate)); + + pstmt.execute(); + } catch (SQLException e) { + } catch (Throwable e) { + } + + try { + pstmt = txn.prepareAutoCloseStatement( + "DELETE FROM async_job WHERE job_dispatcher='VmWorkJobDispatcher' AND job_status != 0 AND last_updated < ?"); + pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate)); + + pstmt.execute(); + } catch (SQLException e) { + } catch (Throwable e) { + } + } + }); } + + @Override + public void expungeLeftoverWorkJobs(final long msid) { + // current DAO machenism does not support following usage + /* + SearchCriteria sc = ExpungePlaceHolderWorkJobSearch.create(); + sc.setParameters("dispatcher", "VmWorkJobPlaceHolder"); + sc.setParameters("msid", msid); + + expunge(sc); + */ + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + TransactionLegacy txn = TransactionLegacy.currentTxn(); + + PreparedStatement pstmt = null; + try { + pstmt = txn.prepareAutoCloseStatement( + "DELETE FROM vm_work_job WHERE id IN (SELECT id FROM async_job WHERE (job_dispatcher='VmWorkJobPlaceHolder' OR job_dispatcher='VmWorkJobDispatcher') AND job_init_msid=?)"); + pstmt.setLong(1, msid); + + pstmt.execute(); + } catch (SQLException e) { + } catch (Throwable e) { + } + + try { + pstmt = txn.prepareAutoCloseStatement( + "DELETE FROM async_job WHERE (job_dispatcher='VmWorkJobPlaceHolder' OR job_dispatcher='VmWorkJobDispatcher') AND job_init_msid=?"); + pstmt.setLong(1, msid); + + pstmt.execute(); + } catch (SQLException e) { + } catch (Throwable e) { + } + } + }); + } } diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java index d79575273cd3..63c365b406d2 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java @@ -17,13 +17,13 @@ package org.apache.cloudstack.framework.jobs.impl; +import java.io.Serializable; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; @@ -33,6 +33,8 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.log4j.Logger; + import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; @@ -52,7 +54,6 @@ import org.apache.cloudstack.jobs.JobInfo.Status; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.utils.identity.ManagementServerNode; -import org.apache.log4j.Logger; import com.cloud.cluster.ClusterManagerListener; import com.cloud.cluster.ManagementServerHost; @@ -86,12 +87,12 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager, private static final Logger s_logger = Logger.getLogger(AsyncJobManagerImpl.class); - private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 3; // 3 seconds - private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC = 60; // 60 seconds + private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 3; // 3 seconds + private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC = 60; // 60 seconds private static final int MAX_ONETIME_SCHEDULE_SIZE = 50; private static final int HEARTBEAT_INTERVAL = 2000; - private static final int GC_INTERVAL = 10000; // 10 seconds + private static final int GC_INTERVAL = 10000; // 10 seconds @Inject private SyncQueueItemDao _queueItemDao; @@ -239,6 +240,8 @@ public List doInTransaction(TransactionStatus status) { if (resultObject != null) { job.setResult(resultObject); + } else { + job.setResult(null); } job.setLastUpdated(DateUtil.currentGMTTime()); @@ -358,38 +361,38 @@ public void completeJoin(long joinJobId, JobInfo.Status joinStatus, String joinR // I removed the temporary solution already. I think my changes should fix the deadlock. /* - ------------------------ - LATEST DETECTED DEADLOCK - ------------------------ - 130625 20:03:10 - *** (1) TRANSACTION: - TRANSACTION 0 98087127, ACTIVE 0 sec, process no 1489, OS thread id 139837829175040 fetching rows, thread declared inside InnoDB 494 - mysql tables in use 2, locked 1 - LOCK WAIT 3 lock struct(s), heap size 368, 2 row lock(s), undo log entries 1 - MySQL thread id 28408, query id 368571321 localhost 127.0.0.1 cloud preparing - UPDATE async_job SET job_pending_signals=1 WHERE id IN (SELECT job_id FROM async_job_join_map WHERE join_job_id = 9) - *** (1) WAITING FOR THIS LOCK TO BE GRANTED: - RECORD LOCKS space id 0 page no 1275 n bits 80 index `PRIMARY` of table `cloud`.`async_job` trx id 0 98087127 lock_mode X locks rec but not gap waiting - Record lock, heap no 9 PHYSICAL RECORD: n_fields 26; compact format; info bits 0 - 0: len 8; hex 0000000000000008; asc ;; 1: len 6; hex 000005d8b0d8; asc ;; 2: len 7; hex 00000009270110; asc ' ;; 3: len 8; hex 0000000000000002; asc ;; 4: len 8; hex 0000000000000002; asc ;; 5: SQL NULL; 6: SQL NULL; 7: len 30; hex 6f72672e6170616368652e636c6f7564737461636b2e6170692e636f6d6d; asc org.apache.cloudstack.api.comm;...(truncated); 8: len 30; hex 7b226964223a2232222c22706879736963616c6e6574776f726b6964223a; asc {"id":"2","physicalnetworkid":;...(truncated); 9: len 4; hex 80000000; asc ;; 10: len 4; hex 80000001; asc ;; 11: len 4; hex 80000000; asc ;; 12: len 4; hex 80000000; asc ;; 13: len 30; hex 6f72672e6170616368652e636c6f7564737461636b2e6170692e72657370; asc org.apache.cloudstack.api.resp;...(truncated); 14: len 8; hex 80001a6f7bb0d0a8; asc o{ ;; 15: len 8; hex 80001a6f7bb0d0a8; asc o{ ;; 16: len 8; hex 8000124f06cfd5b6; asc O ;; 17: len 8; hex 8000124f06cfd5b6; asc O ;; 18: SQL NULL; 19: SQL NULL; 20: len 30; hex 66376466396532362d323139622d346338652d393231332d393766653636; asc f7df9e26-219b-4c8e-9213-97fe66;...(truncated); 21: len 30; hex 36623238306364362d663436652d343563322d383833642d333863616439; asc 6b280cd6-f46e-45c2-883d-38cad9;...(truncated); 22: SQL NULL; 23: len 21; hex 4170694173796e634a6f6244697370617463686572; asc ApiAsyncJobDispatcher;; 24: SQL NULL; 25: len 4; hex 80000000; asc ;; - - *** (2) TRANSACTION: - TRANSACTION 0 98087128, ACTIVE 0 sec, process no 1489, OS thread id 139837671909120 fetching rows, thread declared inside InnoDB 492 - mysql tables in use 2, locked 1 - 3 lock struct(s), heap size 368, 2 row lock(s), undo log entries 1 - MySQL thread id 28406, query id 368571323 localhost 127.0.0.1 cloud preparing - UPDATE async_job SET job_pending_signals=1 WHERE id IN (SELECT job_id FROM async_job_join_map WHERE join_job_id = 8) - *** (2) HOLDS THE LOCK(S): - RECORD LOCKS space id 0 page no 1275 n bits 80 index `PRIMARY` of table `cloud`.`async_job` trx id 0 98087128 lock_mode X locks rec but not gap - Record lock, heap no 9 PHYSICAL RECORD: n_fields 26; compact format; info bits 0 - 0: len 8; hex 0000000000000008; asc ;; 1: len 6; hex 000005d8b0d8; asc ;; 2: len 7; hex 00000009270110; asc ' ;; 3: len 8; hex 0000000000000002; asc ;; 4: len 8; hex 0000000000000002; asc ;; 5: SQL NULL; 6: SQL NULL; 7: len 30; hex 6f72672e6170616368652e636c6f7564737461636b2e6170692e636f6d6d; asc org.apache.cloudstack.api.comm;...(truncated); 8: len 30; hex 7b226964223a2232222c22706879736963616c6e6574776f726b6964223a; asc {"id":"2","physicalnetworkid":;...(truncated); 9: len 4; hex 80000000; asc ;; 10: len 4; hex 80000001; asc ;; 11: len 4; hex 80000000; asc ;; 12: len 4; hex 80000000; asc ;; 13: len 30; hex 6f72672e6170616368652e636c6f7564737461636b2e6170692e72657370; asc org.apache.cloudstack.api.resp;...(truncated); 14: len 8; hex 80001a6f7bb0d0a8; asc o{ ;; 15: len 8; hex 80001a6f7bb0d0a8; asc o{ ;; 16: len 8; hex 8000124f06cfd5b6; asc O ;; 17: len 8; hex 8000124f06cfd5b6; asc O ;; 18: SQL NULL; 19: SQL NULL; 20: len 30; hex 66376466396532362d323139622d346338652d393231332d393766653636; asc f7df9e26-219b-4c8e-9213-97fe66;...(truncated); 21: len 30; hex 36623238306364362d663436652d343563322d383833642d333863616439; asc 6b280cd6-f46e-45c2-883d-38cad9;...(truncated); 22: SQL NULL; 23: len 21; hex 4170694173796e634a6f6244697370617463686572; asc ApiAsyncJobDispatcher;; 24: SQL NULL; 25: len 4; hex 80000000; asc ;; - - *** (2) WAITING FOR THIS LOCK TO BE GRANTED: - RECORD LOCKS space id 0 page no 1275 n bits 80 index `PRIMARY` of table `cloud`.`async_job` trx id 0 98087128 lock_mode X locks rec but not gap waiting - Record lock, heap no 10 PHYSICAL RECORD: n_fields 26; compact format; info bits 0 - 0: len 8; hex 0000000000000009; asc ;; 1: len 6; hex 000005d8b0d7; asc ;; 2: len 7; hex 00000009280110; asc ( ;; 3: len 8; hex 0000000000000002; asc ;; 4: len 8; hex 0000000000000002; asc ;; 5: SQL NULL; 6: SQL NULL; 7: len 30; hex 6f72672e6170616368652e636c6f7564737461636b2e6170692e636f6d6d; asc org.apache.cloudstack.api.comm;...(truncated); 8: len 30; hex 7b226964223a2233222c22706879736963616c6e6574776f726b6964223a; asc {"id":"3","physicalnetworkid":;...(truncated); 9: len 4; hex 80000000; asc ;; 10: len 4; hex 80000001; asc ;; 11: len 4; hex 80000000; asc ;; 12: len 4; hex 80000000; asc ;; 13: len 30; hex 6f72672e6170616368652e636c6f7564737461636b2e6170692e72657370; asc org.apache.cloudstack.api.resp;...(truncated); 14: len 8; hex 80001a6f7bb0d0a8; asc o{ ;; 15: len 8; hex 80001a6f7bb0d0a8; asc o{ ;; 16: len 8; hex 8000124f06cfd5b6; asc O ;; 17: len 8; hex 8000124f06cfd5b6; asc O ;; 18: SQL NULL; 19: SQL NULL; 20: len 30; hex 62313065306432342d336233352d343663622d386361622d623933623562; asc b10e0d24-3b35-46cb-8cab-b93b5b;...(truncated); 21: len 30; hex 39353664383563632d383336622d346663612d623738622d646238343739; asc 956d85cc-836b-4fca-b78b-db8479;...(truncated); 22: SQL NULL; 23: len 21; hex 4170694173796e634a6f6244697370617463686572; asc ApiAsyncJobDispatcher;; 24: SQL NULL; 25: len 4; hex 80000000; asc ;; - - *** WE ROLL BACK TRANSACTION (2) + ------------------------ + LATEST DETECTED DEADLOCK + ------------------------ + 130625 20:03:10 + *** (1) TRANSACTION: + TRANSACTION 0 98087127, ACTIVE 0 sec, process no 1489, OS thread id 139837829175040 fetching rows, thread declared inside InnoDB 494 + mysql tables in use 2, locked 1 + LOCK WAIT 3 lock struct(s), heap size 368, 2 row lock(s), undo log entries 1 + MySQL thread id 28408, query id 368571321 localhost 127.0.0.1 cloud preparing + UPDATE async_job SET job_pending_signals=1 WHERE id IN (SELECT job_id FROM async_job_join_map WHERE join_job_id = 9) + *** (1) WAITING FOR THIS LOCK TO BE GRANTED: + RECORD LOCKS space id 0 page no 1275 n bits 80 index `PRIMARY` of table `cloud`.`async_job` trx id 0 98087127 lock_mode X locks rec but not gap waiting + Record lock, heap no 9 PHYSICAL RECORD: n_fields 26; compact format; info bits 0 + 0: len 8; hex 0000000000000008; asc ;; 1: len 6; hex 000005d8b0d8; asc ;; 2: len 7; hex 00000009270110; asc ' ;; 3: len 8; hex 0000000000000002; asc ;; 4: len 8; hex 0000000000000002; asc ;; 5: SQL NULL; 6: SQL NULL; 7: len 30; hex 6f72672e6170616368652e636c6f7564737461636b2e6170692e636f6d6d; asc org.apache.cloudstack.api.comm;...(truncated); 8: len 30; hex 7b226964223a2232222c22706879736963616c6e6574776f726b6964223a; asc {"id":"2","physicalnetworkid":;...(truncated); 9: len 4; hex 80000000; asc ;; 10: len 4; hex 80000001; asc ;; 11: len 4; hex 80000000; asc ;; 12: len 4; hex 80000000; asc ;; 13: len 30; hex 6f72672e6170616368652e636c6f7564737461636b2e6170692e72657370; asc org.apache.cloudstack.api.resp;...(truncated); 14: len 8; hex 80001a6f7bb0d0a8; asc o{ ;; 15: len 8; hex 80001a6f7bb0d0a8; asc o{ ;; 16: len 8; hex 8000124f06cfd5b6; asc O ;; 17: len 8; hex 8000124f06cfd5b6; asc O ;; 18: SQL NULL; 19: SQL NULL; 20: len 30; hex 66376466396532362d323139622d346338652d393231332d393766653636; asc f7df9e26-219b-4c8e-9213-97fe66;...(truncated); 21: len 30; hex 36623238306364362d663436652d343563322d383833642d333863616439; asc 6b280cd6-f46e-45c2-883d-38cad9;...(truncated); 22: SQL NULL; 23: len 21; hex 4170694173796e634a6f6244697370617463686572; asc ApiAsyncJobDispatcher;; 24: SQL NULL; 25: len 4; hex 80000000; asc ;; + + *** (2) TRANSACTION: + TRANSACTION 0 98087128, ACTIVE 0 sec, process no 1489, OS thread id 139837671909120 fetching rows, thread declared inside InnoDB 492 + mysql tables in use 2, locked 1 + 3 lock struct(s), heap size 368, 2 row lock(s), undo log entries 1 + MySQL thread id 28406, query id 368571323 localhost 127.0.0.1 cloud preparing + UPDATE async_job SET job_pending_signals=1 WHERE id IN (SELECT job_id FROM async_job_join_map WHERE join_job_id = 8) + *** (2) HOLDS THE LOCK(S): + RECORD LOCKS space id 0 page no 1275 n bits 80 index `PRIMARY` of table `cloud`.`async_job` trx id 0 98087128 lock_mode X locks rec but not gap + Record lock, heap no 9 PHYSICAL RECORD: n_fields 26; compact format; info bits 0 + 0: len 8; hex 0000000000000008; asc ;; 1: len 6; hex 000005d8b0d8; asc ;; 2: len 7; hex 00000009270110; asc ' ;; 3: len 8; hex 0000000000000002; asc ;; 4: len 8; hex 0000000000000002; asc ;; 5: SQL NULL; 6: SQL NULL; 7: len 30; hex 6f72672e6170616368652e636c6f7564737461636b2e6170692e636f6d6d; asc org.apache.cloudstack.api.comm;...(truncated); 8: len 30; hex 7b226964223a2232222c22706879736963616c6e6574776f726b6964223a; asc {"id":"2","physicalnetworkid":;...(truncated); 9: len 4; hex 80000000; asc ;; 10: len 4; hex 80000001; asc ;; 11: len 4; hex 80000000; asc ;; 12: len 4; hex 80000000; asc ;; 13: len 30; hex 6f72672e6170616368652e636c6f7564737461636b2e6170692e72657370; asc org.apache.cloudstack.api.resp;...(truncated); 14: len 8; hex 80001a6f7bb0d0a8; asc o{ ;; 15: len 8; hex 80001a6f7bb0d0a8; asc o{ ;; 16: len 8; hex 8000124f06cfd5b6; asc O ;; 17: len 8; hex 8000124f06cfd5b6; asc O ;; 18: SQL NULL; 19: SQL NULL; 20: len 30; hex 66376466396532362d323139622d346338652d393231332d393766653636; asc f7df9e26-219b-4c8e-9213-97fe66;...(truncated); 21: len 30; hex 36623238306364362d663436652d343563322d383833642d333863616439; asc 6b280cd6-f46e-45c2-883d-38cad9;...(truncated); 22: SQL NULL; 23: len 21; hex 4170694173796e634a6f6244697370617463686572; asc ApiAsyncJobDispatcher;; 24: SQL NULL; 25: len 4; hex 80000000; asc ;; + + *** (2) WAITING FOR THIS LOCK TO BE GRANTED: + RECORD LOCKS space id 0 page no 1275 n bits 80 index `PRIMARY` of table `cloud`.`async_job` trx id 0 98087128 lock_mode X locks rec but not gap waiting + Record lock, heap no 10 PHYSICAL RECORD: n_fields 26; compact format; info bits 0 + 0: len 8; hex 0000000000000009; asc ;; 1: len 6; hex 000005d8b0d7; asc ;; 2: len 7; hex 00000009280110; asc ( ;; 3: len 8; hex 0000000000000002; asc ;; 4: len 8; hex 0000000000000002; asc ;; 5: SQL NULL; 6: SQL NULL; 7: len 30; hex 6f72672e6170616368652e636c6f7564737461636b2e6170692e636f6d6d; asc org.apache.cloudstack.api.comm;...(truncated); 8: len 30; hex 7b226964223a2233222c22706879736963616c6e6574776f726b6964223a; asc {"id":"3","physicalnetworkid":;...(truncated); 9: len 4; hex 80000000; asc ;; 10: len 4; hex 80000001; asc ;; 11: len 4; hex 80000000; asc ;; 12: len 4; hex 80000000; asc ;; 13: len 30; hex 6f72672e6170616368652e636c6f7564737461636b2e6170692e72657370; asc org.apache.cloudstack.api.resp;...(truncated); 14: len 8; hex 80001a6f7bb0d0a8; asc o{ ;; 15: len 8; hex 80001a6f7bb0d0a8; asc o{ ;; 16: len 8; hex 8000124f06cfd5b6; asc O ;; 17: len 8; hex 8000124f06cfd5b6; asc O ;; 18: SQL NULL; 19: SQL NULL; 20: len 30; hex 62313065306432342d336233352d343663622d386361622d623933623562; asc b10e0d24-3b35-46cb-8cab-b93b5b;...(truncated); 21: len 30; hex 39353664383563632d383336622d346663612d623738622d646238343739; asc 956d85cc-836b-4fca-b78b-db8479;...(truncated); 22: SQL NULL; 23: len 21; hex 4170694173796e634a6f6244697370617463686572; asc ApiAsyncJobDispatcher;; 24: SQL NULL; 25: len 4; hex 80000000; asc ;; + + *** WE ROLL BACK TRANSACTION (2) */ _joinMapDao.completeJoin(joinJobId, joinStatus, joinResult, getMsid()); @@ -402,23 +405,7 @@ public void syncAsyncJobExecution(AsyncJob job, String syncObjType, long syncObj } SyncQueueVO queue = null; - - // to deal with temporary DB exceptions like DB deadlock/Lock-wait time out cased rollbacks - // we retry five times until we throw an exception - Random random = new Random(); - - for (int i = 0; i < 5; i++) { - queue = _queueMgr.queue(syncObjType, syncObjId, SyncQueueItem.AsyncJobContentType, job.getId(), queueSizeLimit); - if (queue != null) { - break; - } - - try { - Thread.sleep(1000 + random.nextInt(5000)); - } catch (InterruptedException e) { - } - } - + queue = _queueMgr.queue(syncObjType, syncObjId, SyncQueueItem.AsyncJobContentType, job.getId(), queueSizeLimit); if (queue == null) throw new CloudRuntimeException("Unable to insert queue item into database, DB is full?"); } @@ -512,7 +499,9 @@ protected void runInContext() { if (jobDispatcher != null) { jobDispatcher.runJob(job); } else { - s_logger.error("Unable to find a wakeup dispatcher from the joined job: " + job); + // TODO, job wakeup is not in use yet + if (s_logger.isTraceEnabled()) + s_logger.trace("Unable to find a wakeup dispatcher from the joined job: " + job); } } else { AsyncJobDispatcher jobDispatcher = getDispatcher(job.getDispatcher()); @@ -633,7 +622,7 @@ public boolean waitAndCheck(AsyncJob job, String[] wakeupTopicsOnMessageBus, lon msgDetector.open(_messageBus, topics); try { long startTick = System.currentTimeMillis(); - while (System.currentTimeMillis() - startTick < timeoutInMiliseconds) { + while (timeoutInMiliseconds < 0 || System.currentTimeMillis() - startTick < timeoutInMiliseconds) { msgDetector.waitAny(checkIntervalInMilliSeconds); job = _jobDao.findById(job.getId()); if (job.getStatus().done()) { @@ -651,6 +640,21 @@ public boolean waitAndCheck(AsyncJob job, String[] wakeupTopicsOnMessageBus, lon return false; } + @Override + public String marshallResultObject(Serializable obj) { + if (obj != null) + return JobSerializerHelper.toObjectSerializedString(obj); + + return null; + } + + @Override + public Object unmarshallResultObject(AsyncJob job) { + if(job.getResult() != null) + return JobSerializerHelper.fromObjectSerializedString(job.getResult()); + return null; + } + private void checkQueue(long queueId) { while (true) { try { diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/OutcomeImpl.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/OutcomeImpl.java index 03c652c388af..23932e3b9f34 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/OutcomeImpl.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/OutcomeImpl.java @@ -50,7 +50,9 @@ public OutcomeImpl(Class clazz, AsyncJob job, long checkIntervalInMs, Predica @Override public AsyncJob getJob() { - return _job; + // always reload job so that we retrieve the latest job result + AsyncJob job = s_jobMgr.getAsyncJob(_job.getId()); + return job; } @Override @@ -109,13 +111,11 @@ public boolean isDone() { @Override public void execute(Task task) { // TODO Auto-generated method stub - } @Override public void execute(Task task, long wait, TimeUnit unit) { // TODO Auto-generated method stub - } public Predicate getPredicate() { diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/SyncQueueManagerImpl.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/SyncQueueManagerImpl.java index 7fb02454c881..9d3bf80b7dd2 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/SyncQueueManagerImpl.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/SyncQueueManagerImpl.java @@ -23,6 +23,7 @@ import javax.inject.Inject; import org.apache.log4j.Logger; + import org.apache.cloudstack.framework.jobs.dao.SyncQueueDao; import org.apache.cloudstack.framework.jobs.dao.SyncQueueItemDao; @@ -146,18 +147,18 @@ public void doInTransactionWithoutResult(TransactionStatus status) { processNumber = new Long(1); else processNumber = processNumber + 1; - + Date dt = DateUtil.currentGMTTime(); queueVO.setLastProcessNumber(processNumber); queueVO.setLastUpdated(dt); queueVO.setQueueSize(queueVO.getQueueSize() + 1); _syncQueueDao.update(queueVO.getId(), queueVO); - + itemVO.setLastProcessMsid(msid); itemVO.setLastProcessNumber(processNumber); itemVO.setLastProcessTime(dt); _syncQueueItemDao.update(item.getId(), itemVO); - + resultList.add(item); } } @@ -183,9 +184,9 @@ public void doInTransactionWithoutResult(TransactionStatus status) { SyncQueueItemVO itemVO = _syncQueueItemDao.findById(queueItemId); if(itemVO != null) { SyncQueueVO queueVO = _syncQueueDao.lockRow(itemVO.getQueueId(), true); - + _syncQueueItemDao.expunge(itemVO.getId()); - + // if item is active, reset queue information if (itemVO.getLastProcessMsid() != null) { queueVO.setLastUpdated(DateUtil.currentGMTTime()); @@ -239,18 +240,15 @@ public List getBlockedQueueItems(long thresholdMs, boolean excl } private boolean queueReadyToProcess(SyncQueueVO queueVO) { - return true; - - // - // TODO - // - // Need to disable concurrency disable at queue level due to the need to support - // job wake-up dispatching task - // - // Concurrency control is better done at higher level and leave the job scheduling/serializing simpler - // - - // return queueVO.getQueueSize() < queueVO.getQueueSizeLimit(); + int nActiveItems = _syncQueueItemDao.getActiveQueueItemCount(queueVO.getId()); + if (nActiveItems < queueVO.getQueueSizeLimit()) + return true; + + if (s_logger.isDebugEnabled()) + s_logger.debug("Queue (queue id, sync type, sync id) - (" + queueVO.getId() + + "," + queueVO.getSyncObjType() + ", " + queueVO.getSyncObjId() + + ") is reaching concurrency limit " + queueVO.getQueueSizeLimit()); + return false; } @Override diff --git a/framework/managed-context/pom.xml b/framework/managed-context/pom.xml index b4a9d83a0055..0daf27158f4a 100644 --- a/framework/managed-context/pom.xml +++ b/framework/managed-context/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-maven-standard - 4.3.0-SNAPSHOT + 4.3.0 ../../maven-standard/pom.xml diff --git a/framework/pom.xml b/framework/pom.xml index 14e3368d4bad..ebb7dba1b5e2 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.3.0-SNAPSHOT + 4.3.0 install diff --git a/framework/rest/pom.xml b/framework/rest/pom.xml index c6019720f955..8fe6916006fb 100644 --- a/framework/rest/pom.xml +++ b/framework/rest/pom.xml @@ -22,7 +22,7 @@ org.apache.cloudstack cloudstack-framework - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml cloud-framework-rest diff --git a/framework/spring/lifecycle/pom.xml b/framework/spring/lifecycle/pom.xml index 647101c69ca2..e65002fd3d77 100644 --- a/framework/spring/lifecycle/pom.xml +++ b/framework/spring/lifecycle/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-maven-standard - 4.3.0-SNAPSHOT + 4.3.0 ../../../maven-standard/pom.xml diff --git a/framework/spring/module/pom.xml b/framework/spring/module/pom.xml index b9d95a8447fc..5eb1a4192fd3 100644 --- a/framework/spring/module/pom.xml +++ b/framework/spring/module/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloud-maven-standard - 4.3.0-SNAPSHOT + 4.3.0 ../../../maven-standard/pom.xml diff --git a/maven-standard/pom.xml b/maven-standard/pom.xml index e4a81d846de4..90fc2eb239ca 100644 --- a/maven-standard/pom.xml +++ b/maven-standard/pom.xml @@ -25,7 +25,7 @@ org.apache.cloudstack cloudstack - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index cd6ff4bfbe21..b363a2ea5fd2 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -111,6 +111,7 @@ The Apache CloudStack files shared between agent and management server %package agent Summary: CloudStack Agent for KVM hypervisors +Requires: openssh-clients Requires: java >= 1.6.0 Requires: %{name}-common = %{_ver} Requires: libvirt @@ -125,6 +126,8 @@ Requires: jakarta-commons-daemon Requires: jakarta-commons-daemon-jsvc Requires: perl Requires: libvirt-python +Requires: qemu-img +Requires: qemu-kvm Provides: cloud-agent Obsoletes: cloud-agent < 4.1.0 Obsoletes: cloud-agent-libs < 4.1.0 @@ -133,6 +136,18 @@ Group: System Environment/Libraries %description agent The CloudStack agent for KVM hypervisors +%package baremetal-agent +Summary: CloudStack baremetal agent +Requires: tftp-server +Requires: xinetd +Requires: syslinux +Requires: chkconfig +Requires: dhcp +Requires: httpd +Group: System Environment/Libraries +%description baremetal-agent +The CloudStack baremetal agent + %package usage Summary: CloudStack Usage calculation server Requires: java >= 1.6.0 @@ -241,6 +256,7 @@ install -D client/target/utilities/bin/cloud-set-guest-sshkey ${RPM_BUILD_ROOT}% install -D client/target/utilities/bin/cloud-setup-databases ${RPM_BUILD_ROOT}%{_bindir}/%{name}-setup-databases install -D client/target/utilities/bin/cloud-setup-encryption ${RPM_BUILD_ROOT}%{_bindir}/%{name}-setup-encryption install -D client/target/utilities/bin/cloud-setup-management ${RPM_BUILD_ROOT}%{_bindir}/%{name}-setup-management +install -D client/target/utilities/bin/cloud-setup-baremetal ${RPM_BUILD_ROOT}%{_bindir}/%{name}-setup-baremetal install -D client/target/utilities/bin/cloud-sysvmadm ${RPM_BUILD_ROOT}%{_bindir}/%{name}-sysvmadm install -D client/target/utilities/bin/cloud-update-xenserver-licenses ${RPM_BUILD_ROOT}%{_bindir}/%{name}-update-xenserver-licenses @@ -252,7 +268,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 +467,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 +561,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 @@ -632,6 +646,9 @@ fi %{_defaultdocdir}/%{name}-awsapi-%{version}/LICENSE %{_defaultdocdir}/%{name}-awsapi-%{version}/NOTICE +%files baremetal-agent +%attr(0755,root,root) %{_bindir}/cloudstack-setup-baremetal + %changelog * Fri Oct 03 2012 Hugo Trippaers 4.1.0 diff --git a/packaging/debian/init/cloud-agent b/packaging/debian/init/cloud-agent index e7338752f3ef..ff550bb8f668 100755 --- a/packaging/debian/init/cloud-agent +++ b/packaging/debian/init/cloud-agent @@ -96,7 +96,7 @@ start() { wait_for_network - if start_daemon -p $PIDFILE $DAEMON -cp "$CLASSPATH" -pidfile "$PIDFILE" -errfile SYSLOG $CLASS + if start_daemon -p $PIDFILE $DAEMON -cp "$CLASSPATH" -Djna.nosys=true -pidfile "$PIDFILE" -errfile SYSLOG $CLASS RETVAL=$? then rc=0 diff --git a/parents/checkstyle/pom.xml b/parents/checkstyle/pom.xml index 48d58bb51d31..736e57463f8b 100644 --- a/parents/checkstyle/pom.xml +++ b/parents/checkstyle/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloud-maven-standard - 4.3.0-SNAPSHOT + 4.3.0 ../../maven-standard/pom.xml diff --git a/plugins/acl/static-role-based/pom.xml b/plugins/acl/static-role-based/pom.xml index b88c051752dd..fa93a0652f2e 100644 --- a/plugins/acl/static-role-based/pom.xml +++ b/plugins/acl/static-role-based/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/affinity-group-processors/explicit-dedication/pom.xml b/plugins/affinity-group-processors/explicit-dedication/pom.xml index 93859d952b15..3934dadb2c67 100644 --- a/plugins/affinity-group-processors/explicit-dedication/pom.xml +++ b/plugins/affinity-group-processors/explicit-dedication/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/affinity-group-processors/host-anti-affinity/pom.xml b/plugins/affinity-group-processors/host-anti-affinity/pom.xml index 575ddb0e92f9..973f7bad3b85 100644 --- a/plugins/affinity-group-processors/host-anti-affinity/pom.xml +++ b/plugins/affinity-group-processors/host-anti-affinity/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/alert-handlers/snmp-alerts/pom.xml b/plugins/alert-handlers/snmp-alerts/pom.xml index eb2545f4578c..cf07bc57d3a4 100644 --- a/plugins/alert-handlers/snmp-alerts/pom.xml +++ b/plugins/alert-handlers/snmp-alerts/pom.xml @@ -22,7 +22,7 @@ cloudstack-plugins org.apache.cloudstack - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml 4.0.0 diff --git a/plugins/alert-handlers/syslog-alerts/pom.xml b/plugins/alert-handlers/syslog-alerts/pom.xml index 07af6975f450..e0ebc6e5b29a 100644 --- a/plugins/alert-handlers/syslog-alerts/pom.xml +++ b/plugins/alert-handlers/syslog-alerts/pom.xml @@ -22,7 +22,7 @@ cloudstack-plugins org.apache.cloudstack - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml 4.0.0 diff --git a/plugins/api/discovery/pom.xml b/plugins/api/discovery/pom.xml index c86713eb3fcd..272f601d5fff 100644 --- a/plugins/api/discovery/pom.xml +++ b/plugins/api/discovery/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/api/rate-limit/pom.xml b/plugins/api/rate-limit/pom.xml index afbdbad01c95..0ce971c90996 100644 --- a/plugins/api/rate-limit/pom.xml +++ b/plugins/api/rate-limit/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/dedicated-resources/pom.xml b/plugins/dedicated-resources/pom.xml index fa30bbbbf6c3..4e27f63d13e3 100644 --- a/plugins/dedicated-resources/pom.xml +++ b/plugins/dedicated-resources/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../pom.xml diff --git a/plugins/deployment-planners/implicit-dedication/pom.xml b/plugins/deployment-planners/implicit-dedication/pom.xml index 58ee4ce8046a..4abf5e86c85b 100644 --- a/plugins/deployment-planners/implicit-dedication/pom.xml +++ b/plugins/deployment-planners/implicit-dedication/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/deployment-planners/user-concentrated-pod/pom.xml b/plugins/deployment-planners/user-concentrated-pod/pom.xml index 77f6ea30c184..7ffe194a21ad 100644 --- a/plugins/deployment-planners/user-concentrated-pod/pom.xml +++ b/plugins/deployment-planners/user-concentrated-pod/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/deployment-planners/user-dispersing/pom.xml b/plugins/deployment-planners/user-dispersing/pom.xml index 12e614f02529..d6415b52b0a8 100644 --- a/plugins/deployment-planners/user-dispersing/pom.xml +++ b/plugins/deployment-planners/user-dispersing/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/event-bus/rabbitmq/pom.xml b/plugins/event-bus/rabbitmq/pom.xml index 65834b81cd43..1e3ce9bdb466 100644 --- a/plugins/event-bus/rabbitmq/pom.xml +++ b/plugins/event-bus/rabbitmq/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/file-systems/netapp/pom.xml b/plugins/file-systems/netapp/pom.xml index 010df84f90fb..d9fd214e7889 100644 --- a/plugins/file-systems/netapp/pom.xml +++ b/plugins/file-systems/netapp/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/ha-planners/skip-heurestics/pom.xml b/plugins/ha-planners/skip-heurestics/pom.xml new file mode 100644 index 000000000000..21a9bda8fb64 --- /dev/null +++ b/plugins/ha-planners/skip-heurestics/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + cloud-plugin-planner-skip-heurestics + Apache CloudStack Plugin - Skip Heurestics Planner + + org.apache.cloudstack + cloudstack-plugins + 4.3.0 + ../../pom.xml + + diff --git a/plugins/ha-planners/skip-heurestics/resources/META-INF/cloudstack/skip-heurestics/module.properties b/plugins/ha-planners/skip-heurestics/resources/META-INF/cloudstack/skip-heurestics/module.properties new file mode 100644 index 000000000000..dfe0641ba4ad --- /dev/null +++ b/plugins/ha-planners/skip-heurestics/resources/META-INF/cloudstack/skip-heurestics/module.properties @@ -0,0 +1,18 @@ +# 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. +name=skip-heurestics +parent=planner diff --git a/plugins/ha-planners/skip-heurestics/resources/META-INF/cloudstack/skip-heurestics/spring-skip-heurestics-context.xml b/plugins/ha-planners/skip-heurestics/resources/META-INF/cloudstack/skip-heurestics/spring-skip-heurestics-context.xml new file mode 100644 index 000000000000..93a015874af3 --- /dev/null +++ b/plugins/ha-planners/skip-heurestics/resources/META-INF/cloudstack/skip-heurestics/spring-skip-heurestics-context.xml @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/plugins/ha-planners/skip-heurestics/src/com/cloud/deploy/SkipHeuresticsPlanner.java b/plugins/ha-planners/skip-heurestics/src/com/cloud/deploy/SkipHeuresticsPlanner.java new file mode 100644 index 000000000000..b67d112f825d --- /dev/null +++ b/plugins/ha-planners/skip-heurestics/src/com/cloud/deploy/SkipHeuresticsPlanner.java @@ -0,0 +1,61 @@ +// 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.deploy; + +import com.cloud.vm.VirtualMachineProfile; +import org.apache.log4j.Logger; + + +import javax.ejb.Local; +import javax.naming.ConfigurationException; +import java.util.List; +import java.util.Map; + +@Local(value=HAPlanner.class) +public class SkipHeuresticsPlanner extends FirstFitPlanner implements HAPlanner { + private static final Logger s_logger = Logger.getLogger(SkipHeuresticsPlanner.class); + + + /** + * This method should remove the clusters crossing capacity threshold + * to avoid further vm allocation on it. + * + * In case of HA, we shouldn't consider this threshold as we have reserved the capacity for such emergencies. + */ + @Override + protected void removeClustersCrossingThreshold(List clusterListForVmAllocation, ExcludeList avoid, + VirtualMachineProfile vmProfile, DeploymentPlan plan){ + if (s_logger.isDebugEnabled()) { + s_logger.debug("Deploying vm during HA process, so skipping disable threshold check"); + } + return; + } + + @Override + public boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) { + return true; + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + super.configure(name, params); + + return true; + + } + +} \ No newline at end of file diff --git a/plugins/host-allocators/random/pom.xml b/plugins/host-allocators/random/pom.xml index d2a510b2ed95..ecde04961525 100644 --- a/plugins/host-allocators/random/pom.xml +++ b/plugins/host-allocators/random/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/hypervisors/baremetal/pom.xml b/plugins/hypervisors/baremetal/pom.xml index 6b1d2e9f6bb6..d3858a8a004f 100755 --- a/plugins/hypervisors/baremetal/pom.xml +++ b/plugins/hypervisors/baremetal/pom.xml @@ -21,7 +21,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml cloud-plugin-hypervisor-baremetal diff --git a/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/cs_sg_agent.py b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/cs_sg_agent.py index a292c0bcfb8d..9bd541b0a07b 100755 --- a/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/cs_sg_agent.py +++ b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/cs_sg_agent.py @@ -16,222 +16,379 @@ # under the License. # # Automatically generated by addcopyright.py at 01/29/2013 -''' -Created on Jan 2, 2013 - -@author: frank -''' -import cherrypy -import sglib -import xmlobject -import types -import uuid -import os.path -import sys -import os - -class SGRule(object): - def __init__(self): - self.protocol = None - self.start_port = None - self.end_port = None - self.allowed_ips = [] - -class IPSet(object): - IPSET_TYPE = 'hash:ip' - def __init__(self, setname, ips): - self.ips = ips - self.name = setname - - def create(self): - tmpname = str(uuid.uuid4()).replace('-', '')[0:30] - sglib.ShellCmd('ipset -N %s %s' % (tmpname, self.IPSET_TYPE))() - try: - for ip in self.ips: - sglib.ShellCmd('ipset -A %s %s' % (tmpname, ip))() - - try: - sglib.ShellCmd('ipset -N %s %s' % (self.name, self.IPSET_TYPE))() - cherrypy.log('created new ipset: %s' % self.name) - except Exception: - cherrypy.log('%s already exists, no need to create new' % self.name) - finally: - sglib.ShellCmd('ipset -W %s %s' % (tmpname, self.name))() - sglib.ShellCmd('ipset -F %s' % tmpname)() - sglib.ShellCmd('ipset -X %s' % tmpname)() - - @staticmethod - def destroy_sets(sets_to_keep): - sets = sglib.ShellCmd('ipset list')() - for s in sets.split('\n'): - if 'Name:' in s: - set_name = s.split(':', 1)[1].strip() - if not set_name in sets_to_keep: - sglib.ShellCmd('ipset destroy %s' % set_name)() - cherrypy.log('destroyed unused ipset: %s' % set_name) - -class SGAgent(object): - def __init__(self): - pass - - def _self_list(self, obj): - if isinstance(obj, types.ListType): - return obj - else: - return [obj] - - def set_rules(self, req): - body = req.body - doc = xmlobject.loads(body) - vm_name = doc.vmName.text_ - vm_id = doc.vmId.text_ - vm_ip = doc.vmIp.text_ - vm_mac = doc.vmMac.text_ - sig = doc.signature.text_ - seq = doc.sequenceNumber.text_ - - def parse_rules(rules, lst): - for i in self._self_list(rules): - r = SGRule() - r.protocol = i.protocol.text_ - r.start_port = i.startPort.text_ - r.end_port = i.endPort.text_ - if hasattr(i, 'ip'): - for ip in self._self_list(i.ip): - r.allowed_ips.append(ip.text_) - lst.append(r) - - i_rules = [] - if hasattr(doc, 'ingressRules'): - parse_rules(doc.ingressRules, i_rules) - - e_rules = [] - if hasattr(doc, 'egressRules'): - parse_rules(doc.egressRules, e_rules) - - def create_chain(name): - try: - sglib.ShellCmd('iptables -F %s' % name)() - except Exception: - sglib.ShellCmd('iptables -N %s' % name)() - - def apply_rules(rules, chainname, direction, action, current_set_names): - create_chain(chainname) - for r in i_rules: - allow_any = False - if '0.0.0.0/0' in r.allowed_ips: - allow_any = True - r.allowed_ips.remove('0.0.0.0/0') - - if r.allowed_ips: - setname = '_'.join([chainname, r.protocol, r.start_port, r.end_port]) - ipset = IPSet(setname, r.allowed_ips) - ipset.create() - current_set_names.append(setname) - - if r.protocol == 'all': - cmd = ['iptables -I', chainname, '-m state --state NEW -m set --set', setname, direction, '-j', action] - sglib.ShellCmd(' '.join(cmd))() - elif r.protocol != 'icmp': - port_range = ":".join([r.start_port, r.end_port]) - cmd = ['iptables', '-I', chainname, '-p', r.protocol, '-m', r.protocol, '--dport', port_range, '-m state --state NEW -m set --set', setname, direction, '-j', action] - sglib.ShellCmd(' '.join(cmd))() - else: - port_range = "/".join([r.start_port, r.end_port]) - if r.start_port == "-1": - port_range = "any" - cmd = ['iptables', '-I', i_chain_name, '-p', 'icmp', '--icmp-type', port_range, '-m set --set', setname, direction, '-j', action] - sglib.ShellCmd(' '.join(cmd))() - - - if allow_any and r.protocol != 'all': - if r.protocol != 'icmp': - port_range = ":".join([r.start_port, r.end_port]) - cmd = ['iptables', '-I', chainname, '-p', r.protocol, '-m', r.protocol, '--dport', port_range, '-m', 'state', '--state', 'NEW', '-j', action] - sglib.ShellCmd(' '.join(cmd))() - else: - port_range = "/".join([r.start_port, r.end_port]) - if r.start_port == "-1": - port_range = "any" - cmd = ['iptables', '-I', i_chain_name, '-p', 'icmp', '--icmp-type', port_range, '-j', action] - sglib.ShellCmd(' '.join(cmd))() - - current_sets = [] - i_chain_name = vm_name + '-in' - apply_rules(i_rules, i_chain_name, 'src', 'ACCEPT', current_sets) - e_chain_name = vm_name + '-eg' - apply_rules(e_rules, e_chain_name, 'dst', 'RETURN', current_sets) - - if e_rules: - sglib.ShellCmd('iptables -A %s -j RETURN' % e_chain_name) - else: - sglib.ShellCmd('iptables -A %s -j DROP' % e_chain_name) - - sglib.ShellCmd('iptables -A %s -j DROP' % i_chain_name) - IPSet.destroy_sets(current_sets) - - - def echo(self, req): - cherrypy.log("echo: I am alive") - - def index(self): - req = sglib.Request.from_cherrypy_request(cherrypy.request) - cmd_name = req.headers['command'] - - if not hasattr(self, cmd_name): - raise ValueError("SecurityGroupAgent doesn't have a method called '%s'" % cmd_name) - method = getattr(self, cmd_name) - - return method(req) - index.exposed = True - - @staticmethod - def start(): - cherrypy.log.access_file = '/var/log/cs-securitygroup.log' - cherrypy.log.error_file = '/var/log/cs-securitygroup.log' - cherrypy.server.socket_host = '0.0.0.0' - cherrypy.server.socket_port = 9988 - cherrypy.quickstart(SGAgent()) - - @staticmethod - def stop(): - cherrypy.engine.exit() - -PID_FILE = '/var/run/cssgagent.pid' -class SGAgentDaemon(sglib.Daemon): - def __init__(self): - super(SGAgentDaemon, self).__init__(PID_FILE) - self.is_stopped = False - self.agent = SGAgent() - sglib.Daemon.register_atexit_hook(self._do_stop) - - def _do_stop(self): - if self.is_stopped: - return - self.is_stopped = True - self.agent.stop() - - def run(self): - self.agent.start() - - def stop(self): - self.agent.stop() - super(SGAgentDaemon, self).stop() - -def main(): - usage = 'usage: python -c "from security_group_agent import cs_sg_agent; cs_sg_agent.main()" start|stop|restart' - if len(sys.argv) != 2 or not sys.argv[1] in ['start', 'stop', 'restart']: - print usage - sys.exit(1) - - cmd = sys.argv[1] - agentdaemon = SGAgentDaemon() - if cmd == 'start': - agentdaemon.start() - elif cmd == 'stop': - agentdaemon.stop() - else: - agentdaemon.restart() - - sys.exit(0) - \ No newline at end of file + +''' +Created on Jan 2, 2013 + +@author: frank +''' +import cherrypy +import sglib +import xmlobject +import types +import uuid +import os.path +import sys +import os + +class SGRule(object): + def __init__(self): + self.protocol = None + self.start_port = None + self.end_port = None + self.allowed_ips = [] + +# iptables -D cannot handle rules having ipset match +# we have to delete these rules by line number that's why I introduce +# this class that maintains rules with their line number +class IptableChain(object): + def __init__(self): + self.name = None + self.rules = {} + + def delete_rule_by_line_number(self, num): + if str(num) not in self.rules.values(): + return + + sglib.ShellCmd('iptables -D %s %s' % (self.name, num))() + + @staticmethod + def from_iptable_lists(): + txt= sglib.ShellCmd('iptables --list --line-number')() + blocks = txt.split('\n') + + def is_rule_line(rule): + def is_number(n): + try: + int(n) + return True + except Exception: + return False + + words = rule.split() + return is_number(words[0]) + + current_chain = None + chains = [] + for line in blocks: + line = line.strip() + if line == '': + continue + + if line.startswith('Chain'): + current_chain = IptableChain() + current_chain.name = line.split()[1] + chains.append(current_chain) + continue + + if not is_rule_line(line): + continue + + specs = line.split(None, 6) + if len(specs) == 7: + # e.g '1 RETURN tcp -- anywhere anywhere tcp dpt:https state NEW match-set i-4-32-VM-eg_tcp_443_443 dst' + # the last part is spec, using spec as key + current_chain.rules[specs[-1]] = specs[0] + else: + # e.g '3 DROP all -- anywhere anywhere' + # no spec, using target as key + current_chain.rules[specs[1]] = specs[0] + + return chains + + + +class IPSet(object): + IPSET_TYPE = 'hash:net' + def __init__(self, setname, ips): + self.ips = ips + self.name = setname + + def create(self): + tmpname = str(uuid.uuid4()).replace('-', '')[0:30] + sglib.ShellCmd('ipset -N %s %s' % (tmpname, self.IPSET_TYPE))() + try: + for ip in self.ips: + sglib.ShellCmd('ipset -A %s %s' % (tmpname, ip))() + + try: + sglib.ShellCmd('ipset -N %s %s' % (self.name, self.IPSET_TYPE))() + cherrypy.log('created ip set as: \nname: %s\nips: %s\n' % (self.name, self.ips)) + except Exception: + cherrypy.log('%s already exists, no need to create new' % self.name) + finally: + sglib.ShellCmd('ipset -W %s %s' % (tmpname, self.name))() + sglib.ShellCmd('ipset -F %s' % tmpname)() + sglib.ShellCmd('ipset -X %s' % tmpname)() + + @staticmethod + def destroy_sets_not_in(sets_to_keep): + def remove_iptable_rules_having_set_name(setname): + chains = IptableChain.from_iptable_lists() + for c in chains: + for spec, linenum in c.rules.items(): + if setname in spec: + c.delete_rule_by_line_number(linenum) + # as line number will change each time after deleting a rule, + # we have to retrieve all chains again + # this shows that old solid tools also have old bad user experience + remove_iptable_rules_having_set_name(setname) + return + + sets = sglib.ShellCmd('ipset list')() + for s in sets.split('\n'): + if 'Name:' in s: + set_name = s.split(':', 1)[1].strip() + if not set_name in sets_to_keep: + remove_iptable_rules_having_set_name(set_name) + sglib.ShellCmd('ipset destroy %s' % set_name)() + cherrypy.log('destroyed unused ipset: %s' % set_name) + +class SGAgent(object): + RULE_HISTORY_PTH = '/var/lib/cloudstack/cs-agent.history' + + def __init__(self): + history_dir = os.path.dirname(self.RULE_HISTORY_PTH) + if not os.path.exists(history_dir): + os.makedirs(history_dir, 0755) + + def _self_list(self, obj): + if isinstance(obj, types.ListType): + return obj + else: + return [obj] + + def sync(self, req): + if not os.path.exists(self.RULE_HISTORY_PTH): + return '' + + with open(self.RULE_HISTORY_PTH, 'r') as fd: + history = fd.read() + + cherrypy.log('sync: %s' % history) + return history + + def create_rule_if_not_exists(self, rule): + out = sglib.ShellCmd('iptables-save')() + if rule in out: + return + + sglib.ShellCmd('iptables %s' % rule)() + + @sglib.lock('set_rules') + def set_rules(self, req): + body = req.body + cherrypy.log('received security group rules as:\n%s\n' % body) + doc = xmlobject.loads(body) + vm_name = doc.vmName.text_ + vm_id = doc.vmId.text_ + vm_ip = doc.vmIp.text_ + vm_mac = doc.vmMac.text_ + sig = doc.signature.text_ + seq = doc.sequenceNumber.text_ + + def parse_rules(rules, lst): + for i in self._self_list(rules): + r = SGRule() + r.protocol = i.protocol.text_ + r.start_port = i.startPort.text_ + r.end_port = i.endPort.text_ + if hasattr(i, 'ip'): + for ip in self._self_list(i.ip): + r.allowed_ips.append(ip.text_) + lst.append(r) + + i_rules = [] + if hasattr(doc, 'ingressRules'): + parse_rules(doc.ingressRules, i_rules) + + e_rules = [] + if hasattr(doc, 'egressRules'): + parse_rules(doc.egressRules, e_rules) + + def create_chain(name): + try: + sglib.ShellCmd('iptables -F %s' % name)() + except Exception: + sglib.ShellCmd('iptables -N %s' % name)() + + def delete_chain(name): + try: + sglib.ShellCmd('iptables -F %s' % name)() + + try: + sglib.ShellCmd('iptables -D INPUT -j %s' % name)() + except: + pass + + try: + sglib.ShellCmd('iptables -D OUTPUT -j %s' % name)() + except: + pass + + try: + sglib.ShellCmd('iptables -D %s -p tcp --dport 9988 -j ACCEPT' % name)() + except: + pass + + sglib.ShellCmd('iptables -X %s' % name)() + + cherrypy.log('deleted chain %s' % name) + except: + # safely ignore error + pass + + def apply_rules(rules, chainname, direction, action, current_set_names): + for r in rules: + allow_any = False + if '0.0.0.0/0' in r.allowed_ips: + allow_any = True + r.allowed_ips.remove('0.0.0.0/0') + + if r.allowed_ips: + setname = '_'.join([chainname, r.protocol, r.start_port, r.end_port]) + ipset = IPSet(setname, r.allowed_ips) + ipset.create() + current_set_names.append(setname) + + if r.protocol == 'all': + cmd = ['iptables -I', chainname, '-m state --state NEW -m set --set', setname, direction, '-j', action] + sglib.ShellCmd(' '.join(cmd))() + elif r.protocol != 'icmp': + port_range = ":".join([r.start_port, r.end_port]) + cmd = ['iptables', '-I', chainname, '-p', r.protocol, '-m', r.protocol, '--dport', port_range, '-m state --state NEW -m set --set', setname, direction, '-j', action] + sglib.ShellCmd(' '.join(cmd))() + else: + port_range = "/".join([r.start_port, r.end_port]) + if r.start_port == "-1": + port_range = "any" + cmd = ['iptables', '-I', chainname, '-p', 'icmp', '--icmp-type', port_range, '-m set --set', setname, direction, '-j', action] + sglib.ShellCmd(' '.join(cmd))() + + + if allow_any and r.protocol != 'all': + if r.protocol != 'icmp': + port_range = ":".join([r.start_port, r.end_port]) + cmd = ['iptables', '-I', chainname, '-p', r.protocol, '-m', r.protocol, '--dport', port_range, '-m', 'state', '--state', 'NEW', '-j', action] + sglib.ShellCmd(' '.join(cmd))() + else: + port_range = "/".join([r.start_port, r.end_port]) + if r.start_port == "-1": + port_range = "any" + cmd = ['iptables', '-I', chainname, '-p', 'icmp', '--icmp-type', port_range, '-j', action] + sglib.ShellCmd(' '.join(cmd))() + + current_sets = [] + i_chain_name = vm_name + '-in' + if i_rules: + create_chain(i_chain_name) + self.create_rule_if_not_exists('-A INPUT -j %s' % i_chain_name) + sglib.ShellCmd('iptables -A %s -p tcp --dport 9988 -j ACCEPT' % i_chain_name)() + sglib.ShellCmd('iptables -A %s -m state --state RELATED,ESTABLISHED -j ACCEPT' % i_chain_name)() + apply_rules(i_rules, i_chain_name, 'src', 'ACCEPT', current_sets) + sglib.ShellCmd('iptables -A %s -j DROP' % i_chain_name)() + else: + delete_chain(i_chain_name) + + e_chain_name = vm_name + '-eg' + if e_rules: + create_chain(e_chain_name) + self.create_rule_if_not_exists('-A OUTPUT -j %s' % e_chain_name) + sglib.ShellCmd('iptables -A %s -m state --state RELATED,ESTABLISHED -j RETURN' % e_chain_name)() + apply_rules(e_rules, e_chain_name, 'dst', 'RETURN', current_sets) + sglib.ShellCmd('iptables -A %s -j DROP' % e_chain_name) + else: + delete_chain(e_chain_name) + + IPSet.destroy_sets_not_in(current_sets) + + history = ','.join([vm_name, vm_id, vm_ip, '_', sig, seq]) + with open(self.RULE_HISTORY_PTH, 'w') as fd: + fd.write(history) + + + def echo(self, req): + cherrypy.log("echo: I am alive") + + def index(self): + req = sglib.Request.from_cherrypy_request(cherrypy.request) + cmd_name = req.headers['command'] + + if not hasattr(self, cmd_name): + raise ValueError("SecurityGroupAgent doesn't have a method called '%s'" % cmd_name) + method = getattr(self, cmd_name) + + return method(req) + index.exposed = True + + @staticmethod + def start(): + + def create_rule_if_not_exists(rule): + out = sglib.ShellCmd('iptables-save')() + if rule in out: + return + + sglib.ShellCmd('iptables %s' % rule)() + + def prepare_default_rules(): + sglib.ShellCmd('iptables --policy INPUT DROP')() + name = 'default-chain' + try: + sglib.ShellCmd('iptables -F %s' % name)() + except Exception: + sglib.ShellCmd('iptables -N %s' % name)() + + create_rule_if_not_exists('-I INPUT -p tcp --dport 9988 -j ACCEPT') + create_rule_if_not_exists('-I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT') + + + prepare_default_rules() + cherrypy.log.access_file = '/var/log/cs-securitygroup.log' + cherrypy.log.error_file = '/var/log/cs-securitygroup.log' + cherrypy.server.socket_host = '0.0.0.0' + cherrypy.server.socket_port = 9988 + cherrypy.quickstart(SGAgent()) + + @staticmethod + def stop(): + cherrypy.engine.exit() + +PID_FILE = '/var/run/cssgagent.pid' +class SGAgentDaemon(sglib.Daemon): + def __init__(self): + super(SGAgentDaemon, self).__init__(PID_FILE) + self.is_stopped = False + self.agent = SGAgent() + sglib.Daemon.register_atexit_hook(self._do_stop) + + def _do_stop(self): + if self.is_stopped: + return + self.is_stopped = True + self.agent.stop() + + def run(self): + self.agent.start() + + def stop(self): + self.agent.stop() + super(SGAgentDaemon, self).stop() + +def main(): + usage = 'usage: python -c "from security_group_agent import cs_sg_agent; cs_sg_agent.main()" start|stop|restart' + if len(sys.argv) != 2 or not sys.argv[1] in ['start', 'stop', 'restart']: + print usage + sys.exit(1) + + cmd = sys.argv[1] + agentdaemon = SGAgentDaemon() + if cmd == 'start': + agentdaemon.start() + elif cmd == 'stop': + agentdaemon.stop() + else: + agentdaemon.restart() + + sys.exit(0) + diff --git a/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/sglib.py b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/sglib.py index bf64effa1903..4eb8e437b6d4 100755 --- a/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/sglib.py +++ b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/sglib.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # 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 @@ -18,13 +17,55 @@ # # Automatically generated by addcopyright.py at 01/29/2013 -import sys, os, time, atexit -import traceback +#!/usr/bin/env python + +import sys, os, time, atexit +import traceback import subprocess -from signal import SIGTERM +from signal import SIGTERM,SIGKILL import cherrypy import copy +import weakref +import threading +import functools + +_internal_lock = threading.RLock() +_locks = weakref.WeakValueDictionary() + +def _get_lock(name): + with _internal_lock: + lock = _locks.get(name, threading.RLock()) + if not name in _locks: + _locks[name] = lock + return lock + +class NamedLock(object): + def __init__(self, name): + self.name = name + self.lock = None + + def __enter__(self): + self.lock = _get_lock(self.name) + self.lock.acquire() + #logger.debug('%s got lock %s' % (threading.current_thread().name, self.name)) + + def __exit__(self, type, value, traceback): + self.lock.release() + #logger.debug('%s released lock %s' % (threading.current_thread().name, self.name)) + + +def lock(name='defaultLock'): + def wrap(f): + @functools.wraps(f) + def inner(*args, **kwargs): + with NamedLock(name): + retval = f(*args, **kwargs) + return retval + return inner + return wrap + + class Request(object): def __init__(self): self.headers = None @@ -36,7 +77,10 @@ def __init__(self): def from_cherrypy_request(creq): req = Request() req.headers = copy.copy(creq.headers) - req.body = creq.body.fp.read() if creq.body else None + if hasattr(creq.body, 'fp'): + req.body = creq.body.fp.read() if creq.body else None + else: + req.body = creq.body.read() if creq.body else None req.method = copy.copy(creq.method) req.query_string = copy.copy(creq.query_string) if creq.query_string else None return req @@ -80,28 +124,28 @@ class Daemon(object): A generic daemon class. Usage: subclass the Daemon class and override the run() method - """ - atexit_hooks = [] + """ + atexit_hooks = [] def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): self.stdin = stdin self.stdout = stdout self.stderr = stderr self.pidfile = pidfile - - @staticmethod - def register_atexit_hook(hook): - Daemon.atexit_hooks.append(hook) - + @staticmethod - def _atexit(): - for hook in Daemon.atexit_hooks: - try: + def register_atexit_hook(hook): + Daemon.atexit_hooks.append(hook) + + @staticmethod + def _atexit(): + for hook in Daemon.atexit_hooks: + try: hook() - except Exception: + except Exception: content = traceback.format_exc() - err = 'Exception when calling atexit hook[%s]\n%s' % (hook.__name__, content) - #logger.error(err) + err = 'Exception when calling atexit hook[%s]\n%s' % (hook.__name__, content) + #logger.error(err) def daemonize(self): """ @@ -145,7 +189,7 @@ def daemonize(self): # write pidfile Daemon.register_atexit_hook(self.delpid) - atexit.register(Daemon._atexit) + atexit.register(Daemon._atexit) pid = str(os.getpid()) file(self.pidfile,'w').write("%s\n" % pid) @@ -173,12 +217,12 @@ def start(self): sys.exit(0) # Start the daemon - self.daemonize() + self.daemonize() try: - self.run() - except Exception: - content = traceback.format_exc() - #logger.error(content) + self.run() + except Exception: + content = traceback.format_exc() + #logger.error(content) sys.exit(1) def stop(self): @@ -192,25 +236,29 @@ def stop(self): pf.close() except IOError: pid = None - + if not pid: message = "pidfile %s does not exist. Daemon not running?\n" sys.stderr.write(message % self.pidfile) return # not an error in a restart # Try killing the daemon process - try: - while 1: - os.kill(pid, SIGTERM) - time.sleep(0.1) - except OSError, err: - err = str(err) - if err.find("No such process") > 0: - if os.path.exists(self.pidfile): - os.remove(self.pidfile) + wait_stop = 5 + start_time = time.time() + while 1: + if os.path.exists('/proc/' + str(pid)): + curr_time = time.time() + if (curr_time - start_time) > wait_stop: + os.kill(pid, SIGKILL) + else: + os.kill(pid, SIGTERM) + time.sleep(0.3) else: - print str(err) - sys.exit(1) + if os.path.exists(self.pidfile): + self.delpid() + break + + print "Stop Daemon Successfully" def restart(self): """ diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalDiscoverer.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalDiscoverer.java index 23eecd11c787..1120688fa7ca 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalDiscoverer.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalDiscoverer.java @@ -170,6 +170,8 @@ public Map> find(long dcId, Long p params.put(ApiConstants.PRIVATE_IP, ipmiIp); params.put(ApiConstants.USERNAME, username); params.put(ApiConstants.PASSWORD, password); + params.put("vmDao", _vmDao); + params.put("configDao", _configDao); String resourceClassName = _configDao.getValue(Config.ExternalBaremetalResourceClassName.key()); BareMetalResourceBase resource = null; @@ -284,6 +286,8 @@ protected HashMap buildConfigParams(HostVO host) { HashMap params = super.buildConfigParams(host); params.put("hostId", host.getId()); params.put("ipaddress", host.getPrivateIpAddress()); + params.put("vmDao", _vmDao); + params.put("configDao", _configDao); return params; } 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 fa7abd583314..4fe40a274bcf 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java @@ -22,53 +22,18 @@ // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.baremetal.networkservice; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import javax.ejb.Local; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import org.apache.cloudstack.api.ApiConstants; - import com.cloud.agent.IAgentControl; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.CheckNetworkAnswer; -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.MaintainAnswer; -import com.cloud.agent.api.MaintainCommand; -import com.cloud.agent.api.MigrateAnswer; -import com.cloud.agent.api.MigrateCommand; -import com.cloud.agent.api.PingCommand; -import com.cloud.agent.api.PingRoutingCommand; -import com.cloud.agent.api.PrepareForMigrationAnswer; -import com.cloud.agent.api.PrepareForMigrationCommand; -import com.cloud.agent.api.ReadyAnswer; -import com.cloud.agent.api.ReadyCommand; -import com.cloud.agent.api.RebootAnswer; -import com.cloud.agent.api.RebootCommand; -import com.cloud.agent.api.SecurityGroupRulesCmd; -import com.cloud.agent.api.StartAnswer; -import com.cloud.agent.api.StartCommand; -import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.StartupRoutingCommand; -import com.cloud.agent.api.StopAnswer; -import com.cloud.agent.api.StopCommand; +import com.cloud.agent.api.*; import com.cloud.agent.api.baremetal.IpmISetBootDevCommand; import com.cloud.agent.api.baremetal.IpmISetBootDevCommand.BootDev; import com.cloud.agent.api.baremetal.IpmiBootorResetCommand; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.baremetal.manager.BaremetalManager; +import com.cloud.configuration.Config; import com.cloud.host.Host.Type; import com.cloud.hypervisor.Hypervisor; import com.cloud.resource.ServerResource; -import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.Pair; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.OutputInterpreter; @@ -77,8 +42,19 @@ 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; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.log4j.Logger; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; @Local(value = ServerResource.class) public class BareMetalResourceBase extends ManagerBase implements ServerResource { @@ -109,7 +85,10 @@ public class BareMetalResourceBase extends ManagerBase implements ServerResource protected Script2 _forcePowerOffCommand; protected Script2 _bootOrRebootCommand; protected String _vmName; - protected VMInstanceDao vmDao; + protected int ipmiRetryTimes = 5; + + protected ConfigurationDao configDao; + protected VMInstanceDao vmDao; private void changeVmState(String vmName, VirtualMachine.State state) { synchronized (_vms) { @@ -147,6 +126,8 @@ public boolean configure(String name, Map params) throws Configu _password = (String) params.get(ApiConstants.PASSWORD); _vmName = (String) params.get("vmName"); String echoScAgent = (String) params.get(BaremetalManager.EchoSecurityGroupAgent); + vmDao = (VMInstanceDao) params.get("vmDao"); + configDao = (ConfigurationDao) params.get("configDao"); if (_pod == null) { throw new ConfigurationException("Unable to get the pod"); @@ -177,6 +158,19 @@ public boolean configure(String name, Map params) throws Configu _isEchoScAgent = Boolean.valueOf(echoScAgent); } + String ipmiIface = "default"; + try { + ipmiIface = configDao.getValue(Config.BaremetalIpmiLanInterface.key()); + } catch (Exception e) { + s_logger.debug(e.getMessage(), e); + } + + try { + ipmiRetryTimes = Integer.valueOf(configDao.getValue(Config.BaremetalIpmiRetryTimes.key())); + } catch (Exception e) { + s_logger.debug(e.getMessage(), e); + } + String injectScript = "scripts/util/ipmi.py"; String scriptPath = Script.findScript("", injectScript); if (scriptPath == null) { @@ -186,6 +180,7 @@ public boolean configure(String name, Map params) throws Configu _pingCommand = new Script2(pythonPath, s_logger); _pingCommand.add(scriptPath); _pingCommand.add("ping"); + _pingCommand.add("interface=" + ipmiIface); _pingCommand.add("hostname=" + _ip); _pingCommand.add("usrname=" + _username); _pingCommand.add("password=" + _password, ParamType.PASSWORD); @@ -193,6 +188,7 @@ public boolean configure(String name, Map params) throws Configu _setPxeBootCommand = new Script2(pythonPath, s_logger); _setPxeBootCommand.add(scriptPath); _setPxeBootCommand.add("boot_dev"); + _setPxeBootCommand.add("interface=" + ipmiIface); _setPxeBootCommand.add("hostname=" + _ip); _setPxeBootCommand.add("usrname=" + _username); _setPxeBootCommand.add("password=" + _password, ParamType.PASSWORD); @@ -201,6 +197,7 @@ public boolean configure(String name, Map params) throws Configu _setDiskBootCommand = new Script2(pythonPath, s_logger); _setDiskBootCommand.add(scriptPath); _setDiskBootCommand.add("boot_dev"); + _setDiskBootCommand.add("interface=" + ipmiIface); _setDiskBootCommand.add("hostname=" + _ip); _setDiskBootCommand.add("usrname=" + _username); _setDiskBootCommand.add("password=" + _password, ParamType.PASSWORD); @@ -209,6 +206,7 @@ public boolean configure(String name, Map params) throws Configu _rebootCommand = new Script2(pythonPath, s_logger); _rebootCommand.add(scriptPath); _rebootCommand.add("reboot"); + _rebootCommand.add("interface=" + ipmiIface); _rebootCommand.add("hostname=" + _ip); _rebootCommand.add("usrname=" + _username); _rebootCommand.add("password=" + _password, ParamType.PASSWORD); @@ -216,6 +214,7 @@ public boolean configure(String name, Map params) throws Configu _getStatusCommand = new Script2(pythonPath, s_logger); _getStatusCommand.add(scriptPath); _getStatusCommand.add("ping"); + _getStatusCommand.add("interface=" + ipmiIface); _getStatusCommand.add("hostname=" + _ip); _getStatusCommand.add("usrname=" + _username); _getStatusCommand.add("password=" + _password, ParamType.PASSWORD); @@ -223,6 +222,7 @@ public boolean configure(String name, Map params) throws Configu _powerOnCommand = new Script2(pythonPath, s_logger); _powerOnCommand.add(scriptPath); _powerOnCommand.add("power"); + _powerOnCommand.add("interface=" + ipmiIface); _powerOnCommand.add("hostname=" + _ip); _powerOnCommand.add("usrname=" + _username); _powerOnCommand.add("password=" + _password, ParamType.PASSWORD); @@ -231,6 +231,7 @@ public boolean configure(String name, Map params) throws Configu _powerOffCommand = new Script2(pythonPath, s_logger); _powerOffCommand.add(scriptPath); _powerOffCommand.add("power"); + _powerOffCommand.add("interface=" + ipmiIface); _powerOffCommand.add("hostname=" + _ip); _powerOffCommand.add("usrname=" + _username); _powerOffCommand.add("password=" + _password, ParamType.PASSWORD); @@ -239,6 +240,7 @@ public boolean configure(String name, Map params) throws Configu _forcePowerOffCommand = new Script2(pythonPath, s_logger); _forcePowerOffCommand.add(scriptPath); _forcePowerOffCommand.add("power"); + _forcePowerOffCommand.add("interface=" + ipmiIface); _forcePowerOffCommand.add("hostname=" + _ip); _forcePowerOffCommand.add("usrname=" + _username); _forcePowerOffCommand.add("password=" + _password, ParamType.PASSWORD); @@ -247,6 +249,7 @@ public boolean configure(String name, Map params) throws Configu _bootOrRebootCommand = new Script2(pythonPath, s_logger); _bootOrRebootCommand.add(scriptPath); _bootOrRebootCommand.add("boot_or_reboot"); + _bootOrRebootCommand.add("interface=" + ipmiIface); _bootOrRebootCommand.add("hostname=" + _ip); _bootOrRebootCommand.add("usrname=" + _username); _bootOrRebootCommand.add("password=" + _password, ParamType.PASSWORD); @@ -258,8 +261,15 @@ protected boolean doScript(Script cmd) { return doScript(cmd, null); } - protected boolean doScript(Script cmd, OutputInterpreter interpreter) { - int retry = 5; + protected boolean doScript(Script cmd, int retry) { + return doScript(cmd, null, retry); + } + + protected boolean doScript(Script cmd, OutputInterpreter interpreter) { + return doScript(cmd, interpreter, ipmiRetryTimes); + } + + protected boolean doScript(Script cmd, OutputInterpreter interpreter, int retry) { String res = null; while (retry-- > 0) { if (interpreter == null) { @@ -269,7 +279,11 @@ protected boolean doScript(Script cmd, OutputInterpreter interpreter) { } if (res != null && res.startsWith("Error: Unable to establish LAN")) { s_logger.warn("IPMI script timeout(" + cmd.toString() + "), will retry " + retry + " times"); - continue; + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + } + continue; } else if (res == null) { return true; } else { @@ -317,7 +331,6 @@ protected State getVmState() { protected Map fullSync() { 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(), vm.getState()); @@ -332,10 +345,35 @@ protected Map fullSync() { return states; } + + protected Map getHostVmStateReport() { + Map states = new HashMap(); + if (hostId != null) { + 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 +410,19 @@ public PingCommand getCurrentStatus(long id) { return null; } - return new PingRoutingCommand(getType(), id, deltaSync()); + if (hostId != null) { + final List vms = vmDao.listByHostId(hostId); + if (vms.isEmpty()) { + return new PingRoutingCommand(getType(), id, deltaSync(), getHostVmStateReport()); + } else { + VMInstanceVO vm = vms.get(0); + SecurityGroupHttpClient client = new SecurityGroupHttpClient(); + HashMap> nwGrpStates = client.sync(vm.getInstanceName(), vm.getId(), vm.getPrivateIpAddress()); + return new PingRoutingWithNwGroupsCommand(getType(), id, null, getHostVmStateReport(), nwGrpStates); + } + } else { + return new PingRoutingCommand(getType(), id, deltaSync(), getHostVmStateReport()); + } } protected Answer execute(IpmISetBootDevCommand cmd) { @@ -478,8 +528,17 @@ protected boolean isPowerOn(String str) { } protected RebootAnswer execute(final RebootCommand cmd) { - if (!doScript(_rebootCommand)) { - return new RebootAnswer(cmd, "IPMI reboot failed", false); + String infoStr = "Command not supported in present state"; + OutputInterpreter.AllLinesParser interpreter = new OutputInterpreter.AllLinesParser(); + if (!doScript(_rebootCommand, interpreter, 10)) { + if (interpreter.getLines().contains(infoStr)) { + // try again, this error should be temporary + if (!doScript(_rebootCommand, interpreter, 10)) { + return new RebootAnswer(cmd, "IPMI reboot failed", false); + } + } else { + return new RebootAnswer(cmd, "IPMI reboot failed", false); + } } return new RebootAnswer(cmd, "reboot succeeded", true); @@ -503,7 +562,8 @@ protected StopAnswer execute(final StopCommand cmd) { OutputInterpreter.AllLinesParser interpreter = new OutputInterpreter.AllLinesParser(); if (!doScript(_getStatusCommand, interpreter)) { - s_logger.warn("Cannot get power status of " + _name + ", assume VM state was not changed"); + success = true; + s_logger.warn("Cannot get power status of " + _name + ", assume VM state changed successfully"); break; } diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java index 8057cd42f919..b3fdab5b0302 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java @@ -25,6 +25,8 @@ import javax.ejb.Local; import javax.inject.Inject; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; import org.apache.log4j.Logger; import com.cloud.baremetal.database.BaremetalDhcpVO; @@ -64,12 +66,14 @@ public class BaremetalDhcpElement extends AdapterBase implements DhcpServiceProv @Inject NicDao _nicDao; @Inject BaremetalDhcpManager _dhcpMgr; + @Inject + PhysicalNetworkDao phyNwDao; static { Capability cap = new Capability(BaremetalDhcpManager.BAREMETAL_DHCP_SERVICE_CAPABITLITY); Map baremetalCaps = new HashMap(); - baremetalCaps.put(cap, null); - baremetalCaps.put(Capability.DhcpAccrossMultipleSubnets, Boolean.TRUE.toString()); + baremetalCaps.put(cap, null); + baremetalCaps.put(Capability.DhcpAccrossMultipleSubnets, Boolean.TRUE.toString()); capabilities = new HashMap>(); capabilities.put(Service.Dhcp, baremetalCaps); } @@ -87,8 +91,12 @@ public Provider getProvider() { private boolean canHandle(DeployDestination dest, TrafficType trafficType, GuestType networkType) { Pod pod = dest.getPod(); if (pod != null && dest.getDataCenter().getNetworkType() == NetworkType.Basic && trafficType == TrafficType.Guest) { + QueryBuilder phyq = QueryBuilder.create(PhysicalNetworkVO.class); + phyq.and(phyq.entity().getDataCenterId(), Op.EQ, dest.getDataCenter().getId()); + PhysicalNetworkVO phynw = phyq.find(); + QueryBuilder sc = QueryBuilder.create(BaremetalDhcpVO.class); - sc.and(sc.entity().getPodId(), Op.EQ,pod.getId()); + sc.and(sc.entity().getPhysicalNetworkId(), Op.EQ, phynw.getId()); return sc.find() != null; } diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java index 82397f5b31b6..e507b4d87167 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java @@ -133,14 +133,13 @@ protected String getDhcpServerGuid(String zoneId, String name, String ip) { public boolean addVirtualMachineIntoNetwork(Network network, NicProfile nic, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException { Long zoneId = profile.getVirtualMachine().getDataCenterId(); - Long podId = profile.getVirtualMachine().getPodIdToDeployIn(); - List hosts = _resourceMgr.listAllUpAndEnabledHosts(Type.BaremetalDhcp, null, podId, zoneId); + List hosts = _resourceMgr.listAllUpAndEnabledHosts(Type.BaremetalDhcp, null, null, zoneId); if (hosts.size() == 0) { - throw new CloudRuntimeException("No external Dhcp found in zone " + zoneId + " pod " + podId); + throw new CloudRuntimeException("No external Dhcp found in zone " + zoneId); } if (hosts.size() > 1) { - throw new CloudRuntimeException("Something wrong, more than 1 external Dhcp found in zone " + zoneId + " pod " + podId); + throw new CloudRuntimeException("Something wrong, more than 1 external Dhcp found in zone " + zoneId); } HostVO h = hosts.get(0); 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 2a17a4368420..f992fe9af3b1 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 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 StartupCommand[] initialize() { @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 a27a6f268963..dc778125777d 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 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 PingCommand getCurrentStatus(long id) { 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 d0fb2b4c0987..19a4d903609a 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 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 PingCommand getCurrentStatus(long id) { 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 7a7a5153e5c6..e4f0cee6faba 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 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 PingCommand getCurrentStatus(long id) { 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 2fb541544895..59efe245224e 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 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 PingCommand getCurrentStatus(long id) { 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/BaremetalPxeManagerImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManagerImpl.java index 9618e6bb47fd..e82eeceff5aa 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManagerImpl.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManagerImpl.java @@ -184,9 +184,9 @@ public List listPxeServers(ListBaremetalPxeServersCmd cmd) @Override public boolean addUserData(NicProfile nic, VirtualMachineProfile profile) { - UserVmVO vm = (UserVmVO) profile.getVirtualMachine(); + UserVmVO vm = _vmDao.findById(profile.getVirtualMachine().getId()); _vmDao.loadDetails(vm); - + String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()).getDisplayText(); String zoneName = _dcDao.findById(vm.getDataCenterId()).getName(); NicVO nvo = _nicDao.findById(nic.getId()); diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java index b9c2e8484aa0..efd4f2b70696 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java @@ -1,38 +1,220 @@ -// 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. -// -// Automatically generated by addcopyright.py at 01/29/2013 -// Apache License, Version 2.0 (the "License"); you may not use this -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -package com.cloud.baremetal.networkservice; - -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.SecurityGroupRulesCmd; - -public class SecurityGroupHttpClient { - - public Answer call(String guestIp, SecurityGroupRulesCmd cmd) { - // TODO Auto-generated method stub - return null; - } - - public boolean echo(String ip, long millis, long millis2) { - // TODO Auto-generated method stub - return false; - } - -} +// 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. +// +// Automatically generated by addcopyright.py at 01/29/2013 +// Apache License, Version 2.0 (the "License"); you may not use this +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// Automatically generated by addcopyright.py at 04/03/2012 + +package com.cloud.baremetal.networkservice; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.net.SocketTimeoutException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.zip.DeflaterOutputStream; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; + +import com.cloud.agent.api.SecurityGroupRuleAnswer; +import com.cloud.agent.api.SecurityGroupRulesCmd; +import com.cloud.agent.api.SecurityGroupRulesCmd.IpPortAndProto; +import com.cloud.baremetal.networkservice.schema.SecurityGroupRule; +import com.cloud.baremetal.networkservice.schema.SecurityGroupVmRuleSet; +import com.cloud.utils.Pair; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.StringRequestEntity; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; +import org.apache.log4j.Logger; + +public class SecurityGroupHttpClient { + private static final Logger logger = Logger.getLogger(SecurityGroupHttpClient.class); + private static final String ARG_NAME = "args"; + private static final String COMMAND = "command"; + private JAXBContext context; + private int port; + private static HttpClient httpClient; + + static { + MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager(); + httpClient = new HttpClient(connman); + httpClient.setConnectionTimeout(5000); + } + + private enum OpConstant { + setRules, echo, + } + + public SecurityGroupHttpClient() { + try { + context = JAXBContext.newInstance(SecurityGroupRule.class, SecurityGroupVmRuleSet.class); + port = 9988; + } catch (Exception e) { + throw new CloudRuntimeException( + "Unable to create JAXBContext for security group", e); + } + } + + private List generateRules(IpPortAndProto[] ipps) { + List rules = new ArrayList( + ipps.length); + for (SecurityGroupRulesCmd.IpPortAndProto ipp : ipps) { + SecurityGroupRule r = new SecurityGroupRule(); + r.setProtocol(ipp.getProto()); + r.setStartPort(ipp.getStartPort()); + r.setEndPort(ipp.getEndPort()); + for (String cidr : ipp.getAllowedCidrs()) { + r.getIp().add(cidr); + } + rules.add(r); + } + return rules; + } + + public HashMap> sync(String vmName, Long vmId, String agentIp) { + HashMap> states = new HashMap>(); + + PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort())); + try { + post.addRequestHeader("command", "sync"); + if (httpClient.executeMethod(post) != 200) { + logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString())); + } else { + String res = post.getResponseBodyAsString(); + // res = ';'.join([vmName, vmId, seqno]) + String[] rulelogs = res.split(","); + if (rulelogs.length != 6) { + logger.debug(String.format("host[%s] returns invalid security group sync document[%s], reset rules", agentIp, res)); + states.put(vmName, new Pair(vmId, -1L)); + return states; + } + + Pair p = new Pair(Long.valueOf(rulelogs[1]), Long.valueOf(rulelogs[5])); + states.put(rulelogs[0], p); + return states; + } + } catch (SocketTimeoutException se) { + logger.warn(String.format("unable to sync security group rules on host[%s], %s", agentIp, se.getMessage())); + } catch (Exception e) { + logger.warn(String.format("unable to sync security group rules on host[%s]", agentIp), e); + } finally { + if (post != null) { + post.releaseConnection(); + } + } + return states; + } + + public boolean echo(String agentIp, long l, long m) { + boolean ret = false; + int count = 1; + while (true) { + try { + Thread.sleep(m); + count++; + } catch (InterruptedException e1) { + logger.warn("", e1); + break; + } + + PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort())); + try { + post.addRequestHeader("command", "echo"); + if (httpClient.executeMethod(post) != 200) { + logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString())); + } else { + ret = true; + } + break; + } catch (Exception e) { + if (count*m >= l) { + logger.debug(String.format("ping security group agent on vm[%s] timeout after %s minutes, starting vm failed, count=%s", agentIp, TimeUnit.MILLISECONDS.toSeconds(l), count)); + break; + } else { + logger.debug(String.format("Having pinged security group agent on vm[%s] %s times, continue to wait...", agentIp, count)); + } + } finally { + if (post != null) { + post.releaseConnection(); + } + } + } + return ret; + } + + public SecurityGroupRuleAnswer call(String agentIp, + SecurityGroupRulesCmd cmd) { + PostMethod post = new PostMethod(String.format( + "http://%s:%s", agentIp, getPort())); + try { + SecurityGroupVmRuleSet rset = new SecurityGroupVmRuleSet(); + rset.getEgressRules().addAll(generateRules(cmd.getEgressRuleSet())); + rset.getIngressRules().addAll( + generateRules(cmd.getIngressRuleSet())); + rset.setVmName(cmd.getVmName()); + rset.setVmIp(cmd.getGuestIp()); + rset.setVmMac(cmd.getGuestMac()); + rset.setVmId(cmd.getVmId()); + rset.setSignature(cmd.getSignature()); + rset.setSequenceNumber(cmd.getSeqNum()); + Marshaller marshaller = context.createMarshaller(); + StringWriter writer = new StringWriter(); + marshaller.marshal(rset, writer); + String xmlContents = writer.toString(); + logger.debug(xmlContents); + + post.addRequestHeader("command", "set_rules"); + StringRequestEntity entity = new StringRequestEntity(xmlContents); + post.setRequestEntity(entity); + if (httpClient.executeMethod(post) != 200) { + return new SecurityGroupRuleAnswer(cmd, false, + post.getResponseBodyAsString()); + } else { + return new SecurityGroupRuleAnswer(cmd); + } + } catch (Exception e) { + return new SecurityGroupRuleAnswer(cmd, false, e.getMessage()); + } finally { + if (post != null) { + post.releaseConnection(); + } + } + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } +} diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/ObjectFactory.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/ObjectFactory.java new file mode 100644 index 000000000000..d0944ce984d0 --- /dev/null +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/ObjectFactory.java @@ -0,0 +1,55 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2012.07.11 at 03:24:15 PM PDT +// + + +package com.cloud.baremetal.networkservice.schema; + +import javax.xml.bind.annotation.XmlRegistry; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the com.cloud.network.security.schema package. + *

An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.cloud.network.security.schema + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link SecurityGroupRule } + * + */ + public SecurityGroupRule createSecurityGroupRule() { + return new SecurityGroupRule(); + } + + /** + * Create an instance of {@link SecurityGroupVmRuleSet } + * + */ + public SecurityGroupVmRuleSet createSecurityGroupVmRuleSet() { + return new SecurityGroupVmRuleSet(); + } + +} diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupRule.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupRule.java new file mode 100644 index 000000000000..a8958dda1004 --- /dev/null +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupRule.java @@ -0,0 +1,146 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2012.07.11 at 03:24:15 PM PDT +// + + +package com.cloud.baremetal.networkservice.schema; + +import java.util.ArrayList; +import java.util.List; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for SecurityGroupRule complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="SecurityGroupRule">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="protocol" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="startPort" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
+ *         <element name="endPort" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
+ *         <sequence maxOccurs="unbounded" minOccurs="0">
+ *           <element name="ip" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         </sequence>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "SecurityGroupRule", propOrder = { + "protocol", + "startPort", + "endPort", + "ip" +}) +public class SecurityGroupRule { + + @XmlElement(required = true) + protected String protocol; + @XmlSchemaType(name = "unsignedInt") + protected long startPort; + @XmlSchemaType(name = "unsignedInt") + protected long endPort; + protected List ip; + + /** + * Gets the value of the protocol property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getProtocol() { + return protocol; + } + + /** + * Sets the value of the protocol property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setProtocol(String value) { + this.protocol = value; + } + + /** + * Gets the value of the startPort property. + * + */ + public long getStartPort() { + return startPort; + } + + /** + * Sets the value of the startPort property. + * + */ + public void setStartPort(long value) { + this.startPort = value; + } + + /** + * Gets the value of the endPort property. + * + */ + public long getEndPort() { + return endPort; + } + + /** + * Sets the value of the endPort property. + * + */ + public void setEndPort(long value) { + this.endPort = value; + } + + /** + * Gets the value of the ip property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the ip property. + * + *

+ * For example, to add a new item, do as follows: + *

+     *    getIp().add(newItem);
+     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link String } + * + * + */ + public List getIp() { + if (ip == null) { + ip = new ArrayList(); + } + return this.ip; + } + +} diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupVmRuleSet.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupVmRuleSet.java new file mode 100644 index 000000000000..7ad13cea3d19 --- /dev/null +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupVmRuleSet.java @@ -0,0 +1,263 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2012.07.11 at 03:24:15 PM PDT +// + + +package com.cloud.baremetal.networkservice.schema; + +import java.util.ArrayList; +import java.util.List; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType>
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="vmName" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="vmId" type="{http://www.w3.org/2001/XMLSchema}long"/>
+ *         <element name="vmIp" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="vmMac" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="signature" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="sequenceNumber" type="{http://www.w3.org/2001/XMLSchema}long"/>
+ *         <sequence maxOccurs="unbounded" minOccurs="0">
+ *           <element name="ingressRules" type="{}SecurityGroupRule"/>
+ *         </sequence>
+ *         <sequence maxOccurs="unbounded" minOccurs="0">
+ *           <element name="egressRules" type="{}SecurityGroupRule"/>
+ *         </sequence>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "vmName", + "vmId", + "vmIp", + "vmMac", + "signature", + "sequenceNumber", + "ingressRules", + "egressRules" +}) +@XmlRootElement(name = "SecurityGroupVmRuleSet") +public class SecurityGroupVmRuleSet { + + @XmlElement(required = true) + protected String vmName; + protected long vmId; + @XmlElement(required = true) + protected String vmIp; + @XmlElement(required = true) + protected String vmMac; + @XmlElement(required = true) + protected String signature; + protected long sequenceNumber; + protected List ingressRules; + protected List egressRules; + + /** + * Gets the value of the vmName property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getVmName() { + return vmName; + } + + /** + * Sets the value of the vmName property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setVmName(String value) { + this.vmName = value; + } + + /** + * Gets the value of the vmId property. + * + */ + public long getVmId() { + return vmId; + } + + /** + * Sets the value of the vmId property. + * + */ + public void setVmId(long value) { + this.vmId = value; + } + + /** + * Gets the value of the vmIp property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getVmIp() { + return vmIp; + } + + /** + * Sets the value of the vmIp property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setVmIp(String value) { + this.vmIp = value; + } + + /** + * Gets the value of the vmMac property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getVmMac() { + return vmMac; + } + + /** + * Sets the value of the vmMac property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setVmMac(String value) { + this.vmMac = value; + } + + /** + * Gets the value of the signature property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getSignature() { + return signature; + } + + /** + * Sets the value of the signature property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setSignature(String value) { + this.signature = value; + } + + /** + * Gets the value of the sequenceNumber property. + * + */ + public long getSequenceNumber() { + return sequenceNumber; + } + + /** + * Sets the value of the sequenceNumber property. + * + */ + public void setSequenceNumber(long value) { + this.sequenceNumber = value; + } + + /** + * Gets the value of the ingressRules property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the ingressRules property. + * + *

+ * For example, to add a new item, do as follows: + *

+     *    getIngressRules().add(newItem);
+     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link SecurityGroupRule } + * + * + */ + public List getIngressRules() { + if (ingressRules == null) { + ingressRules = new ArrayList(); + } + return this.ingressRules; + } + + /** + * Gets the value of the egressRules property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the egressRules property. + * + *

+ * For example, to add a new item, do as follows: + *

+     *    getEgressRules().add(newItem);
+     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link SecurityGroupRule } + * + * + */ + public List getEgressRules() { + if (egressRules == null) { + egressRules = new ArrayList(); + } + return this.egressRules; + } + +} diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/.nuget/NuGet.targets b/plugins/hypervisors/hyperv/DotNet/ServerResource/.nuget/NuGet.targets index d0ebc7535f3b..a56da2432df4 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/.nuget/NuGet.targets +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/.nuget/NuGet.targets @@ -2,7 +2,7 @@ $(MSBuildProjectDirectory)\..\ - + false @@ -11,11 +11,10 @@ true - + false - @@ -25,37 +24,34 @@ --> - + $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) $([System.IO.Path]::Combine($(ProjectDir), "packages.config")) - - + + $(SolutionDir).nuget - packages.config + $(ProjectDir)packages.config - + $(NuGetToolsPath)\NuGet.exe @(PackageSource) - - "$(NuGetExePath)" - mono --runtime=v4.0.30319 $(NuGetExePath) + + "$(NuGetExePath)" + mono --runtime=v4.0.30319 $(NuGetExePath) $(TargetDir.Trim('\\')) - + -RequireConsent -NonInteractive - - "$(SolutionDir) " - "$(SolutionDir)" - $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) - $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols + $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir "$(SolutionDir)\" + $(NuGetCommand) pack "$(ProjectPath)" -Properties Configuration=$(Configuration) $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols @@ -87,22 +83,22 @@ - + Condition="( '$(OS)' != 'Windows_NT' Or '$(BuildWithMono)' == 'true' ) And Exists('$(PackagesConfig)')" /> + + Condition="'$(OS)' == 'Windows_NT' And '$(BuildWithMono)' != 'true' And Exists('$(PackagesConfig)')" /> - - + + + Condition=" '$(OS)' == 'Windows_NT' And '$(BuildWithMono)' != 'true' " /> - + @@ -133,4 +129,4 @@ - \ No newline at end of file + diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentService.Designer.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentService.Designer.cs index 854427732aa1..4bf424fa4b93 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentService.Designer.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentService.Designer.cs @@ -45,7 +45,7 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { components = new System.ComponentModel.Container(); - this.ServiceName = "CloudStack ServerResource"; + this.ServiceName = Program.serviceName; } #endregion diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentService.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentService.cs index e18709735114..9d66a5cd1bfc 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentService.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentService.cs @@ -47,7 +47,7 @@ public AgentService() logger.Info("Starting CloudStack agent"); InitializeComponent(); - UriBuilder baseUri = new UriBuilder("http", AgentSettings.Default.private_ip_address, AgentSettings.Default.port); + UriBuilder baseUri = new UriBuilder("https", AgentSettings.Default.private_ip_address, AgentSettings.Default.port); var config = new HttpSelfHostConfiguration(baseUri.Uri); diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentShell.csproj b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentShell.csproj index 39fef1606a2b..f804ef6f6704 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentShell.csproj +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentShell.csproj @@ -70,6 +70,7 @@ ..\packages\NSubstitute.1.6.1.0\lib\NET40\NSubstitute.dll + @@ -101,6 +102,12 @@ + + Component + + + ProjectInstaller.cs + True @@ -130,6 +137,10 @@ + + + + - + \ No newline at end of file diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/App.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/App.config index 68ab80ee5557..b783dfecd631 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/App.config +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/App.config @@ -10,9 +10,9 @@ - + - + @@ -25,13 +25,14 @@ + - + diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/Program.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/Program.cs index 10663708508e..7545644fb70b 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/Program.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/Program.cs @@ -21,12 +21,21 @@ using System.ServiceProcess; using System.Text; using System.Threading.Tasks; +using System.Configuration.Install; +using System.Collections; namespace CloudStack.Plugin.AgentShell { static class Program { private static ILog logger = LogManager.GetLogger(typeof(Program)); + public const string serviceName = "CloudStack Hyper-V Agent"; + private static string option = null; + private static string user = null; + private static string password = null; + private const string install = "--install"; + private const string uninstall = "--uninstall"; + private const string console = "--console"; ///

/// Application entry point allows service to run in console application or as a Windows service. @@ -34,24 +43,240 @@ static class Program /// static void Main(params string[] args) { - string arg1 = string.Empty; + if (args.Length == 0) + { + logger.InfoFormat(serviceName + " running as Windows Service"); + ServiceBase[] ServicesToRun = new ServiceBase[] { new AgentService() }; + ServiceBase.Run(ServicesToRun); + } + else if (ParseArguments(args)) + { + switch (option) + { + case install: + logger.InfoFormat("Installing and running " + serviceName); + InstallService(); + StartService(); + break; + case uninstall: + logger.InfoFormat("Stopping and uninstalling " + serviceName); + StopService(); + UninstallService(); + break; + case console: + logger.InfoFormat(serviceName + " is running as console application"); + new AgentService().RunConsole(args); + break; + default: + throw new NotImplementedException(); + } + } + else + { + string argumentExample = "--(install/uninstall/console) [-u ] [-p ].\n" + + " For example:\n " + + " --install -u domain1\\user1 -p mypwd\n"+ + " --uninstall"; + logger.Error("Invalid arguments passed for installing\\uninstalling the service. \n" + argumentExample); + } + } - if (args.Length > 0) + static private Boolean ParseArguments(string[] args) + { + logger.DebugFormat(serviceName + " arg is ", args[0]); + int argIndex = 0; + while (argIndex < args.Length) { - arg1 = args[0]; - logger.DebugFormat("CloudStack ServerResource arg is ", arg1); + switch (args[argIndex]) + { + case install: + case uninstall: + case console: + option = args[argIndex]; + argIndex++; + break; + case "-u": + user = args[argIndex+1]; + argIndex+=2; + break; + case "-p": + password = args[argIndex+1]; + argIndex+=2; + break; + default: + argIndex++; + // Unrecognised argument. Do nothing; + break; + } } - if (string.Compare(arg1, "--console", true) == 0) + // Validate arguments + return ValidateArguments(); + } + + private static Boolean ValidateArguments() + { + Boolean argsValid = false; + switch (option) { - logger.InfoFormat("CloudStack ServerResource running as console app"); - new AgentService().RunConsole(args); + case uninstall: + case install: + case console: + argsValid = true; + break; + default: + break; } - else + + return argsValid; + } + + public static string GetPassword() + { + return password; + } + + public static string GetUser() + { + return user; + } + + private static bool IsInstalled() + { + using (ServiceController controller = + new ServiceController(serviceName)) { - logger.InfoFormat("CloudStack ServerResource running as Windows Service"); - ServiceBase[] ServicesToRun = new ServiceBase[] { new AgentService() }; - ServiceBase.Run(ServicesToRun); + try + { + ServiceControllerStatus status = controller.Status; + } + catch + { + return false; + } + return true; + } + } + + private static bool IsRunning() + { + using (ServiceController controller = + new ServiceController(serviceName)) + { + if (!IsInstalled()) return false; + return (controller.Status == ServiceControllerStatus.Running); + } + } + + private static AssemblyInstaller GetInstaller() + { + AssemblyInstaller installer = new AssemblyInstaller( + typeof(Program).Assembly, null); + installer.UseNewContext = true; + return installer; + } + + private static void InstallService() + { + if (IsInstalled()) return; + + try + { + using (AssemblyInstaller installer = GetInstaller()) + { + IDictionary state = new Hashtable(); + try + { + installer.Install(state); + installer.Commit(state); + } + catch + { + try + { + installer.Rollback(state); + } + catch { } + throw; + } + } + } + catch (Exception ex) + { + logger.ErrorFormat(" Error occured in installing service " + ex.Message); + throw; + } + } + + private static void UninstallService() + { + if (!IsInstalled()) return; + try + { + using (AssemblyInstaller installer = GetInstaller()) + { + IDictionary state = new Hashtable(); + try + { + installer.Uninstall(state); + } + catch + { + throw; + } + } + } + catch (Exception ex) + { + logger.ErrorFormat(" Error occured in uninstalling service " + ex.Message); + throw; + } + } + + private static void StartService() + { + if (!IsInstalled()) return; + + using (ServiceController controller = + new ServiceController(serviceName)) + { + try + { + if (controller.Status != ServiceControllerStatus.Running) + { + controller.Start(); + controller.WaitForStatus(ServiceControllerStatus.Running, + TimeSpan.FromSeconds(10)); + } + } + catch (Exception ex) + { + logger.ErrorFormat(" Error occured in starting service " + ex.Message); + throw; + } + } + } + + private static void StopService() + { + if (!IsInstalled()) return; + using (ServiceController controller = + new ServiceController(serviceName)) + { + try + { + if (controller.Status != ServiceControllerStatus.Stopped) + { + controller.Stop(); + controller.WaitForStatus(ServiceControllerStatus.Stopped, + TimeSpan.FromSeconds(10)); + } + } + catch (Exception ex) + { + logger.ErrorFormat(" Error occured in stopping service " + ex.Message); + throw; + } } } } diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/ProjectInstaller.Designer.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/ProjectInstaller.Designer.cs new file mode 100644 index 000000000000..2c6ffe24462a --- /dev/null +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/ProjectInstaller.Designer.cs @@ -0,0 +1,89 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +namespace CloudStack.Plugin.AgentShell +{ + partial class ProjectInstaller + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.serviceProcessInstaller = new System.ServiceProcess.ServiceProcessInstaller(); + this.serviceInstaller = new System.ServiceProcess.ServiceInstaller(); + // + // serviceProcessInstaller + // + string user = Program.GetUser(); + string password = Program.GetPassword(); + + if (string.IsNullOrEmpty(user)) + { + this.serviceProcessInstaller.Account = System.ServiceProcess.ServiceAccount.LocalSystem; + this.serviceProcessInstaller.Password = null; + this.serviceProcessInstaller.Username = null; + } + else + { + this.serviceProcessInstaller.Account = System.ServiceProcess.ServiceAccount.User; + this.serviceProcessInstaller.Password = password; + this.serviceProcessInstaller.Username = user; + } + + // + // serviceInstaller + // + this.serviceInstaller.Description = "CloudStack agent for managing a hyper-v host"; + this.serviceInstaller.DisplayName = Program.serviceName; + this.serviceInstaller.ServiceName = Program.serviceName; + this.serviceInstaller.StartType = System.ServiceProcess.ServiceStartMode.Automatic; + // + // ProjectInstaller + // + this.Installers.AddRange(new System.Configuration.Install.Installer[] { + this.serviceProcessInstaller, + this.serviceInstaller}); + + } + + #endregion + + private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller; + private System.ServiceProcess.ServiceInstaller serviceInstaller; + } +} diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/ProjectInstaller.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/ProjectInstaller.cs new file mode 100644 index 000000000000..78356c64848f --- /dev/null +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/ProjectInstaller.cs @@ -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. +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Configuration.Install; +using System.Linq; +using System.Threading.Tasks; + +namespace CloudStack.Plugin.AgentShell +{ + [RunInstaller(true)] + public partial class ProjectInstaller : System.Configuration.Install.Installer + { + public ProjectInstaller() + { + InitializeComponent(); + } + } +} diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/App.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/App.config index 1bf17d4791f0..0e75ef9b5f46 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/App.config +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/App.config @@ -24,7 +24,7 @@ 8 - 10.1.1.1 + 0.0.0.0 Routing @@ -45,13 +45,13 @@ 34359738368 - camldonall01.citrite.net + 0.0.0.0 1 - 10.70.176.1 + 0.0.0.0 2 diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs index dfc3e206f06e..b6989a977023 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs @@ -31,23 +31,129 @@ namespace HypervResource { public class PrimaryDataStoreTO { - public string path; + private string path; + public string host; + private string poolType; + public Uri uri; + public string _role; + + public string Path + { + get + { + if (this.isLocal) + { + return path; + } + else + { + return this.UncPath; + } + } + set + { + this.path = value; + } + } + + public string UncPath + { + get + { + string uncPath = null; + if (uri != null && (uri.Scheme.Equals("cifs") || uri.Scheme.Equals("networkfilesystem") || uri.Scheme.Equals("smb"))) + { + uncPath = @"\\" + uri.Host + uri.LocalPath; + } + return uncPath; + } + } + + public string User + { + get + { + string user = null; + if (uri != null) + { + var queryDictionary = System.Web.HttpUtility.ParseQueryString(uri.Query); + user = System.Web.HttpUtility.UrlDecode(queryDictionary["user"]); + } + return user; + } + } + + public string Password + { + get + { + string password = null; + if (uri != null) + { + var queryDictionary = System.Web.HttpUtility.ParseQueryString(uri.Query); + password = System.Web.HttpUtility.UrlDecode(queryDictionary["password"]); + } + return password; + } + } + + public string Domain + { + get + { + string domain = null; + if (uri != null) + { + var queryDictionary = System.Web.HttpUtility.ParseQueryString(uri.Query); + if (queryDictionary["domain"] != null) + { + domain = System.Web.HttpUtility.UrlDecode(queryDictionary["domain"]); + } + else domain = uri.Host; + } + return domain; + } + } + + public Boolean isLocal + { + get + { + if (poolType.Equals("Filesystem")) + { + return true; + } + else + { + return false; + } + } + } public static PrimaryDataStoreTO ParseJson(dynamic json) { PrimaryDataStoreTO result = null; - if (json == null) { return result; } + dynamic primaryDataStoreTOJson = json[CloudStackTypes.PrimaryDataStoreTO]; if (primaryDataStoreTOJson != null) { result = new PrimaryDataStoreTO() { - path = (string)primaryDataStoreTOJson.path + path = (string)primaryDataStoreTOJson.path, + host = (string)primaryDataStoreTOJson.host, + poolType = (string)primaryDataStoreTOJson.poolType }; + + if (!result.isLocal) + { + // Delete security credentials in original command. Prevents logger from spilling the beans, as it were. + String uriStr = @"cifs://" + result.host + result.path; + result.uri = new Uri(uriStr); + } } return result; } @@ -61,20 +167,67 @@ public string FullFileName { get { - String result = Path.Combine(this.primaryDataStore.path, this.name); - if (this.format != null) + string fileName = null; + if (this.primaryDataStore != null) { - result = result + "." + this.format.ToLowerInvariant(); + PrimaryDataStoreTO store = this.primaryDataStore; + if (store.isLocal) + { + String volume = this.path; + if (String.IsNullOrEmpty(volume)) + { + volume = this.uuid; + } + fileName = Path.Combine(store.Path, volume); + } + else + { + String volume = this.path; + if (String.IsNullOrEmpty(volume)) + { + volume = this.uuid; + } + fileName = @"\\" + store.uri.Host + store.uri.LocalPath + @"\" + volume; + fileName = Utils.NormalizePath(fileName); + } } - return result; + else if (this.nfsDataStore != null) + { + fileName = this.nfsDataStore.UncPath; + if (this.path != null) + { + fileName = Utils.NormalizePath(fileName + @"\" + this.path); + } + + if (fileName != null && !File.Exists(fileName)) + { + fileName = Utils.NormalizePath(fileName + @"\" + this.uuid); + } + } + else + { + String errMsg = "Invalid dataStore in VolumeObjectTO spec"; + logger.Error(errMsg); + throw new InvalidDataException(errMsg); + } + + if (fileName != null && !Path.HasExtension(fileName) && this.format != null) + { + fileName = fileName + "." + this.format.ToLowerInvariant(); + } + + return fileName; } } public dynamic dataStore; public string format; public string name; + public string path; public string uuid; + public ulong size; public PrimaryDataStoreTO primaryDataStore; + public NFSTO nfsDataStore; public static VolumeObjectTO ParseJson(dynamic json) { @@ -93,14 +246,17 @@ public static VolumeObjectTO ParseJson(dynamic json) dataStore = volumeObjectTOJson.dataStore, format = ((string)volumeObjectTOJson.format), name = (string)volumeObjectTOJson.name, - uuid = (string)volumeObjectTOJson.uuid + path = volumeObjectTOJson.path, + uuid = (string)volumeObjectTOJson.uuid, + size = (ulong)volumeObjectTOJson.size }; result.primaryDataStore = PrimaryDataStoreTO.ParseJson(volumeObjectTOJson.dataStore); + result.nfsDataStore = NFSTO.ParseJson(volumeObjectTOJson.dataStore); // Assert - if (result.dataStore == null || result.primaryDataStore == null) + if (result.dataStore == null || (result.primaryDataStore == null && result.nfsDataStore == null)) { - String errMsg = "VolumeObjectTO missing primary dataStore in spec " + volumeObjectTOJson.ToString(); + String errMsg = "VolumeObjectTO missing dataStore in spec " + Utils.CleanString(volumeObjectTOJson.ToString()); logger.Error(errMsg); throw new ArgumentNullException(errMsg); } @@ -116,17 +272,48 @@ private static void GuessFileExtension(VolumeObjectTO volInfo) { logger.Info("No image format in VolumeObjectTO, going to use format from first file that matches " + volInfo.FullFileName); - string[] choices = Directory.GetFiles(volInfo.primaryDataStore.path, volInfo.name + ".vhd*"); - - if (choices.Length != 1) + string path = null; + if (volInfo.primaryDataStore != null) { - String errMsg = "Tried to guess file extension, but cannot find file corresponding to " + Path.Combine(volInfo.primaryDataStore.path, volInfo.name); // format being guessed. - logger.Debug(errMsg); + if (volInfo.primaryDataStore.isLocal) + { + path = volInfo.primaryDataStore.Path; + } + else + { + path = volInfo.primaryDataStore.UncPath; + } + } + else if (volInfo.nfsDataStore != null) + { + path = volInfo.nfsDataStore.UncPath; + if (volInfo.path != null) + { + path += @"\" + volInfo.path; + } } else { - string[] splitFileName = choices[0].Split(new char[] { '.' }); - volInfo.format = splitFileName[splitFileName.Length - 1]; + String errMsg = "VolumeObjectTO missing dataStore in spec " + Utils.CleanString(volInfo.ToString()); + logger.Error(errMsg); + throw new ArgumentNullException(errMsg); + } + + path = Utils.NormalizePath(path); + if (Directory.Exists(path)) + { + string[] choices = choices = Directory.GetFiles(path, volInfo.uuid + ".vhd*"); + if (choices.Length != 1) + { + String errMsg = "Tried to guess file extension, but cannot find file corresponding to " + + Path.Combine(volInfo.primaryDataStore.Path, volInfo.uuid); + logger.Debug(errMsg); + } + else + { + string[] splitFileName = choices[0].Split(new char[] { '.' }); + volInfo.format = splitFileName[splitFileName.Length - 1]; + } } logger.Debug("Going to use file " + volInfo.FullFileName); } @@ -143,11 +330,43 @@ public string FullFileName { get { - if (String.IsNullOrEmpty(this.path)) + string fileName = null; + if (this.primaryDataStore != null) { - return Path.Combine(this.primaryDataStore.path, this.name) + '.' + this.format.ToLowerInvariant(); + PrimaryDataStoreTO store = this.primaryDataStore; + if (store.isLocal) + { + fileName = Path.Combine(store.Path, this.uuid); + } + else + { + fileName = @"\\" + store.uri.Host + store.uri.LocalPath + @"\" + this.uuid; + } + fileName = fileName + '.' + this.format.ToLowerInvariant(); } - return this.path; + else if (this.nfsDataStoreTO != null) + { + fileName = this.nfsDataStoreTO.UncPath; + if (this.path != null) + { + fileName = Utils.NormalizePath(fileName + @"\" + this.path); + } + + if (fileName != null && !File.Exists(fileName)) + { + fileName = Utils.NormalizePath(fileName + @"\" + this.uuid); + } + + if (!this.format.Equals("RAW")) + { + fileName = fileName + '.' + this.format.ToLowerInvariant(); + } + } + else + { + fileName = this.path; + } + return Utils.NormalizePath(fileName); } } @@ -160,6 +379,8 @@ public string FullFileName public PrimaryDataStoreTO primaryDataStore = null; public string path; public string checksum; + public string size; + public string id; public static TemplateObjectTO ParseJson(dynamic json) { @@ -174,7 +395,9 @@ public static TemplateObjectTO ParseJson(dynamic json) name = (string)templateObjectTOJson.name, uuid = (string)templateObjectTOJson.uuid, path = (string)templateObjectTOJson.path, - checksum = (string)templateObjectTOJson.checksum + checksum = (string)templateObjectTOJson.checksum, + size = (string)templateObjectTOJson.size, + id = (string)templateObjectTOJson.id }; result.s3DataStoreTO = S3TO.ParseJson(templateObjectTOJson.imageDataStore); result.nfsDataStoreTO = NFSTO.ParseJson(templateObjectTOJson.imageDataStore); @@ -196,20 +419,23 @@ public class S3TO public static S3TO ParseJson(dynamic json) { S3TO result = null; - dynamic s3TOJson = json[CloudStackTypes.S3TO]; - if (s3TOJson != null) + if (json != null) { - result = new S3TO() + dynamic s3TOJson = json[CloudStackTypes.S3TO]; + if (s3TOJson != null) { - bucketName = (string)s3TOJson.bucketName, - secretKey = (string)s3TOJson.secretKey, - accessKey = (string)s3TOJson.accessKey, - endpoint = (string)s3TOJson.endPoint, - httpsFlag = (bool)s3TOJson.httpsFlag - }; - // Delete security credentials in original command. Prevents logger from spilling the beans, as it were. - s3TOJson.secretKey = string.Empty; - s3TOJson.accessKey = string.Empty; + result = new S3TO() + { + bucketName = (string)s3TOJson.bucketName, + secretKey = (string)s3TOJson.secretKey, + accessKey = (string)s3TOJson.accessKey, + endpoint = (string)s3TOJson.endPoint, + httpsFlag = (bool)s3TOJson.httpsFlag + }; + // Delete security credentials in original command. Prevents logger from spilling the beans, as it were. + s3TOJson.secretKey = string.Empty; + s3TOJson.accessKey = string.Empty; + } } return result; } @@ -264,16 +490,19 @@ public string Domain public static NFSTO ParseJson(dynamic json) { NFSTO result = null; - dynamic nfsTOJson = json[CloudStackTypes.NFSTO]; - if (nfsTOJson != null) + if (json != null) { - result = new NFSTO() + dynamic nfsTOJson = json[CloudStackTypes.NFSTO]; + if (nfsTOJson != null) { - _role = (string)nfsTOJson._role, - }; - // Delete security credentials in original command. Prevents logger from spilling the beans, as it were. - String uriStr = (String)nfsTOJson._url; - result.uri = new Uri(uriStr); + result = new NFSTO() + { + _role = (string)nfsTOJson._role, + }; + // Delete security credentials in original command. Prevents logger from spilling the beans, as it were. + String uriStr = (String)nfsTOJson._url; + result.uri = new Uri(uriStr); + } } return result; } @@ -282,7 +511,9 @@ public static NFSTO ParseJson(dynamic json) public class DiskTO { public string type; + public string diskSequence = null; public TemplateObjectTO templateObjectTO = null; + public VolumeObjectTO volumeObjectTO = null; public static DiskTO ParseJson(dynamic json) { @@ -292,7 +523,9 @@ public static DiskTO ParseJson(dynamic json) result = new DiskTO() { templateObjectTO = TemplateObjectTO.ParseJson(json.data), + volumeObjectTO = VolumeObjectTO.ParseJson(json.data), type = (string)json.type, + diskSequence = json.diskSeq }; } @@ -362,7 +595,11 @@ public enum StoragePoolType /// /// /// - OCFS2 + OCFS2, + /// + /// for hyper-v + /// + SMB } public enum StorageResourceType diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj index 05a0f513d8b3..ec4456881cf5 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj @@ -63,6 +63,7 @@ ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll + @@ -93,6 +94,10 @@ + + + + - + \ No newline at end of file diff --git a/plugins/hypervisors/hyperv/pom.xml b/plugins/hypervisors/hyperv/pom.xml index 19aa28a10fa9..c6c3c004e137 100644 --- a/plugins/hypervisors/hyperv/pom.xml +++ b/plugins/hypervisors/hyperv/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/hypervisors/hyperv/resources/META-INF/cloudstack/core/spring-hyperv-core-context.xml b/plugins/hypervisors/hyperv/resources/META-INF/cloudstack/core/spring-hyperv-core-context.xml new file mode 100644 index 000000000000..84d50ca97e05 --- /dev/null +++ b/plugins/hypervisors/hyperv/resources/META-INF/cloudstack/core/spring-hyperv-core-context.xml @@ -0,0 +1,32 @@ + + + + + + diff --git a/plugins/hypervisors/hyperv/resources/META-INF/cloudstack/hyperv-compute/spring-hyperv-compute-context.xml b/plugins/hypervisors/hyperv/resources/META-INF/cloudstack/hyperv-compute/spring-hyperv-compute-context.xml index 63521618df5b..a128fbc88763 100644 --- a/plugins/hypervisors/hyperv/resources/META-INF/cloudstack/hyperv-compute/spring-hyperv-compute-context.xml +++ b/plugins/hypervisors/hyperv/resources/META-INF/cloudstack/hyperv-compute/spring-hyperv-compute-context.xml @@ -20,5 +20,7 @@ - + + + diff --git a/plugins/hypervisors/hyperv/src/com/cloud/ha/HypervInvestigator.java b/plugins/hypervisors/hyperv/src/com/cloud/ha/HypervInvestigator.java new file mode 100644 index 000000000000..cebfb7ac70c1 --- /dev/null +++ b/plugins/hypervisors/hyperv/src/com/cloud/ha/HypervInvestigator.java @@ -0,0 +1,77 @@ +/* + * 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.ha; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.CheckOnHostCommand; +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; +import com.cloud.resource.ResourceManager; +import com.cloud.utils.component.AdapterBase; +import org.apache.log4j.Logger; + +import javax.ejb.Local; +import javax.inject.Inject; +import java.util.List; + +@Local(value=Investigator.class) +public class HypervInvestigator extends AdapterBase implements Investigator { + private final static Logger s_logger = Logger.getLogger(HypervInvestigator.class); + @Inject HostDao _hostDao; + @Inject AgentManager _agentMgr; + @Inject ResourceManager _resourceMgr; + + @Override + public Boolean isVmAlive(com.cloud.vm.VirtualMachine vm, Host host) { + Status status = isAgentAlive(host); + if (status == null) { + return null; + } + return status == Status.Up ? true : null; + } + + @Override + public Status isAgentAlive(Host agent) { + if (agent.getHypervisorType() != Hypervisor.HypervisorType.Hyperv) { + return null; + } + CheckOnHostCommand cmd = new CheckOnHostCommand(agent); + List neighbors = _resourceMgr.listHostsInClusterByStatus(agent.getClusterId(), Status.Up); + for (HostVO neighbor : neighbors) { + if (neighbor.getId() == agent.getId() || neighbor.getHypervisorType() != Hypervisor.HypervisorType.Hyperv) { + continue; + } + + try { + Answer answer = _agentMgr.easySend(neighbor.getId(), cmd); + if (answer != null) { + return answer.getResult() ? Status.Down : Status.Up; + } + } catch (Exception e) { + s_logger.debug("Failed to send command to host: " + neighbor.getId()); + } + } + + return null; + } +} diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java index f011ce03fa3d..2330da1b6e03 100644 --- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java +++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java @@ -114,8 +114,6 @@ public class HypervServerDiscoverer extends DiscovererBase implements private HostPodDao _podDao; @Inject private DataCenterDao _dcDao; - @Inject - DataStoreManager _dataStoreMgr; // TODO: AgentManager and AlertManager not being used to transmit info, // may want to reconsider. @@ -177,17 +175,8 @@ public final void processConnect(final Host agent, s_logger.debug("Setting up host " + agentId); } - String secondaryStorageUri = getSecondaryStorageStoreUrl(cluster.getDataCenterId()); - if (secondaryStorageUri == null) { - s_logger.debug("Secondary storage uri for dc " + cluster.getDataCenterId() + " couldn't be obtained"); - } else { - prepareSecondaryStorageStore(secondaryStorageUri); - } - HostEnvironment env = new HostEnvironment(); SetupCommand setup = new SetupCommand(env); - setup.setSecondaryStorage(secondaryStorageUri); - setup.setSystemVmIso("systemvm/" + getSystemVMIsoFileNameOnDatastore()); if (!host.isSetup()) { setup.setNeedSetup(true); } @@ -332,7 +321,6 @@ public final Map> find( params.put("cluster", Long.toString(clusterId)); params.put("guid", guidWithTail); params.put("ipaddress", agentIp); - params.put("sec.storage.url", getSecondaryStorageStoreUrl(dcId)); // Hyper-V specific settings Map details = new HashMap(); @@ -367,12 +355,12 @@ public final Map> find( // TODO: does the resource have to create a connection? return resources; } catch (ConfigurationException e) { - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, dcId, podId, "Unable to add " + uri.getHost(), "Error is " + e.getMessage()); s_logger.warn("Unable to instantiate " + uri.getHost(), e); } catch (UnknownHostException e) { - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, dcId, podId, "Unable to add " + uri.getHost(), "Error is " + e.getMessage()); s_logger.warn("Unable to instantiate " + uri.getHost(), e); @@ -383,177 +371,6 @@ public final Map> find( } return null; } - - - private void prepareSecondaryStorageStore(String storageUrl) { - String mountPoint = getMountPoint(storageUrl); - - GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm"); - try { - if(lock.lock(3600)) { - try { - File patchFolder = new File(mountPoint + "/systemvm"); - if(!patchFolder.exists()) { - if(!patchFolder.mkdirs()) { - String msg = "Unable to create systemvm folder on secondary storage. location: " + patchFolder.toString(); - s_logger.error(msg); - throw new CloudRuntimeException(msg); - } - } - - File srcIso = getSystemVMPatchIsoFile(); - File destIso = new File(mountPoint + "/systemvm/" + getSystemVMIsoFileNameOnDatastore()); - if(!destIso.exists()) { - s_logger.info("Copy System VM patch ISO file to secondary storage. source ISO: " + - srcIso.getAbsolutePath() + ", destination: " + destIso.getAbsolutePath()); - try { - FileUtil.copyfile(srcIso, destIso); - } catch(IOException e) { - s_logger.error("Unexpected exception ", e); - - String msg = "Unable to copy systemvm ISO on secondary storage. src location: " + srcIso.toString() + ", dest location: " + destIso; - s_logger.error(msg); - throw new CloudRuntimeException(msg); - } - } else { - if(s_logger.isTraceEnabled()) { - s_logger.trace("SystemVM ISO file " + destIso.getPath() + " already exists"); - } - } - } finally { - lock.unlock(); - } - } - } finally { - lock.releaseRef(); - } - } - - private String getMountPoint(String storageUrl) { - String mountPoint = null; - synchronized(_storageMounts) { - mountPoint = _storageMounts.get(storageUrl); - if(mountPoint != null) { - return mountPoint; - } - - URI uri; - try { - uri = new URI(storageUrl); - } catch (URISyntaxException e) { - s_logger.error("Invalid storage URL format ", e); - throw new CloudRuntimeException("Unable to create mount point due to invalid storage URL format " + storageUrl); - } - - mountPoint = mount(File.separator + File.separator + uri.getHost() + uri.getPath(), _mountParent, - uri.getScheme(), uri.getQuery()); - if(mountPoint == null) { - s_logger.error("Unable to create mount point for " + storageUrl); - return "/mnt/sec"; - } - - _storageMounts.put(storageUrl, mountPoint); - return mountPoint; - } - } - - protected String mount(String path, String parent, String scheme, String query) { - String mountPoint = setupMountPoint(parent); - if (mountPoint == null) { - s_logger.warn("Unable to create a mount point"); - return null; - } - - Script script = null; - String result = null; - if (scheme.equals("cifs")) { - Script command = new Script(true, "mount", _timeout, s_logger); - command.add("-t", "cifs"); - command.add(path); - command.add(mountPoint); - - if (query != null) { - query = query.replace('&', ','); - command.add("-o", query); - } - result = command.execute(); - } - - if (result != null) { - s_logger.warn("Unable to mount " + path + " due to " + result); - File file = new File(mountPoint); - if (file.exists()) { - file.delete(); - } - return null; - } - - // Change permissions for the mountpoint - script = new Script(true, "chmod", _timeout, s_logger); - script.add("-R", "777", mountPoint); - result = script.execute(); - if (result != null) { - s_logger.warn("Unable to set permissions for " + mountPoint + " due to " + result); - } - return mountPoint; - } - - private String setupMountPoint(String parent) { - String mountPoint = null; - long mshostId = ManagementServerNode.getManagementServerId(); - for (int i = 0; i < 10; i++) { - String mntPt = parent + File.separator + String.valueOf(mshostId) + "." + Integer.toHexString(_rand.nextInt(Integer.MAX_VALUE)); - File file = new File(mntPt); - if (!file.exists()) { - if (_storage.mkdir(mntPt)) { - mountPoint = mntPt; - break; - } - } - s_logger.error("Unable to create mount: " + mntPt); - } - - return mountPoint; - } - - private String getSystemVMIsoFileNameOnDatastore() { - String version = this.getClass().getPackage().getImplementationVersion(); - String fileName = "systemvm-" + version + ".iso"; - return fileName.replace(':', '-'); - } - - private File getSystemVMPatchIsoFile() { - // locate systemvm.iso - URL url = this.getClass().getClassLoader().getResource("vms/systemvm.iso"); - File isoFile = null; - if (url != null) { - isoFile = new File(url.getPath()); - } - - if(isoFile == null || !isoFile.exists()) { - isoFile = new File("/usr/share/cloudstack-common/vms/systemvm.iso"); - } - - assert(isoFile != null); - if(!isoFile.exists()) { - s_logger.error("Unable to locate systemvm.iso in your setup at " + isoFile.toString()); - } - return isoFile; - } - - private String getSecondaryStorageStoreUrl(long zoneId) { - String secUrl = null; - DataStore secStore = _dataStoreMgr.getImageStore(zoneId); - if (secStore != null) { - secUrl = secStore.getUri(); - } - - if (secUrl == null) { - s_logger.warn("Secondary storage uri couldn't be retrieved"); - } - - return secUrl; - } /** * Encapsulate GUID calculation in public method to allow access to test @@ -580,24 +397,6 @@ public static String calcServerResourceGuid(final String uuidSeed) { public final boolean configure(final String name, final Map params) throws ConfigurationException { super.configure(name, params); - _mountParent = (String) params.get(Config.MountParent.key()); - if (_mountParent == null) { - _mountParent = File.separator + "mnt"; - } - - if (_instance != null) { - _mountParent = _mountParent + File.separator + _instance; - } - - String value = (String)params.get("scripts.timeout"); - _timeout = NumbersUtil.parseInt(value, 30) * 1000; - - _storage = (StorageLayer)params.get(StorageLayer.InstanceConfigKey); - if (_storage == null) { - _storage = new JavaStorageLayer(); - _storage.configure("StorageLayer", params); - } - // TODO: allow timeout on we HTTPRequests to be configured _agentMgr.registerForHostEvents(this, true, false, true); _resourceMgr.registerResourceStateAdapter(this.getClass() diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManager.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManager.java new file mode 100644 index 000000000000..9030e29e7a4d --- /dev/null +++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManager.java @@ -0,0 +1,24 @@ +// 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.hypervisor.hyperv.manager; + +import com.cloud.utils.component.Manager; + +public interface HypervManager extends Manager { + public String prepareSecondaryStorageStore(long zoneId); +} diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java new file mode 100644 index 000000000000..9ee3c8aa717c --- /dev/null +++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java @@ -0,0 +1,373 @@ +// 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.hypervisor.hyperv.manager; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.utils.identity.ManagementServerNode; +import org.apache.log4j.Logger; + +import com.cloud.configuration.Config; +import com.cloud.storage.JavaStorageLayer; +import com.cloud.storage.StorageLayer; +import com.cloud.utils.FileUtil; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; + +@Local(value = { HypervManager.class }) +public class HypervManagerImpl implements HypervManager { + public static final Logger s_logger = Logger.getLogger(HypervManagerImpl.class); + + private String name; + private int runLevel; + private Map params; + + private int _timeout; + Random _rand = new Random(System.currentTimeMillis()); + + Map _storageMounts = new HashMap(); + StorageLayer _storage; + + @Inject ConfigurationDao _configDao; + @Inject DataStoreManager _dataStoreMgr; + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + if (params != null) { + String value = (String)params.get("scripts.timeout"); + _timeout = NumbersUtil.parseInt(value, 30) * 1000; + _storage = (StorageLayer)params.get(StorageLayer.InstanceConfigKey); + } + + if (_storage == null) { + _storage = new JavaStorageLayer(); + _storage.configure("StorageLayer", params); + } + + return true; + } + + @Override + public boolean start() { + startupCleanup(getMountParent()); + return true; + } + + @Override + public boolean stop() { + shutdownCleanup(); + return true; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public void setConfigParams(Map params) { + this.params = params; + } + + @Override + public Map getConfigParams() { + return params; + } + + @Override + public int getRunLevel() { + return runLevel; + } + + @Override + public void setRunLevel(int level) { + runLevel = level; + } + + public String prepareSecondaryStorageStore(long zoneId) { + String secondaryStorageUri = getSecondaryStorageStoreUrl(zoneId); + if (secondaryStorageUri == null) { + s_logger.debug("Secondary storage uri for dc " + zoneId + " couldn't be obtained"); + } else { + prepareSecondaryStorageStore(secondaryStorageUri); + } + + return secondaryStorageUri; + } + + private String getSecondaryStorageStoreUrl(long zoneId) { + String secUrl = null; + DataStore secStore = _dataStoreMgr.getImageStore(zoneId); + if (secStore != null) { + secUrl = secStore.getUri(); + } + + if (secUrl == null) { + s_logger.warn("Secondary storage uri couldn't be retrieved"); + } + + return secUrl; + } + + private void prepareSecondaryStorageStore(String storageUrl) { + String mountPoint = getMountPoint(storageUrl); + + GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm"); + try { + if(lock.lock(3600)) { + try { + File patchFolder = new File(mountPoint + "/systemvm"); + if(!patchFolder.exists()) { + if(!patchFolder.mkdirs()) { + String msg = "Unable to create systemvm folder on secondary storage. location: " + patchFolder.toString(); + s_logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + File srcIso = getSystemVMPatchIsoFile(); + File destIso = new File(mountPoint + "/systemvm/" + getSystemVMIsoFileNameOnDatastore()); + if(!destIso.exists()) { + s_logger.info("Copy System VM patch ISO file to secondary storage. source ISO: " + + srcIso.getAbsolutePath() + ", destination: " + destIso.getAbsolutePath()); + try { + FileUtil.copyfile(srcIso, destIso); + } catch(IOException e) { + s_logger.error("Unexpected exception ", e); + + String msg = "Unable to copy systemvm ISO on secondary storage. src location: " + srcIso.toString() + ", dest location: " + destIso; + s_logger.error(msg); + throw new CloudRuntimeException(msg); + } + } else { + if(s_logger.isTraceEnabled()) { + s_logger.trace("SystemVM ISO file " + destIso.getPath() + " already exists"); + } + } + } finally { + lock.unlock(); + } + } + } finally { + lock.releaseRef(); + } + } + + private String getMountPoint(String storageUrl) { + String mountPoint = null; + synchronized(_storageMounts) { + mountPoint = _storageMounts.get(storageUrl); + if(mountPoint != null) { + return mountPoint; + } + + URI uri; + try { + uri = new URI(storageUrl); + } catch (URISyntaxException e) { + s_logger.error("Invalid storage URL format ", e); + throw new CloudRuntimeException("Unable to create mount point due to invalid storage URL format " + storageUrl); + } + + mountPoint = mount(File.separator + File.separator + uri.getHost() + uri.getPath(), getMountParent(), + uri.getScheme(), uri.getQuery()); + if(mountPoint == null) { + s_logger.error("Unable to create mount point for " + storageUrl); + return "/mnt/sec"; + } + + _storageMounts.put(storageUrl, mountPoint); + return mountPoint; + } + } + + protected String mount(String path, String parent, String scheme, String query) { + String mountPoint = setupMountPoint(parent); + if (mountPoint == null) { + s_logger.warn("Unable to create a mount point"); + return null; + } + + Script script = null; + String result = null; + if (scheme.equals("cifs")) { + String user = System.getProperty("user.name"); + Script command = new Script(true, "mount", _timeout, s_logger); + command.add("-t", "cifs"); + command.add(path); + command.add(mountPoint); + + if (user != null) { + command.add("-o", "uid=" + user + ",gid=" + user); + } + + if (query != null) { + query = query.replace('&', ','); + command.add("-o", query); + } + + result = command.execute(); + } + + if (result != null) { + s_logger.warn("Unable to mount " + path + " due to " + result); + File file = new File(mountPoint); + if (file.exists()) { + file.delete(); + } + return null; + } + + // Change permissions for the mountpoint + script = new Script(true, "chmod", _timeout, s_logger); + script.add("-R", "777", mountPoint); + result = script.execute(); + if (result != null) { + s_logger.warn("Unable to set permissions for " + mountPoint + " due to " + result); + } + return mountPoint; + } + + private String setupMountPoint(String parent) { + String mountPoint = null; + long mshostId = ManagementServerNode.getManagementServerId(); + for (int i = 0; i < 10; i++) { + String mntPt = parent + File.separator + String.valueOf(mshostId) + "." + Integer.toHexString(_rand.nextInt(Integer.MAX_VALUE)); + File file = new File(mntPt); + if (!file.exists()) { + if (_storage.mkdir(mntPt)) { + mountPoint = mntPt; + break; + } + } + s_logger.error("Unable to create mount: " + mntPt); + } + + return mountPoint; + } + + private String getSystemVMIsoFileNameOnDatastore() { + String version = this.getClass().getPackage().getImplementationVersion(); + String fileName = "systemvm-" + version + ".iso"; + return fileName.replace(':', '-'); + } + + private File getSystemVMPatchIsoFile() { + // locate systemvm.iso + URL url = this.getClass().getClassLoader().getResource("vms/systemvm.iso"); + File isoFile = null; + if (url != null) { + isoFile = new File(url.getPath()); + } + + if(isoFile == null || !isoFile.exists()) { + isoFile = new File("/usr/share/cloudstack-common/vms/systemvm.iso"); + } + + assert(isoFile != null); + if(!isoFile.exists()) { + s_logger.error("Unable to locate systemvm.iso in your setup at " + isoFile.toString()); + } + return isoFile; + } + + private String getMountParent() { + String mountParent = _configDao.getValue(Config.MountParent.key()); + if (mountParent == null) { + mountParent = File.separator + "mnt"; + } + + String instance = _configDao.getValue(Config.InstanceName.key()); + if (instance == null) { + instance = "DEFAULT"; + } + + if (instance != null) { + mountParent = mountParent + File.separator + instance; + } + + return mountParent; + } + + private void startupCleanup(String parent) { + s_logger.info("Cleanup mounted mount points used in previous session"); + + long mshostId = ManagementServerNode.getManagementServerId(); + + // cleanup left-over NFS mounts from previous session + String[] mounts = _storage.listFiles(parent + File.separator + String.valueOf(mshostId) + ".*"); + if(mounts != null && mounts.length > 0) { + for(String mountPoint : mounts) { + s_logger.info("umount NFS mount from previous session: " + mountPoint); + + String result = null; + Script command = new Script(true, "umount", _timeout, s_logger); + command.add(mountPoint); + result = command.execute(); + if (result != null) { + s_logger.warn("Unable to umount " + mountPoint + " due to " + result); + } + File file = new File(mountPoint); + if (file.exists()) { + file.delete(); + } + } + } + } + + private void shutdownCleanup() { + s_logger.info("Cleanup mounted mount points used in current session"); + + for(String mountPoint : _storageMounts.values()) { + s_logger.info("umount NFS mount: " + mountPoint); + + String result = null; + Script command = new Script(true, "umount", _timeout, s_logger); + command.add(mountPoint); + result = command.execute(); + if (result != null) { + s_logger.warn("Unable to umount " + mountPoint + " due to " + result); + } + File file = new File(mountPoint); + if (file.exists()) { + file.delete(); + } + } + } +} 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 194ad77b05dc..a4dca6a3fa7c 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 @@ -19,25 +19,45 @@ import java.io.File; import java.io.IOException; import java.net.ConnectException; +import java.net.InetSocketAddress; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.channels.SocketChannel; +import java.rmi.RemoteException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import javax.annotation.PostConstruct; import javax.ejb.Local; +import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.commons.lang.StringEscapeUtils; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.AllowAllHostnameVerifier; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.BasicClientConnectionManager; import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; @@ -51,11 +71,13 @@ 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; import com.cloud.agent.api.PingRoutingCommand; import com.cloud.agent.api.PingTestCommand; +import com.cloud.agent.api.StartCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.api.StartupRoutingCommand.VmState; @@ -72,9 +94,11 @@ 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.SetFirewallRulesAnswer; import com.cloud.agent.api.routing.SetFirewallRulesCommand; +import com.cloud.agent.api.routing.SetMonitorServiceCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesAnswer; import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; import com.cloud.agent.api.routing.SetSourceNatAnswer; @@ -85,14 +109,17 @@ import com.cloud.agent.api.routing.SetStaticRouteCommand; import com.cloud.agent.api.routing.Site2SiteVpnCfgCommand; import com.cloud.agent.api.routing.VmDataCommand; +import com.cloud.agent.api.routing.VpnUsersCfgCommand; import com.cloud.agent.api.to.DhcpTO; import com.cloud.agent.api.to.FirewallRuleTO; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.PortForwardingRuleTO; import com.cloud.agent.api.to.StaticNatRuleTO; +import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.host.Host.Type; import com.cloud.hypervisor.Hypervisor; +import com.cloud.hypervisor.hyperv.manager.HypervManager; import com.cloud.network.HAProxyConfigurator; import com.cloud.network.LoadBalancerConfigurator; import com.cloud.network.Networks.RouterPrivateIpStrategy; @@ -104,16 +131,15 @@ import com.cloud.utils.StringUtils; import com.cloud.utils.net.NetUtils; import com.cloud.utils.ssh.SshHelper; +import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineName; - /** * Implementation of dummy resource to be returned from discoverer. **/ @Local(value = ServerResource.class) public class HypervDirectConnectResource extends ServerResourceBase implements ServerResource { public static final int DEFAULT_AGENT_PORT = 8250; - private static final Logger s_logger = Logger - .getLogger(HypervDirectConnectResource.class.getName()); + private static final Logger s_logger = Logger.getLogger(HypervDirectConnectResource.class.getName()); private static final Gson s_gson = GsonHelper.getGson(); private String _zoneId; @@ -121,7 +147,7 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S private String _clusterId; private String _guid; private String _agentIp; - private int _port = DEFAULT_AGENT_PORT; + private final int _port = DEFAULT_AGENT_PORT; protected final long _ops_timeout = 900000; // 15 minutes time out to time protected final int _retry = 24; @@ -137,6 +163,15 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S private String _username; private String _password; + private static HypervManager s_hypervMgr; + @Inject HypervManager _hypervMgr; + + @PostConstruct + void init() { + s_hypervMgr = _hypervMgr; + } + + @Override public final Type getType() { return Type.Routing; @@ -158,7 +193,8 @@ public final StartupCommand[] initialize() { 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() @@ -174,8 +210,7 @@ public final StartupCommand[] initialize() { s_logger.debug("Generated StartupRoutingCommand for _agentIp \"" + _agentIp + "\""); - // TODO: does version need to be hard coded. - defaultStartRoutCmd.setVersion("4.2.0"); + defaultStartRoutCmd.setVersion(this.getClass().getPackage().getImplementationVersion()); // Specifics of the host's resource capacity and network configuration // comes from the host itself. CloudStack sanity checks network @@ -293,7 +328,8 @@ public final StartupCommand[] initialize() { @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 + ")"); @@ -320,7 +356,7 @@ public final Command[] requestStartupCommand(final Command[] cmd) { try { String cmdName = StartupCommand.class.getName(); agentUri = - new URI("http", null, _agentIp, _port, + new URI("https", null, _agentIp, _port, "/api/HypervResource/" + cmdName, null, null); } catch (URISyntaxException e) { // TODO add proper logging @@ -360,7 +396,7 @@ public final Answer executeRequest(final Command cmd) { try { String cmdName = cmd.getClass().getName(); agentUri = - new URI("http", null, _agentIp, _port, + new URI("https", null, _agentIp, _port, "/api/HypervResource/" + cmdName, null, null); } catch (URISyntaxException e) { // TODO add proper logging @@ -407,11 +443,30 @@ public final Answer executeRequest(final Command cmd) { answer = execute((Site2SiteVpnCfgCommand) cmd); } else if (clazz == CheckS2SVpnConnectionsCommand.class) { answer = execute((CheckS2SVpnConnectionsCommand) cmd); + } else if (clazz == RemoteAccessVpnCfgCommand.class) { + answer = execute((RemoteAccessVpnCfgCommand) cmd); + } else if (clazz == VpnUsersCfgCommand.class) { + answer = execute((VpnUsersCfgCommand) cmd); } else if (clazz == SetStaticRouteCommand.class) { answer = execute((SetStaticRouteCommand) cmd); - } - else { - // Else send the cmd to hyperv agent. + } else if (clazz == SetMonitorServiceCommand.class) { + answer = execute((SetMonitorServiceCommand) cmd); + } else { + if (clazz == StartCommand.class) { + VirtualMachineTO vmSpec = ((StartCommand)cmd).getVirtualMachine(); + if (vmSpec.getType() != VirtualMachine.Type.User) { + if (s_hypervMgr != null) { + String secondary = s_hypervMgr.prepareSecondaryStorageStore(Long.parseLong(_zoneId)); + if (secondary != null) { + ((StartCommand)cmd).setSecondaryStorage(secondary); + } + } else { + s_logger.error("Hyperv manager isn't available. Couldn't check and copy the systemvm iso."); + } + } + } + + // Send the cmd to hyperv agent. String ansStr = postHttpRequest(s_gson.toJson(cmd), agentUri); if (ansStr == null) { return Answer.createUnsupportedCommandAnswer(cmd); @@ -419,15 +474,99 @@ public final Answer executeRequest(final Command cmd) { // Only Answer instances are returned by remote agents. // E.g. see Response.getAnswers() Answer[] result = s_gson.fromJson(ansStr, Answer[].class); - s_logger.debug("executeRequest received response " - + s_gson.toJson(result)); + String logResult = cleanPassword(StringEscapeUtils.unescapeJava(result.toString())); + s_logger.debug("executeRequest received response " + logResult); if (result.length > 0) { return result[0]; } } return answer; } + + protected Answer execute(final RemoteAccessVpnCfgCommand cmd) { + String controlIp = getRouterSshControlIp(cmd); + StringBuffer argsBuf = new StringBuffer(); + if (cmd.isCreate()) { + argsBuf.append(" -r ").append(cmd.getIpRange()).append(" -p ").append(cmd.getPresharedKey()).append(" -s ").append(cmd.getVpnServerIp()).append(" -l ").append(cmd.getLocalIp()) + .append(" -c "); + + } else { + argsBuf.append(" -d ").append(" -s ").append(cmd.getVpnServerIp()); + } + argsBuf.append(" -C ").append(cmd.getLocalCidr()); + argsBuf.append(" -i ").append(cmd.getPublicInterface()); + + try { + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Executing /opt/cloud/bin/vpn_lt2p.sh "); + } + + Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/opt/cloud/bin/vpn_l2tp.sh " + argsBuf.toString()); + + if (!result.first()) { + s_logger.error("RemoteAccessVpnCfg command on domR failed, message: " + result.second()); + return new Answer(cmd, false, "RemoteAccessVpnCfg command failed due to " + result.second()); + } + + if (s_logger.isInfoEnabled()) { + s_logger.info("RemoteAccessVpnCfg command on domain router " + argsBuf.toString() + " completed"); + } + + } catch (Throwable e) { + if (e instanceof RemoteException) { + s_logger.warn(e.getMessage()); + } + + String msg = "RemoteAccessVpnCfg command failed due to " + e.getMessage(); + s_logger.error(msg, e); + return new Answer(cmd, false, msg); + } + + return new Answer(cmd); + } + + protected Answer execute(final VpnUsersCfgCommand cmd) { + + String controlIp = getRouterSshControlIp(cmd); + for (VpnUsersCfgCommand.UsernamePassword userpwd : cmd.getUserpwds()) { + StringBuffer argsBuf = new StringBuffer(); + if (!userpwd.isAdd()) { + argsBuf.append(" -U ").append(userpwd.getUsername()); + } else { + argsBuf.append(" -u ").append(userpwd.getUsernamePassword()); + } + + try { + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Executing /opt/cloud/bin/vpn_lt2p.sh "); + } + + Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/opt/cloud/bin/vpn_l2tp.sh " + argsBuf.toString()); + + if (!result.first()) { + s_logger.error("VpnUserCfg command on domR failed, message: " + result.second()); + + return new Answer(cmd, false, "VpnUserCfg command failed due to " + result.second()); + } + } catch (Throwable e) { + if (e instanceof RemoteException) { + s_logger.warn(e.getMessage()); + } + + String msg = "VpnUserCfg command failed due to " + e.getMessage(); + s_logger.error(msg, e); + return new Answer(cmd, false, msg); + } + } + + return new Answer(cmd); + } + + + private SetStaticRouteAnswer execute(SetStaticRouteCommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource SetStaticRouteCommand: " + s_gson.toJson(cmd)); @@ -977,14 +1116,14 @@ protected Answer execute(SavePasswordCommand cmd) { String args = " -v " + vmIpAddress; if (s_logger.isDebugEnabled()) { - s_logger.debug("Run command on domain router " + controlIp + ", /root/savepassword.sh " + args + " -p " + StringUtils.getMaskedPasswordForDisplay(cmd.getPassword())); + s_logger.debug("Run command on domain router " + controlIp + ", /opt/cloud/bin/savepassword.sh " + args + " -p " + StringUtils.getMaskedPasswordForDisplay(cmd.getPassword())); } args += " -p " + password; try { - Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/root/savepassword.sh " + args); + Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/opt/cloud/bin/savepassword.sh " + args); if (!result.first()) { s_logger.error("savepassword command on domain router " + controlIp + " failed, message: " + result.second()); @@ -1480,6 +1619,34 @@ private long[] getNetworkStats(String privateIP) { return stats; } + protected Answer execute(SetMonitorServiceCommand cmd) { + if (s_logger.isInfoEnabled()) { + s_logger.info("Executing resource SetMonitorServiceCommand: " + s_gson.toJson(cmd)); + } + + String controlIp = getRouterSshControlIp(cmd); + String config = cmd.getConfiguration(); + + String args = ""; + + args += " -c " + config; + + try { + Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/opt/cloud/bin/monitor_service.sh " + args); + + if (!result.first()) { + String msg= "monitor_service.sh failed on domain router " + controlIp + " failed " + result.second(); + s_logger.error(msg); + return new Answer(cmd, false, msg); + } + + return new Answer(cmd); + + } catch (Throwable e) { + s_logger.error("Unexpected exception: " + e.toString(), e); + return new Answer(cmd, false, "SetMonitorServiceCommand failed due to " + e); + } + } protected CheckSshAnswer execute(CheckSshCommand cmd) { String vmName = cmd.getName(); @@ -1576,11 +1743,37 @@ public static String postHttpRequest(final String jsonCmd, // comment to use Apache HttpClient // http://stackoverflow.com/a/2793153/939250, but final comment is to // use Apache. - s_logger.debug("POST request to" + agentUri.toString() - + " with contents" + jsonCmd); + String logMessage = StringEscapeUtils.unescapeJava(jsonCmd); + logMessage = cleanPassword(logMessage); + s_logger.debug("POST request to " + agentUri.toString() + + " with contents " + logMessage); // Create request - HttpClient httpClient = new DefaultHttpClient(); + HttpClient httpClient = null; + TrustStrategy easyStrategy = new TrustStrategy() { + @Override + public boolean isTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + return true; + } + }; + + try { + SSLSocketFactory sf = new SSLSocketFactory(easyStrategy, new AllowAllHostnameVerifier()); + SchemeRegistry registry = new SchemeRegistry(); + registry.register(new Scheme("https", DEFAULT_AGENT_PORT, sf)); + ClientConnectionManager ccm = new BasicClientConnectionManager(registry); + httpClient = new DefaultHttpClient(ccm); + } catch (KeyManagementException e) { + s_logger.error("failed to initialize http client " + e.getMessage()); + } catch (UnrecoverableKeyException e) { + s_logger.error("failed to initialize http client " + e.getMessage()); + } catch (NoSuchAlgorithmException e) { + s_logger.error("failed to initialize http client " + e.getMessage()); + } catch (KeyStoreException e) { + s_logger.error("failed to initialize http client " + e.getMessage()); + } + String result = null; // TODO: are there timeout settings and worker thread settings to tweak? @@ -1594,7 +1787,7 @@ public static String postHttpRequest(final String jsonCmd, request.addHeader("content-type", "application/json"); request.setEntity(cmdJson); s_logger.debug("Sending cmd to " + agentUri.toString() - + " cmd data:" + jsonCmd); + + " cmd data:" + logMessage); HttpResponse response = httpClient.execute(request); // Unsupported commands will not route. @@ -1622,7 +1815,8 @@ public static String postHttpRequest(final String jsonCmd, return null; } else { result = EntityUtils.toString(response.getEntity()); - s_logger.debug("POST response is" + result); + String logResult = cleanPassword(StringEscapeUtils.unescapeJava(result)); + s_logger.debug("POST response is " + logResult); } } catch (ClientProtocolException protocolEx) { // Problem with HTTP message exchange @@ -1654,19 +1848,21 @@ protected final String getDefaultScriptsDir() { public final boolean configure(final String name, final Map params) throws ConfigurationException { /* todo: update, make consistent with the xen server equivalent. */ - _guid = (String) params.get("guid"); - _zoneId = (String) params.get("zone"); - _podId = (String) params.get("pod"); - _clusterId = (String) params.get("cluster"); - _agentIp = (String) params.get("ipaddress"); // was agentIp - _name = name; - - _clusterGuid = (String) params.get("cluster.guid"); - _username = (String) params.get("url"); - _password = (String) params.get("password"); - _username = (String) params.get("username"); - - _configureCalled = true; + if (params != null) { + _guid = (String) params.get("guid"); + _zoneId = (String) params.get("zone"); + _podId = (String) params.get("pod"); + _clusterId = (String) params.get("cluster"); + _agentIp = (String) params.get("ipaddress"); // was agentIp + _name = name; + + _clusterGuid = (String) params.get("cluster.guid"); + _username = (String) params.get("url"); + _password = (String) params.get("password"); + _username = (String) params.get("username"); + _configureCalled = true; + } + return true; } @@ -1711,10 +1907,9 @@ protected String connect(final String vmName, final String ipAddress, final int sch = SocketChannel.open(); sch.configureBlocking(true); sch.socket().setSoTimeout(5000); - // we need to connect to the public ip address to check the status of the VM - /* + // we need to connect to the control ip address to check the status of the system vm InetSocketAddress addr = new InetSocketAddress(ipAddress, port); - sch.connect(addr);*/ + sch.connect(addr); return null; } catch (IOException e) { s_logger.info("Could not connect to " + ipAddress + " due to " + e.toString()); @@ -1747,4 +1942,22 @@ protected String connect(final String vmName, final String ipAddress, final int return "Unable to connect"; } + public static String cleanPassword(String logString) { + String cleanLogString = null; + if (logString != null) { + cleanLogString = logString; + String[] temp = logString.split(","); + int i = 0; + if (temp != null) { + while (i < temp.length) { + temp[i] = StringUtils.cleanString(temp[i]); + i++; + } + List stringList = new ArrayList(); + Collections.addAll(stringList, temp); + cleanLogString = StringUtils.join(stringList, ","); + } + } + return cleanLogString; + } } 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 1f90da9adedc..33694603f744 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.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 final void testStartupCommand() { 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/pom.xml b/plugins/hypervisors/kvm/pom.xml index e2796218985f..1aff8f0b4c83 100644 --- a/plugins/hypervisors/kvm/pom.xml +++ b/plugins/hypervisors/kvm/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java index b400fd25032e..932447c7a5eb 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java @@ -23,7 +23,6 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.net.URI; import javax.naming.ConfigurationException; @@ -117,7 +116,13 @@ else if (nic.getBroadcastType() == Networks.BroadcastDomainType.Lswitch) { intf.defBridgeNet(brName, null, nic.getMac(), getGuestNicModel(guestOsType), networkRateKBps); } } else { - intf.defBridgeNet(_bridges.get("guest"), null, nic.getMac(), getGuestNicModel(guestOsType), networkRateKBps); + String brname = ""; + if (trafficLabel != null && !trafficLabel.isEmpty()) { + brname = trafficLabel; + } else { + brname = _bridges.get("guest"); + } + intf.defBridgeNet(brname, null, nic.getMac(), getGuestNicModel(guestOsType), networkRateKBps); } } else if (nic.getType() == Networks.TrafficType.Control) { /* Make sure the network is still there */ @@ -126,7 +131,7 @@ else if (nic.getBroadcastType() == Networks.BroadcastDomainType.Lswitch) { } else if (nic.getType() == Networks.TrafficType.Public) { Integer networkRateKBps = (nic.getNetworkRateMbps() != null && nic.getNetworkRateMbps().intValue() != -1) ? nic.getNetworkRateMbps().intValue() * 128 : 0; if (nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan - && !vNetId.equalsIgnoreCase("untagged")) { + && !vNetId.equalsIgnoreCase("untagged") || nic.getBroadcastType() == Networks.BroadcastDomainType.Vxlan) { if(trafficLabel != null && !trafficLabel.isEmpty()){ s_logger.debug("creating a vNet dev and bridge for public traffic per traffic label " + trafficLabel); String brName = createVnetBr(vNetId, trafficLabel, protocol); 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 eda311f6f1cf..ab7b9b54551e 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 @@ -16,11 +16,11 @@ // under the License. package com.cloud.hypervisor.kvm.resource; +import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; -import java.io.BufferedOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; @@ -51,14 +51,12 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import java.util.regex.Pattern; import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.ejb.Local; 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; @@ -70,6 +68,13 @@ import org.libvirt.LibvirtException; import org.libvirt.NodeInfo; +import com.ceph.rados.IoCTX; +import com.ceph.rados.Rados; +import com.ceph.rados.RadosException; +import com.ceph.rbd.Rbd; +import com.ceph.rbd.RbdException; +import com.ceph.rbd.RbdImage; + import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; @@ -88,6 +93,7 @@ import com.cloud.agent.api.CheckHealthCommand; import com.cloud.agent.api.CheckNetworkAnswer; import com.cloud.agent.api.CheckNetworkCommand; +import com.cloud.agent.api.CheckOnHostCommand; import com.cloud.agent.api.CheckStateCommand; import com.cloud.agent.api.CheckVirtualMachineAnswer; import com.cloud.agent.api.CheckVirtualMachineCommand; @@ -112,6 +118,7 @@ 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; @@ -160,6 +167,14 @@ import com.cloud.agent.api.proxy.CheckConsoleProxyLoadCommand; import com.cloud.agent.api.proxy.ConsoleProxyLoadAnswer; import com.cloud.agent.api.proxy.WatchConsoleProxyLoadCommand; +import com.cloud.agent.api.routing.IpAssocAnswer; +import com.cloud.agent.api.routing.IpAssocCommand; +import com.cloud.agent.api.routing.IpAssocVpcCommand; +import com.cloud.agent.api.routing.NetworkElementCommand; +import com.cloud.agent.api.routing.SetNetworkACLAnswer; +import com.cloud.agent.api.routing.SetNetworkACLCommand; +import com.cloud.agent.api.routing.SetSourceNatAnswer; +import com.cloud.agent.api.routing.SetSourceNatCommand; import com.cloud.agent.api.storage.CopyVolumeAnswer; import com.cloud.agent.api.storage.CopyVolumeCommand; import com.cloud.agent.api.storage.CreateAnswer; @@ -191,6 +206,7 @@ import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.CpuTuneDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DevicesDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.deviceType; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.diskProtocol; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.FeaturesDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.FilesystemDef; @@ -236,15 +252,9 @@ 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; -import com.ceph.rbd.Rbd; -import com.ceph.rbd.RbdImage; -import com.ceph.rbd.RbdException; - /** * LibvirtComputingResource execute requests on the computing/routing host using * the libvirt API @@ -364,6 +374,7 @@ protected String getDefaultScriptsDir() { private boolean _can_bridge_firewall; protected String _localStoragePath; protected String _localStorageUUID; + protected boolean _noMemBalloon = false; protected String _guestCpuMode; protected String _guestCpuModel; private final Map _pifs = new HashMap(); @@ -373,6 +384,8 @@ protected String getDefaultScriptsDir() { protected int _timeout; protected int _cmdsTimeout; protected int _stopTimeout; + + // TODO vmsync { protected static HashMap s_statesTable; static { s_statesTable = new HashMap(); @@ -389,6 +402,24 @@ protected String getDefaultScriptsDir() { 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(); @@ -719,6 +750,11 @@ public boolean configure(String name, Map params) value = (String) params.get("cmds.timeout"); _cmdsTimeout = NumbersUtil.parseInt(value, 7200) * 1000; + value = (String) params.get("vm.memballoon.disable"); + if (Boolean.parseBoolean(value)) { + _noMemBalloon = true; + } + value = (String) params.get("host.reserved.mem.mb"); _dom0MinMem = NumbersUtil.parseInt(value, 0) * 1024 * 1024; @@ -994,6 +1030,17 @@ private void getPifs() { } } + // public creates bridges on a pif, if private bridge not found try pif direct + // This addresses the unnecessary requirement of someone to create an unused bridge just for traffic label + if (_pifs.get("public") == null) { + s_logger.debug("public traffic label '" + _publicBridgeName+ "' not found as bridge, looking for physical interface"); + File dev = new File("/sys/class/net/" + _publicBridgeName); + if (dev.exists()) { + s_logger.debug("public traffic label '" + _publicBridgeName + "' found as a physical device"); + _pifs.put("public", _publicBridgeName); + } + } + s_logger.debug("done looking for pifs, no more bridges"); } @@ -1051,7 +1098,7 @@ private String matchPifFileInDirectory(String bridgeName){ String fname = interfaces[i].getName(); s_logger.debug("matchPifFileInDirectory: file name '"+fname+"'"); if (fname.startsWith("eth") || fname.startsWith("bond") - || fname.startsWith("vlan") || fname.startsWith("vxlan") || fname.startsWith("em") + || fname.startsWith("vlan") || fname.startsWith("vx") || fname.startsWith("em") || fname.matches("^p\\d+p\\d+.*")) { return fname; } @@ -1100,7 +1147,7 @@ private boolean checkOvsNetwork(String networkName) { command.add("-c"); command.add("ovs-vsctl br-exists " + networkName); String result = command.execute(null); - if ("Ok".equals(result)) { + if ("0".equals(result)) { return true; } else { return false; @@ -1294,8 +1341,6 @@ public Answer executeRequest(Command cmd) { return storageHandler.handleStorageCommands((StorageSubSystemCommand)cmd); } else if (cmd instanceof PvlanSetupCommand) { return execute((PvlanSetupCommand) cmd); - } else if (cmd instanceof SetMonitorServiceCommand) { - return execute((SetMonitorServiceCommand) cmd); } else if (cmd instanceof CheckOnHostCommand) { return execute((CheckOnHostCommand)cmd); } else { @@ -1661,14 +1706,22 @@ public Answer execute(DestroyCommand cmd) { private String getBroadcastUriFromBridge(String brName) { String pif= matchPifFileInDirectory(brName); - Pattern pattern = Pattern.compile("(\\D+)(\\d+)"); + Pattern pattern = Pattern.compile("(\\D+)(\\d+)(\\D*)(\\d*)"); Matcher matcher = pattern.matcher(pif); + s_logger.debug("getting broadcast uri for pif " + pif + " and bridge " + brName); if(matcher.find()) { if (brName.startsWith("brvx")){ return BroadcastDomainType.Vxlan.toUri(matcher.group(2)).toString(); } else{ - return BroadcastDomainType.Vlan.toUri(matcher.group(2)).toString(); + if (!matcher.group(4).isEmpty()) { + return BroadcastDomainType.Vlan.toUri(matcher.group(4)).toString(); + } else { + //untagged or not matching (eth|bond)#.# + s_logger.debug("failed to get vNet id from bridge " + brName + + "attached to physical interface" + pif + ", perhaps untagged interface"); + return ""; + } } } else { s_logger.debug("failed to get vNet id from bridge " + brName @@ -1736,6 +1789,23 @@ private Answer execute(PvlanSetupCommand cmd) { return new Answer(cmd, true, result); } + private void vifHotUnPlug (Connect conn, String vmName, String macAddr) throws InternalErrorException, LibvirtException { + + Domain vm = null; + vm = getDomain(conn, vmName); + List pluggedNics = getInterfaces(conn, vmName); + for (InterfaceDef pluggedNic : pluggedNics) { + if (pluggedNic.getMacAddress().equalsIgnoreCase(macAddr)) { + vm.detachDevice(pluggedNic.toString()); + // We don't know which "traffic type" is associated with + // each interface at this point, so inform all vif drivers + for (VifDriver vifDriver : getAllVifDrivers()) { + vifDriver.unplug(pluggedNic); + } + } + } + } + private void VifHotPlug(Connect conn, String vmName, String broadcastUri, String macAddr) throws InternalErrorException, LibvirtException { NicTO nicTO = new NicTO(); @@ -1755,6 +1825,15 @@ private void VifHotPlug(Connect conn, String vmName, String broadcastUri, private PlugNicAnswer execute(PlugNicCommand cmd) { NicTO nic = cmd.getNic(); + // rely on broadcastType as authoritiative rather than broadcast uri + // TODO: fix mismatches in mgmt server + if (nic.getBroadcastType() == BroadcastDomainType.Vxlan && !nic.getBroadcastUri().getScheme().equals("vxlan")) { + s_logger.error("mismatch in broadcast type and uri for nic " + nic +" find what is doing this and fix it"); + String vnet = nic.getBroadcastUri().getAuthority(); + nic.setBroadcastUri(BroadcastDomainType.Vxlan.toUri(vnet)); + nic.setIsolationuri(BroadcastDomainType.Vxlan.toUri(vnet)); + s_logger.error("mismatch now resolved to " + nic); + } String vmName = cmd.getVmName(); Domain vm = null; try { @@ -1878,19 +1957,6 @@ private SetupGuestNetworkAnswer execute(SetupGuestNetworkCommand cmd) { } } - private Answer execute(SetMonitorServiceCommand cmd) { - - String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP); - String config = cmd.getConfiguration(); - - String result = _virtRouterResource.configureMonitor(routerIp, config); - - if (result != null) { - return new Answer(cmd, false, "SetMonitorServiceCommand failed"); - } - return new Answer(cmd); - - } private SetNetworkACLAnswer execute(SetNetworkACLCommand cmd) { String[] results = new String[cmd.getRules().length]; @@ -2025,6 +2091,9 @@ public Answer execute(IpAssocCommand cmd) { .getAccessDetail(NetworkElementCommand.ROUTER_NAME); String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP); String[] results = new String[cmd.getIpAddresses().length]; + for (int i = 0; i < results.length; i++) { + results[i] = IpAssocAnswer.errorResult; + } Connect conn; try { conn = LibvirtConnection.getConnectionByVmName(routerName); @@ -2051,6 +2120,12 @@ public Answer execute(IpAssocCommand cmd) { String result = null; int nicNum = 0; boolean newNic = false; + int numOfIps = 0; + + if (ips != null) { + numOfIps = ips.length; + } + for (IpAddressTO ip : ips) { if (!broadcastUriAllocatedToVM.containsKey(ip.getBroadcastUri())) { /* plug a vif into router */ @@ -2066,17 +2141,24 @@ public Answer execute(IpAssocCommand cmd) { ip.isSourceNat(), ip.getBroadcastUri(), ip.getVlanGateway(), ip.getVlanNetmask(), ip.getVifMacAddress(), nicNum, newNic); - if (result != null) { - results[i++] = IpAssocAnswer.errorResult; - } else { + if (result == null) { results[i++] = ip.getPublicIp() + " - success"; - ; } + + //there is only only ip in public subnet and it is deleted so unplug the vif + if (numOfIps == 1 && !ip.isAdd()) { + // There are no ips on the vm so delete the vif + networkUsage(routerIp, "deleteVif", "eth" + nicNum); + vifHotUnPlug(conn, routerName, ip.getVifMacAddress()); + } + } return new IpAssocAnswer(cmd, results); } catch (LibvirtException e) { + s_logger.error("ipassoccmd failed", e); return new IpAssocAnswer(cmd, results); } catch (InternalErrorException e) { + s_logger.error("ipassoccmd failed", e); return new IpAssocAnswer(cmd, results); } } @@ -2249,8 +2331,6 @@ protected BackupSnapshotAnswer execute(final BackupSnapshotCommand cmd) { Rbd rbd = new Rbd(io); RbdImage image = rbd.open(snapshotDisk.getName(), snapshotName); - long startTime = System.currentTimeMillis() / 1000; - File fh = new File(snapshotDestPath); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fh)); int chunkSize = 4194304; @@ -2812,6 +2892,11 @@ protected State convertToState(DomainInfo.DomainState ps) { 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; @@ -2902,6 +2987,7 @@ private Answer execute(MigrateCommand cmd) { } List ifaces = null; + List disks = null; Domain dm = null; Connect dconn = null; @@ -2911,6 +2997,7 @@ private Answer execute(MigrateCommand cmd) { try { conn = LibvirtConnection.getConnectionByVmName(cmd.getVmName()); ifaces = getInterfaces(conn, vmName); + disks = getDisks(conn, vmName); dm = conn.domainLookupByName(vmName); /* We replace the private IP address with the address of the destination host. @@ -2936,7 +3023,9 @@ private Answer execute(MigrateCommand cmd) { destDomain = dm.migrate(dconn, (1 << 0) | (1 << 3), xmlDesc, vmName, "tcp:" + cmd.getDestinationIp(), _migrateSpeed); - _storagePoolMgr.disconnectPhysicalDisksViaVmSpec(cmd.getVirtualMachine()); + for (DiskDef disk : disks) { + cleanupDisk(disk); + } } catch (LibvirtException e) { s_logger.debug("Can't migrate domain: " + e.getMessage()); result = e.getMessage(); @@ -3441,7 +3530,7 @@ protected LibvirtVMDef createVMFromSpec(VirtualMachineTO vmTO) { GuestResourceDef grd = new GuestResourceDef(); - if (vmTO.getMinRam() != vmTO.getMaxRam()){ + if (vmTO.getMinRam() != vmTO.getMaxRam() && !_noMemBalloon) { grd.setMemBalloning(true); grd.setCurrentMem(vmTO.getMinRam()/1024); grd.setMemorySize(vmTO.getMaxRam()/1024); @@ -3449,12 +3538,21 @@ protected LibvirtVMDef createVMFromSpec(VirtualMachineTO vmTO) { else{ grd.setMemorySize(vmTO.getMaxRam() / 1024); } - grd.setVcpuNum(vmTO.getCpus()); + int vcpus = vmTO.getCpus(); + grd.setVcpuNum(vcpus); vm.addComp(grd); CpuModeDef cmd = new CpuModeDef(); cmd.setMode(_guestCpuMode); cmd.setModel(_guestCpuModel); + // multi cores per socket, for larger core configs + if (vcpus % 6 == 0) { + int sockets = vcpus / 6; + cmd.setTopology(6, sockets); + } else if (vcpus % 4 == 0) { + int sockets = vcpus / 4; + cmd.setTopology(4, sockets); + } vm.addComp(cmd); if (_hypervisorLibvirtVersion >= 9000) { @@ -3960,10 +4058,10 @@ public PingCommand getCurrentStatus(long id) { 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 +4106,8 @@ public StartupCommand[] initialize() { cmd.setPool(_pool); cmd.setCluster(_clusterId); cmd.setGatewayIpAddress(_localGateway); + cmd.setHostVmStateReport(getHostVmStateReport()); + cmd.setIqn(getIqn()); StartupStorageCommand sscmd = null; try { @@ -4037,6 +4137,32 @@ public StartupCommand[] initialize() { } } + private String getIqn() { + try { + final String textToFind = "InitiatorName="; + + Script iScsiAdmCmd = new Script(true, "grep", 0, s_logger); + + iScsiAdmCmd.add(textToFind); + iScsiAdmCmd.add("/etc/iscsi/initiatorname.iscsi"); + + OutputInterpreter.OneLineParser parser = new OutputInterpreter.OneLineParser(); + + String result = iScsiAdmCmd.execute(parser); + + if (result != null) { + return null; + } + + String textFound = parser.getLine().trim(); + + return textFound.substring(textToFind.length()); + } + catch (Exception ex) { + return null; + } + } + protected HashMap sync() { HashMap newStates; HashMap oldStates = null; @@ -4321,6 +4447,104 @@ private HashMap getAllVms(Connect conn) { 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(); @@ -4744,6 +4968,8 @@ private List getVmDiskStat(Connect conn, String vmName) List disks = getDisks(conn, vmName); for (DiskDef disk : disks) { + if (disk.getDeviceType() != deviceType.DISK) + break; DomainBlockStats blockStats = dm.blockStats(disk.getDiskLabel()); String path = disk.getDiskPath(); // for example, path = /mnt/pool_uuid/disk_path/ String diskPath = null; diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index 6aaabc5be13f..6a5db84d9e82 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -166,6 +166,8 @@ public String toString() { } if (_memBalloning){ resBuidler.append("\n" + "\n" + "\n"); + } else { + resBuidler.append("\n" + "\n" + "\n"); } if (_vcpu != -1) { resBuidler.append("" + _vcpu + "\n"); @@ -941,6 +943,8 @@ public String toString() { public static class CpuModeDef { private String _mode; private String _model; + private int _coresPerSocket = -1; + private int _sockets = -1; public void setMode(String mode) { _mode = mode; @@ -950,18 +954,35 @@ public void setModel(String model) { _model = model; } + public void setTopology(int coresPerSocket, int sockets) { + _coresPerSocket = coresPerSocket; + _sockets = sockets; + } + @Override public String toString() { - StringBuilder modeBuidler = new StringBuilder(); + StringBuilder modeBuilder = new StringBuilder(); + + // start cpu def, adding mode, model if ("custom".equalsIgnoreCase(_mode) && _model != null) { - modeBuidler.append("" - + _model + ""); + modeBuilder.append("" + + _model + ""); } else if ("host-model".equals(_mode)) { - modeBuidler.append(""); + modeBuilder.append(""); } else if ("host-passthrough".equals(_mode)) { - modeBuidler.append(""); + modeBuilder.append(""); + } else { + modeBuilder.append(""); + } + + // add topology + if (_sockets > 0 && _coresPerSocket > 0) { + modeBuilder.append(""); } - return modeBuidler.toString(); + + // close cpu def + modeBuilder.append(""); + return modeBuilder.toString(); } } diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java index 4ddec1337888..89100a3adddc 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java @@ -165,7 +165,7 @@ private boolean isBridgeExists(String bridgeName) { command.add("-c"); command.add("ovs-vsctl br-exists " + bridgeName); String result = command.execute(null); - if ("Ok".equals(result)) { + if ("0".equals(result)) { return true; } else { return false; diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java index 9ca709c3ca33..42af993beb5d 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java @@ -178,6 +178,11 @@ public boolean disconnectPhysicalDisksViaVmSpec(VirtualMachineTO vmSpec) { KVMStoragePool pool = getStoragePool(store.getPoolType(), store.getUuid()); + if (pool == null) { + s_logger.error("Pool " + store.getUuid() + " of type " + store.getPoolType() + " was not found, skipping disconnect logic"); + continue; + } + StorageAdaptor adaptor = getStorageAdaptor(pool.getType()); // if a disk fails to disconnect, still try to disconnect remaining diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index 8b8cd9ed93d6..8d237cc0c4d9 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -18,6 +18,9 @@ */ package com.cloud.hypervisor.kvm.storage; +import static com.cloud.utils.S3Utils.mputFile; +import static com.cloud.utils.S3Utils.putFile; + import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; @@ -35,6 +38,21 @@ import javax.naming.ConfigurationException; +import org.apache.commons.io.FileUtils; +import org.apache.log4j.Logger; +import org.libvirt.Connect; +import org.libvirt.Domain; +import org.libvirt.DomainInfo; +import org.libvirt.DomainSnapshot; +import org.libvirt.LibvirtException; + +import com.ceph.rados.IoCTX; +import com.ceph.rados.Rados; +import com.ceph.rados.RadosException; +import com.ceph.rbd.Rbd; +import com.ceph.rbd.RbdException; +import com.ceph.rbd.RbdImage; + import org.apache.cloudstack.storage.command.AttachAnswer; import org.apache.cloudstack.storage.command.AttachCommand; import org.apache.cloudstack.storage.command.CopyCmdAnswer; @@ -54,20 +72,7 @@ import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat; import org.apache.cloudstack.utils.qemu.QemuImgException; import org.apache.cloudstack.utils.qemu.QemuImgFile; -import org.apache.commons.io.FileUtils; -import org.apache.log4j.Logger; -import org.libvirt.Connect; -import org.libvirt.Domain; -import org.libvirt.DomainInfo; -import org.libvirt.DomainSnapshot; -import org.libvirt.LibvirtException; -import com.ceph.rados.IoCTX; -import com.ceph.rados.Rados; -import com.ceph.rados.RadosException; -import com.ceph.rbd.Rbd; -import com.ceph.rbd.RbdException; -import com.ceph.rbd.RbdImage; import com.cloud.agent.api.Answer; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; import com.cloud.agent.api.to.DataObjectType; @@ -96,8 +101,6 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; -import static com.cloud.utils.S3Utils.putFile; - public class KVMStorageProcessor implements StorageProcessor { private static final Logger s_logger = Logger.getLogger(KVMStorageProcessor.class); private KVMStoragePoolManager storagePoolMgr; @@ -196,7 +199,7 @@ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { if (destData instanceof VolumeObjectTO) { VolumeObjectTO volume = (VolumeObjectTO) destData; primaryVol = storagePoolMgr.copyPhysicalDisk(tmplVol, volume.getUuid(), - primaryPool, cmd.getWaitInMillSeconds()); + primaryPool, cmd.getWaitInMillSeconds()); } else if (destData instanceof TemplateObjectTO) { TemplateObjectTO destTempl = (TemplateObjectTO) destData; primaryVol = storagePoolMgr.copyPhysicalDisk(tmplVol, destTempl.getUuid(), @@ -235,8 +238,12 @@ else if (primaryVol.getFormat() == PhysicalDiskFormat.QCOW2) { } catch (CloudRuntimeException e) { return new CopyCmdAnswer(e.toString()); } finally { - if (secondaryPool != null) { - secondaryPool.delete(); + try { + if (secondaryPool != null) { + secondaryPool.delete(); + } + } catch(Exception e) { + s_logger.debug("Failed to clean up secondary storage", e); } } } @@ -476,7 +483,7 @@ public Answer createTemplateFromVolume(CopyCommand cmd) { KVMPhysicalDisk disk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), volume.getPath()); String tmpltPath = secondaryStorage.getLocalPath() + File.separator + templateFolder; - this.storageLayer.mkdirs(tmpltPath); + storageLayer.mkdirs(tmpltPath); String templateName = UUID.randomUUID().toString(); if (primary.getType() != StoragePoolType.RBD) { @@ -527,14 +534,14 @@ public Answer createTemplateFromVolume(CopyCommand cmd) { } Map params = new HashMap(); - params.put(StorageLayer.InstanceConfigKey, this.storageLayer); + params.put(StorageLayer.InstanceConfigKey, storageLayer); Processor qcow2Processor = new QCOW2Processor(); qcow2Processor.configure("QCOW2 Processor", params); FormatInfo info = qcow2Processor.process(tmpltPath, null, templateName); - TemplateLocation loc = new TemplateLocation(this.storageLayer, tmpltPath); + TemplateLocation loc = new TemplateLocation(storageLayer, tmpltPath); loc.create(1, true, templateName); loc.addFormat(info); loc.save(); @@ -560,13 +567,20 @@ public Answer createTemplateFromVolume(CopyCommand cmd) { public Answer createTemplateFromSnapshot(CopyCommand cmd) { return null; //To change body of implemented methods use File | Settings | File Templates. } - protected String copyToS3(File srcFile, S3TO destStore, String destPath) { + + protected String copyToS3(File srcFile, S3TO destStore, String destPath) throws InterruptedException { final String bucket = destStore.getBucketName(); + long srcSize = srcFile.length(); String key = destPath + S3Utils.SEPARATOR + srcFile.getName(); - putFile(destStore, srcFile, bucket, key); + if (!destStore.getSingleUpload(srcSize)) { + mputFile(destStore, srcFile, bucket, key); + } else { + putFile(destStore, srcFile, bucket, key); + } return key; } + protected Answer copyToObjectStore(CopyCommand cmd) { DataTO srcData = cmd.getSrcTO(); DataTO destData = cmd.getDestTO(); @@ -597,6 +611,9 @@ protected Answer copyToObjectStore(CopyCommand cmd) { SnapshotObjectTO newSnapshot = new SnapshotObjectTO(); newSnapshot.setPath(destPath); return new CopyCmdAnswer(newSnapshot); + } catch (Exception e) { + s_logger.error("failed to upload" + srcPath, e); + return new CopyCmdAnswer("failed to upload" + srcPath + e.toString()); } finally { try { if (srcFile != null) { @@ -656,8 +673,11 @@ public Answer backupSnapshot(CopyCommand cmd) { String snapshotRelPath = null; String vmName = snapshot.getVmName(); KVMStoragePool secondaryStoragePool = null; + Connect conn = null; + KVMPhysicalDisk snapshotDisk = null; + KVMStoragePool primaryPool = null; try { - Connect conn = LibvirtConnection.getConnectionByVmName(vmName); + conn = LibvirtConnection.getConnectionByVmName(vmName); secondaryStoragePool = storagePoolMgr.getStoragePoolByURI(secondaryStoragePoolUrl); @@ -665,9 +685,9 @@ public Answer backupSnapshot(CopyCommand cmd) { snapshotRelPath = destSnapshot.getPath(); snapshotDestPath = ssPmountPath + File.separator + snapshotRelPath; - KVMPhysicalDisk snapshotDisk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), + snapshotDisk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), volumePath); - KVMStoragePool primaryPool = snapshotDisk.getPool(); + primaryPool = snapshotDisk.getPool(); /** * RBD snapshots can't be copied using qemu-img, so we have to use @@ -745,47 +765,6 @@ public Answer backupSnapshot(CopyCommand cmd) { } } - /* Delete the snapshot on primary */ - - DomainInfo.DomainState state = null; - Domain vm = null; - if (vmName != null) { - try { - vm = this.resource.getDomain(conn, vmName); - state = vm.getInfo().state; - } catch (LibvirtException e) { - s_logger.trace("Ignoring libvirt error.", e); - } - } - - KVMStoragePool primaryStorage = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), - primaryStore.getUuid()); - if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING && !primaryStorage.isExternalSnapshot()) { - DomainSnapshot snap = vm.snapshotLookupByName(snapshotName); - snap.delete(0); - - /* - * libvirt on RHEL6 doesn't handle resume event emitted from - * qemu - */ - vm = this.resource.getDomain(conn, vmName); - state = vm.getInfo().state; - if (state == DomainInfo.DomainState.VIR_DOMAIN_PAUSED) { - vm.resume(); - } - } else { - if (primaryPool.getType() != StoragePoolType.RBD) { - Script command = new Script(_manageSnapshotPath, _cmdsTimeout, s_logger); - command.add("-d", snapshotDisk.getPath()); - command.add("-n", snapshotName); - String result = command.execute(); - if (result != null) { - s_logger.debug("Failed to backup snapshot: " + result); - return new CopyCmdAnswer("Failed to backup snapshot: " + result); - } - } - } - SnapshotObjectTO newSnapshot = new SnapshotObjectTO(); newSnapshot.setPath(snapshotRelPath + File.separator + snapshotName); return new CopyCmdAnswer(newSnapshot); @@ -796,8 +775,56 @@ public Answer backupSnapshot(CopyCommand cmd) { s_logger.debug("Failed to backup snapshot: " + e.toString()); return new CopyCmdAnswer(e.toString()); } finally { - if (secondaryStoragePool != null) { - secondaryStoragePool.delete(); + try { + /* Delete the snapshot on primary */ + DomainInfo.DomainState state = null; + Domain vm = null; + if (vmName != null) { + try { + vm = resource.getDomain(conn, vmName); + state = vm.getInfo().state; + } catch (LibvirtException e) { + s_logger.trace("Ignoring libvirt error.", e); + } + } + + KVMStoragePool primaryStorage = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), + primaryStore.getUuid()); + if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING && !primaryStorage.isExternalSnapshot()) { + DomainSnapshot snap = vm.snapshotLookupByName(snapshotName); + snap.delete(0); + + /* + * libvirt on RHEL6 doesn't handle resume event emitted from + * qemu + */ + vm = resource.getDomain(conn, vmName); + state = vm.getInfo().state; + if (state == DomainInfo.DomainState.VIR_DOMAIN_PAUSED) { + vm.resume(); + } + } else { + if (primaryPool.getType() != StoragePoolType.RBD) { + Script command = new Script(_manageSnapshotPath, _cmdsTimeout, s_logger); + command.add("-d", snapshotDisk.getPath()); + command.add("-n", snapshotName); + String result = command.execute(); + if (result != null) { + s_logger.debug("Failed to delete snapshot on primary: " + result); + // return new CopyCmdAnswer("Failed to backup snapshot: " + result); + } + } + } + } catch (Exception ex) { + s_logger.debug("Failed to delete snapshots on primary", ex); + } + + try { + if (secondaryStoragePool != null) { + secondaryStoragePool.delete(); + } + } catch (Exception ex) { + s_logger.debug("Failed to delete secondary storage", ex); } } } @@ -823,12 +850,12 @@ protected synchronized String attachOrDetachISO(Connect conn, String vmName, Str isoXml = iso.toString(); } - List disks = this.resource.getDisks(conn, vmName); + List disks = resource.getDisks(conn, vmName); String result = attachOrDetachDevice(conn, true, vmName, isoXml); if (result == null && !isAttach) { for (DiskDef disk : disks) { if (disk.getDeviceType() == DiskDef.deviceType.CDROM) { - this.resource.cleanupDisk(disk); + resource.cleanupDisk(disk); } } @@ -1063,7 +1090,7 @@ public Answer createSnapshot(CreateObjectCommand cmd) { Domain vm = null; if (vmName != null) { try { - vm = this.resource.getDomain(conn, vmName); + vm = resource.getDomain(conn, vmName); state = vm.getInfo().state; } catch (LibvirtException e) { s_logger.trace("Ignoring libvirt error.", e); @@ -1086,7 +1113,7 @@ public Answer createSnapshot(CreateObjectCommand cmd) { * libvirt on RHEL6 doesn't handle resume event emitted from * qemu */ - vm = this.resource.getDomain(conn, vmName); + vm = resource.getDomain(conn, vmName); state = vm.getInfo().state; if (state == DomainInfo.DomainState.VIR_DOMAIN_PAUSED) { vm.resume(); @@ -1127,7 +1154,7 @@ public Answer createSnapshot(CreateObjectCommand cmd) { } } else { /* VM is not running, create a snapshot by ourself */ - final Script command = new Script(_manageSnapshotPath, this._cmdsTimeout, s_logger); + final Script command = new Script(_manageSnapshotPath, _cmdsTimeout, s_logger); command.add("-c", disk.getPath()); command.add("-n", snapshotName); String result = command.execute(); diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java index 9402d0fdee93..76659ec1dfd3 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java @@ -617,7 +617,7 @@ public boolean deleteStoragePool(String uuid) { } s_logger.error("failed in umount retry"); } - throw new CloudRuntimeException(e.toString()); + throw new CloudRuntimeException(e.toString(), e); } } @@ -715,10 +715,8 @@ public boolean disconnectPhysicalDisk(String uuid, KVMStoragePool pool) { @Override public boolean disconnectPhysicalDiskByPath(String localPath) { // we've only ever cleaned up ISOs that are NFS mounted - String poolUuid = null; - - if (localPath != null && localPath.startsWith(_mountPoint)) { + if (localPath != null && localPath.startsWith(_mountPoint) && localPath.endsWith(".iso")) { String[] token = localPath.split("/"); if (token.length > 3) { @@ -772,7 +770,13 @@ public boolean deletePhysicalDisk(String uuid, KVMStoragePool pool) { RbdImage image = rbd.open(uuid); List snaps = image.snapList(); for (RbdSnapInfo snap : snaps) { - image.snapUnprotect(snap.name); + if (image.snapIsProtected(snap.name)) { + s_logger.debug("Unprotecting snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name); + image.snapUnprotect(snap.name); + } else { + s_logger.debug("Snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name + " is not protected."); + } + s_logger.debug("Removing snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name); image.snapRemove(snap.name); } @@ -962,7 +966,7 @@ public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, } if (disk == null) { - throw new CloudRuntimeException("Failed to create " + disk.getPath() + " from template " + template.getName()); + throw new CloudRuntimeException("Failed to create disk from template " + template.getName()); } return disk; diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java index df0af5f05307..7eed47497ee5 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java @@ -181,11 +181,10 @@ public boolean refresh() { @Override public boolean isExternalSnapshot() { - if (this.type == StoragePoolType.Filesystem) { - return false; + if (this.type == StoragePoolType.CLVM || type == StoragePoolType.RBD) { + return true; } - - return true; + return false; } @Override @@ -253,7 +252,12 @@ public StoragePool getPool() { @Override public boolean delete() { - return this._storageAdaptor.deleteStoragePool(this); + try { + return this._storageAdaptor.deleteStoragePool(this); + } catch (Exception e) { + s_logger.debug("Failed to delete storage pool", e); + } + return false; } @Override 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 803ac3288017..87730671cb84 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 @@ -67,7 +67,7 @@ public void testCreateVMFromSpecLegacy() { int id = _random.nextInt(65534); String name = "test-instance-1"; - int cpus = _random.nextInt(7) + 1; + int cpus = _random.nextInt(2) + 1; int speed = 1024; int minRam = 256 * 1024; int maxRam = 512 * 1024; @@ -122,6 +122,7 @@ public void testCreateVMFromSpecLegacy() { //vmStr += "\n"; //vmStr += "" + (cpus * speed) + "\n"; //vmStr += "\n"; + vmStr += ""; vmStr += "restart\n"; vmStr += "destroy\n"; vmStr += "destroy\n"; @@ -129,6 +130,146 @@ public void testCreateVMFromSpecLegacy() { assertEquals(vmStr, vm.toString()); } + /** + This test verifies that CPU topology is properly set for hex-core + */ + @Test + public void testCreateVMFromSpecWithTopology6() { + int id = _random.nextInt(65534); + String name = "test-instance-1"; + + int cpus = 12; + int minSpeed = 1024; + int maxSpeed = 2048; + int minRam = 256 * 1024; + int maxRam = 512 * 1024; + + String os = "Ubuntu"; + boolean haEnabled = false; + boolean limitCpuUse = false; + + String vncAddr = ""; + String vncPassword = "mySuperSecretPassword"; + + LibvirtComputingResource lcr = new LibvirtComputingResource(); + VirtualMachineTO to = new VirtualMachineTO(id, name, VirtualMachine.Type.User, cpus, minSpeed, maxSpeed, minRam, maxRam, BootloaderType.HVM, os, false, false, vncPassword); + to.setVncAddr(vncAddr); + to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); + + LibvirtVMDef vm = lcr.createVMFromSpec(to); + vm.setHvsType(_hyperVisorType); + + String vmStr = "\n"; + vmStr += "" + name + "\n"; + vmStr += "b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9\n"; + vmStr += "" + os + "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "" + maxRam / 1024 + "\n"; + vmStr += "" + minRam / 1024 + "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "" + cpus + "\n"; + vmStr += "\n"; + vmStr += "hvm\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += ""; + vmStr += "restart\n"; + vmStr += "destroy\n"; + vmStr += "destroy\n"; + vmStr += "\n"; + + assertEquals(vmStr, vm.toString()); + } + + /** + This test verifies that CPU topology is properly set for quad-core + */ + @Test + public void testCreateVMFromSpecWithTopology4() { + int id = _random.nextInt(65534); + String name = "test-instance-1"; + + int cpus = 8; + int minSpeed = 1024; + int maxSpeed = 2048; + int minRam = 256 * 1024; + int maxRam = 512 * 1024; + + String os = "Ubuntu"; + boolean haEnabled = false; + boolean limitCpuUse = false; + + String vncAddr = ""; + String vncPassword = "mySuperSecretPassword"; + + LibvirtComputingResource lcr = new LibvirtComputingResource(); + VirtualMachineTO to = new VirtualMachineTO(id, name, VirtualMachine.Type.User, cpus, minSpeed, maxSpeed, minRam, maxRam, BootloaderType.HVM, os, false, false, vncPassword); + to.setVncAddr(vncAddr); + to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); + + LibvirtVMDef vm = lcr.createVMFromSpec(to); + vm.setHvsType(_hyperVisorType); + + String vmStr = "\n"; + vmStr += "" + name + "\n"; + vmStr += "b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9\n"; + vmStr += "" + os + "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "" + maxRam / 1024 + "\n"; + vmStr += "" + minRam / 1024 + "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "" + cpus + "\n"; + vmStr += "\n"; + vmStr += "hvm\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += "\n"; + vmStr += ""; + vmStr += "restart\n"; + vmStr += "destroy\n"; + vmStr += "destroy\n"; + vmStr += "\n"; + + assertEquals(vmStr, vm.toString()); + } + /** This test tests if the Agent can handle a vmSpec coming from a >4.1 management server. @@ -141,7 +282,7 @@ public void testCreateVMFromSpec() { int id = _random.nextInt(65534); String name = "test-instance-1"; - int cpus = _random.nextInt(7) + 1; + int cpus = _random.nextInt(2) + 1; int minSpeed = 1024; int maxSpeed = 2048; int minRam = 256 * 1024; @@ -197,6 +338,7 @@ public void testCreateVMFromSpec() { //vmStr += "\n"; //vmStr += "" + (cpus * minSpeed) + "\n"; //vmStr += "\n"; + vmStr += ""; vmStr += "restart\n"; vmStr += "destroy\n"; vmStr += "destroy\n"; diff --git a/plugins/hypervisors/ovm/pom.xml b/plugins/hypervisors/ovm/pom.xml index 17987b1df632..dced9f661e3b 100644 --- a/plugins/hypervisors/ovm/pom.xml +++ b/plugins/hypervisors/ovm/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml 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 2d0d67b2f414..32679c8ff132 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.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.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.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 @@ protected void fillHostInfo(StartupRoutingCommand cmd) { //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 PingCommand getCurrentStatus(long id) { 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 @@ private State toState(String vmName, String s) { 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/pom.xml b/plugins/hypervisors/simulator/pom.xml index a44997bf2527..fd2a97635751 100644 --- a/plugins/hypervisors/simulator/pom.xml +++ b/plugins/hypervisors/simulator/pom.xml @@ -22,7 +22,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml cloud-plugin-hypervisor-simulator diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java index 4071aeb4c464..447482b9642e 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java @@ -32,6 +32,8 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.user.AccountManager; +import org.apache.cloudstack.context.CallContext; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -87,6 +89,7 @@ public class MockAgentManagerImpl extends ManagerBase implements MockAgentManage MockStorageManager _storageMgr = null; @Inject ResourceManager _resourceMgr; + @Inject private AccountManager _accountMgr; SimulatorSecondaryDiscoverer discoverer; @Inject @@ -306,8 +309,10 @@ private void handleSystemVMStop() { @Override @DB public void run() { + CallContext.register(_accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); if (this.mode.equalsIgnoreCase("Stop")) { handleSystemVMStop(); + CallContext.unregister(); return; } @@ -363,10 +368,12 @@ public void run() { _resourceMgr.discoverHosts(cmd); } catch (DiscoveryException e) { s_logger.debug("Failed to discover host: " + e.toString()); + CallContext.unregister(); return; } } catch (ConfigurationException e) { s_logger.debug("Failed to load secondary storage resource: " + e.toString()); + CallContext.unregister(); return; } } diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java index f30bd3661d04..0801287379bd 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java @@ -70,6 +70,7 @@ import com.cloud.agent.api.routing.IpAssocCommand; import com.cloud.agent.api.routing.IpAssocVpcCommand; import com.cloud.agent.api.routing.LoadBalancerConfigCommand; +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.SetNetworkACLCommand; @@ -80,6 +81,7 @@ import com.cloud.agent.api.routing.SetStaticRouteCommand; import com.cloud.agent.api.routing.Site2SiteVpnCfgCommand; import com.cloud.agent.api.routing.VmDataCommand; +import com.cloud.agent.api.routing.VpnUsersCfgCommand; import com.cloud.agent.api.storage.CopyVolumeCommand; import com.cloud.agent.api.storage.CreateCommand; import com.cloud.agent.api.storage.DestroyCommand; @@ -362,7 +364,9 @@ public Answer simulate(Command cmd, String hostGuid) { } else if (cmd instanceof PvlanSetupCommand) { return _mockNetworkMgr.setupPVLAN((PvlanSetupCommand) cmd); } else if (cmd instanceof StorageSubSystemCommand) { - return this.storageHandler.handleStorageCommands((StorageSubSystemCommand)cmd); + return this.storageHandler.handleStorageCommands((StorageSubSystemCommand) cmd); + } else if (cmd instanceof VpnUsersCfgCommand || cmd instanceof RemoteAccessVpnCfgCommand) { + return new Answer(cmd); } else { s_logger.error("Simulator does not implement command of type "+cmd.toString()); return Answer.createUnsupportedCommandAnswer(cmd); diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java index 9a27d748a291..727e067e5276 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.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.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 PingCommand getCurrentStatus(long id) { } 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 @@ protected List getHostInfo() { 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/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java b/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java index 26f8a40e1d51..854e7d1abbc3 100644 --- a/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java +++ b/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java @@ -24,6 +24,7 @@ import javax.inject.Inject; +import org.apache.cloudstack.storage.command.CommandResult; import org.apache.log4j.Logger; import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; @@ -80,6 +81,11 @@ public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCal } } + @Override + public void deleteAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback callback) { + callback.complete(new CommandResult()); + } + protected void createTemplate(DataObject data, AsyncCompletionCallback callback) { CreateContext context = new CreateContext(callback, data); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher diff --git a/plugins/hypervisors/ucs/pom.xml b/plugins/hypervisors/ucs/pom.xml index ae9708cba98a..359be87a2684 100755 --- a/plugins/hypervisors/ucs/pom.xml +++ b/plugins/hypervisors/ucs/pom.xml @@ -1,30 +1,47 @@ - - + + xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 4.0.0 org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml + org.apache.cloudstack cloud-plugin-hypervisor-ucs + 4.3.0 Apache CloudStack Plugin - Hypervisor UCS http://maven.apache.org UTF-8 + + junit + junit + 3.8.1 + test + org.apache.cloudstack cloud-utils @@ -35,5 +52,10 @@ cloud-api ${project.version} + + javax.inject + javax.inject + 1 + diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDaoImpl.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDaoImpl.java index 5dc6f79bf7d5..985319468628 100644 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDaoImpl.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDaoImpl.java @@ -19,6 +19,8 @@ import javax.ejb.Local; +import org.springframework.stereotype.Component; + import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; @Local(value = { UcsBladeDao.class }) diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDao.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDao.java index b341a1b2279c..9ae4e7712836 100644 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDao.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDao.java @@ -27,7 +27,6 @@ import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.GenericQueryBuilder; public interface UcsManagerDao extends GenericDao { } diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDaoImpl.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDaoImpl.java index 9500886875fe..30919784adf9 100644 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDaoImpl.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDaoImpl.java @@ -19,6 +19,8 @@ import javax.ejb.Local; +import org.springframework.stereotype.Component; + import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsCommands.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsCommands.java index c0753f463cd9..82328446614a 100644 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsCommands.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsCommands.java @@ -50,6 +50,27 @@ public static String listProfiles(String cookie) { return cmd.dump(); } + public static String listTemplates(String cookie) { + XmlObject cmd = new XmlObject("configResolveClass"); + cmd.putElement("cookie", cookie); + cmd.putElement("inHierarchical", "false"); + cmd.putElement("classId", "lsServer"); + cmd.putElement("inFilter", new XmlObject("inFilter") + .putElement("eq", new XmlObject("eq") + .putElement("class", "lsServer").putElement("property", "type").putElement("value", "initial-template"))); + return cmd.dump(); + } + + public static String instantiateTemplate(String cookie, String dn, String name) { + XmlObject cmd = new XmlObject("lsInstantiateTemplate"); + cmd.putElement("dn",dn); + cmd.putElement("cookie", cookie); + cmd.putElement("inTargetOrg", "org-root"); + cmd.putElement("inServerName", name); + cmd.putElement("inHierarchical", "no"); + return cmd.toString(); + } + public static String cloneProfile(String cookie, String srcDn, String newProfileName) { XmlObject cmd = new XmlObject("lsClone"); cmd.putElement("cookie", cookie); @@ -67,41 +88,64 @@ public static String configResolveDn(String cookie, String dn) { return cmd.toString(); } + public static String disassociateProfileFromBlade(String cookie, String profileDn) { + XmlObject cmd = new XmlObject("configConfMo"); + cmd.putElement("cookie", cookie); + cmd.putElement("inHierarchical", "false") + .putElement("inConfig", new XmlObject("inConfig") + .putElement("lsServer", new XmlObject("lsServer") + .putElement("dn", profileDn).putElement("lsBinding", new XmlObject("lsBinding").putElement("rn", "pn").putElement("status", "deleted")) + ) + ); + + return cmd.dump(); + } + + public static String deleteProfile(String cookie, String profileDn) { + XmlObject cmd = new XmlObject("configConfMos"); + cmd.putElement("cookie", cookie); + cmd.putElement("inHierarchical", "true") + .putElement("inConfigs", new XmlObject("inConfigs").putElement("pair", new XmlObject("pair").putElement("key", profileDn) + .putElement("lsServer", new XmlObject("lsServer").putElement("dn", profileDn).putElement("status", "deleted")) + )); + return cmd.dump(); + } + public static String associateProfileToBlade(String cookie, String profileDn, String bladeDn) { XmlObject cmd = new XmlObject("configConfMos").putElement("cookie", cookie).putElement("inHierarchical", "true").putElement( "inConfigs", new XmlObject("inConfigs").putElement( - "pair", new XmlObject("pair").putElement("key", profileDn).putElement( - "lsServer", new XmlObject("lsServer") - .putElement("agentPolicyName", "") - .putElement("biosProfileName", "") - .putElement("bootPolicyName", "") - .putElement("descr", "") - .putElement("dn", profileDn) - .putElement("dynamicConPolicyName", "") - .putElement("extIPState", "none") - .putElement("hostFwPolicyName", "") - .putElement("identPoolName", "") - .putElement("localDiskPolicyName", "") - .putElement("maintPolicyName", "") - .putElement("mgmtAccessPolicyName", "") - .putElement("mgmtFwPolicyName", "") - .putElement("powerPolicyName", "") - .putElement("scrubPolicyName", "") - .putElement("solPolicyName", "") - .putElement("srcTemplName", "") - .putElement("statsPolicyName", "default") - .putElement("status", "") - .putElement("usrLbl", "") - .putElement("uuid", "") - .putElement("vconProfileName", "") - .putElement("lsBinding", new XmlObject("lsBinding") - .putElement("pnDn", bladeDn) - .putElement("restrictMigration", "no") - .putElement("rn", "pn") - ) - ) - ) - ); + "pair", new XmlObject("pair").putElement("key", profileDn).putElement( + "lsServer", new XmlObject("lsServer") + .putElement("agentPolicyName", "") + .putElement("biosProfileName", "") + .putElement("bootPolicyName", "") + .putElement("descr", "") + .putElement("dn", profileDn) + .putElement("dynamicConPolicyName", "") + .putElement("extIPState", "none") + .putElement("hostFwPolicyName", "") + .putElement("identPoolName", "") + .putElement("localDiskPolicyName", "") + .putElement("maintPolicyName", "") + .putElement("mgmtAccessPolicyName", "") + .putElement("mgmtFwPolicyName", "") + .putElement("powerPolicyName", "") + .putElement("scrubPolicyName", "") + .putElement("solPolicyName", "") + .putElement("srcTemplName", "") + .putElement("statsPolicyName", "default") + .putElement("status", "") + .putElement("usrLbl", "") + .putElement("uuid", "") + .putElement("vconProfileName", "") + .putElement("lsBinding", new XmlObject("lsBinding") + .putElement("pnDn", bladeDn) + .putElement("restrictMigration", "no") + .putElement("rn", "pn") + ) + ) + ) + ); return cmd.dump(); } diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsHttpClient.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsHttpClient.java index 945d921a8d33..1eb422c32390 100644 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsHttpClient.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsHttpClient.java @@ -17,27 +17,76 @@ // package com.cloud.ucs.manager; -import org.apache.commons.httpclient.Header; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.URI; +import com.cloud.utils.exception.CloudRuntimeException; import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.StringRequestEntity; import org.apache.commons.httpclient.protocol.Protocol; +import org.apache.log4j.Logger; +import org.springframework.http.*; +import org.springframework.web.client.RestTemplate; -import com.cloud.utils.exception.CloudRuntimeException; +import java.net.URI; +import java.net.URISyntaxException; public class UcsHttpClient { - private static HttpClient client = new HttpClient(); + private static final Logger logger = Logger.getLogger(UcsHttpClient.class); + //private static HttpClient client; private static Protocol ucsHttpsProtocol = new org.apache.commons.httpclient.protocol.Protocol("https", new EasySSLProtocolSocketFactory(), 443); private final String url; + private static RestTemplate template; + + static { + //client = new HttpClient(); + template = new RestTemplate(); + } public UcsHttpClient(String ip) { url = String.format("http://%s/nuova", ip); Protocol.registerProtocol("https", ucsHttpsProtocol); } - public String call(String xml) { + + private String call(URI uri, String body) { + HttpHeaders requestHeaders = new HttpHeaders(); + requestHeaders.setContentType(MediaType.APPLICATION_XML); + requestHeaders.setContentLength(body.length()); + HttpEntity req = new HttpEntity(body, requestHeaders); + if (!body.contains("aaaLogin")) { + logger.debug(String.format("UCS call: %s", body)); + } + ResponseEntity rsp = template.exchange(uri, HttpMethod.POST, req, String.class); + if (rsp.getStatusCode() == org.springframework.http.HttpStatus.OK) { + return rsp.getBody(); + } else if (rsp.getStatusCode() == org.springframework.http.HttpStatus.FOUND) { + // Handle HTTPS redirect + // Ideal way might be to configure from add manager API + // for using either HTTP / HTTPS + // Allow only one level of redirect + java.net.URI location = rsp.getHeaders().getLocation(); + if (location == null) { + throw new CloudRuntimeException("Call failed: Bad redirect from UCS Manager"); + } + //call(location, body); + rsp = template.exchange(location, HttpMethod.POST, req, String.class); + } + if (rsp.getStatusCode() != org.springframework.http.HttpStatus.OK) { + String err = String.format("http status: %s, response body:%s", rsp.getStatusCode().toString(), rsp.getBody()); + throw new CloudRuntimeException(String.format("UCS API call failed, details: %s\n", err)); + } + + if (rsp.getBody().contains("errorCode")) { + String err = String.format("ucs call failed:\nsubmitted doc:%s\nresponse:%s\n", body, rsp.getBody()); + throw new CloudRuntimeException(err); + } + return rsp.getBody(); + } + + public String call(String body) { + try { + return call(new URI(url), body); + } catch (URISyntaxException e) { + throw new CloudRuntimeException(e); + } + /* PostMethod post = new PostMethod(url); post.setRequestEntity(new StringRequestEntity(xml)); post.setRequestHeader("Content-type", "text/xml"); @@ -75,5 +124,6 @@ public String call(String xml) { } finally { post.releaseConnection(); } + */ } } diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManager.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManager.java index 0833e31f0f39..0cd695c485e0 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManager.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManager.java @@ -17,15 +17,8 @@ // package com.cloud.ucs.manager; -import org.apache.cloudstack.api.AddUcsManagerCmd; -import org.apache.cloudstack.api.AssociateUcsProfileToBladeCmd; -import org.apache.cloudstack.api.ListUcsBladeCmd; -import org.apache.cloudstack.api.ListUcsManagerCmd; -import org.apache.cloudstack.api.ListUcsProfileCmd; -import org.apache.cloudstack.api.response.ListResponse; -import org.apache.cloudstack.api.response.UcsBladeResponse; -import org.apache.cloudstack.api.response.UcsManagerResponse; -import org.apache.cloudstack.api.response.UcsProfileResponse; +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.*; import com.cloud.utils.component.Manager; import com.cloud.utils.component.PluggableService; @@ -35,11 +28,19 @@ public interface UcsManager extends Manager, PluggableService { ListResponse listUcsProfiles(ListUcsProfileCmd cmd); + ListResponse listUcsTemplates(ListUcsTemplatesCmd cmd); + ListResponse listUcsManager(ListUcsManagerCmd cmd); UcsBladeResponse associateProfileToBlade(AssociateUcsProfileToBladeCmd cmd); + UcsBladeResponse instantiateTemplateAndAssociateToBlade(InstantiateUcsTemplateAndAssociateToBladeCmd cmd); + ListResponse listUcsBlades(ListUcsBladeCmd cmd); void deleteUcsManager(Long id); + + ListResponse refreshBlades(Long mgrId); + + UcsBladeResponse disassociateProfile(DisassociateUcsProfileCmd cmd); } diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java index 4239482d1cbc..7c9aff060643 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java @@ -17,33 +17,6 @@ // package com.cloud.ucs.manager; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; -import org.apache.cloudstack.api.AddUcsManagerCmd; -import org.apache.cloudstack.api.AssociateUcsProfileToBladeCmd; -import org.apache.cloudstack.api.DeleteUcsManagerCmd; -import org.apache.cloudstack.api.ListUcsBladeCmd; -import org.apache.cloudstack.api.ListUcsManagerCmd; -import org.apache.cloudstack.api.ListUcsProfileCmd; -import org.apache.cloudstack.api.response.ListResponse; -import org.apache.cloudstack.api.response.UcsBladeResponse; -import org.apache.cloudstack.api.response.UcsManagerResponse; -import org.apache.cloudstack.api.response.UcsProfileResponse; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.managed.context.ManagedContextRunnable; - import com.cloud.configuration.Config; import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.DataCenterVO; @@ -59,14 +32,26 @@ import com.cloud.ucs.structure.ComputeBlade; import com.cloud.ucs.structure.UcsCookie; import com.cloud.ucs.structure.UcsProfile; +import com.cloud.ucs.structure.UcsTemplate; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; -import com.cloud.utils.db.QueryBuilder; +import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.xmlobject.XmlObject; import com.cloud.utils.xmlobject.XmlObjectParser; +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.*; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.log4j.Logger; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; @Local(value = { UcsManager.class }) public class UcsManagerImpl implements UcsManager { @@ -98,7 +83,7 @@ public class UcsManagerImpl implements UcsManager { private ScheduledExecutorService syncBladesExecutor; private int syncBladeInterval; - private class SyncBladesThread extends ManagedContextRunnable { + private class SyncBladesThread implements Runnable { private void discoverNewBlades(Map previous, Map now, UcsManagerVO mgr) { @@ -132,9 +117,9 @@ private void decommissionFadedBlade(Map previous, Map q = QueryBuilder.create(UcsBladeVO.class); - q.and(q.entity().getUcsManagerId(), Op.EQ, mgr.getId()); - List pblades = q.list(); + SearchCriteria q = bladeDao.createSearchCriteria(); + q.addAnd("ucsManagerId", Op.EQ, mgr.getId()); + List pblades = bladeDao.search(q, null); if (pblades.isEmpty()) { return; } @@ -156,7 +141,7 @@ private void syncBlades(UcsManagerVO mgr) { } @Override - protected void runInContext() { + public void run() { try { List mgrs = ucsDao.listAll(); for (UcsManagerVO mgr : mgrs) { @@ -203,6 +188,9 @@ private void discoverBlades(UcsManagerVO ucsMgrVo) { vo.setDn(b.getDn()); vo.setUcsManagerId(ucsMgrVo.getId()); vo.setUuid(UUID.randomUUID().toString()); + if (!"".equals(b.getAssignedToDn())) { + vo.setProfileDn(b.getAssignedToDn()); + } bladeDao.persist(vo); } } @@ -210,9 +198,9 @@ private void discoverBlades(UcsManagerVO ucsMgrVo) { @Override @DB public UcsManagerResponse addUcsManager(AddUcsManagerCmd cmd) { - QueryBuilder q = QueryBuilder.create(UcsManagerVO.class); - q.and(q.entity().getUrl(), Op.EQ, cmd.getUrl()); - UcsManagerVO mgrvo = q.find(); + SearchCriteria q = ucsDao.createSearchCriteria(); + q.addAnd("url", Op.EQ, cmd.getUrl()); + UcsManagerVO mgrvo = ucsDao.findOneBy(q); if (mgrvo != null) { throw new IllegalArgumentException(String.format("duplicate UCS manager. url[%s] is used by another UCS manager already", cmd.getUrl())); } @@ -263,7 +251,7 @@ else if(currentTime - cookieStartTime > COOKIE_REFRESH_TTL) { cmd = UcsCommands.refreshCmd(mgrvo.getUsername(), mgrvo.getPassword(), cookie); } } - if(!(cmd == null)) { + if(cmd != null) { String ret = client.call(cmd); XmlObject xo = XmlObjectParser.parseFromString(ret); String cookie = xo.get("outCookie"); @@ -286,14 +274,24 @@ private List listBlades(Long ucsMgrId) { return ComputeBlade.fromXmString(ret); } + private List getUcsTemplates(Long ucsMgrId) { + String cookie = getCookie(ucsMgrId); + UcsManagerVO mgrvo = ucsDao.findById(ucsMgrId); + String cmd = UcsCommands.listTemplates(cookie); + UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); + String res = client.call(cmd); + List tmps = UcsTemplate.fromXmlString(res); + return tmps; + } + private List getUcsProfiles(Long ucsMgrId) { String cookie = getCookie(ucsMgrId); UcsManagerVO mgrvo = ucsDao.findById(ucsMgrId); - String cmd = UcsCommands.listProfiles(cookie); + String cmd = UcsCommands.listTemplates(cookie); UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); String res = client.call(cmd); - List profiles = UcsProfile.fromXmlString(res); - return profiles; + List tmps = UcsTemplate.fromXmlString(res); + return null; } @Override @@ -311,6 +309,21 @@ public ListResponse listUcsProfiles(ListUcsProfileCmd cmd) { return response; } + @Override + public ListResponse listUcsTemplates(ListUcsTemplatesCmd cmd) { + List templates = getUcsTemplates(cmd.getUcsManagerId()); + ListResponse response = new ListResponse(); + List rs = new ArrayList(); + for (UcsTemplate t : templates) { + UcsTemplateResponse r = new UcsTemplateResponse(); + r.setObjectName("ucstemplate"); + r.setDn(t.getDn()); + rs.add(r); + } + response.setResponses(rs); + return response; + } + private String cloneProfile(Long ucsMgrId, String srcDn, String newProfileName) { UcsManagerVO mgrvo = ucsDao.findById(ucsMgrId); UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); @@ -321,6 +334,7 @@ private String cloneProfile(Long ucsMgrId, String srcDn, String newProfileName) return xo.get("outConfig.lsServer.dn"); } + private boolean isProfileAssociated(Long ucsMgrId, String dn) { UcsManagerVO mgrvo = ucsDao.findById(ucsMgrId); UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); @@ -328,21 +342,33 @@ private boolean isProfileAssociated(Long ucsMgrId, String dn) { String cmd = UcsCommands.configResolveDn(cookie, dn); String res = client.call(cmd); XmlObject xo = XmlObjectParser.parseFromString(res); + + return xo.get("outConfig.lsServer.assocState").equals("associated"); + } + + private boolean isBladeAssociated(Long ucsMgrId, String dn) { + UcsManagerVO mgrvo = ucsDao.findById(ucsMgrId); + UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); + String cookie = getCookie(ucsMgrId); + String cmd = UcsCommands.configResolveDn(cookie, dn); + String res = client.call(cmd); + XmlObject xo = XmlObjectParser.parseFromString(res); s_logger.debug(String.format("association response is %s", res)); if (xo.get("outConfig.computeBlade.association").equals("none")) { throw new CloudRuntimeException(String.format("cannot associated a profile to blade[dn:%s]. please check your UCS manasger for detailed error information", dn)); } - + return xo.get("outConfig.computeBlade.association").equals("associated"); + //return !xo.get("outConfig.computeBlade.assignedToDn").equals(""); } @Override public UcsBladeResponse associateProfileToBlade(AssociateUcsProfileToBladeCmd cmd) { - QueryBuilder q = QueryBuilder.create(UcsBladeVO.class); - q.and(q.entity().getUcsManagerId(), Op.EQ, cmd.getUcsManagerId()); - q.and(q.entity().getId(), Op.EQ, cmd.getBladeId()); - UcsBladeVO bvo = q.find(); + SearchCriteria sc = bladeDao.createSearchCriteria(); + sc.addAnd("ucsManagerId", Op.EQ, cmd.getUcsManagerId()); + sc.addAnd("id", Op.EQ, cmd.getBladeId()); + UcsBladeVO bvo = bladeDao.findOneBy(sc); if (bvo == null) { throw new IllegalArgumentException(String.format("cannot find UCS blade[id:%s, ucs manager id:%s]", cmd.getBladeId(), cmd.getUcsManagerId())); } @@ -358,9 +384,9 @@ public UcsBladeResponse associateProfileToBlade(AssociateUcsProfileToBladeCmd cm UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); String res = client.call(ucscmd); int count = 0; - int timeout = 600; + int timeout = 3600; while (count < timeout) { - if (isProfileAssociated(mgrvo.getId(), bvo.getDn())) { + if (isBladeAssociated(mgrvo.getId(), bvo.getDn())) { break; } @@ -386,6 +412,63 @@ public UcsBladeResponse associateProfileToBlade(AssociateUcsProfileToBladeCmd cm return rsp; } + @Override + public UcsBladeResponse instantiateTemplateAndAssociateToBlade(InstantiateUcsTemplateAndAssociateToBladeCmd cmd) { + String profileName = cmd.getProfileName(); + if (profileName == null || "".equals(profileName)) { + profileName = UUID.randomUUID().toString().replace("-", ""); + } + + SearchCriteria sc = bladeDao.createSearchCriteria(); + sc.addAnd("ucsManagerId", Op.EQ, cmd.getUcsManagerId()); + sc.addAnd("id", Op.EQ, cmd.getBladeId()); + UcsBladeVO bvo = bladeDao.findOneBy(sc); + if (bvo == null) { + throw new IllegalArgumentException(String.format("cannot find UCS blade[id:%s, ucs manager id:%s]", cmd.getBladeId(), cmd.getUcsManagerId())); + } + + if (bvo.getHostId() != null) { + throw new CloudRuntimeException(String.format("blade[id:%s, dn:%s] has been associated with host[id:%s]", bvo.getId(), bvo.getDn(), bvo.getHostId())); + } + + UcsManagerVO mgrvo = ucsDao.findById(cmd.getUcsManagerId()); + String cookie = getCookie(cmd.getUcsManagerId()); + String instantiateTemplateCmd = UcsCommands.instantiateTemplate(cookie, cmd.getTemplateDn(), profileName); + UcsHttpClient http = new UcsHttpClient(mgrvo.getUrl()); + String res = http.call(instantiateTemplateCmd); + XmlObject xo = XmlObjectParser.parseFromString(res); + String profileDn = xo.get("outConfig.lsServer.dn"); + String ucscmd = UcsCommands.associateProfileToBlade(cookie, profileDn, bvo.getDn()); + res = http.call(ucscmd); + int count = 0; + int timeout = 3600; + while (count < timeout) { + if (isBladeAssociated(mgrvo.getId(), bvo.getDn())) { + break; + } + + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + throw new CloudRuntimeException(e); + } + + count += 2; + } + + if (count >= timeout) { + throw new CloudRuntimeException(String.format("associating profile[%s] to balde[%s] timeout after 600 seconds", profileDn, bvo.getDn())); + } + + bvo.setProfileDn(profileDn); + bladeDao.update(bvo.getId(), bvo); + + UcsBladeResponse rsp = bladeVOToResponse(bvo); + + s_logger.debug(String.format("successfully associated profile[%s] to blade[%s]", profileDn, bvo.getDn())); + return rsp; + } + private String hostIdToUuid(Long hostId) { if (hostId == null) { return null; @@ -420,10 +503,10 @@ public ListResponse listUcsManager(ListUcsManagerCmd cmd) { response.setResponses(rsps); return response; } - - QueryBuilder serv = QueryBuilder.create(UcsManagerVO.class); - serv.and(serv.entity().getZoneId(), Op.EQ, cmd.getZoneId()); - List vos = serv.list(); + + SearchCriteria sc = ucsDao.createSearchCriteria(); + sc.addAnd("zoneId", Op.EQ, cmd.getZoneId()); + List vos = ucsDao.search(sc, null); for (UcsManagerVO vo : vos) { UcsManagerResponse rsp = new UcsManagerResponse(); @@ -448,25 +531,29 @@ private UcsBladeResponse bladeVOToResponse(UcsBladeVO vo) { rsp.setUcsManagerId(ucsManagerIdToUuid(vo.getUcsManagerId())); return rsp; } - - @Override - public ListResponse listUcsBlades(ListUcsBladeCmd cmd) { - QueryBuilder serv = QueryBuilder.create(UcsBladeVO.class); - serv.and(serv.entity().getUcsManagerId(), Op.EQ, cmd.getUcsManagerId()); - List vos = serv.list(); - + + private ListResponse listUcsBlades(long mgrId) { + SearchCriteria sc = bladeDao.createSearchCriteria(); + sc.addAnd("ucsManagerId", Op.EQ, mgrId); + List vos = bladeDao.search(sc, null); + List rsps = new ArrayList(vos.size()); for (UcsBladeVO vo : vos) { UcsBladeResponse rsp = bladeVOToResponse(vo); rsps.add(rsp); } - + ListResponse response = new ListResponse(); response.setResponses(rsps); return response; } + @Override + public ListResponse listUcsBlades(ListUcsBladeCmd cmd) { + return listUcsBlades(cmd.getUcsManagerId()); + } + @Override public void setName(String name) { this.name = name; @@ -501,17 +588,68 @@ public List> getCommands() { cmds.add(AddUcsManagerCmd.class); cmds.add(AssociateUcsProfileToBladeCmd.class); cmds.add(DeleteUcsManagerCmd.class); + cmds.add(DisassociateUcsProfileCmd.class); + cmds.add(RefreshUcsBladesCmd.class); + cmds.add(ListUcsTemplatesCmd.class); + cmds.add(InstantiateUcsTemplateAndAssociateToBladeCmd.class); return cmds; } @Override public void deleteUcsManager(Long id) { - QueryBuilder serv = QueryBuilder.create(UcsBladeVO.class); - serv.and(serv.entity().getUcsManagerId(), Op.EQ, id); - List vos = serv.list(); + SearchCriteria sc = bladeDao.createSearchCriteria(); + sc.addAnd("ucsManagerId", Op.EQ, id); + List vos = bladeDao.search(sc, null); for (UcsBladeVO vo : vos) { bladeDao.remove(vo.getId()); } ucsDao.remove(id); } + + @Override + @DB + public ListResponse refreshBlades(Long mgrId) { + SyncBladesThread synct = new SyncBladesThread(); + synct.run(); + + UcsManagerVO mgrvo = ucsDao.findById(mgrId); + List blades = listBlades(mgrvo.getId()); + for (ComputeBlade b : blades) { + SearchCriteria sc = bladeDao.createSearchCriteria(); + sc.addAnd("dn", Op.EQ, b.getDn()); + UcsBladeVO vo = bladeDao.findOneBy(sc); + if (vo == null) { + vo = new UcsBladeVO(); + vo.setProfileDn("".equals(b.getAssignedToDn()) ? null : b.getAssignedToDn()); + vo.setDn(b.getDn()); + vo.setUuid(UUID.randomUUID().toString()); + vo.setUcsManagerId(mgrId); + bladeDao.persist(vo); + } else { + vo.setProfileDn("".equals(b.getAssignedToDn()) ? null : b.getAssignedToDn()); + bladeDao.update(vo.getId(), vo); + } + } + + return listUcsBlades(mgrId); + } + + @Override + public UcsBladeResponse disassociateProfile(DisassociateUcsProfileCmd cmd) { + UcsBladeVO blade = bladeDao.findById(cmd.getBladeId()); + UcsManagerVO mgrvo = ucsDao.findById(blade.getUcsManagerId()); + UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); + String cookie = getCookie(mgrvo.getId()); + String call = UcsCommands.disassociateProfileFromBlade(cookie, blade.getProfileDn()); + client.call(call); + if (cmd.isDeleteProfile()) { + call = UcsCommands.deleteProfile(cookie, blade.getProfileDn()); + client = new UcsHttpClient(mgrvo.getUrl()); + client.call(call); + } + blade.setProfileDn(null); + bladeDao.update(blade.getId(), blade); + UcsBladeResponse rsp = bladeVOToResponse(blade); + return rsp; + } } diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/structure/UcsTemplate.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/structure/UcsTemplate.java new file mode 100644 index 000000000000..cbe559055af8 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/structure/UcsTemplate.java @@ -0,0 +1,57 @@ +// 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.ucs.structure; + +import com.cloud.utils.xmlobject.XmlObject; +import com.cloud.utils.xmlobject.XmlObjectParser; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: frank + * Date: 10/8/13 + * Time: 3:01 PM + * To change this template use File | Settings | File Templates. + */ +public class UcsTemplate { + private String dn; + + public static List fromXmlString(String xmlstr) { + List tmps = new ArrayList(); + XmlObject xo = XmlObjectParser.parseFromString(xmlstr); + List xos = xo.getAsList("outConfigs.lsServer"); + if (xos != null) { + for (XmlObject x : xos) { + UcsTemplate t = new UcsTemplate(); + t.setDn(x.get("dn").toString()); + tmps.add(t); + } + } + return tmps; + } + + public String getDn() { + return dn; + } + + public void setDn(String dn) { + this.dn = dn; + } +} diff --git a/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/DisassociateUcsProfileCmd.java b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/DisassociateUcsProfileCmd.java new file mode 100644 index 000000000000..96d662c6f036 --- /dev/null +++ b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/DisassociateUcsProfileCmd.java @@ -0,0 +1,98 @@ +// 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.api; + +import com.cloud.event.EventTypes; + +import com.cloud.exception.*; +import com.cloud.ucs.manager.UcsManager; +import com.cloud.user.Account; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.api.response.UcsBladeResponse; +import org.apache.log4j.Logger; + +import javax.inject.Inject; + +/** + * Created with IntelliJ IDEA. + * User: frank + * Date: 9/13/13 + * Time: 6:23 PM + * To change this template use File | Settings | File Templates. + */ +@APICommand(name="disassociateUcsProfileFromBlade", description="disassociate a profile from a blade", responseObject=UcsBladeResponse.class) +public class DisassociateUcsProfileCmd extends BaseAsyncCmd { + private static Logger logger = Logger.getLogger(DisassociateUcsProfileCmd.class); + + @Inject + private UcsManager mgr; + + @Parameter(name=ApiConstants.UCS_BLADE_ID, type=CommandType.UUID, entityType=UcsBladeResponse.class, description="blade id", required=true) + private Long bladeId; + + @Parameter(name=ApiConstants.UCS_DELETE_PROFILE, type=CommandType.BOOLEAN, description="is deleting profile after disassociating") + private boolean deleteProfile; + + @Override + public String getEventType() { + return EventTypes.EVENT_UCS_DISASSOCIATED_PROFILE; + } + + @Override + public String getEventDescription() { + return "disassociate a profile from blade"; + } + + public Long getBladeId() { + return bladeId; + } + + public void setBladeId(Long bladeId) { + this.bladeId = bladeId; + } + + public boolean isDeleteProfile() { + return deleteProfile; + } + + public void setDeleteProfile(boolean deleteProfile) { + this.deleteProfile = deleteProfile; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try { + UcsBladeResponse rsp = mgr.disassociateProfile(this); + rsp.setResponseName(getCommandName()); + this.setResponseObject(rsp); + } catch(Exception e) { + logger.warn(e.getMessage(), e); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); + } + } + + @Override + public String getCommandName() { + return "disassociateucsprofilefrombladeresponse"; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } +} diff --git a/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/InstantiateUcsTemplateAndAssociateToBladeCmd.java b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/InstantiateUcsTemplateAndAssociateToBladeCmd.java new file mode 100644 index 000000000000..ef7a73f38f12 --- /dev/null +++ b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/InstantiateUcsTemplateAndAssociateToBladeCmd.java @@ -0,0 +1,116 @@ +// 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.api; + +import com.cloud.event.EventTypes; +import com.cloud.exception.*; +import com.cloud.ucs.manager.UcsManager; +import com.cloud.user.Account; +import org.apache.cloudstack.api.response.UcsBladeResponse; +import org.apache.cloudstack.api.response.UcsManagerResponse; +import org.apache.log4j.Logger; + +import javax.inject.Inject; + +/** + * Created with IntelliJ IDEA. + * User: frank + * Date: 10/8/13 + * Time: 3:17 PM + * To change this template use File | Settings | File Templates. + */ +@APICommand(name="instantiateUcsTemplateAndAssocaciateToBlade", description="create a profile of template and associate to a blade", responseObject=UcsBladeResponse.class) +public class InstantiateUcsTemplateAndAssociateToBladeCmd extends BaseAsyncCmd{ + public static final Logger s_logger = Logger.getLogger(InstantiateUcsTemplateAndAssociateToBladeCmd.class); + + @Inject + private UcsManager mgr; + + @Parameter(name=ApiConstants.UCS_MANAGER_ID, type= BaseCmd.CommandType.UUID, description="ucs manager id", entityType=UcsManagerResponse.class, required=true) + private Long ucsManagerId; + @Parameter(name=ApiConstants.UCS_TEMPLATE_DN, type= BaseCmd.CommandType.STRING, description="template dn", required=true) + private String templateDn; + @Parameter(name=ApiConstants.UCS_BLADE_ID, type= BaseCmd.CommandType.UUID, entityType=UcsBladeResponse.class, description="blade id", required=true) + private Long bladeId; + @Parameter(name=ApiConstants.UCS_PROFILE_NAME, type= BaseCmd.CommandType.STRING, description="profile name") + private String profileName; + + @Override + public String getEventType() { + return EventTypes.EVENT_UCS_INSTANTIATE_TEMPLATE_AND_ASSOCIATE; + } + + @Override + public String getEventDescription() { + return "create a profile off template and associate to a blade"; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try { + UcsBladeResponse rsp = mgr.instantiateTemplateAndAssociateToBlade(this); + rsp.setResponseName(getCommandName()); + this.setResponseObject(rsp); + } catch (Exception e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); + } + } + + @Override + public String getCommandName() { + return "instantiateucstemplateandassociatetobladeresponse"; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + public Long getUcsManagerId() { + return ucsManagerId; + } + + public void setUcsManagerId(Long ucsManagerId) { + this.ucsManagerId = ucsManagerId; + } + + public String getTemplateDn() { + return templateDn; + } + + public void setTemplateDn(String templateDn) { + this.templateDn = templateDn; + } + + public Long getBladeId() { + return bladeId; + } + + public void setBladeId(Long bladeId) { + this.bladeId = bladeId; + } + + public String getProfileName() { + return profileName; + } + + public void setProfileName(String profileName) { + this.profileName = profileName; + } +} diff --git a/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/ListUcsTemplatesCmd.java b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/ListUcsTemplatesCmd.java new file mode 100644 index 000000000000..f0ea2ec8f622 --- /dev/null +++ b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/ListUcsTemplatesCmd.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 org.apache.cloudstack.api; + +import com.cloud.exception.*; +import com.cloud.ucs.manager.UcsManager; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.UcsManagerResponse; +import org.apache.cloudstack.api.response.UcsProfileResponse; +import org.apache.cloudstack.api.response.UcsTemplateResponse; +import org.apache.log4j.Logger; + +import javax.inject.Inject; + +/** + * Created with IntelliJ IDEA. + * User: frank + * Date: 10/8/13 + * Time: 3:08 PM + * To change this template use File | Settings | File Templates. + */ +@APICommand(name="listUcsTemplates", description="List templates in ucs manager", responseObject=UcsTemplateResponse.class) +public class ListUcsTemplatesCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(ListUcsTemplatesCmd.class); + + @Inject + UcsManager mgr; + + @Parameter(name=ApiConstants.UCS_MANAGER_ID, type= BaseCmd.CommandType.UUID, entityType=UcsManagerResponse.class, description="the id for the ucs manager", required=true) + private Long ucsManagerId; + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try { + ListResponse response = mgr.listUcsTemplates(this); + response.setResponseName(getCommandName()); + response.setObjectName("ucstemplate"); + this.setResponseObject(response); + } catch (Exception e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); + } + } + + @Override + public String getCommandName() { + return "listucstemplatesresponse"; + } + + public Long getUcsManagerId() { + return ucsManagerId; + } + + public void setUcsManagerId(Long ucsManagerId) { + this.ucsManagerId = ucsManagerId; + } +} diff --git a/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/RefreshUcsBladesCmd.java b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/RefreshUcsBladesCmd.java new file mode 100644 index 000000000000..ac9201ff4fd5 --- /dev/null +++ b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/RefreshUcsBladesCmd.java @@ -0,0 +1,78 @@ +// 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.api; + +import com.cloud.event.EventTypes; +import com.cloud.exception.*; +import com.cloud.ucs.manager.UcsManager; +import com.cloud.user.Account; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.UcsBladeResponse; +import org.apache.cloudstack.api.response.UcsManagerResponse; +import org.apache.log4j.Logger; + +import javax.inject.Inject; + +/** + * Created with IntelliJ IDEA. + * User: frank + * Date: 10/3/13 + * Time: 2:18 PM + * To change this template use File | Settings | File Templates. + */ +@APICommand(name="refreshUcsBlades", description="refresh ucs blades to sync with UCS manager", responseObject=UcsBladeResponse.class) +public class RefreshUcsBladesCmd extends BaseListCmd { + private static Logger s_logger = Logger.getLogger(RefreshUcsBladesCmd.class); + + @Inject + private UcsManager mgr; + + @Parameter(name=ApiConstants.UCS_MANAGER_ID, type= BaseCmd.CommandType.UUID, description="ucs manager id", entityType=UcsManagerResponse.class, required=true) + private Long ucsManagerId; + + public UcsManager getMgr() { + return mgr; + } + + public void setMgr(UcsManager mgr) { + this.mgr = mgr; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try { + ListResponse response = mgr.refreshBlades(ucsManagerId); + response.setResponseName(getCommandName()); + response.setObjectName("ucsblade"); + this.setResponseObject(response); + } catch (Exception e) { + s_logger.warn("unhandled exception:", e); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); + } + } + + @Override + public String getCommandName() { + return "refreshucsbladesresponse"; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } +} diff --git a/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/response/UcsTemplateResponse.java b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/response/UcsTemplateResponse.java new file mode 100644 index 000000000000..0a31dae29fd3 --- /dev/null +++ b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/response/UcsTemplateResponse.java @@ -0,0 +1,36 @@ +// 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.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +public class UcsTemplateResponse extends BaseResponse { + @SerializedName(ApiConstants.UCS_DN) @Param(description="ucs template dn") + private String dn; + + public String getDn() { + return dn; + } + + public void setDn(String dn) { + this.dn = dn; + } +} diff --git a/plugins/hypervisors/vmware/pom.xml b/plugins/hypervisors/vmware/pom.xml index 46d51e820ca4..cdd0fbe2bc96 100644 --- a/plugins/hypervisors/vmware/pom.xml +++ b/plugins/hypervisors/vmware/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java index 76ee59bc8b41..349b516c8be3 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java @@ -96,9 +96,13 @@ import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VmDetailConstants; import com.cloud.vm.dao.NicDao; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.vm.dao.VMInstanceDao; @Local(value=HypervisorGuru.class) -public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru { +public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Configurable { private static final Logger s_logger = Logger.getLogger(VMwareGuru.class); @Inject NetworkDao _networkDao; @@ -117,11 +121,20 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru { @Inject PhysicalNetworkTrafficTypeDao _physicalNetworkTrafficTypeDao; @Inject ClusterManager _clusterMgr; + @Inject + VMInstanceDao _vmDao; + @Inject + ClusterDao _clusterDao; protected VMwareGuru() { super(); } + static final ConfigKey VmwareReserveCpu = new ConfigKey(Boolean.class, "vmware.reserve.cpu", "Advanced", "false", + "Specify whether or not to reserve CPU when not overprovisioning, In case of cpu overprovisioning we will always reserve cpu.", true, ConfigKey.Scope.Cluster, null); + static final ConfigKey VmwareReserveMemory = new ConfigKey(Boolean.class, "vmware.reserve.cpu", "Advanced", "false", + "Specify whether or not to reserve memory when not overprovisioning, In case of memory overprovisioning we will always reserve memory.", true, ConfigKey.Scope.Cluster, null); + @Override public HypervisorType getHypervisorType() { return HypervisorType.VMware; @@ -184,6 +197,9 @@ public VirtualMachineTO implement(VirtualMachineProfile vm) { } } + long clusterId = this.getClusterId(vm.getId()); + details.put(Config.VmwareReserveCpu.key(), VmwareReserveCpu.valueIn(clusterId).toString()); + details.put(Config.VmwareReserveMem.key(), VmwareReserveMemory.valueIn(clusterId).toString()); to.setDetails(details); if(vm.getVirtualMachine() instanceof DomainRouterVO) { @@ -277,6 +293,20 @@ public VirtualMachineTO implement(VirtualMachineProfile vm) { return to; } + private long getClusterId(long vmId) { + long clusterId; + Long hostId; + + hostId = _vmDao.findById(vmId).getHostId(); + if (hostId == null) { + // If VM is in stopped state then hostId would be undefined. Hence read last host's Id instead. + hostId = _vmDao.findById(vmId).getLastHostId(); + } + clusterId = _hostDao.findById(hostId).getClusterId(); + + return clusterId; + } + private NicTO[] sortNicsByDeviceId(NicTO[] nics) { List listForSort = new ArrayList(); @@ -368,6 +398,7 @@ public Pair getCommandHostDelegation(long hostId, Command cmd) { _cmdExecLogDao.persist(execLog); cmd.setContextParam("execid", String.valueOf(execLog.getId())); cmd.setContextParam("noderuninfo", String.format("%d-%d", _clusterMgr.getManagementNodeId(), _clusterMgr.getCurrentRunId())); + cmd.setContextParam("vCenterSessionTimeout", String.valueOf(_vmwareMgr.getVcenterSessionTimeout())); if(cmd instanceof BackupSnapshotCommand || cmd instanceof CreatePrivateTemplateFromVolumeCommand || @@ -439,4 +470,14 @@ public List finalizeExpungeNics(VirtualMachine vm, List nic } return commands; } + + @Override + public String getConfigComponentName() { + return VMwareGuru.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[] {VmwareReserveCpu, VmwareReserveMemory}; + } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java index 58255bf2e582..54e981512723 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java @@ -168,7 +168,7 @@ public Map> find(long dcId, Long p _clusterDetailsDao.persist(clusterId, clusterDetails); } String updatedInventoryPath = validateCluster(url, vmwareDc); - if (url.getPath() != updatedInventoryPath) { + if (!url.getPath().equals(updatedInventoryPath)) { // If url from API doesn't specify DC then update url in database with DC associated with this zone. clusterDetails.put("url", url.getScheme() + "://" + url.getHost() + updatedInventoryPath); _clusterDetailsDao.persist(clusterId, clusterDetails); @@ -417,7 +417,7 @@ public Map> find(long dcId, Long p try { resource.configure("VMware", params); } catch (ConfigurationException e) { - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, dcId, podId, "Unable to add " + url.getHost(), "Error is " + e.getMessage()); s_logger.warn("Unable to instantiate " + url.getHost(), e); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java index d5a228411ce5..f6bbd15bcede 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java @@ -19,7 +19,6 @@ import java.util.List; import com.cloud.agent.api.Command; -import com.cloud.hypervisor.vmware.mo.DatastoreMO; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; import com.cloud.hypervisor.vmware.util.VmwareContext; import com.vmware.vim25.ManagedObjectReference; @@ -31,9 +30,9 @@ public interface VmwareHostService { String getWorkerName(VmwareContext context, Command cmd, int workerSequence); - ManagedObjectReference getVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress, int storagePortNumber, - String iqn, String initiatorChapName, String initiatorChapSecret, String mutualChapName, String mutualChapSecret) throws Exception; - void createVmdk(Command cmd, DatastoreMO dsMo, String volumeDatastorePath, Long volumeSize) throws Exception; + ManagedObjectReference prepareManagedStorage(VmwareHypervisorHost hyperHost, String iScsiName, + String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret, + String chapTargetUsername, String chapTargetSecret, long size, Command cmd) throws Exception; void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception; void removeManagedTargetsFromCluster(List managedIqns) throws Exception; } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java index 6c675990bb35..bc0c9a484207 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java @@ -69,5 +69,7 @@ List addHostToPodCluster(VmwareContext serviceContext, l public String getRootDiskController(); + public int getVcenterSessionTimeout(); + boolean isLegacyZone(long dcId); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index 9af0aa002d85..028fa942d578 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -132,8 +132,8 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, VmwareStorageMount, Listener, VmwareDatacenterService { private static final Logger s_logger = Logger.getLogger(VmwareManagerImpl.class); - private static final int STARTUP_DELAY = 60000; // 60 seconds - private static final long DEFAULT_HOST_SCAN_INTERVAL = 600000; // every 10 minutes + private static final int STARTUP_DELAY = 60000; // 60 seconds + private static final long DEFAULT_HOST_SCAN_INTERVAL = 600000; // every 10 minutes private long _hostScanInterval = DEFAULT_HOST_SCAN_INTERVAL; int _timeout; @@ -173,10 +173,11 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw String _managemetPortGroupName; String _defaultSystemVmNicAdapterType = VirtualEthernetCardType.E1000.toString(); String _recycleHungWorker = "false"; - long _hungWorkerTimeout = 7200000; // 2 hour + long _hungWorkerTimeout = 7200000; // 2 hour int _additionalPortRangeStart; int _additionalPortRangeSize; int _routerExtraPublicNics = 2; + int _vCenterSessionTimeout = 1200000; // Timeout in milliseconds String _reserveCpu = "false"; @@ -279,6 +280,9 @@ public boolean configure(String name, Map params) throws Configu _routerExtraPublicNics = NumbersUtil.parseInt(_configDao.getValue(Config.RouterExtraPublicNics.key()), 2); + _vCenterSessionTimeout = NumbersUtil.parseInt(_configDao.getValue(Config.VmwareVcenterSessionTimeout.key()), 1200) * 1000; + s_logger.info("VmwareManagerImpl config - vmware.vcenter.session.timeout: " + _vCenterSessionTimeout); + _reserveCpu = _configDao.getValue(Config.VmwareReserveCpu.key()); if(_reserveCpu == null || _reserveCpu.isEmpty()) { _reserveCpu = "false"; @@ -292,10 +296,10 @@ public boolean configure(String name, Map params) throws Configu if(_recycleHungWorker == null || _recycleHungWorker.isEmpty()) { _recycleHungWorker = "false"; } - + value = _configDao.getValue(Config.VmwareHungWorkerTimeout.key()); if(value != null) - _hungWorkerTimeout = Long.parseLong(value) * 1000; + _hungWorkerTimeout = Long.parseLong(value) * 1000; _rootDiskController = _configDao.getValue(Config.VmwareRootDiskControllerType.key()); if(_rootDiskController == null || _rootDiskController.isEmpty()) { @@ -455,7 +459,7 @@ private ManagedObjectReference addHostToVCenterCluster(VmwareContext serviceCont hostSpec.setUserName(userName); hostSpec.setPassword(password); hostSpec.setHostName(host); - hostSpec.setForce(true); // forcely take over the host + hostSpec.setForce(true); // forcely take over the host ManagedObjectReference morTask = serviceContext.getService().addHostTask(morCluster, hostSpec, true, null, null); boolean taskResult = vclient.waitForTask(morTask); @@ -529,8 +533,6 @@ public void setupResourceStartupParams(Map params) { params.put("vm.instancename.flag", _instanceNameFlag); params.put("service.console.name", _serviceConsoleName); params.put("management.portgroup.name", _managemetPortGroupName); - params.put("vmware.reserve.cpu", _reserveCpu); - params.put("vmware.reserve.mem", _reserveMem); params.put("vmware.root.disk.controller", _rootDiskController); params.put("vmware.recycle.hung.wokervm", _recycleHungWorker); params.put("ports.per.dvportgroup", _portsPerDvPortGroup); @@ -545,49 +547,49 @@ public VmwareStorageManager getStorageManager() { public void gcLeftOverVMs(VmwareContext context) { VmwareCleanupMaid.gcLeftOverVMs(context); } - + @Override public boolean needRecycle(String workerTag) { - if(s_logger.isInfoEnabled()) - s_logger.info("Check to see if a worker VM with tag " + workerTag + " needs to be recycled"); - - if(workerTag == null || workerTag.isEmpty()) { - s_logger.error("Invalid worker VM tag " + workerTag); - return false; - } - - String tokens[] = workerTag.split("-"); - if(tokens.length != 3) { - s_logger.error("Invalid worker VM tag " + workerTag); - return false; - } - - long startTick = Long.parseLong(tokens[0]); - long msid = Long.parseLong(tokens[1]); - long runid = Long.parseLong(tokens[2]); - + if (s_logger.isInfoEnabled()) + s_logger.info("Check to see if a worker VM with tag " + workerTag + " needs to be recycled"); + + if (workerTag == null || workerTag.isEmpty()) { + s_logger.error("Invalid worker VM tag " + workerTag); + return false; + } + + String tokens[] = workerTag.split("-"); + if (tokens.length != 3) { + s_logger.error("Invalid worker VM tag " + workerTag); + return false; + } + + long startTick = Long.parseLong(tokens[0]); + long msid = Long.parseLong(tokens[1]); + long runid = Long.parseLong(tokens[2]); + if(_mshostPeerDao.countStateSeenInPeers(msid, runid, ManagementServerHost.State.Down) > 0) { - if(s_logger.isInfoEnabled()) - s_logger.info("Worker VM's owner management server node has been detected down from peer nodes, recycle it"); - return true; + if (s_logger.isInfoEnabled()) + s_logger.info("Worker VM's owner management server node has been detected down from peer nodes, recycle it"); + return true; } - + if(msid == _clusterMgr.getManagementNodeId() && runid != _clusterMgr.getCurrentRunId()) { - if(s_logger.isInfoEnabled()) - s_logger.info("Worker VM's owner management server has changed runid, recycle it"); - return true; + if (s_logger.isInfoEnabled()) + s_logger.info("Worker VM's owner management server has changed runid, recycle it"); + return true; } - + // disable time-out check until we have found out a VMware API that can check if // there are pending tasks on the subject VM -/* - if(System.currentTimeMillis() - startTick > _hungWorkerTimeout) { - if(s_logger.isInfoEnabled()) - s_logger.info("Worker VM expired, seconds elapsed: " + (System.currentTimeMillis() - startTick) / 1000); - return true; - } -*/ - return false; + /* + if(System.currentTimeMillis() - startTick > _hungWorkerTimeout) { + if(s_logger.isInfoEnabled()) + s_logger.info("Worker VM expired, seconds elapsed: " + (System.currentTimeMillis() - startTick) / 1000); + return true; + } + */ + return false; } @Override @@ -617,6 +619,9 @@ public void prepareSecondaryStorageStore(String storageUrl) { ", destination: " + destIso.getAbsolutePath()); try { FileUtil.copyfile(srcIso, destIso); + + s_logger.info("System VM patch ISO file is copied to secondary storage. source ISO: " + srcIso.getAbsolutePath() + + ", destination: " + destIso.getAbsolutePath()); } catch(IOException e) { s_logger.error("Unexpected exception ", e); @@ -985,6 +990,11 @@ public String getRootDiskController() { return _rootDiskController; } + @Override + public int getVcenterSessionTimeout() { + return _vCenterSessionTimeout; + } + @Override public List> getCommands() { List> cmdList = new ArrayList>(); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java index 14f293a32a1e..5b76f40eeb9b 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java @@ -11,11 +11,13 @@ // 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 +// KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package com.cloud.hypervisor.vmware.manager; +import org.apache.cloudstack.storage.to.TemplateObjectTO; + import com.cloud.agent.api.Answer; import com.cloud.agent.api.BackupSnapshotCommand; import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand; @@ -24,7 +26,9 @@ import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; import com.cloud.agent.api.DeleteVMSnapshotCommand; import com.cloud.agent.api.RevertToVMSnapshotCommand; -import com.cloud.agent.api.storage.*; +import com.cloud.agent.api.storage.CopyVolumeCommand; +import com.cloud.agent.api.storage.CreateEntityDownloadURLCommand; +import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; public interface VmwareStorageManager { Answer execute(VmwareHostService hostService, PrimaryStorageDownloadCommand cmd); @@ -38,4 +42,6 @@ public interface VmwareStorageManager { Answer execute(VmwareHostService hostService, RevertToVMSnapshotCommand cmd); boolean execute(VmwareHostService hostService, CreateEntityDownloadURLCommand cmd); public void createOva(String path, String name); + + public String createOvaForTemplate(TemplateObjectTO template); } 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 3519ca1c4dcd..7e71d9070737 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 @@ -29,9 +29,18 @@ import java.util.Properties; import java.util.UUID; +import org.apache.log4j.Logger; + +import com.vmware.vim25.FileInfo; +import com.vmware.vim25.FileQueryFlags; +import com.vmware.vim25.HostDatastoreBrowserSearchResults; +import com.vmware.vim25.HostDatastoreBrowserSearchSpec; +import com.vmware.vim25.ManagedObjectReference; +import com.vmware.vim25.TaskInfo; +import com.vmware.vim25.VirtualDisk; + import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; -import org.apache.log4j.Logger; import com.cloud.agent.api.Answer; import com.cloud.agent.api.BackupSnapshotAnswer; @@ -80,13 +89,6 @@ import com.cloud.utils.script.Script; import com.cloud.vm.VirtualMachine; import com.cloud.vm.snapshot.VMSnapshot; -import com.vmware.vim25.FileInfo; -import com.vmware.vim25.FileQueryFlags; -import com.vmware.vim25.HostDatastoreBrowserSearchResults; -import com.vmware.vim25.HostDatastoreBrowserSearchSpec; -import com.vmware.vim25.ManagedObjectReference; -import com.vmware.vim25.TaskInfo; -import com.vmware.vim25.VirtualDisk; public class VmwareStorageManagerImpl implements VmwareStorageManager { @Override @@ -142,6 +144,7 @@ public void configure(Map params) { _timeout = NumbersUtil.parseInt(value, 1440) * 1000; } + @Override public String createOvaForTemplate(TemplateObjectTO template) { DataStoreTO storeTO = template.getDataStore(); if (!(storeTO instanceof NfsTO)) { @@ -1215,10 +1218,9 @@ private static String getSnapshotRelativeDirInSecStorage(long accountId, long vo } private long getVMSnapshotChainSize(VmwareContext context, VmwareHypervisorHost hyperHost, - String fileName, String poolUuid, String exceptFileName) + String fileName, ManagedObjectReference morDs, String exceptFileName) throws Exception{ long size = 0; - ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolUuid); DatastoreMO dsMo = new DatastoreMO(context, morDs); HostDatastoreBrowserMO browserMo = dsMo.getHostDatastoreBrowserMO(); String datastorePath = "[" + dsMo.getName() + "]"; @@ -1278,97 +1280,179 @@ public CreateVMSnapshotAnswer execute(VmwareHostService hostService, CreateVMSna boolean quiescevm = cmd.getTarget().getQuiescevm(); VirtualMachineMO vmMo = null; VmwareContext context = hostService.getServiceContext(cmd); - Map mapNewDisk = new HashMap(); + try { VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd); // wait if there are already VM snapshot task running ManagedObjectReference taskmgr = context.getServiceContent().getTaskManager(); List tasks = (ArrayList)context.getVimClient().getDynamicProperty(taskmgr, "recentTask"); + for (ManagedObjectReference taskMor : tasks) { - TaskInfo info = (TaskInfo) (context.getVimClient().getDynamicProperty(taskMor, "info")); - if(info.getEntityName().equals(cmd.getVmName()) && info.getName().equalsIgnoreCase("CreateSnapshot_Task")){ + TaskInfo info = (TaskInfo)(context.getVimClient().getDynamicProperty(taskMor, "info")); + + if (info.getEntityName().equals(cmd.getVmName()) && info.getName().equalsIgnoreCase("CreateSnapshot_Task")) { s_logger.debug("There is already a VM snapshot task running, wait for it"); context.getVimClient().waitForTask(taskMor); } } vmMo = hyperHost.findVmOnHyperHost(vmName); - if(vmMo == null) { + + if (vmMo == null) { vmMo = hyperHost.findVmOnPeerHyperHost(vmName); } + if (vmMo == null) { String msg = "Unable to find VM for CreateVMSnapshotCommand"; s_logger.debug(msg); + return new CreateVMSnapshotAnswer(cmd, false, msg); } else { if (vmMo.getSnapshotMor(vmSnapshotName) != null){ s_logger.debug("VM snapshot " + vmSnapshotName + " already exists"); - }else if (!vmMo.createSnapshot(vmSnapshotName, vmSnapshotDesc, snapshotMemory, quiescevm)) { - return new CreateVMSnapshotAnswer(cmd, false, - "Unable to create snapshot due to esxi internal failed"); + } else if (!vmMo.createSnapshot(vmSnapshotName, vmSnapshotDesc, snapshotMemory, quiescevm)) { + return new CreateVMSnapshotAnswer(cmd, false, "Unable to create snapshot due to esxi internal failed"); } - // find VM disk file path after creating snapshot - VirtualDisk[] vdisks = vmMo.getAllDiskDevice(); - for (int i = 0; i < vdisks.length; i ++){ - List> vmdkFiles = vmMo.getDiskDatastorePathChain(vdisks[i], false); - for(Pair fileItem : vmdkFiles) { - String vmdkName = fileItem.first().split(" ")[1]; - if (vmdkName.endsWith(".vmdk")){ - vmdkName = vmdkName.substring(0, vmdkName.length() - (".vmdk").length()); - } - String baseName = extractSnapshotBaseFileName(vmdkName); - mapNewDisk.put(baseName, vmdkName); - } - } - for (VolumeObjectTO volumeTO : volumeTOs) { - String baseName = extractSnapshotBaseFileName(volumeTO.getPath()); - String newPath = mapNewDisk.get(baseName); - // get volume's chain size for this VM snapshot, exclude current volume vdisk - DataStoreTO store = volumeTO.getDataStore(); - long size = getVMSnapshotChainSize(context,hyperHost,baseName + "*.vmdk", - store.getUuid(), newPath); - - if(volumeTO.getVolumeType()== Volume.Type.ROOT){ - // add memory snapshot size - size = size + getVMSnapshotChainSize(context,hyperHost,cmd.getVmName()+"*.vmsn",store.getUuid(),null); - } - volumeTO.setSize(size); - volumeTO.setPath(newPath); - } + Map mapNewDisk = getNewDiskMap(vmMo); + + setVolumeToPathAndSize(volumeTOs, mapNewDisk, context, hyperHost, cmd.getVmName()); + return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), volumeTOs); } } catch (Exception e) { String msg = e.getMessage(); s_logger.error("failed to create snapshot for vm:" + vmName + " due to " + msg); + try { if (vmMo.getSnapshotMor(vmSnapshotName) != null) { vmMo.removeSnapshot(vmSnapshotName, false); } } catch (Exception e1) { } + return new CreateVMSnapshotAnswer(cmd, false, e.getMessage()); } } + private Map getNewDiskMap(VirtualMachineMO vmMo) throws Exception { + Map mapNewDisk = new HashMap(); + + // find VM disk file path after creating snapshot + VirtualDisk[] vdisks = vmMo.getAllDiskDevice(); + + for (int i = 0; i < vdisks.length; i++) { + List> vmdkFiles = vmMo.getDiskDatastorePathChain(vdisks[i], false); + + for (Pair fileItem : vmdkFiles) { + String fullPath = fileItem.first(); + String baseName = null; + String vmdkName = null; + + // if this is managed storage + if (fullPath.startsWith("[-iqn.")) { // ex. [-iqn.2010-01.com.company:3y8w.vol-10.64-0] -iqn.2010-01.com.company:3y8w.vol-10.64-0-000001.vmdk + baseName = fullPath.split(" ")[0]; // ex. [-iqn.2010-01.com.company:3y8w.vol-10.64-0] + + // remove '[' and ']' + baseName = baseName.substring(1, baseName.length() - 1); + + vmdkName = fullPath; // for managed storage, vmdkName == fullPath + } + else { + vmdkName = fullPath.split(" ")[1]; + + if (vmdkName.endsWith(".vmdk")) { + vmdkName = vmdkName.substring(0, vmdkName.length() - (".vmdk").length()); + } + + String token = "/"; + + if (vmdkName.contains(token)) { + vmdkName = vmdkName.substring(vmdkName.indexOf(token) + token.length()); + } + + baseName = extractSnapshotBaseFileName(vmdkName); + } + + mapNewDisk.put(baseName, vmdkName); + } + } + + return mapNewDisk; + } + + private void setVolumeToPathAndSize(List volumeTOs, Map mapNewDisk, VmwareContext context, + VmwareHypervisorHost hyperHost, String vmName) throws Exception { + for (VolumeObjectTO volumeTO : volumeTOs) { + String oldPath = volumeTO.getPath(); + + final String baseName; + + // if this is managed storage + if (oldPath.startsWith("[-iqn.")) { // ex. [-iqn.2010-01.com.company:3y8w.vol-10.64-0] -iqn.2010-01.com.company:3y8w.vol-10.64-0-000001.vmdk + oldPath = oldPath.split(" ")[0]; // ex. [-iqn.2010-01.com.company:3y8w.vol-10.64-0] + + // remove '[' and ']' + baseName = oldPath.substring(1, oldPath.length() - 1); + } + else { + baseName = extractSnapshotBaseFileName(volumeTO.getPath()); + } + + String newPath = mapNewDisk.get(baseName); + + // get volume's chain size for this VM snapshot; exclude current volume vdisk + DataStoreTO store = volumeTO.getDataStore(); + ManagedObjectReference morDs = getDatastoreAsManagedObjectReference(baseName, hyperHost, store); + long size = getVMSnapshotChainSize(context, hyperHost, baseName + "*.vmdk", morDs, newPath); + + if (volumeTO.getVolumeType()== Volume.Type.ROOT) { + // add memory snapshot size + size += getVMSnapshotChainSize(context, hyperHost, vmName + "*.vmsn", morDs, null); + } + + volumeTO.setSize(size); + volumeTO.setPath(newPath); + } + } + + private ManagedObjectReference getDatastoreAsManagedObjectReference(String baseName, VmwareHypervisorHost hyperHost, DataStoreTO store) throws Exception { + try { + // if baseName equates to a datastore name, this should be managed storage + ManagedObjectReference morDs = hyperHost.findDatastoreByName(baseName); + + if (morDs != null) { + return morDs; + } + } + catch (Exception ex) { + } + + // not managed storage, so use the standard way of getting a ManagedObjectReference for a datastore + return HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, store.getUuid()); + } + @Override public DeleteVMSnapshotAnswer execute(VmwareHostService hostService, DeleteVMSnapshotCommand cmd) { List listVolumeTo = cmd.getVolumeTOs(); VirtualMachineMO vmMo = null; VmwareContext context = hostService.getServiceContext(cmd); - Map mapNewDisk = new HashMap(); String vmName = cmd.getVmName(); String vmSnapshotName = cmd.getTarget().getSnapshotName(); + try { VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd); vmMo = hyperHost.findVmOnHyperHost(vmName); - if(vmMo == null) { + + if (vmMo == null) { vmMo = hyperHost.findVmOnPeerHyperHost(vmName); } + if (vmMo == null) { String msg = "Unable to find VM for RevertToVMSnapshotCommand"; s_logger.debug(msg); + return new DeleteVMSnapshotAnswer(cmd, false, msg); } else { if (vmMo.getSnapshotMor(vmSnapshotName) == null) { @@ -1377,42 +1461,25 @@ public DeleteVMSnapshotAnswer execute(VmwareHostService hostService, DeleteVMSna if (!vmMo.removeSnapshot(vmSnapshotName, false)) { String msg = "delete vm snapshot " + vmSnapshotName + " due to error occured in vmware"; s_logger.error(msg); + return new DeleteVMSnapshotAnswer(cmd, false, msg); } } + s_logger.debug("snapshot: " + vmSnapshotName + " is removed"); + // after removed snapshot, the volumes' paths have been changed for the VM, needs to report new paths to manager - VirtualDisk[] vdisks = vmMo.getAllDiskDevice(); - for (int i = 0; i < vdisks.length; i++) { - @SuppressWarnings("deprecation") - List> vmdkFiles = vmMo.getDiskDatastorePathChain(vdisks[i], false); - for (Pair fileItem : vmdkFiles) { - String vmdkName = fileItem.first().split(" ")[1]; - if (vmdkName.endsWith(".vmdk")) { - vmdkName = vmdkName.substring(0, vmdkName.length() - (".vmdk").length()); - } - String baseName = extractSnapshotBaseFileName(vmdkName); - mapNewDisk.put(baseName, vmdkName); - } - } - for (VolumeObjectTO volumeTo : listVolumeTo) { - String baseName = extractSnapshotBaseFileName(volumeTo.getPath()); - String newPath = mapNewDisk.get(baseName); - DataStoreTO store = volumeTo.getDataStore(); - long size = getVMSnapshotChainSize(context,hyperHost, - baseName + "*.vmdk", store.getUuid(), newPath); - if(volumeTo.getVolumeType()== Volume.Type.ROOT){ - // add memory snapshot size - size = size + getVMSnapshotChainSize(context,hyperHost,cmd.getVmName()+"*.vmsn",store.getUuid(),null); - } - volumeTo.setSize(size); - volumeTo.setPath(newPath); - } + + Map mapNewDisk = getNewDiskMap(vmMo); + + setVolumeToPathAndSize(listVolumeTo, mapNewDisk, context, hyperHost, cmd.getVmName()); + return new DeleteVMSnapshotAnswer(cmd, listVolumeTo); } } catch (Exception e) { String msg = e.getMessage(); s_logger.error("failed to delete vm snapshot " + vmSnapshotName + " of vm " + vmName + " due to " + msg); + return new DeleteVMSnapshotAnswer(cmd, false, msg); } } @@ -1426,16 +1493,18 @@ public RevertToVMSnapshotAnswer execute(VmwareHostService hostService, RevertToV VirtualMachine.State vmState = VirtualMachine.State.Running; VirtualMachineMO vmMo = null; VmwareContext context = hostService.getServiceContext(cmd); - Map mapNewDisk = new HashMap(); + try { VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd); // wait if there are already VM revert task running ManagedObjectReference taskmgr = context.getServiceContent().getTaskManager(); List tasks = (ArrayList)context.getVimClient().getDynamicProperty(taskmgr, "recentTask"); + for (ManagedObjectReference taskMor : tasks) { - TaskInfo info = (TaskInfo) (context.getVimClient().getDynamicProperty(taskMor, "info")); - if(info.getEntityName().equals(cmd.getVmName()) && info.getName().equalsIgnoreCase("RevertToSnapshot_Task")){ + TaskInfo info = (TaskInfo)(context.getVimClient().getDynamicProperty(taskMor, "info")) +; + if (info.getEntityName().equals(cmd.getVmName()) && info.getName().equalsIgnoreCase("RevertToSnapshot_Task")) { s_logger.debug("There is already a VM snapshot task running, wait for it"); context.getVimClient().waitForTask(taskMor); } @@ -1443,60 +1512,49 @@ public RevertToVMSnapshotAnswer execute(VmwareHostService hostService, RevertToV HostMO hostMo = (HostMO) hyperHost; vmMo = hyperHost.findVmOnHyperHost(vmName); - if(vmMo == null) { + + if (vmMo == null) { vmMo = hyperHost.findVmOnPeerHyperHost(vmName); } + if (vmMo == null) { String msg = "Unable to find VM for RevertToVMSnapshotCommand"; s_logger.debug(msg); + return new RevertToVMSnapshotAnswer(cmd, false, msg); } else { if (cmd.isReloadVm()) { vmMo.reload(); } + boolean result = false; + if (snapshotName != null) { ManagedObjectReference morSnapshot = vmMo.getSnapshotMor(snapshotName); + result = hostMo.revertToSnapshot(morSnapshot); } else { return new RevertToVMSnapshotAnswer(cmd, false, "Unable to find the snapshot by name " + snapshotName); } if (result) { - VirtualDisk[] vdisks = vmMo.getAllDiskDevice(); - // build a map - for (int i = 0; i < vdisks.length; i++) { - @SuppressWarnings("deprecation") - List> vmdkFiles = vmMo.getDiskDatastorePathChain( - vdisks[i], false); - for (Pair fileItem : vmdkFiles) { - String vmdkName = fileItem.first().split(" ")[1]; - if (vmdkName.endsWith(".vmdk")) { - vmdkName = vmdkName.substring(0, vmdkName.length() - (".vmdk").length()); - } - String[] s = vmdkName.split("-"); - mapNewDisk.put(s[0], vmdkName); - } - } - String key = null; - for (VolumeObjectTO volumeTo : listVolumeTo) { - String parentUUID = volumeTo.getPath(); - String[] s = parentUUID.split("-"); - key = s[0]; - volumeTo.setPath(mapNewDisk.get(key)); - } + Map mapNewDisk = getNewDiskMap(vmMo); + + setVolumeToPathAndSize(listVolumeTo, mapNewDisk, context, hyperHost, cmd.getVmName()); + if (!snapshotMemory) { vmState = VirtualMachine.State.Stopped; } + return new RevertToVMSnapshotAnswer(cmd, listVolumeTo, vmState); } else { - return new RevertToVMSnapshotAnswer(cmd, false, - "Error while reverting to snapshot due to execute in esxi"); + return new RevertToVMSnapshotAnswer(cmd, false, "Error while reverting to snapshot due to execute in ESXi"); } } } catch (Exception e) { String msg = "revert vm " + vmName + " to snapshot " + snapshotName + " failed due to " + e.getMessage(); s_logger.error(msg); + return new RevertToVMSnapshotAnswer(cmd, false, msg); } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java index 3079998198c9..d52cbd481575 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java @@ -63,6 +63,7 @@ public static VmwareContext create(String vCenterAddress, String vCenterUserName s_logger.debug("initialize VmwareContext. url: " + serviceUrl + ", username: " + vCenterUserName + ", password: " + StringUtils.getMaskedPasswordForDisplay(vCenterPassword)); VmwareClient vimClient = new VmwareClient(vCenterAddress + "-" + s_seq++); + vimClient.setVcenterSessionTimeout(s_vmwareMgr.getVcenterSessionTimeout()); vimClient.connect(serviceUrl, vCenterUserName, vCenterPassword); VmwareContext context = new VmwareContext(vimClient, vCenterAddress); @@ -83,13 +84,14 @@ public static VmwareContext getContext(String vCenterAddress, String vCenterUser if(context == null) { context = create(vCenterAddress, vCenterUserName, vCenterPassword); } else { - if(!context.validate()) { - s_logger.info("Validation of the context faild. dispose and create a new one"); + // Validate current context and verify if vCenter session timeout value of the context matches the timeout value set by Admin + if(!context.validate() || (context.getVimClient().getVcenterSessionTimeout() != s_vmwareMgr.getVcenterSessionTimeout())) { + s_logger.info("Validation of the context failed. dispose and create a new one"); context.close(); context = create(vCenterAddress, vCenterUserName, vCenterPassword); } } - + if(context != null) { context.registerStockObject(VmwareManager.CONTEXT_STOCK_NAME, s_vmwareMgr); 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 03af0da51b1e..9f5cf045866e 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 @@ -42,10 +42,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.agent.api.routing.*; import org.apache.log4j.Logger; import org.apache.log4j.NDC; @@ -64,8 +62,6 @@ import com.vmware.vim25.DynamicProperty; import com.vmware.vim25.GuestInfo; import com.vmware.vim25.HostCapability; -import com.vmware.vim25.HostFirewallInfo; -import com.vmware.vim25.HostFirewallRuleset; import com.vmware.vim25.HostHostBusAdapter; import com.vmware.vim25.HostInternetScsiHba; import com.vmware.vim25.HostInternetScsiHbaAuthenticationProperties; @@ -99,19 +95,14 @@ import com.vmware.vim25.VirtualEthernetCard; import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo; import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo; -import com.vmware.vim25.VirtualLsiLogicController; import com.vmware.vim25.VirtualMachineConfigSpec; -import com.vmware.vim25.VirtualMachineFileInfo; import com.vmware.vim25.VirtualMachineGuestOsIdentifier; import com.vmware.vim25.VirtualMachinePowerState; import com.vmware.vim25.VirtualMachineRelocateSpec; import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator; import com.vmware.vim25.VirtualMachineRuntimeInfo; -import com.vmware.vim25.VirtualSCSISharing; import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec; -import org.apache.cloudstack.engine.orchestration.VolumeOrchestrator; -import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.to.TemplateObjectTO; @@ -161,6 +152,7 @@ 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; @@ -214,6 +206,35 @@ import com.cloud.agent.api.VmStatsEntry; 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.IpAssocAnswer; +import com.cloud.agent.api.routing.IpAssocCommand; +import com.cloud.agent.api.routing.IpAssocVpcCommand; +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.SetFirewallRulesAnswer; +import com.cloud.agent.api.routing.SetFirewallRulesCommand; +import com.cloud.agent.api.routing.SetMonitorServiceCommand; +import com.cloud.agent.api.routing.SetNetworkACLAnswer; +import com.cloud.agent.api.routing.SetNetworkACLCommand; +import com.cloud.agent.api.routing.SetPortForwardingRulesAnswer; +import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; +import com.cloud.agent.api.routing.SetPortForwardingRulesVpcCommand; +import com.cloud.agent.api.routing.SetSourceNatAnswer; +import com.cloud.agent.api.routing.SetSourceNatCommand; +import com.cloud.agent.api.routing.SetStaticNatRulesAnswer; +import com.cloud.agent.api.routing.SetStaticNatRulesCommand; +import com.cloud.agent.api.routing.SetStaticRouteAnswer; +import com.cloud.agent.api.routing.SetStaticRouteCommand; +import com.cloud.agent.api.routing.Site2SiteVpnCfgCommand; +import com.cloud.agent.api.routing.VmDataCommand; +import com.cloud.agent.api.routing.VpnUsersCfgCommand; import com.cloud.agent.api.storage.CopyVolumeAnswer; import com.cloud.agent.api.storage.CopyVolumeCommand; import com.cloud.agent.api.storage.CreateAnswer; @@ -238,8 +259,10 @@ import com.cloud.agent.api.to.StorageFilerTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.api.to.VolumeTO; +import com.cloud.configuration.Config; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.Vlan; +import com.cloud.exception.CloudException; import com.cloud.exception.InternalErrorException; import com.cloud.host.Host.Type; import com.cloud.hypervisor.Hypervisor.HypervisorType; @@ -292,6 +315,7 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; +import com.cloud.utils.Ternary; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExceptionUtil; @@ -301,6 +325,7 @@ 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; @@ -314,9 +339,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa protected final int _shutdown_waitMs = 300000; // wait up to 5 minutes for shutdown - @Inject - protected VolumeOrchestrationService volMgr; - // out an operation protected final int _retry = 24; protected final int _sleep = 10000; @@ -338,10 +360,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa protected int _portsPerDvPortGroup; protected boolean _fullCloneFlag = false; protected boolean _instanceNameFlag = false; + protected boolean _reserveCpu; + protected boolean _reserveMem; - protected boolean _reserveCpu = false; - - protected boolean _reserveMem = false; protected boolean _recycleHungWorker = false; protected DiskControllerType _rootDiskController = DiskControllerType.ide; @@ -358,6 +379,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 +397,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; @@ -576,7 +609,7 @@ public Answer executeRequest(Command cmd) { } } finally { - recycleServiceContext(); + recycleServiceContext(); NDC.pop(); } @@ -773,10 +806,14 @@ protected Answer execute(SetMonitorServiceCommand cmd) { String controlIp = getRouterSshControlIp(cmd); String config = cmd.getConfiguration(); + String disable = cmd.getAccessDetail(NetworkElementCommand.ROUTER_MONITORING_DISABLE); String args = ""; args += " -c " + config; + if (disable != null) { + args = args + " -d "; + } try { VmwareManager mgr = getServiceContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME); @@ -1564,7 +1601,7 @@ protected Answer execute(Site2SiteVpnCfgCommand cmd) { args += "0"; } if (cmd.isPassive()) { - args += " -p "; + args += " -p "; } } else { args += " -D"; @@ -1625,13 +1662,13 @@ private PlugNicAnswer execute(PlugNicCommand cmd) { throw new Exception(msg); } -/* + /* if(!isVMWareToolsInstalled(vmMo)){ String errMsg = "vmware tools is not installed or not running, cannot add nic to vm " + vmName; s_logger.debug(errMsg); return new PlugNicAnswer(cmd, false, "Unable to execute PlugNicCommand due to " + errMsg); } -*/ + */ // TODO need a way to specify the control of NIC device type VirtualEthernetCardType nicDeviceType = VirtualEthernetCardType.E1000; @@ -1706,13 +1743,13 @@ private UnPlugNicAnswer execute(UnPlugNicCommand cmd) { throw new Exception(msg); } -/* + /* if(!isVMWareToolsInstalled(vmMo)){ String errMsg = "vmware tools not installed or not running, cannot remove nic from vm " + vmName; s_logger.debug(errMsg); return new UnPlugNicAnswer(cmd, false, "Unable to execute unPlugNicCommand due to " + errMsg); } -*/ + */ VirtualDevice nic = findVirtualNicDevice(vmMo, cmd.getNic().getMac()); if ( nic == null ) { return new UnPlugNicAnswer(cmd, true, "success"); @@ -1925,10 +1962,10 @@ private void plugPublicNic(VirtualMachineMO vmMo, final String vlanId, final Str * so we assume that it's VLAN for now */ if (VirtualSwitchType.StandardVirtualSwitch == vSwitchType) { - synchronized(vmMo.getRunningHost().getMor().getValue().intern()) { - networkInfo = HypervisorHostHelper.prepareNetwork(_publicTrafficInfo.getVirtualSwitchName(), "cloud.public", - vmMo.getRunningHost(), vlanId, null, null, _ops_timeout, true, BroadcastDomainType.Vlan, null); - } + synchronized(vmMo.getRunningHost().getMor().getValue().intern()) { + networkInfo = HypervisorHostHelper.prepareNetwork(_publicTrafficInfo.getVirtualSwitchName(), "cloud.public", + vmMo.getRunningHost(), vlanId, null, null, _ops_timeout, true, BroadcastDomainType.Vlan, null); + } } else { networkInfo = HypervisorHostHelper.prepareNetwork(_publicTrafficInfo.getVirtualSwitchName(), "cloud.public", vmMo.getRunningHost(), vlanId, null, null, null, _ops_timeout, vSwitchType, _portsPerDvPortGroup, null, false, BroadcastDomainType.Vlan); @@ -2248,7 +2285,7 @@ protected Answer execute(final DnsMasqConfigCommand cmd) { args = args + dhcpTo.getRouterIp()+":"+dhcpTo.getGateway()+":"+dhcpTo.getNetmask()+":"+dhcpTo.getStartIpOfSubnet()+"-"; } VmwareManager mgr = getServiceContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME); - File keyFile = mgr.getSystemVMKeyFile(); + mgr.getSystemVMKeyFile(); try { Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", mgr.getSystemVMKeyFile(), null, "/root/dnsmasq.sh " + args); @@ -2306,7 +2343,7 @@ protected CheckS2SVpnConnectionsAnswer execute(CheckS2SVpnConnectionsCommand cmd } return new CheckS2SVpnConnectionsAnswer(cmd, true, result.second()); } - + protected Answer execute(CheckRouterCommand cmd) { if (s_logger.isDebugEnabled()) { s_logger.debug("Executing resource CheckRouterCommand: " + _gson.toJson(cmd)); @@ -2535,7 +2572,7 @@ private DiskTO[] validateDisks(DiskTO[] disks) { return validatedDisks.toArray(new DiskTO[0]); } - + private static DiskTO getIsoDiskTO(DiskTO[] disks) { for (DiskTO vol : disks) { if (vol.getType() == Volume.Type.ISO) { @@ -2559,7 +2596,7 @@ protected ScaleVmAnswer execute(ScaleVmCommand cmd) { 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"); } @@ -2596,20 +2633,20 @@ protected StartAnswer execute(StartCommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource StartCommand: " + _gson.toJson(cmd)); } - + VirtualMachineTO vmSpec = cmd.getVirtualMachine(); - + Pair names = composeVmNames(vmSpec); String vmInternalCSName = names.first(); String vmNameOnVcenter = names.second(); - + // Thus, vmInternalCSName always holds i-x-y, the cloudstack generated internal VM name. State state = State.Stopped; VmwareContext context = getServiceContext(); 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); } @@ -2618,37 +2655,38 @@ protected StartAnswer execute(StartCommand cmd) { DiskTO[] disks = validateDisks(vmSpec.getDisks()); assert (disks.length > 0); NicTO[] nics = vmSpec.getNics(); + Map iqnToPath = new HashMap(); - HashMap> dataStoresDetails = inferDatastoreDetailsFromDiskInfo(hyperHost, context, disks); + HashMap> dataStoresDetails = inferDatastoreDetailsFromDiskInfo(hyperHost, context, disks, iqnToPath, cmd); if ((dataStoresDetails == null) || (dataStoresDetails.isEmpty()) ){ String msg = "Unable to locate datastore details of the volumes to be attached"; s_logger.error(msg); throw new Exception(msg); } - + DatastoreMO dsRootVolumeIsOn = getDatastoreThatRootDiskIsOn(dataStoresDetails, disks); if(dsRootVolumeIsOn == null) { String msg = "Unable to locate datastore details of root volume"; s_logger.error(msg); throw new Exception(msg); } - + DatacenterMO dcMo = new DatacenterMO(hyperHost.getContext(), hyperHost.getHyperHostDatacenter()); VirtualMachineDiskInfoBuilder diskInfoBuilder = null; VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName); 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 diskInfoBuilder = vmMo.getDiskInfoBuilder(); hasSnapshot = vmMo.hasSnapshot(); if(!hasSnapshot) - vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); + vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); else - vmMo.tearDownDevices(new Class[] { VirtualEthernetCard.class }); + vmMo.tearDownDevices(new Class[] { VirtualEthernetCard.class }); vmMo.ensureScsiDeviceController(); } else { ManagedObjectReference morDc = hyperHost.getHyperHostDatacenter(); @@ -2662,22 +2700,22 @@ protected StartAnswer execute(StartCommand cmd) { takeVmFromOtherHyperHost(hyperHost, vmInternalCSName); - if (getVmState(vmMo) != State.Stopped) + if (getVmPowerState(vmMo) != PowerState.PowerOff) vmMo.safePowerOff(_shutdown_waitMs); - + diskInfoBuilder = vmMo.getDiskInfoBuilder(); hasSnapshot = vmMo.hasSnapshot(); if(!hasSnapshot) - vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); + vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); else - vmMo.tearDownDevices(new Class[] { VirtualEthernetCard.class }); + vmMo.tearDownDevices(new Class[] { VirtualEthernetCard.class }); vmMo.ensureScsiDeviceController(); } else { - int ramMb = (int) (vmSpec.getMinRam() / (1024 * 1024)); Pair rootDiskDataStoreDetails = null; for (DiskTO vol : disks) { if (vol.getType() == Volume.Type.ROOT) { DataStoreTO primaryStore = vol.getData().getDataStore(); + /** @todo Mike T. update this in 4.4 to support root disks on managed storage */ rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); } } @@ -2685,13 +2723,13 @@ protected StartAnswer execute(StartCommand cmd) { assert (vmSpec.getMinSpeed() != null) && (rootDiskDataStoreDetails != null); if(rootDiskDataStoreDetails.second().folderExists(String.format("[%s]", rootDiskDataStoreDetails.second().getName()), vmNameOnVcenter)) { - s_logger.warn("WARN!!! Folder already exists on datastore for new VM " + vmNameOnVcenter + ", erase it"); - rootDiskDataStoreDetails.second().deleteFile(String.format("[%s] %s/", rootDiskDataStoreDetails.second().getName(), - vmNameOnVcenter), dcMo.getMor(), false); + s_logger.warn("WARN!!! Folder already exists on datastore for new VM " + vmNameOnVcenter + ", erase it"); + rootDiskDataStoreDetails.second().deleteFile(String.format("[%s] %s/", rootDiskDataStoreDetails.second().getName(), + vmNameOnVcenter), dcMo.getMor(), false); } - + if (!hyperHost.createBlankVm(vmNameOnVcenter, vmInternalCSName, vmSpec.getCpus(), vmSpec.getMaxSpeed().intValue(), - vmSpec.getMinSpeed(), vmSpec.getLimitCpuUse(),(int)(vmSpec.getMaxRam()/(1024*1024)), ramMb, + getReservedCpuMHZ(vmSpec), vmSpec.getLimitCpuUse(),(int)(vmSpec.getMaxRam()/(1024*1024)), getReservedMemoryMb(vmSpec), translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs()).value(), rootDiskDataStoreDetails.first(), false)) { throw new Exception("Failed to create VM. vmName: " + vmInternalCSName); } @@ -2702,27 +2740,26 @@ protected StartAnswer execute(StartCommand cmd) { throw new Exception("Failed to find the newly create or relocated VM. vmName: " + vmInternalCSName); } } - + int totalChangeDevices = disks.length + nics.length; - + DiskTO volIso = null; if (vmSpec.getType() != VirtualMachine.Type.User) { // system VM needs a patch ISO totalChangeDevices++; } else { - volIso = getIsoDiskTO(disks); + volIso = getIsoDiskTO(disks); if (volIso == null) totalChangeDevices++; } VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); - int ramMb = (int) (vmSpec.getMinRam() / (1024 * 1024)); String guestOsId = translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs()).value(); - + VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(), - vmSpec.getMinSpeed(),(int) (vmSpec.getMaxRam()/(1024*1024)), ramMb, + getReservedCpuMHZ(vmSpec),(int) (vmSpec.getMaxRam()/(1024*1024)), getReservedMemoryMb(vmSpec), guestOsId, vmSpec.getLimitCpuUse()); - + // Check for hotadd settings vmConfigSpec.setMemoryHotAddEnabled(vmMo.isMemoryHotAddSupported(guestOsId)); vmConfigSpec.setCpuHotAddEnabled(vmMo.isCpuHotAddSupported(guestOsId)); @@ -2740,7 +2777,7 @@ protected StartAnswer execute(StartCommand cmd) { // // Setup ISO device // - + // prepare systemvm patch ISO if (vmSpec.getType() != VirtualMachine.Type.User) { // attach ISO (for patching of system VM) @@ -2818,52 +2855,64 @@ protected StartAnswer execute(StartCommand cmd) { } } } - + i++; - + // // Setup ROOT/DATA disk devices // DiskTO[] sortedDisks = sortVolumesByDeviceId(disks); for (DiskTO vol : sortedDisks) { if (vol.getType() == Volume.Type.ISO) - continue; - + continue; + VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDisk(diskInfoBuilder, vol); controllerKey = getDiskController(matchingExistingDisk, vol, vmSpec, ideControllerKey, scsiControllerKey); if(!hasSnapshot) { deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); - - VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); - DataStoreTO primaryStore = volumeTO.getDataStore(); - Pair volumeDsDetails = dataStoresDetails.get(primaryStore.getUuid()); - assert (volumeDsDetails != null); - - String[] diskChain = syncDiskChain(dcMo, vmMo, vmSpec, - vol, matchingExistingDisk, - dataStoresDetails); - if(controllerKey == scsiControllerKey && VmwareHelper.isReservedScsiDeviceNumber(scsiUnitNumber)) - scsiUnitNumber++; - VirtualDevice device = VmwareHelper.prepareDiskDevice(vmMo, null, controllerKey, - diskChain, - volumeDsDetails.first(), - (controllerKey == ideControllerKey) ? ideUnitNumber++ : scsiUnitNumber++, i + 1); - - deviceConfigSpecArray[i].setDevice(device); - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); - - if(s_logger.isDebugEnabled()) - s_logger.debug("Prepare volume at new device " + _gson.toJson(device)); - - i++; + + VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); + DataStoreTO primaryStore = volumeTO.getDataStore(); + Map details = vol.getDetails(); + boolean managed = false; + String iScsiName = null; + + if (details != null) { + managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + iScsiName = details.get(DiskTO.IQN); + } + + // if the storage is managed, iScsiName should not be null + String datastoreName = managed ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid(); + Pair volumeDsDetails = dataStoresDetails.get(datastoreName); + + assert (volumeDsDetails != null); + + String[] diskChain = syncDiskChain(dcMo, vmMo, vmSpec, + vol, matchingExistingDisk, + dataStoresDetails); + if(controllerKey == scsiControllerKey && VmwareHelper.isReservedScsiDeviceNumber(scsiUnitNumber)) + scsiUnitNumber++; + VirtualDevice device = VmwareHelper.prepareDiskDevice(vmMo, null, controllerKey, + diskChain, + volumeDsDetails.first(), + (controllerKey == ideControllerKey) ? ideUnitNumber++ : scsiUnitNumber++, i + 1); + + deviceConfigSpecArray[i].setDevice(device); + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); + + if(s_logger.isDebugEnabled()) + s_logger.debug("Prepare volume at new device " + _gson.toJson(device)); + + i++; } else { - if(controllerKey == scsiControllerKey && VmwareHelper.isReservedScsiDeviceNumber(scsiUnitNumber)) - scsiUnitNumber++; - if(controllerKey == ideControllerKey) - ideUnitNumber++; - else - scsiUnitNumber++; + if(controllerKey == scsiControllerKey && VmwareHelper.isReservedScsiDeviceNumber(scsiUnitNumber)) + scsiUnitNumber++; + if(controllerKey == ideControllerKey) + ideUnitNumber++; + else + scsiUnitNumber++; } } @@ -2876,7 +2925,7 @@ protected StartAnswer execute(StartCommand cmd) { VirtualEthernetCardType nicDeviceType = VirtualEthernetCardType.valueOf(vmSpec.getDetails().get(VmDetailConstants.NIC_ADAPTER)); if(s_logger.isDebugEnabled()) s_logger.debug("VM " + vmInternalCSName + " will be started with NIC device type: " + nicDeviceType); - + for (NicTO nicTo : sortNicsByDeviceId(nics)) { s_logger.info("Prepare NIC device based on NicTO: " + _gson.toJson(nicTo)); @@ -2912,12 +2961,12 @@ protected StartAnswer execute(StartCommand cmd) { } for(int j = 0; j < i; j++) - vmConfigSpec.getDeviceChange().add(deviceConfigSpecArray[j]); + vmConfigSpec.getDeviceChange().add(deviceConfigSpecArray[j]); // // Setup VM options // - + // pass boot arguments through machine.id & perform customized options to VMX ArrayList extraOptions = new ArrayList(); configBasicExtraOption(extraOptions, vmSpec); @@ -2929,13 +2978,13 @@ protected StartAnswer execute(StartCommand cmd) { if(vmSpec.getDetails() != null) keyboardLayout = vmSpec.getDetails().get(VmDetailConstants.KEYBOARD); vmConfigSpec.getExtraConfig().addAll( - Arrays.asList( - configureVnc( - extraOptions.toArray(new OptionValue[0]), - hyperHost, vmInternalCSName, vmSpec.getVncPassword(), keyboardLayout - ) - ) - ); + Arrays.asList( + configureVnc( + extraOptions.toArray(new OptionValue[0]), + hyperHost, vmInternalCSName, vmSpec.getVncPassword(), keyboardLayout + ) + ) + ); // // Configure VM @@ -2947,11 +2996,11 @@ protected StartAnswer execute(StartCommand cmd) { // // Post Configuration // - + vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_NIC_MASK, String.valueOf(nicMask)); postNvpConfigBeforeStart(vmMo, vmSpec); postDiskConfigBeforeStart(vmMo, vmSpec, sortedDisks, ideControllerKey, scsiControllerKey); - + // // Power-on VM // @@ -2960,7 +3009,12 @@ protected StartAnswer execute(StartCommand cmd) { } state = State.Running; - return new StartAnswer(cmd); + + StartAnswer startAnswer = new StartAnswer(cmd); + + startAnswer.setIqnToPath(iqnToPath); + + return startAnswer; } catch (Throwable e) { if (e instanceof RemoteException) { s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context"); @@ -2980,37 +3034,78 @@ protected StartAnswer execute(StartCommand cmd) { } } } - + + @Override + public ManagedObjectReference prepareManagedStorage(VmwareHypervisorHost hyperHost, String iScsiName, + String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret, + String chapTargetUsername, String chapTargetSecret, long size, Command cmd) throws Exception { + ManagedObjectReference morDs = getVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iScsiName), + storageHost, storagePort, VmwareResource.trimIqn(iScsiName), chapInitiatorUsername, chapInitiatorSecret, + chapTargetUsername, chapTargetSecret); + + DatastoreMO dsMo = new DatastoreMO(getServiceContext(null), morDs); + + String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName()); + + if (!dsMo.fileExists(volumeDatastorePath)) { + createVmdk(cmd, dsMo, volumeDatastorePath, size); + } + + return morDs; + } + + int getReservedMemoryMb(VirtualMachineTO vmSpec) { + if (vmSpec.getDetails().get(Config.VmwareReserveMem.key()).equalsIgnoreCase("true")) { + return (int) (vmSpec.getMinRam() / (1024 * 1024)); + } + return 0; + } + + int getReservedCpuMHZ(VirtualMachineTO vmSpec) { + if (vmSpec.getDetails().get(Config.VmwareReserveCpu.key()).equalsIgnoreCase("true")) { + return vmSpec.getMinSpeed(); + } + return 0; + } + // return the finalized disk chain for startup, from top to bottom - private String[] syncDiskChain(DatacenterMO dcMo, VirtualMachineMO vmMo, VirtualMachineTO vmSpec, - DiskTO vol, VirtualMachineDiskInfo diskInfo, - HashMap> dataStoresDetails - ) throws Exception { - + private String[] syncDiskChain(DatacenterMO dcMo, VirtualMachineMO vmMo, VirtualMachineTO vmSpec, + DiskTO vol, VirtualMachineDiskInfo diskInfo, + HashMap> dataStoresDetails + ) throws Exception { + VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); DataStoreTO primaryStore = volumeTO.getDataStore(); Map details = vol.getDetails(); - boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + boolean isManaged = false; + String iScsiName = null; - Pair volumeDsDetails = dataStoresDetails.get(primaryStore.getUuid()); + if (details != null) { + isManaged = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + iScsiName = details.get(DiskTO.IQN); + } + + // if the storage is managed, iScsiName should not be null + String datastoreName = isManaged ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid(); + Pair volumeDsDetails = dataStoresDetails.get(datastoreName); if(volumeDsDetails == null) - throw new Exception("Primary datastore " + primaryStore.getUuid() + " is not mounted on host."); + throw new Exception("Primary datastore " + primaryStore.getUuid() + " is not mounted on host."); DatastoreMO dsMo = volumeDsDetails.second(); // we will honor vCenter's meta if it exists - if(diskInfo != null) { - // to deal with run-time upgrade to maintain the new datastore folder structure - String disks[] = diskInfo.getDiskChain(); - for(int i = 0; i < disks.length; i++) { - DatastoreFile file = new DatastoreFile(disks[i]); - if (!isManaged && file.getDir() != null && file.getDir().isEmpty()) { - s_logger.info("Perform run-time datastore folder upgrade. sync " + disks[i] + " to VM folder"); - disks[i] = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder( - dcMo, vmMo.getName(), dsMo, file.getFileBaseName()); - } - } - return disks; - } + if(diskInfo != null) { + // to deal with run-time upgrade to maintain the new datastore folder structure + String disks[] = diskInfo.getDiskChain(); + for(int i = 0; i < disks.length; i++) { + DatastoreFile file = new DatastoreFile(disks[i]); + if (!isManaged && file.getDir() != null && file.getDir().isEmpty()) { + s_logger.info("Perform run-time datastore folder upgrade. sync " + disks[i] + " to VM folder"); + disks[i] = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder( + dcMo, vmMo.getName(), dsMo, file.getFileBaseName()); + } + } + return disks; + } final String datastoreDiskPath; @@ -3019,14 +3114,14 @@ private String[] syncDiskChain(DatacenterMO dcMo, VirtualMachineMO vmMo, Virtual } else { datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder( - dcMo, vmMo.getName(), dsMo, volumeTO.getPath()); + dcMo, vmMo.getName(), dsMo, volumeTO.getPath()); } if(!dsMo.fileExists(datastoreDiskPath)) { - s_logger.warn("Volume " + volumeTO.getId() + " does not seem to exist on datastore, out of sync? path: " + datastoreDiskPath); - } - - return new String[] { datastoreDiskPath }; + s_logger.warn("Volume " + volumeTO.getId() + " does not seem to exist on datastore, out of sync? path: " + datastoreDiskPath); + } + + return new String[] { datastoreDiskPath }; } // Pair @@ -3042,19 +3137,19 @@ private Pair composeVmNames(VirtualMachineTO vmSpec) { } else { vmNameOnVcenter = vmInternalCSName = vmSpec.getName(); } - + return new Pair(vmInternalCSName, vmNameOnVcenter); } - - private static void configNestedHVSupport(VirtualMachineMO vmMo, - VirtualMachineTO vmSpec, VirtualMachineConfigSpec vmConfigSpec) throws Exception { - - VmwareContext context = vmMo.getContext(); + + private static void configNestedHVSupport(VirtualMachineMO vmMo, + VirtualMachineTO vmSpec, VirtualMachineConfigSpec vmConfigSpec) throws Exception { + + VmwareContext context = vmMo.getContext(); if ("true".equals(vmSpec.getDetails().get(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG))) { - if(s_logger.isDebugEnabled()) - s_logger.debug("Nested Virtualization enabled in configuration, checking hypervisor capability"); - - ManagedObjectReference hostMor = vmMo.getRunningHost().getMor(); + if(s_logger.isDebugEnabled()) + s_logger.debug("Nested Virtualization enabled in configuration, checking hypervisor capability"); + + ManagedObjectReference hostMor = vmMo.getRunningHost().getMor(); ManagedObjectReference computeMor = context.getVimClient().getMoRefProp(hostMor, "parent"); ManagedObjectReference environmentBrowser = context.getVimClient().getMoRefProp(computeMor, "environmentBrowser"); HostCapability hostCapability = context.getService().queryTargetCapabilities(environmentBrowser, hostMor); @@ -3072,7 +3167,7 @@ private static void configNestedHVSupport(VirtualMachineMO vmMo, } } } - + private static void configBasicExtraOption(List extraOptions, VirtualMachineTO vmSpec) { OptionValue newVal = new OptionValue(); newVal.setKey("machine.id"); @@ -3084,13 +3179,13 @@ private static void configBasicExtraOption(List extraOptions, Virtu newVal.setValue("true"); extraOptions.add(newVal); } - + private static void configNvpExtraOption(List extraOptions, VirtualMachineTO vmSpec) { /** * Extra Config : nvp.vm-uuid = uuid * - Required for Nicira NVP integration */ - OptionValue newVal = new OptionValue(); + OptionValue newVal = new OptionValue(); newVal.setKey("nvp.vm-uuid"); newVal.setValue(vmSpec.getUuid()); extraOptions.add(newVal); @@ -3112,15 +3207,15 @@ private static void configNvpExtraOption(List extraOptions, Virtual } private static void configCustomExtraOption(List extraOptions, VirtualMachineTO vmSpec) { - // we no longer to validation anymore + // we no longer to validation anymore for(Map.Entry entry : vmSpec.getDetails().entrySet()) { - OptionValue newVal = new OptionValue(); + OptionValue newVal = new OptionValue(); newVal.setKey(entry.getKey()); newVal.setValue(entry.getValue()); extraOptions.add(newVal); } } - + private static void postNvpConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec) throws Exception { /** * We need to configure the port on the DV switch after the host is @@ -3232,130 +3327,130 @@ private static void postNvpConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachi nicIndex++; } } - + private VirtualMachineDiskInfo getMatchingExistingDisk(VirtualMachineDiskInfoBuilder diskInfoBuilder, DiskTO vol) { - if(diskInfoBuilder != null) { - VolumeObjectTO volume = (VolumeObjectTO)vol.getData(); + if(diskInfoBuilder != null) { + VolumeObjectTO volume = (VolumeObjectTO)vol.getData(); Map details = vol.getDetails(); boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(isManaged ? new DatastoreFile(volume.getPath()).getFileBaseName() : volume.getPath()); - if(diskInfo != null) { - s_logger.info("Found existing disk info from volume path: " + volume.getPath()); - return diskInfo; - } else { - String chainInfo = volume.getChainInfo(); - if(chainInfo != null) { - VirtualMachineDiskInfo infoInChain = _gson.fromJson(chainInfo, VirtualMachineDiskInfo.class); - if(infoInChain != null) { - String[] disks = infoInChain.getDiskChain(); - if(disks.length > 0) { - for(String diskPath : disks) { - DatastoreFile file = new DatastoreFile(diskPath); - diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(file.getFileBaseName()); - if(diskInfo != null) { - s_logger.info("Found existing disk from chain info: " + diskPath); - return diskInfo; - } - } - } - - if(diskInfo == null) { - diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(infoInChain.getDiskDeviceBusName()); - if(diskInfo != null) { - s_logger.info("Found existing disk from from chain device bus information: " + infoInChain.getDiskDeviceBusName()); - return diskInfo; - } - } - } - } - } - } - - return null; - } - - private int getDiskController(VirtualMachineDiskInfo matchingExistingDisk, DiskTO vol, - VirtualMachineTO vmSpec, int ideControllerKey, int scsiControllerKey) { - - int controllerKey; - if(matchingExistingDisk != null) { - s_logger.info("Chose disk controller based on existing information: " + matchingExistingDisk.getDiskDeviceBusName()); - if(matchingExistingDisk.getDiskDeviceBusName().startsWith("ide")) - return ideControllerKey; - else - return scsiControllerKey; - } - + VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(isManaged ? new DatastoreFile(volume.getPath()).getFileBaseName() : volume.getPath()); + if(diskInfo != null) { + s_logger.info("Found existing disk info from volume path: " + volume.getPath()); + return diskInfo; + } else { + String chainInfo = volume.getChainInfo(); + if(chainInfo != null) { + VirtualMachineDiskInfo infoInChain = _gson.fromJson(chainInfo, VirtualMachineDiskInfo.class); + if(infoInChain != null) { + String[] disks = infoInChain.getDiskChain(); + if(disks.length > 0) { + for(String diskPath : disks) { + DatastoreFile file = new DatastoreFile(diskPath); + diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(file.getFileBaseName()); + if(diskInfo != null) { + s_logger.info("Found existing disk from chain info: " + diskPath); + return diskInfo; + } + } + } + + if(diskInfo == null) { + diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(infoInChain.getDiskDeviceBusName()); + if(diskInfo != null) { + s_logger.info("Found existing disk from from chain device bus information: " + infoInChain.getDiskDeviceBusName()); + return diskInfo; + } + } + } + } + } + } + + return null; + } + + private int getDiskController(VirtualMachineDiskInfo matchingExistingDisk, DiskTO vol, + VirtualMachineTO vmSpec, int ideControllerKey, int scsiControllerKey) { + + int controllerKey; + if(matchingExistingDisk != null) { + s_logger.info("Chose disk controller based on existing information: " + matchingExistingDisk.getDiskDeviceBusName()); + if(matchingExistingDisk.getDiskDeviceBusName().startsWith("ide")) + return ideControllerKey; + else + return scsiControllerKey; + } + if(vol.getType() == Volume.Type.ROOT) { - Map vmDetails = vmSpec.getDetails(); + Map vmDetails = vmSpec.getDetails(); if(vmDetails != null && vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER) != null) { if(vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER).equalsIgnoreCase("scsi")) { - s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi, based on root disk controller settings: " - + vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER)); + s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi, based on root disk controller settings: " + + vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER)); controllerKey = scsiControllerKey; } else { - s_logger.info("Chose disk controller for vol " + vol.getType() + " -> ide, based on root disk controller settings: " - + vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER)); + s_logger.info("Chose disk controller for vol " + vol.getType() + " -> ide, based on root disk controller settings: " + + vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER)); controllerKey = ideControllerKey; } } else { - s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi. due to null root disk controller setting"); + s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi. due to null root disk controller setting"); controllerKey = scsiControllerKey; } - + } else { // DATA volume always use SCSI device - s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi"); + s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi"); controllerKey = scsiControllerKey; } - + return controllerKey; } - + private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec, DiskTO[] sortedDisks, - int ideControllerKey, int scsiControllerKey) throws Exception { + int ideControllerKey, int scsiControllerKey) throws Exception { + + VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); - VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); - - for(DiskTO vol: sortedDisks) { + for(DiskTO vol: sortedDisks) { if (vol.getType() == Volume.Type.ISO) continue; - - VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); + + VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); VirtualMachineDiskInfo diskInfo = getMatchingExistingDisk(diskInfoBuilder, vol); - assert(diskInfo != null); - - String[] diskChain = diskInfo.getDiskChain(); - assert(diskChain.length > 0); - - DatastoreFile file = new DatastoreFile(diskChain[0]); - if(!file.getFileBaseName().equalsIgnoreCase(volumeTO.getPath())) { - if(s_logger.isInfoEnabled()) - s_logger.info("Detected disk-chain top file change on volume: " + volumeTO.getId() + " " - + volumeTO.getPath() + " -> " + file.getFileBaseName()); - } - - VolumeObjectTO volInSpec = getVolumeInSpec(vmSpec, volumeTO); - volInSpec.setPath(file.getFileBaseName()); - volInSpec.setChainInfo(_gson.toJson(diskInfo)); - } - } - + assert(diskInfo != null); + + String[] diskChain = diskInfo.getDiskChain(); + assert(diskChain.length > 0); + + DatastoreFile file = new DatastoreFile(diskChain[0]); + if(!file.getFileBaseName().equalsIgnoreCase(volumeTO.getPath())) { + if(s_logger.isInfoEnabled()) + s_logger.info("Detected disk-chain top file change on volume: " + volumeTO.getId() + " " + + volumeTO.getPath() + " -> " + file.getFileBaseName()); + } + + VolumeObjectTO volInSpec = getVolumeInSpec(vmSpec, volumeTO); + volInSpec.setPath(file.getFileBaseName()); + volInSpec.setChainInfo(_gson.toJson(diskInfo)); + } + } + private static VolumeObjectTO getVolumeInSpec(VirtualMachineTO vmSpec, VolumeObjectTO srcVol) { - for(DiskTO disk : vmSpec.getDisks()) { - VolumeObjectTO vol = (VolumeObjectTO)disk.getData(); - if(vol.getId() == srcVol.getId()) - return vol; - } - - return null; - } - + for(DiskTO disk : vmSpec.getDisks()) { + VolumeObjectTO vol = (VolumeObjectTO)disk.getData(); + if(vol.getId() == srcVol.getId()) + return vol; + } + + return null; + } + @Deprecated private Map validateVmDetails(Map vmDetails) { @@ -3417,7 +3512,7 @@ private static DiskTO[] sortVolumesByDeviceId(DiskTO[] volumes) { public int compare(DiskTO arg0, DiskTO arg1) { if (arg0.getDiskSeq() < arg1.getDiskSeq()) { return -1; - } else if (arg0.getDiskSeq() == arg1.getDiskSeq()) { + } else if (arg0.getDiskSeq().equals(arg1.getDiskSeq())) { return 0; } @@ -3428,52 +3523,105 @@ public int compare(DiskTO arg0, DiskTO arg1) { return listForSort.toArray(new DiskTO[0]); } - private HashMap> inferDatastoreDetailsFromDiskInfo(VmwareHypervisorHost hyperHost, VmwareContext context, DiskTO[] disks) throws Exception { - HashMap> poolMors = new HashMap>(); + private HashMap> inferDatastoreDetailsFromDiskInfo(VmwareHypervisorHost hyperHost, VmwareContext context, + DiskTO[] disks, Map iqnToPath, Command cmd) throws Exception { + HashMap> mapIdToMors = new HashMap>(); assert (hyperHost != null) && (context != null); + for (DiskTO vol : disks) { if (vol.getType() != Volume.Type.ISO) { VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); DataStoreTO primaryStore = volumeTO.getDataStore(); String poolUuid = primaryStore.getUuid(); - if(poolMors.get(poolUuid) == null) { + + if (mapIdToMors.get(poolUuid) == null) { boolean isManaged = false; - String iScsiName = null; Map details = vol.getDetails(); if (details != null) { isManaged = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - iScsiName = details.get(DiskTO.IQN); } - ManagedObjectReference morDataStore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, isManaged ? VmwareResource.getDatastoreName(iScsiName) : poolUuid); - if (morDataStore == null) { - String msg = "Failed to get the mounted datastore for the volume's pool " + poolUuid; - s_logger.error(msg); - throw new Exception(msg); + if (isManaged) { + String iScsiName = details.get(DiskTO.IQN); // details should not be null for managed storage (it may or may not be null for non-managed storage) + String datastoreName = VmwareResource.getDatastoreName(iScsiName); + ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, datastoreName); + + // if the datastore is not present, we need to discover the iSCSI device that will support it, + // create the datastore, and create a VMDK file in the datastore + if (morDatastore == null) { + morDatastore = prepareManagedStorage(hyperHost, iScsiName, + details.get(DiskTO.STORAGE_HOST), Integer.parseInt(details.get(DiskTO.STORAGE_PORT)), + details.get(DiskTO.CHAP_INITIATOR_USERNAME), details.get(DiskTO.CHAP_INITIATOR_SECRET), + details.get(DiskTO.CHAP_TARGET_USERNAME), details.get(DiskTO.CHAP_TARGET_SECRET), + Long.parseLong(details.get(DiskTO.VOLUME_SIZE)), cmd); + + DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDatastore); + String datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk"); + + iqnToPath.put(iScsiName, datastoreVolumePath); + + volumeTO.setPath(datastoreVolumePath); + vol.setPath(datastoreVolumePath); + } + + mapIdToMors.put(datastoreName, new Pair(morDatastore, new DatastoreMO(context, morDatastore))); + } + else { + ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolUuid); + + if (morDatastore == null) { + String msg = "Failed to get the mounted datastore for the volume's pool " + poolUuid; + + s_logger.error(msg); + + throw new Exception(msg); + } + + mapIdToMors.put(poolUuid, new Pair(morDatastore, new DatastoreMO(context, morDatastore))); } - poolMors.put(poolUuid, new Pair (morDataStore, new DatastoreMO(context, morDataStore))); } } } - return poolMors; + + return mapIdToMors; } - private DatastoreMO getDatastoreThatRootDiskIsOn(HashMap> dataStoresDetails, - DiskTO disks[]) { + private DatastoreMO getDatastoreThatRootDiskIsOn(HashMap> dataStoresDetails, DiskTO disks[]) { + Pair rootDiskDataStoreDetails = null; - Pair rootDiskDataStoreDetails = null; for (DiskTO vol : disks) { if (vol.getType() == Volume.Type.ROOT) { - DataStoreTO primaryStore = vol.getData().getDataStore(); - rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); + Map details = vol.getDetails(); + boolean managed = false; + + if (details != null) { + managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + } + + if (managed) { + String datastoreName = VmwareResource.getDatastoreName(details.get(DiskTO.IQN)); + + rootDiskDataStoreDetails = dataStoresDetails.get(datastoreName); + + break; + } + else { + DataStoreTO primaryStore = vol.getData().getDataStore(); + + rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); + + break; + } } } - - if(rootDiskDataStoreDetails != null) - return rootDiskDataStoreDetails.second(); - return null; + + if (rootDiskDataStoreDetails != null) { + return rootDiskDataStoreDetails.second(); + } + + return null; } private String getPvlanInfo(NicTO nicTo) { @@ -3511,22 +3659,12 @@ else if (nicTo.getBroadcastType() == BroadcastDomainType.Vlan || nicTo.getBroadc } private Pair prepareNetworkFromNicInfo(HostMO hostMo, NicTO nicTo, boolean configureVServiceInNexus, VirtualMachine.Type vmType) throws Exception { - Pair switchName; - TrafficType trafficType; - VirtualSwitchType switchType; - - switchName = getTargetSwitch(nicTo); - trafficType = nicTo.getType(); - // Get switch type from resource property which is dictated by cluster property - // If a virtual switch type is specified while adding cluster that will be used. - // Else If virtual switch type is specified in physical traffic label that will be used - // Else use standard vSwitch - switchType = VirtualSwitchType.StandardVirtualSwitch; - if (trafficType == TrafficType.Guest && _guestTrafficInfo != null) { - switchType = _guestTrafficInfo.getVirtualSwitchType(); - } else if (trafficType == TrafficType.Public && _publicTrafficInfo != null) { - switchType = _publicTrafficInfo.getVirtualSwitchType(); - } + + Ternary switchDetails = getTargetSwitch(nicTo); + nicTo.getType(); + VirtualSwitchType switchType = VirtualSwitchType.getType(switchDetails.second()); + String switchName = switchDetails.first(); + String vlanToken = switchDetails.third(); String namePrefix = getNetworkNamePrefix(nicTo); Pair networkInfo = null; @@ -3534,14 +3672,14 @@ private Pair prepareNetworkFromNicInfo(HostMO ho s_logger.info("Prepare network on " + switchType + " " + switchName + " with name prefix: " + namePrefix); if (VirtualSwitchType.StandardVirtualSwitch == switchType) { - synchronized(hostMo.getMor().getValue().intern()) { - networkInfo = HypervisorHostHelper.prepareNetwork(switchName.first(), namePrefix, - hostMo, getVlanInfo(nicTo, switchName.second()), nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _ops_timeout, - !namePrefix.startsWith("cloud.private"), nicTo.getBroadcastType(), nicTo.getUuid()); - } + synchronized(hostMo.getMor().getValue().intern()) { + networkInfo = HypervisorHostHelper.prepareNetwork(switchName, namePrefix, hostMo, getVlanInfo(nicTo, vlanToken), nicTo.getNetworkRateMbps(), + nicTo.getNetworkRateMulticastMbps(), _ops_timeout, + !namePrefix.startsWith("cloud.private"), nicTo.getBroadcastType(), nicTo.getUuid()); + } } else { - String vlanId = getVlanInfo(nicTo, switchName.second()); + String vlanId = getVlanInfo(nicTo, vlanToken); String svlanId = null; boolean pvlannetwork = (getPvlanInfo(nicTo) == null)?false:true; if (vmType != null && vmType.equals(VirtualMachine.Type.DomainRouter) && pvlannetwork) { @@ -3551,7 +3689,7 @@ hostMo, getVlanInfo(nicTo, switchName.second()), nicTo.getNetworkRateMbps(), nic // plumb this network to the isolated vlan. svlanId = getPvlanInfo(nicTo); } - networkInfo = HypervisorHostHelper.prepareNetwork(switchName.first(), namePrefix, hostMo, vlanId, svlanId, + networkInfo = HypervisorHostHelper.prepareNetwork(switchName, namePrefix, hostMo, vlanId, svlanId, nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _ops_timeout, switchType, _portsPerDvPortGroup, nicTo.getGateway(), configureVServiceInNexus, nicTo.getBroadcastType()); } @@ -3559,39 +3697,57 @@ hostMo, getVlanInfo(nicTo, switchName.second()), nicTo.getNetworkRateMbps(), nic return networkInfo; } - // return Pair - private Pair getTargetSwitch(NicTO nicTo) throws Exception { - if (nicTo.getType() == Networks.TrafficType.Guest) { - return new Pair(_guestTrafficInfo.getVirtualSwitchName(), Vlan.UNTAGGED); - } else if (nicTo.getType() == Networks.TrafficType.Public) { - return new Pair(_publicTrafficInfo.getVirtualSwitchName(), Vlan.UNTAGGED); + // return Ternary + private Ternary getTargetSwitch(NicTO nicTo) throws CloudException { + TrafficType[] supportedTrafficTypes = + new TrafficType[] { + TrafficType.Guest, + TrafficType.Public, + TrafficType.Control, + TrafficType.Management, + TrafficType.Storage + }; + + TrafficType trafficType = nicTo.getType(); + if (!Arrays.asList(supportedTrafficTypes).contains(trafficType)) { + throw new CloudException("Traffic type " + trafficType.toString() + " for nic " + nicTo.toString() + " is not supported."); } + String switchName = null; + VirtualSwitchType switchType = VirtualSwitchType.StandardVirtualSwitch; + String vlanToken = Vlan.UNTAGGED; + + // Get switch details from the nicTO object if(nicTo.getName() != null && !nicTo.getName().isEmpty()) { String[] tokens = nicTo.getName().split(","); // Format of network traffic label is ,, // If all 3 fields are mentioned then number of tokens would be 3. // If only , are mentioned then number of tokens would be 2. + switchName = tokens[0]; if(tokens.length == 2 || tokens.length == 3) { - String vlanToken = tokens[1]; + vlanToken = tokens[1]; if (vlanToken.isEmpty()) { vlanToken = Vlan.UNTAGGED; } - return new Pair(tokens[0], vlanToken); - } else { - return new Pair(nicTo.getName(), Vlan.UNTAGGED); + if (tokens.length == 3) { + switchType = VirtualSwitchType.getType(tokens[2]); + } + } + } else { + if (trafficType == TrafficType.Guest && _guestTrafficInfo != null) { + switchType = _guestTrafficInfo.getVirtualSwitchType(); + switchName = _guestTrafficInfo.getVirtualSwitchName(); + } else if (trafficType == TrafficType.Public && _publicTrafficInfo != null) { + switchType = _publicTrafficInfo.getVirtualSwitchType(); + switchName = _publicTrafficInfo.getVirtualSwitchName(); } } - if (nicTo.getType() == Networks.TrafficType.Control || nicTo.getType() == Networks.TrafficType.Management) { - return new Pair(_privateNetworkVSwitchName, Vlan.UNTAGGED); - } else if (nicTo.getType() == Networks.TrafficType.Storage) { - return new Pair(_privateNetworkVSwitchName, Vlan.UNTAGGED); - } else if (nicTo.getType() == Networks.TrafficType.Vpn) { - throw new Exception("Unsupported traffic type: " + nicTo.getType().toString()); - } else { - throw new Exception("Unsupported traffic type: " + nicTo.getType().toString()); + if (nicTo.getType() == Networks.TrafficType.Control || nicTo.getType() == Networks.TrafficType.Management || nicTo.getType() == Networks.TrafficType.Storage) { + switchName = _privateNetworkVSwitchName; } + + return new Ternary(switchName, switchType.toString(), vlanToken); } private String getNetworkNamePrefix(NicTO nicTo) throws Exception { @@ -3885,7 +4041,7 @@ protected Answer execute(StopCommand cmd) { 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); @@ -4175,8 +4331,6 @@ protected Answer execute(MigrateWithStorageCommand cmd) { VirtualMachineRelocateSpecDiskLocator diskLocator = null; boolean isFirstDs = true; - String srcDiskName = ""; - String srcDsName = ""; String tgtDsName = ""; String tgtDsNfsHost; String tgtDsNfsPath; @@ -4184,6 +4338,8 @@ protected Answer execute(MigrateWithStorageCommand cmd) { VolumeTO volume; StorageFilerTO filerTo; Set mountedDatastoresAtSource = new HashSet(); + List volumeToList = new ArrayList(); + Map volumeDeviceKey = new HashMap(); Map volToFiler = cmd.getVolumeToFiler(); String tgtHost = cmd.getTargetHost(); @@ -4215,7 +4371,7 @@ protected Answer execute(MigrateWithStorageCommand cmd) { volume = entry.getKey(); filerTo = entry.getValue(); - srcDsName = volume.getPoolUuid().replace("-", ""); + volume.getPoolUuid().replace("-", ""); tgtDsName = filerTo.getUuid().replace("-", ""); tgtDsNfsHost = filerTo.getHost(); tgtDsNfsPath = filerTo.getPath(); @@ -4242,15 +4398,17 @@ protected Answer execute(MigrateWithStorageCommand cmd) { relocateSpec.setDatastore(morDsAtSource); isFirstDs = false; } - srcDiskName = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName( - new DatastoreMO(srcHyperHost.getContext(), morDsAtSource), - vmName, - volume.getPath() + ".vmdk"); + VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName( + new DatastoreMO(srcHyperHost.getContext(), morDsAtSource), + vmName, + volume.getPath() + ".vmdk"); diskLocator = new VirtualMachineRelocateSpecDiskLocator(); diskLocator.setDatastore(morDsAtSource); - diskLocator.setDiskId(getVirtualDiskInfo(vmMo, volume.getPath() + ".vmdk")); + int diskId = getVirtualDiskInfo(vmMo, volume.getPath() + ".vmdk"); + diskLocator.setDiskId(diskId); diskLocators.add(diskLocator); + volumeDeviceKey.put(volume.getId(), diskId); } relocateSpec.getDisk().addAll(diskLocators); @@ -4282,6 +4440,22 @@ protected Answer execute(MigrateWithStorageCommand cmd) { s_logger.debug("Successfully migrated storage of VM " + vmName + " to target datastore(s)"); } + // Update and return volume path for every disk because that could have changed after migration + for (Entry entry : volToFiler.entrySet()) { + volume = entry.getKey(); + long volumeId = volume.getId(); + VirtualDisk[] disks = vmMo.getAllDiskDevice(); + for (VirtualDisk disk : disks) { + if (volumeDeviceKey.get(volumeId) == disk.getKey()) { + VolumeObjectTO newVol = new VolumeObjectTO(); + newVol.setId(volumeId); + newVol.setPath(vmMo.getVmdkFileBaseName(disk)); + volumeToList.add(newVol); + break; + } + } + } + // Change host ManagedObjectReference morPool = tgtHyperHost.getHyperHostOwnerResourcePool(); if (!vmMo.migrate(morPool, tgtHyperHost.getMor())) { @@ -4291,7 +4465,6 @@ protected Answer execute(MigrateWithStorageCommand cmd) { } state = State.Stopping; - List volumeToList = null; return new MigrateWithStorageAnswer(cmd, volumeToList); } catch (Throwable e) { if (e instanceof RemoteException) { @@ -4329,7 +4502,7 @@ private Answer execute(MigrateVolumeCommand cmd) { s_logger.info("Executing resource MigrateVolumeCommand: " + _gson.toJson(cmd)); } - final String vmName = volMgr.getVmNameFromVolumeId(cmd.getVolumeId()); + final String vmName = cmd.getAttachedVmName(); VirtualMachineMO vmMo = null; VmwareHypervisorHost srcHyperHost = null; @@ -4340,14 +4513,11 @@ private Answer execute(MigrateVolumeCommand cmd) { List diskLocators = new ArrayList(); VirtualMachineRelocateSpecDiskLocator diskLocator = null; - String srcDiskName = ""; - String srcDsName = ""; String tgtDsName = ""; try { srcHyperHost = getHyperHost(getServiceContext()); morDc = srcHyperHost.getHyperHostDatacenter(); - srcDsName = volMgr.getStoragePoolOfVolume(cmd.getVolumeId()); tgtDsName = poolTo.getUuid().replace("-", ""); // find VM in this datacenter not just in this cluster. @@ -4366,12 +4536,12 @@ private Answer execute(MigrateVolumeCommand cmd) { throw new Exception(msg); } - srcDiskName = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName( - new DatastoreMO(srcHyperHost.getContext(), morDs), vmName, - volumePath + ".vmdk"); + DatastoreMO targetDsMo = new DatastoreMO(srcHyperHost.getContext(), morDs); + String fullVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(targetDsMo, vmName, volumePath + ".vmdk"); + int diskId = getVirtualDiskInfo(vmMo, volumePath + ".vmdk"); diskLocator = new VirtualMachineRelocateSpecDiskLocator(); diskLocator.setDatastore(morDs); - diskLocator.setDiskId(getVirtualDiskInfo(vmMo, volumePath + ".vmdk")); + diskLocator.setDiskId(diskId); diskLocators.add(diskLocator); relocateSpec.getDisk().add(diskLocator); @@ -4383,6 +4553,15 @@ private Answer execute(MigrateVolumeCommand cmd) { s_logger.debug("Successfully migrated volume " + volumePath + " to target datastore " + tgtDsName); } + // Update and return volume path because that could have changed after migration + if (!targetDsMo.fileExists(fullVolumePath)) { + VirtualDisk[] disks = vmMo.getAllDiskDevice(); + for (VirtualDisk disk : disks) + if (disk.getKey() == diskId) { + volumePath = vmMo.getVmdkFileBaseName(disk); + } + } + return new MigrateVolumeAnswer(cmd, true, null, volumePath); } catch (Exception e) { String msg = "Catch Exception " + e.getClass().getName() + " due to " + e.toString(); @@ -4392,7 +4571,7 @@ private Answer execute(MigrateVolumeCommand cmd) { } private int getVirtualDiskInfo(VirtualMachineMO vmMo, String srcDiskName) throws Exception { - Pair deviceInfo = vmMo.getDiskDevice(srcDiskName, false); + Pair deviceInfo = vmMo.getDiskDevice(srcDiskName, true); if(deviceInfo == null) { throw new Exception("No such disk device: " + srcDiskName); } @@ -4488,7 +4667,7 @@ public static String getDatastoreName(String str) { return str.replace('/', '-'); } - public static String trimIqn(String iqn) { + private static String trimIqn(String iqn) { String[] tmp = iqn.split("/"); if (tmp.length != 3) { @@ -4502,8 +4681,7 @@ public static String trimIqn(String iqn) { return tmp[1].trim(); } - @Override - public void createVmdk(Command cmd, DatastoreMO dsMo, String vmdkDatastorePath, Long volumeSize) throws Exception { + private void createVmdk(Command cmd, DatastoreMO dsMo, String vmdkDatastorePath, Long volumeSize) throws Exception { VmwareContext context = getServiceContext(); VmwareHypervisorHost hyperHost = getHyperHost(context); @@ -4527,7 +4705,7 @@ public void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int sto VmwareContext context = getServiceContext(); VmwareHypervisorHost hyperHost = getHyperHost(context); - deleteVmfsDatastore(hyperHost, getDatastoreName(iqn), storageHost, storagePort, trimIqn(iqn)); + deleteVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iqn), storageHost, storagePort, VmwareResource.trimIqn(iqn)); } protected Answer execute(AttachVolumeCommand cmd) { @@ -4552,16 +4730,9 @@ protected Answer execute(AttachVolumeCommand cmd) { ManagedObjectReference morDs = null; if (cmd.getAttach() && cmd.isManaged()) { - morDs = getVmfsDatastore(hyperHost, getDatastoreName(cmd.get_iScsiName()), cmd.getStorageHost(), cmd.getStoragePort(), trimIqn(cmd.get_iScsiName()), - cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(), cmd.getChapTargetUsername(), cmd.getChapTargetPassword()); - - DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDs); - - String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName()); - - if (!dsMo.fileExists(volumeDatastorePath)) { - createVmdk(cmd, dsMo, volumeDatastorePath, cmd.getVolumeSize()); - } + morDs = prepareManagedStorage(hyperHost, cmd.get_iScsiName(), cmd.getStorageHost(), cmd.getStoragePort(), + cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(), + cmd.getChapTargetUsername(), cmd.getChapTargetPassword(), cmd.getVolumeSize(), cmd); } else { morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid()); @@ -4601,7 +4772,7 @@ protected Answer execute(AttachVolumeCommand cmd) { if (cmd.isManaged()) { handleDatastoreAndVmdkDetach(cmd.get_iScsiName(), cmd.getStorageHost(), cmd.getStoragePort()); } else { - VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, cmd.getVolumePath()); + VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, cmd.getVolumePath()); } } @@ -4767,7 +4938,7 @@ public void run() { } } - public ManagedObjectReference getVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress, + private ManagedObjectReference getVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress, int storagePortNumber, String iqn, String chapName, String chapSecret, String mutualChapName, String mutualChapSecret) throws Exception { VmwareContext context = getServiceContext(); ManagedObjectReference morCluster = hyperHost.getHyperHostCluster(); @@ -4780,25 +4951,26 @@ public ManagedObjectReference getVmfsDatastore(VmwareHypervisorHost hyperHost, S target.setPort(storagePortNumber); target.setIScsiName(iqn); - HostInternetScsiHbaAuthenticationProperties auth = new HostInternetScsiHbaAuthenticationProperties(); + if (StringUtils.isNotBlank(chapName) && StringUtils.isNotBlank(chapSecret)) { + HostInternetScsiHbaAuthenticationProperties auth = new HostInternetScsiHbaAuthenticationProperties(); - String strAuthType = "chapRequired"; + String strAuthType = "chapRequired"; - auth.setChapAuthEnabled(true); - auth.setChapInherited(false); - auth.setChapAuthenticationType(strAuthType); - auth.setChapName(chapName); - auth.setChapSecret(chapSecret); + auth.setChapAuthEnabled(true); + auth.setChapInherited(false); + auth.setChapAuthenticationType(strAuthType); + auth.setChapName(chapName); + auth.setChapSecret(chapSecret); - if (StringUtils.isNotBlank(mutualChapName) && - StringUtils.isNotBlank(mutualChapSecret)) { - auth.setMutualChapInherited(false); - auth.setMutualChapAuthenticationType(strAuthType); - auth.setMutualChapName(mutualChapName); - auth.setMutualChapSecret(mutualChapSecret); - } + if (StringUtils.isNotBlank(mutualChapName) && StringUtils.isNotBlank(mutualChapSecret)) { + auth.setMutualChapInherited(false); + auth.setMutualChapAuthenticationType(strAuthType); + auth.setMutualChapName(mutualChapName); + auth.setMutualChapSecret(mutualChapSecret); + } - target.setAuthenticationProperties(auth); + target.setAuthenticationProperties(auth); + } final List lstTargets = new ArrayList(); @@ -4921,7 +5093,10 @@ protected Answer execute(AttachIsoCommand cmd) { vmMo.mountToolsInstaller(); } else { try{ - vmMo.unmountToolsInstaller(); + if (!vmMo.unmountToolsInstaller()) { + return new Answer(cmd, false, + "Failed to unmount vmware-tools installer ISO as the corresponding CDROM device is locked by VM. Please unmount the CDROM device inside the VM and ret-try."); + } }catch(Throwable e){ vmMo.detachIso(null); } @@ -5488,7 +5663,7 @@ public Answer execute(DeleteCommand cmd) { 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 +5988,85 @@ public IAgentControl getAgentControl() { @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); - - // 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(); - } + 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); + + 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); + + // 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); - - } finally { - recycleServiceContext(); - } + } + } + } else { + s_logger.error("Host is no longer connected."); + } + + } catch (Throwable e) { + if (e instanceof RemoteException) { + s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context"); + invalidateServiceContext(); + } + } finally { + recycleServiceContext(); + } } @Override @@ -5902,54 +6076,61 @@ public Type getType() { @Override public StartupCommand[] initialize() { - try { - String hostApiVersion = "4.1"; - VmwareContext context = getServiceContext(); - try { - VmwareHypervisorHost hyperHost = getHyperHost(context); - assert(hyperHost instanceof HostMO); - if(!((HostMO)hyperHost).isHyperHostConnected()) { - s_logger.info("Host " + hyperHost.getHyperHostName() + " is not in connected state"); - return null; - } - - ((HostMO)hyperHost).enableVncOnHostFirewall(); - - AboutInfo aboutInfo = ((HostMO)hyperHost).getHostAboutInfo(); - hostApiVersion = aboutInfo.getApiVersion(); - - } catch (Exception e) { - String msg = "VmwareResource intialize() failed due to : " + VmwareHelper.getExceptionMessage(e); - s_logger.error(msg); - invalidateServiceContext(); - return null; - } - - StartupRoutingCommand cmd = new StartupRoutingCommand(); - fillHostInfo(cmd); - - Map changes = null; - synchronized (_vms) { - _vms.clear(); - changes = sync(); - } - - cmd.setHypervisorType(HypervisorType.VMware); - cmd.setStateChanges(changes); - cmd.setCluster(_cluster); - cmd.setHypervisorVersion(hostApiVersion); - - List storageCmds = initializeLocalStorage(); - StartupCommand[] answerCmds = new StartupCommand[1 + storageCmds.size()]; - answerCmds[0] = cmd; - for (int i = 0; i < storageCmds.size(); i++) { - answerCmds[i + 1] = storageCmds.get(i); - } - - return answerCmds; - } finally { - recycleServiceContext(); - } + try { + String hostApiVersion = "4.1"; + VmwareContext context = getServiceContext(); + try { + VmwareHypervisorHost hyperHost = getHyperHost(context); + assert(hyperHost instanceof HostMO); + if(!((HostMO)hyperHost).isHyperHostConnected()) { + s_logger.info("Host " + hyperHost.getHyperHostName() + " is not in connected state"); + return null; + } + + ((HostMO)hyperHost).enableVncOnHostFirewall(); + + AboutInfo aboutInfo = ((HostMO)hyperHost).getHostAboutInfo(); + hostApiVersion = aboutInfo.getApiVersion(); + + } catch (Exception e) { + String msg = "VmwareResource intialize() failed due to : " + VmwareHelper.getExceptionMessage(e); + s_logger.error(msg); + invalidateServiceContext(); + return null; + } + + StartupRoutingCommand cmd = new StartupRoutingCommand(); + fillHostInfo(cmd); + + Map changes = null; + synchronized (_vms) { + _vms.clear(); + changes = sync(); + } + + cmd.setHypervisorType(HypervisorType.VMware); + + // TODO vmsync { + // deprecated after full replacement + cmd.setStateChanges(changes); + // TODO vmsync} + + cmd.setHostVmStateReport(syncHostVmStates()); + + cmd.setCluster(_cluster); + cmd.setHypervisorVersion(hostApiVersion); + + List storageCmds = initializeLocalStorage(); + StartupCommand[] answerCmds = new StartupCommand[1 + storageCmds.size()]; + answerCmds[0] = cmd; + for (int i = 0; i < storageCmds.size(); i++) { + answerCmds[i + 1] = storageCmds.get(i); + } + + return answerCmds; + } finally { + recycleServiceContext(); + } } private List initializeLocalStorage() { @@ -6028,11 +6209,34 @@ protected void fillHostInfo(StartupRoutingCommand cmd) { cmd.setName(_url); cmd.setGuid(_guid); cmd.setDataCenter(_dcId); + cmd.setIqn(getIqn()); cmd.setPod(_pod); cmd.setCluster(_cluster); cmd.setVersion(VmwareResource.class.getPackage().getImplementationVersion()); } + private String getIqn() { + try { + VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); + + if (hyperHost instanceof HostMO) { + HostMO host = (HostMO)hyperHost; + HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO(); + + for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) { + if (hba instanceof HostInternetScsiHba) { + return ((HostInternetScsiHba)hba).getIScsiName(); + } + } + } + } + catch (Exception ex) { + s_logger.info("Could not locate an IQN for this host."); + } + + return null; + } + private void fillHostHardwareInfo(VmwareContext serviceContext, StartupRoutingCommand cmd) throws RuntimeFaultFaultMsg, RemoteException, Exception { VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); @@ -6091,6 +6295,14 @@ private void fillHostDetailsInfo(VmwareContext serviceContext, Map syncHostVmStates() { + try { + return getHostVmStateReport(); + } catch(Exception e) { + return new HashMap(); + } + } + protected HashMap sync() { HashMap changes = new HashMap(); HashMap oldStates = null; @@ -6295,15 +6507,74 @@ private VirtualMachineGuestOsIdentifier translateGuestOsIdentifier(String cpuArc 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()); - - 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 + "]"; - + + 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 }); @@ -6328,14 +6599,14 @@ private HashMap getVmStates() throws Exception { } 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(); - } + if(objProp.getVal() != null) + VMInternalCSName = ((CustomFieldStringValue)objProp.getVal()).getValue(); + } else { assert (false); } } - + if (VMInternalCSName != null) name = VMInternalCSName; @@ -6367,12 +6638,12 @@ private HashMap getVmStats(List vmNames) throws Ex } } } - - 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 + "]"; + + 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 + "]"; ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(new String[] {"name", "summary.config.numCpu", "summary.quickStats.overallCpuUsage", instanceNameCustomField}); if (ocs != null && ocs.length > 0) { @@ -6388,16 +6659,16 @@ private HashMap getVmStats(List vmNames) throws Ex if (objProp.getName().equals("name")) { vmNameOnVcenter = objProp.getVal().toString(); } else if(objProp.getName().contains(instanceNameCustomField)) { - if(objProp.getVal() != null) - vmInternalCSName = ((CustomFieldStringValue)objProp.getVal()).getValue(); - } + if(objProp.getVal() != null) + vmInternalCSName = ((CustomFieldStringValue)objProp.getVal()).getValue(); + } else if (objProp.getName().equals("summary.config.numCpu")) { numberCPUs = objProp.getVal().toString(); } else if (objProp.getName().equals("summary.quickStats.overallCpuUsage")) { maxCpuUsage = objProp.getVal().toString(); } } - VirtualMachineMO vmMo = new VirtualMachineMO(hyperHost.getContext(), oc.getObj()); + new VirtualMachineMO(hyperHost.getContext(), oc.getObj()); if (vmInternalCSName != null) { name = vmInternalCSName; } else { @@ -6438,19 +6709,26 @@ else if (objProp.getName().equals("summary.config.numCpu")) { for(int i=0; i infos = ((PerfEntityMetric)values.get(i)).getSampleInfo(); - int endMs = infos.get(infos.size()-1).getTimestamp().getSecond() * 1000 + infos.get(infos.size()-1).getTimestamp().getMillisecond(); - int beginMs = infos.get(0).getTimestamp().getSecond() * 1000 + infos.get(0).getTimestamp().getMillisecond(); - sampleDuration = (endMs - beginMs) /1000; - List vals = ((PerfEntityMetric)values.get(i)).getValue(); - for(int vi = 0; ((vals!= null) && (vi < vals.size())); ++vi){ - if(vals.get(vi) instanceof PerfMetricIntSeries) { - PerfMetricIntSeries val = (PerfMetricIntSeries)vals.get(vi); - List perfValues = val.getValue(); - if (vals.get(vi).getId().getCounterId() == rxPerfCounterInfo.getKey()) { - networkReadKBs = sampleDuration * perfValues.get(3); //get the average RX rate multiplied by sampled duration - } - if (vals.get(vi).getId().getCounterId() == txPerfCounterInfo.getKey()) { - networkWriteKBs = sampleDuration * perfValues.get(3);//get the average TX rate multiplied by sampled duration + if (infos != null && infos.size() > 0) { + int endMs = infos.get(infos.size()-1).getTimestamp().getSecond() * 1000 + infos.get(infos.size()-1).getTimestamp().getMillisecond(); + int beginMs = infos.get(0).getTimestamp().getSecond() * 1000 + infos.get(0).getTimestamp().getMillisecond(); + sampleDuration = (endMs - beginMs) /1000; + List vals = ((PerfEntityMetric)values.get(i)).getValue(); + for(int vi = 0; ((vals!= null) && (vi < vals.size())); ++vi){ + if(vals.get(vi) instanceof PerfMetricIntSeries) { + PerfMetricIntSeries val = (PerfMetricIntSeries)vals.get(vi); + List perfValues = val.getValue(); + Long sumRate = 0L; + for (int j = 0; j < infos.size(); j++) { // Size of the array matches the size as the PerfSampleInfo + sumRate += perfValues.get(j); + } + Long averageRate = sumRate / infos.size(); + if (vals.get(vi).getId().getCounterId() == rxPerfCounterInfo.getKey()) { + networkReadKBs = sampleDuration * averageRate; //get the average RX rate multiplied by sampled duration + } + if (vals.get(vi).getId().getCounterId() == txPerfCounterInfo.getKey()) { + networkWriteKBs = sampleDuration * averageRate; //get the average TX rate multiplied by sampled duration + } } } } @@ -6462,6 +6740,7 @@ else if (objProp.getName().equals("summary.config.numCpu")) { } return vmResponseMap; } + // TODO vmsync } protected String networkUsage(final String privateIpAddress, final String option, final String ethName) { String args = null; @@ -6572,6 +6851,8 @@ protected String connect(final String vmname, final String ipAddress) { return connect(vmname, ipAddress, 3922); } + // TODO vmsync { + // deprecated after full replacement private static State convertState(VirtualMachinePowerState powerState) { return s_statesTable.get(powerState); } @@ -6580,6 +6861,16 @@ public static State getVmState(VirtualMachineMO vmMo) throws Exception { 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(); @@ -6620,123 +6911,123 @@ public void setAgentControl(IAgentControl agentControl) { @Override public boolean configure(String name, Map params) throws ConfigurationException { - try { - _name = name; - - _url = (String) params.get("url"); - _username = (String) params.get("username"); - _password = (String) params.get("password"); - _dcId = (String) params.get("zone"); - _pod = (String) params.get("pod"); - _cluster = (String) params.get("cluster"); - - _guid = (String) params.get("guid"); - String[] tokens = _guid.split("@"); - _vCenterAddress = tokens[1]; - _morHyperHost = new ManagedObjectReference(); - String[] hostTokens = tokens[0].split(":"); - _morHyperHost.setType(hostTokens[0]); - _morHyperHost.setValue(hostTokens[1]); - - _guestTrafficInfo = (VmwareTrafficLabel) params.get("guestTrafficInfo"); - _publicTrafficInfo = (VmwareTrafficLabel) params.get("publicTrafficInfo"); - VmwareContext context = getServiceContext(); - - // TODO ??? this is an invalid usage pattern. need to fix the reference to VolumeManagerImp here at resource file - // volMgr = ComponentContext.inject(VolumeManagerImpl.class); - try { - VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); - mgr.setupResourceStartupParams(params); - - CustomFieldsManagerMO cfmMo = new CustomFieldsManagerMO(context, context.getServiceContent().getCustomFieldsManager()); - cfmMo.ensureCustomFieldDef("Datastore", CustomFieldConstants.CLOUD_UUID); - if (_publicTrafficInfo != null && _publicTrafficInfo.getVirtualSwitchType() != VirtualSwitchType.StandardVirtualSwitch || - _guestTrafficInfo != null && _guestTrafficInfo.getVirtualSwitchType() != VirtualSwitchType.StandardVirtualSwitch) { - cfmMo.ensureCustomFieldDef("DistributedVirtualPortgroup", CustomFieldConstants.CLOUD_GC_DVP); - } - cfmMo.ensureCustomFieldDef("Network", CustomFieldConstants.CLOUD_GC); - cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_UUID); - cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_NIC_MASK); - cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME); - cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_WORKER); - cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_WORKER_TAG); - - VmwareHypervisorHost hostMo = this.getHyperHost(context); - _hostName = hostMo.getHyperHostName(); - - Map vsmCredentials; - if (_guestTrafficInfo.getVirtualSwitchType() == VirtualSwitchType.NexusDistributedVirtualSwitch || - _publicTrafficInfo.getVirtualSwitchType() == VirtualSwitchType.NexusDistributedVirtualSwitch) { - vsmCredentials = mgr.getNexusVSMCredentialsByClusterId(Long.parseLong(_cluster)); - if (vsmCredentials != null) { - s_logger.info("Stocking credentials while configuring resource."); - context.registerStockObject("vsmcredentials", vsmCredentials); - } - _privateNetworkVSwitchName = mgr.getPrivateVSwitchName(Long.parseLong(_dcId), HypervisorType.VMware); - } - - } catch (Exception e) { - s_logger.error("Unexpected Exception ", e); - } - - if(_privateNetworkVSwitchName == null) { - _privateNetworkVSwitchName = (String) params.get("private.network.vswitch.name"); - } - - String value = (String) params.get("vmware.reserve.cpu"); - if(value != null && value.equalsIgnoreCase("true")) - _reserveCpu = true; - - value = (String) params.get("vmware.recycle.hung.wokervm"); - if(value != null && value.equalsIgnoreCase("true")) - _recycleHungWorker = true; - - value = (String) params.get("vmware.reserve.mem"); - if(value != null && value.equalsIgnoreCase("true")) - _reserveMem = true; - - value = (String)params.get("vmware.root.disk.controller"); - if(value != null && value.equalsIgnoreCase("scsi")) - _rootDiskController = DiskControllerType.scsi; - else - _rootDiskController = DiskControllerType.ide; - - Integer intObj = (Integer) params.get("ports.per.dvportgroup"); - if (intObj != null) - _portsPerDvPortGroup = intObj.intValue(); - - s_logger.info("VmwareResource network configuration info." + - " private traffic over vSwitch: " + _privateNetworkVSwitchName + ", public traffic over " + - _publicTrafficInfo.getVirtualSwitchType() + " : " + _publicTrafficInfo.getVirtualSwitchName() + - ", guest traffic over " + _guestTrafficInfo.getVirtualSwitchType() + " : " + - _guestTrafficInfo.getVirtualSwitchName()); - - value = params.get("vmware.create.full.clone").toString(); - if (value != null && value.equalsIgnoreCase("true")) { - _fullCloneFlag = true; - } else { - _fullCloneFlag = false; - } - - value = params.get("vm.instancename.flag").toString(); - if (value != null && value.equalsIgnoreCase("true")) { - _instanceNameFlag = true; - } else { - _instanceNameFlag = false; - } - - value = (String)params.get("scripts.timeout"); - int timeout = NumbersUtil.parseInt(value, 1440) * 1000; - VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); - VmwareStorageProcessor storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, _fullCloneFlag, (VmwareStorageMount)mgr, - timeout, this, _shutdown_waitMs, null - ); - storageHandler = new VmwareStorageSubsystemCommandHandler(storageProcessor); - - return true; - } finally { - recycleServiceContext(); - } + try { + _name = name; + + _url = (String) params.get("url"); + _username = (String) params.get("username"); + _password = (String) params.get("password"); + _dcId = (String) params.get("zone"); + _pod = (String) params.get("pod"); + _cluster = (String) params.get("cluster"); + + _guid = (String) params.get("guid"); + String[] tokens = _guid.split("@"); + _vCenterAddress = tokens[1]; + _morHyperHost = new ManagedObjectReference(); + String[] hostTokens = tokens[0].split(":"); + _morHyperHost.setType(hostTokens[0]); + _morHyperHost.setValue(hostTokens[1]); + + _guestTrafficInfo = (VmwareTrafficLabel) params.get("guestTrafficInfo"); + _publicTrafficInfo = (VmwareTrafficLabel) params.get("publicTrafficInfo"); + VmwareContext context = getServiceContext(); + + // TODO ??? this is an invalid usage pattern. need to fix the reference to VolumeManagerImp here at resource file + // volMgr = ComponentContext.inject(VolumeManagerImpl.class); + try { + VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); + mgr.setupResourceStartupParams(params); + + CustomFieldsManagerMO cfmMo = new CustomFieldsManagerMO(context, context.getServiceContent().getCustomFieldsManager()); + cfmMo.ensureCustomFieldDef("Datastore", CustomFieldConstants.CLOUD_UUID); + if (_publicTrafficInfo != null && _publicTrafficInfo.getVirtualSwitchType() != VirtualSwitchType.StandardVirtualSwitch || + _guestTrafficInfo != null && _guestTrafficInfo.getVirtualSwitchType() != VirtualSwitchType.StandardVirtualSwitch) { + cfmMo.ensureCustomFieldDef("DistributedVirtualPortgroup", CustomFieldConstants.CLOUD_GC_DVP); + } + cfmMo.ensureCustomFieldDef("Network", CustomFieldConstants.CLOUD_GC); + cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_UUID); + cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_NIC_MASK); + cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME); + cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_WORKER); + cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_WORKER_TAG); + + VmwareHypervisorHost hostMo = this.getHyperHost(context); + _hostName = hostMo.getHyperHostName(); + + Map vsmCredentials; + if (_guestTrafficInfo.getVirtualSwitchType() == VirtualSwitchType.NexusDistributedVirtualSwitch || + _publicTrafficInfo.getVirtualSwitchType() == VirtualSwitchType.NexusDistributedVirtualSwitch) { + vsmCredentials = mgr.getNexusVSMCredentialsByClusterId(Long.parseLong(_cluster)); + if (vsmCredentials != null) { + s_logger.info("Stocking credentials while configuring resource."); + context.registerStockObject("vsmcredentials", vsmCredentials); + } + _privateNetworkVSwitchName = mgr.getPrivateVSwitchName(Long.parseLong(_dcId), HypervisorType.VMware); + } + + } catch (Exception e) { + s_logger.error("Unexpected Exception ", e); + } + + if(_privateNetworkVSwitchName == null) { + _privateNetworkVSwitchName = (String) params.get("private.network.vswitch.name"); + } + + String value = (String) params.get("vmware.reserve.cpu"); + if(value != null && value.equalsIgnoreCase("true")) + _reserveCpu = true; + + value = (String) params.get("vmware.recycle.hung.wokervm"); + if(value != null && value.equalsIgnoreCase("true")) + _recycleHungWorker = true; + + value = (String) params.get("vmware.reserve.mem"); + if(value != null && value.equalsIgnoreCase("true")) + _reserveMem = true; + + value = (String)params.get("vmware.root.disk.controller"); + if(value != null && value.equalsIgnoreCase("scsi")) + _rootDiskController = DiskControllerType.scsi; + else + _rootDiskController = DiskControllerType.ide; + + Integer intObj = (Integer) params.get("ports.per.dvportgroup"); + if (intObj != null) + _portsPerDvPortGroup = intObj.intValue(); + + s_logger.info("VmwareResource network configuration info." + + " private traffic over vSwitch: " + _privateNetworkVSwitchName + ", public traffic over " + + _publicTrafficInfo.getVirtualSwitchType() + " : " + _publicTrafficInfo.getVirtualSwitchName() + + ", guest traffic over " + _guestTrafficInfo.getVirtualSwitchType() + " : " + + _guestTrafficInfo.getVirtualSwitchName()); + + value = params.get("vmware.create.full.clone").toString(); + if (value != null && value.equalsIgnoreCase("true")) { + _fullCloneFlag = true; + } else { + _fullCloneFlag = false; + } + + value = params.get("vm.instancename.flag").toString(); + if (value != null && value.equalsIgnoreCase("true")) { + _instanceNameFlag = true; + } else { + _instanceNameFlag = false; + } + + value = (String)params.get("scripts.timeout"); + int timeout = NumbersUtil.parseInt(value, 1440) * 1000; + VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); + VmwareStorageProcessor storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, _fullCloneFlag, (VmwareStorageMount)mgr, + timeout, this, _shutdown_waitMs, null + ); + storageHandler = new VmwareStorageSubsystemCommandHandler(storageProcessor); + + return true; + } finally { + recycleServiceContext(); + } } @Override @@ -6768,10 +7059,16 @@ public VmwareHypervisorHost getHyperHost(VmwareContext context) { @Override public VmwareContext getServiceContext(Command cmd) { - if(s_serviceContext.get() != null) - return s_serviceContext.get(); - - VmwareContext context = null; + VmwareContext context = null; + if(s_serviceContext.get() != null) { + context = s_serviceContext.get(); + if (context.validate()) { + return context; + } else { + s_logger.info("Validation of the context failed, dispose and use a new one"); + invalidateServiceContext(context); + } + } try { context = VmwareContextFactory.getContext(_vCenterAddress, _username, _password); s_serviceContext.set(context); @@ -6784,23 +7081,23 @@ public VmwareContext getServiceContext(Command cmd) { @Override public void invalidateServiceContext(VmwareContext context) { - assert(s_serviceContext.get() == context); - - s_serviceContext.set(null); - if(context != null) - context.close(); - } - - private static void recycleServiceContext() { - VmwareContext context = s_serviceContext.get(); - s_serviceContext.set(null); - - if(context != null) { - assert(context.getPool() != null); - context.getPool().returnContext(context); - } - } - + assert(s_serviceContext.get() == context); + + s_serviceContext.set(null); + if(context != null) + context.close(); + } + + private static void recycleServiceContext() { + VmwareContext context = s_serviceContext.get(); + s_serviceContext.set(null); + + if(context != null) { + assert(context.getPool() != null); + context.getPool().returnContext(context); + } + } + @Override public VmwareHypervisorHost getHyperHost(VmwareContext context, Command cmd) { if (_morHyperHost.getType().equalsIgnoreCase("HostSystem")) { @@ -6860,7 +7157,7 @@ public Answer execute(DestroyCommand cmd) { VmwareContext context = getServiceContext(null); VmwareHypervisorHost hyperHost = getHyperHost(context, null); VolumeTO vol = cmd.getVolume(); - + ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, vol.getPoolUuid()); if (morDs == null) { String msg = "Unable to find datastore based on volume mount point " + vol.getMountPoint(); @@ -6881,7 +7178,7 @@ public Answer execute(DestroyCommand cmd) { else{ if (s_logger.isInfoEnabled()) { s_logger.info("Template volume " + vol.getPath() + " is not found, no need to delete."); - } + } } return new Answer(cmd, true, "Success"); @@ -6896,7 +7193,7 @@ public Answer execute(DestroyCommand cmd) { return new Answer(cmd, false, msg); } } - + private boolean isVMWareToolsInstalled(VirtualMachineMO vmMo) throws Exception{ GuestInfo guestInfo = vmMo.getVmGuestInfo(); return (guestInfo != null && guestInfo.getGuestState() != null && guestInfo.getGuestState().equalsIgnoreCase("running")); diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageContextFactory.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageContextFactory.java index ac8b294b76ef..e2f57df02dcc 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageContextFactory.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageContextFactory.java @@ -31,6 +31,8 @@ public class VmwareSecondaryStorageContextFactory { private static VmwareContextPool s_pool; + public static int s_vCenterSessionTimeout = 1200000; // Timeout in milliseconds + public static void initFactoryEnvironment() { System.setProperty("axis.socketSecureFactory", "org.apache.axis.components.net.SunFakeTrustSocketFactory"); s_pool = new VmwareContextPool(); @@ -43,6 +45,7 @@ public static VmwareContext create(String vCenterAddress, String vCenterUserName String serviceUrl = "https://" + vCenterAddress + "/sdk/vimService"; VmwareClient vimClient = new VmwareClient(vCenterAddress + "-" + s_seq++); + vimClient.setVcenterSessionTimeout(s_vCenterSessionTimeout); vimClient.connect(serviceUrl, vCenterUserName, vCenterPassword); VmwareContext context = new VmwareContext(vimClient, vCenterAddress); assert(context != null); @@ -58,7 +61,8 @@ public static VmwareContext getContext(String vCenterAddress, String vCenterUser if(context == null) { context = create(vCenterAddress, vCenterUserName, vCenterPassword); } else { - if(!context.validate()) { + // Validate current context and verify if vCenter session timeout value of the context matches the timeout value set by Admin + if(!context.validate() || (context.getVimClient().getVcenterSessionTimeout() != s_vCenterSessionTimeout)) { s_logger.info("Validation of the context faild. dispose and create a new one"); context.close(); context = create(vCenterAddress, vCenterUserName, vCenterPassword); @@ -76,4 +80,9 @@ public static VmwareContext getContext(String vCenterAddress, String vCenterUser public static void invalidate(VmwareContext context) { context.close(); } + + public static void setVcenterSessionTimeout(int timeout) { + s_vCenterSessionTimeout = timeout; + } + } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java index 81f7bd9a7fa8..8ff1a2dbddd4 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java @@ -21,7 +21,7 @@ import javax.naming.OperationNotSupportedException; import com.cloud.agent.api.storage.*; -import com.cloud.agent.api.to.DataTO; + import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.resource.SecondaryStorageResourceHandler; import org.apache.log4j.Logger; @@ -37,7 +37,6 @@ import com.cloud.hypervisor.vmware.manager.VmwareStorageManagerImpl; import com.cloud.hypervisor.vmware.manager.VmwareStorageMount; import com.cloud.hypervisor.vmware.mo.ClusterMO; -import com.cloud.hypervisor.vmware.mo.DatastoreMO; import com.cloud.hypervisor.vmware.mo.HostMO; import com.cloud.hypervisor.vmware.mo.VmwareHostType; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; @@ -45,6 +44,7 @@ import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.hypervisor.vmware.util.VmwareHelper; import com.cloud.serializer.GsonHelper; +import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; import com.google.gson.Gson; @@ -206,21 +206,29 @@ public VmwareContext getServiceContext(Command cmd) { return null; } + int vCenterSessionTimeout = NumbersUtil.parseInt(cmd.getContextParam("vCenterSessionTimeout"), 1200000); + try { _resource.ensureOutgoingRuleForAddress(vCenterAddress); - + VmwareContext context = currentContext.get(); - if(context == null) { + if (context != null) { + if(!context.validate()) { + invalidateServiceContext(context); + context = null; + } else { + context.registerStockObject("serviceconsole", cmd.getContextParam("serviceconsole")); + context.registerStockObject("manageportgroup", cmd.getContextParam("manageportgroup")); + context.registerStockObject("noderuninfo", cmd.getContextParam("noderuninfo")); + } + } + if(context == null) { s_logger.info("Open new VmwareContext. vCenter: " + vCenterAddress + ", user: " + username + ", password: " + StringUtils.getMaskedPasswordForDisplay(password)); + VmwareSecondaryStorageContextFactory.setVcenterSessionTimeout(vCenterSessionTimeout); context = VmwareSecondaryStorageContextFactory.getContext(vCenterAddress, username, password); } - - if (context != null) { - context.registerStockObject("serviceconsole", cmd.getContextParam("serviceconsole")); - context.registerStockObject("manageportgroup", cmd.getContextParam("manageportgroup")); - context.registerStockObject("noderuninfo", cmd.getContextParam("noderuninfo")); - } + currentContext.set(context); return context; } catch (Exception e) { @@ -348,12 +356,10 @@ private boolean validateContext(VmwareContext context, Command cmd) { return true; } - public ManagedObjectReference getVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress, int storagePortNumber, - String iqn, String initiatorChapName, String initiatorChapSecret, String mutualChapName, String mutualChapSecret) throws Exception { - throw new OperationNotSupportedException(); - } - - public void createVmdk(Command cmd, DatastoreMO dsMo, String volumeDatastorePath, Long volumeSize) throws Exception { + @Override + public ManagedObjectReference prepareManagedStorage(VmwareHypervisorHost hyperHost, String iScsiName, + String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret, + String chapTargetUsername, String chapTargetSecret, long size, Command cmd) throws Exception { throw new OperationNotSupportedException(); } 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 fbbbc13c6b35..6f3f2ef8651c 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -256,22 +256,6 @@ private boolean createVMLinkedClone(VirtualMachineMO vmTemplate, DatacenterMO dc throw new Exception(msg); } - s_logger.info("Move volume out of volume-wrapper VM "); - String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, - vmdkName, vmdkName, VmwareStorageLayoutType.VMWARE, true); - String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, - vmdkName, vmdkName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, true); - - dsMo.moveDatastoreFile(vmwareLayoutFilePair[0], - dcMo.getMor(), dsMo.getMor(), - legacyCloudStackLayoutFilePair[0], - dcMo.getMor(), true); - - dsMo.moveDatastoreFile(vmwareLayoutFilePair[1], - dcMo.getMor(), dsMo.getMor(), - legacyCloudStackLayoutFilePair[1], - dcMo.getMor(), true); - return true; } @@ -285,21 +269,6 @@ private boolean createVMFullClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo throw new Exception(msg); } - s_logger.info("Move volume out of volume-wrapper VM "); - String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, - vmdkName, vmdkName, VmwareStorageLayoutType.VMWARE, false); - String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, - vmdkName, vmdkName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, false); - - dsMo.moveDatastoreFile(vmwareLayoutFilePair[0], - dcMo.getMor(), dsMo.getMor(), - legacyCloudStackLayoutFilePair[0], - dcMo.getMor(), true); - - dsMo.moveDatastoreFile(vmwareLayoutFilePair[1], - dcMo.getMor(), dsMo.getMor(), - legacyCloudStackLayoutFilePair[1], - dcMo.getMor(), true); return true; } @@ -325,6 +294,7 @@ public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd) { DatastoreMO dsMo = new DatastoreMO(context, morDatastore); String vmdkName = volume.getName(); + String vmdkFileBaseName = null; if (srcStore == null) { // create a root volume for blank VM (created from ISO) String dummyVmName = this.hostService.getWorkerName(context, cmd, 0); @@ -334,8 +304,8 @@ public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd) { if (vmMo == null) { throw new Exception("Unable to create a dummy VM for volume creation"); } - - String vmdkFilePair[] = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, null, vmdkName, + vmdkFileBaseName = vmMo.getVmdkFileBaseNames().get(0); + String vmdkFilePair[] = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, null, vmdkFileBaseName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, true // we only use the first file in the pair, linked or not will not matter ); @@ -371,6 +341,16 @@ public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd) { vmMo = new ClusterMO(context, morCluster).findVmOnHyperHost(vmdkName); assert (vmMo != null); + vmdkFileBaseName = vmMo.getVmdkFileBaseNames().get(0); // TO-DO: Support for base template containing multiple disks + s_logger.info("Move volume out of volume-wrapper VM "); + String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, vmdkName, vmdkFileBaseName, + VmwareStorageLayoutType.VMWARE, !_fullCloneFlag); + String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, vmdkName, vmdkFileBaseName, + VmwareStorageLayoutType.CLOUDSTACK_LEGACY, !_fullCloneFlag); + + dsMo.moveDatastoreFile(vmwareLayoutFilePair[0], dcMo.getMor(), dsMo.getMor(), legacyCloudStackLayoutFilePair[0], dcMo.getMor(), true); + dsMo.moveDatastoreFile(vmwareLayoutFilePair[1], dcMo.getMor(), dsMo.getMor(), legacyCloudStackLayoutFilePair[1], dcMo.getMor(), true); + s_logger.info("detach disks from volume-wrapper VM " + vmdkName); vmMo.detachAllDisks(); @@ -383,13 +363,11 @@ public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd) { // 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, vmdkFileBaseName); } VolumeObjectTO newVol = new VolumeObjectTO(); - newVol.setPath(vmdkName); + newVol.setPath(vmdkFileBaseName); newVol.setSize(volume.getSize()); return new CopyCmdAnswer(newVol); } catch (Throwable e) { @@ -655,9 +633,22 @@ private Ternary createTemplateFromVolume(VirtualMachineMO vm VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first())); clonedVm = cloneResult.first(); - clonedVm.exportVm(secondaryMountPoint + "/" + installPath, templateUniqueName, true, false); + clonedVm.exportVm(secondaryMountPoint + "/" + installPath, templateUniqueName, false, false); + + // Get VMDK filename + String templateVMDKName = ""; + File[] files = new File(installFullPath).listFiles(); + if(files != null) { + for(File file : files) { + String fileName = file.getName(); + if(fileName.toLowerCase().startsWith(templateUniqueName) && fileName.toLowerCase().endsWith(".vmdk")) { + templateVMDKName += fileName; + break; + } + } + } - long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length(); + long physicalSize = new File(installFullPath + "/" + templateVMDKName).length(); VmdkProcessor processor = new VmdkProcessor(); Map params = new HashMap(); params.put(StorageLayer.InstanceConfigKey, _storage); @@ -665,6 +656,7 @@ private Ternary createTemplateFromVolume(VirtualMachineMO vm long virtualSize = processor.getTemplateVirtualSize(installFullPath, templateUniqueName); postCreatePrivateTemplate(installFullPath, templateId, templateUniqueName, physicalSize, virtualSize); + writeMetaOvaForTemplate(installFullPath, templateUniqueName + ".ovf", templateVMDKName, templateUniqueName, physicalSize); return new Ternary(installPath + "/" + templateUniqueName + ".ova", physicalSize, virtualSize); } finally { @@ -993,7 +985,7 @@ private Ternary backupSnapshotToSecondaryStorage(Virtu String backupUuid = UUID.randomUUID().toString(); Pair snapshotInfo = exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, installPath, backupUuid, workerVmName); - return new Ternary(backupUuid + "/" + backupUuid, snapshotInfo.first(), snapshotInfo.second()); + return new Ternary(backupUuid, snapshotInfo.first(), snapshotInfo.second()); } @Override @@ -1036,32 +1028,26 @@ public Answer backupSnapshot(CopyCommand cmd) { CopyCmdAnswer answer = null; try { - vmMo = hyperHost.findVmOnHyperHost(vmName); - if (vmMo == null) { - if(s_logger.isDebugEnabled()) { - s_logger.debug("Unable to find owner VM for BackupSnapshotCommand on host " + hyperHost.getHyperHostName() + ", will try within datacenter"); - } - - vmMo = hyperHost.findVmOnPeerHyperHost(vmName); - if(vmMo == null) { - dsMo = new DatastoreMO(hyperHost.getContext(), morDs); - - workerVMName = hostService.getWorkerName(context, cmd, 0); - - vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, workerVMName); - - if (vmMo == null) { - throw new Exception("Failed to find the newly create or relocated VM. vmName: " + workerVMName); + if(vmName != null) { + vmMo = hyperHost.findVmOnHyperHost(vmName); + if (vmMo == null) { + if(s_logger.isDebugEnabled()) { + s_logger.debug("Unable to find owner VM for BackupSnapshotCommand on host " + hyperHost.getHyperHostName() + ", will try within datacenter"); } - workerVm = vmMo; - - // attach volume to worker VM - String datastoreVolumePath = dsMo.getDatastorePath(volumePath + ".vmdk"); - vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs); - } else { - s_logger.info("Using owner VM " + vmName + " for snapshot operation"); - hasOwnerVm = true; + vmMo = hyperHost.findVmOnPeerHyperHost(vmName); + } + } + if(vmMo == null) { + dsMo = new DatastoreMO(hyperHost.getContext(), morDs); + workerVMName = hostService.getWorkerName(context, cmd, 0); + vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, workerVMName); + if (vmMo == null) { + throw new Exception("Failed to find the newly create or relocated VM. vmName: " + workerVMName); } + workerVm = vmMo; + // attach volume to worker VM + String datastoreVolumePath = dsMo.getDatastorePath(volumePath + ".vmdk"); + vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs); } else { s_logger.info("Using owner VM " + vmName + " for snapshot operation"); hasOwnerVm = true; @@ -1081,8 +1067,25 @@ public Answer backupSnapshot(CopyCommand cmd) { answer = new CopyCmdAnswer(details); } else { details = "Successfully backedUp the snapshot with Uuid: " + snapshotUuid + " to secondary storage."; + + // Get snapshot physical size + long physicalSize = 0l; + String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl); + String snapshotDir = destSnapshot.getPath() + "/" + snapshotBackupUuid; + File[] files = new File(secondaryMountPoint + "/" + snapshotDir).listFiles(); + if(files != null) { + for(File file : files) { + String fileName = file.getName(); + if(fileName.toLowerCase().startsWith(snapshotBackupUuid) && fileName.toLowerCase().endsWith(".vmdk")) { + physicalSize = new File(secondaryMountPoint + "/" + snapshotDir + "/" + fileName).length(); + break; + } + } + } + SnapshotObjectTO newSnapshot = new SnapshotObjectTO(); - newSnapshot.setPath(destSnapshot.getPath() + "/" + snapshotBackupUuid); + newSnapshot.setPath(snapshotDir + "/" + snapshotBackupUuid); + newSnapshot.setPhysicalSize(physicalSize); answer = new CopyCmdAnswer(newSnapshot); } } finally { @@ -1196,17 +1199,10 @@ private Answer attachVolume(Command cmd, DiskTO disk, boolean isAttach, boolean if (isAttach && isManaged) { Map details = disk.getDetails(); - morDs = hostService.getVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iScsiName), storageHost, storagePort, - VmwareResource.trimIqn(iScsiName), details.get(DiskTO.CHAP_INITIATOR_USERNAME), details.get(DiskTO.CHAP_INITIATOR_SECRET), - details.get(DiskTO.CHAP_TARGET_USERNAME), details.get(DiskTO.CHAP_TARGET_SECRET)); - - DatastoreMO dsMo = new DatastoreMO(hostService.getServiceContext(null), morDs); - - String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName()); - - if (!dsMo.fileExists(volumeDatastorePath)) { - hostService.createVmdk(cmd, dsMo, volumeDatastorePath, volumeTO.getSize()); - } + morDs = hostService.prepareManagedStorage(hyperHost, iScsiName, storageHost, storagePort, + details.get(DiskTO.CHAP_INITIATOR_USERNAME), details.get(DiskTO.CHAP_INITIATOR_SECRET), + details.get(DiskTO.CHAP_TARGET_USERNAME), details.get(DiskTO.CHAP_TARGET_SECRET), + volumeTO.getSize(), cmd); } else { morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, isManaged ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid()); @@ -1316,7 +1312,9 @@ private Answer attachIso(DiskTO disk, boolean isAttach, String vmName) { vmMo.mountToolsInstaller(); } else { try{ - vmMo.unmountToolsInstaller(); + if (!vmMo.unmountToolsInstaller()) { + return new AttachAnswer("Failed to unmount vmware-tools installer ISO as the corresponding CDROM device is locked by VM. Please unmount the CDROM device inside the VM and ret-try."); + } } catch(Throwable e){ vmMo.detachIso(null); } @@ -1517,7 +1515,9 @@ public Answer deleteVolume(DeleteCommand cmd) { vmMo.destroy(); // this.hostService.handleDatastoreAndVmdkDetach(iScsiName, storageHost, storagePort); - this.hostService.removeManagedTargetsFromCluster(managedIqns); + if (managedIqns != null && !managedIqns.isEmpty()) { + this.hostService.removeManagedTargetsFromCluster(managedIqns); + } for (NetworkDetails netDetails : networks) { if (netDetails.getGCTag() != null && netDetails.getGCTag().equalsIgnoreCase("true")) { @@ -1705,6 +1705,12 @@ public Answer createVolumeFromSnapshot(CopyCommand cmd) { throw new Exception(msg); } + // strip off the extension since restoreVolumeFromSecStorage internally will append suffix there. + if (backedUpSnapshotUuid.endsWith(".ova")){ + backedUpSnapshotUuid = backedUpSnapshotUuid.replace(".ova", ""); + } else if (backedUpSnapshotUuid.endsWith(".ovf")){ + backedUpSnapshotUuid = backedUpSnapshotUuid.replace(".ovf", ""); + } DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs); restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secondaryStorageUrl, backupPath, backedUpSnapshotUuid); diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java index ba72e8ff167f..a708add44f2c 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java @@ -18,6 +18,17 @@ */ package com.cloud.storage.resource; +import java.io.File; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.storage.command.CopyCmdAnswer; +import org.apache.cloudstack.storage.command.CopyCommand; +import org.apache.cloudstack.storage.command.DeleteCommand; +import org.apache.cloudstack.storage.to.SnapshotObjectTO; +import org.apache.cloudstack.storage.to.TemplateObjectTO; +import org.apache.cloudstack.storage.to.VolumeObjectTO; + import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataStoreTO; @@ -27,15 +38,6 @@ import com.cloud.agent.api.to.SwiftTO; import com.cloud.hypervisor.vmware.manager.VmwareStorageManager; import com.cloud.storage.DataStoreRole; -import org.apache.cloudstack.storage.command.CopyCmdAnswer; -import org.apache.cloudstack.storage.command.CopyCommand; -import org.apache.cloudstack.storage.command.DeleteCommand; -import org.apache.cloudstack.storage.to.SnapshotObjectTO; -import org.apache.cloudstack.storage.to.TemplateObjectTO; -import org.apache.cloudstack.storage.to.VolumeObjectTO; -import org.apache.log4j.Logger; - -import java.io.File; public class VmwareStorageSubsystemCommandHandler extends StorageSubsystemCommandHandlerBase { private static final Logger s_logger = Logger.getLogger(VmwareStorageSubsystemCommandHandler.class); @@ -90,27 +92,41 @@ protected Answer execute(CopyCommand cmd) { String name = path.substring(index + 1); storageManager.createOva(parentPath + File.separator + path, name); vol.setPath(path + File.separator + name + ".ova"); - } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.TEMPLATE) { - //create template from snapshot on src at first, then copy it to s3 - TemplateObjectTO cacheTemplate = (TemplateObjectTO)destData; - cacheTemplate.setDataStore(srcDataStore); - CopyCmdAnswer answer = (CopyCmdAnswer)processor.createTemplateFromSnapshot(cmd); - if (!answer.getResult()) { - return answer; - } - cacheTemplate.setDataStore(destDataStore); - TemplateObjectTO template = (TemplateObjectTO)answer.getNewData(); - template.setDataStore(srcDataStore); - CopyCommand newCmd = new CopyCommand(template, destData, cmd.getWait(), cmd.executeInSequence()); - Answer result = storageResource.defaultAction(newCmd); - //clean up template data on staging area - try { - DeleteCommand deleteCommand = new DeleteCommand(template); - storageResource.defaultAction(deleteCommand); - } catch (Exception e) { - s_logger.debug("Failed to clean up staging area:", e); + } else if (srcData.getObjectType() == DataObjectType.TEMPLATE) { + // sync template from NFS cache to S3 in NFS migration to S3 case + storageManager.createOvaForTemplate((TemplateObjectTO)srcData); + } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT) { + // pack ova first + // sync snapshot from NFS cache to S3 in NFS migration to S3 case + String parentPath = storageResource.getRootDir(srcDataStore.getUrl()); + SnapshotObjectTO snap = (SnapshotObjectTO)srcData; + String path = snap.getPath(); + int index = path.lastIndexOf(File.separator); + String name = path.substring(index + 1); + String snapDir = path.substring(0, index); + storageManager.createOva(parentPath + File.separator + snapDir, name); + if (destData.getObjectType() == DataObjectType.TEMPLATE) { + //create template from snapshot on src at first, then copy it to s3 + TemplateObjectTO cacheTemplate = (TemplateObjectTO)destData; + cacheTemplate.setDataStore(srcDataStore); + CopyCmdAnswer answer = (CopyCmdAnswer)processor.createTemplateFromSnapshot(cmd); + if (!answer.getResult()) { + return answer; + } + cacheTemplate.setDataStore(destDataStore); + TemplateObjectTO template = (TemplateObjectTO)answer.getNewData(); + template.setDataStore(srcDataStore); + CopyCommand newCmd = new CopyCommand(template, destData, cmd.getWait(), cmd.executeInSequence()); + Answer result = storageResource.defaultAction(newCmd); + //clean up template data on staging area + try { + DeleteCommand deleteCommand = new DeleteCommand(template); + storageResource.defaultAction(deleteCommand); + } catch (Exception e) { + s_logger.debug("Failed to clean up staging area:", e); + } + return result; } - return result; } needDelegation = true; } diff --git a/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java b/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java index 5c9b3af52b9c..3c4d704138b9 100644 --- a/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java +++ b/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java @@ -20,6 +20,7 @@ package org.apache.cloudstack.storage.motion; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.inject.Inject; @@ -33,6 +34,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -95,7 +97,7 @@ public Void copyAsync(Map volumeMap, VirtualMachineTO vmT try { VMInstanceVO instance = instanceDao.findById(vmTo.getId()); if (instance != null) { - if (srcHost.getClusterId() == destHost.getClusterId()) { + if (srcHost.getClusterId().equals(destHost.getClusterId())) { answer = migrateVmWithVolumesWithinCluster(instance, vmTo, srcHost, destHost, volumeMap); } else { answer = migrateVmWithVolumesAcrossCluster(instance, vmTo, srcHost, destHost, volumeMap); @@ -105,7 +107,7 @@ public Void copyAsync(Map volumeMap, VirtualMachineTO vmT } } catch (Exception e) { s_logger.error("copy failed", e); - errMsg = e.toString(); + errMsg = e.getLocalizedMessage(); } CopyCommandResult result = new CopyCommandResult(null, answer); @@ -143,7 +145,7 @@ private Answer migrateVmWithVolumesAcrossCluster(VMInstanceVO vm, VirtualMachine ". " + migrateWithStorageAnswer.getDetails()); } else { // Update the volume details after migration. - updateVolumesAfterMigration(volumeToPool); + updateVolumesAfterMigration(volumeToPool, migrateWithStorageAnswer.getVolumeTos()); } s_logger.debug("Storage migration of VM " + vm.getInstanceName() + " completed successfully. Migrated to host " + destHost.getName()); @@ -178,7 +180,7 @@ private Answer migrateVmWithVolumesWithinCluster(VMInstanceVO vm, VirtualMachine ". " + answer.getDetails()); } else { // Update the volume details after migration. - updateVolumesAfterMigration(volumeToPool); + updateVolumesAfterMigration(volumeToPool, answer.getVolumeTos()); } return answer; @@ -188,20 +190,28 @@ private Answer migrateVmWithVolumesWithinCluster(VMInstanceVO vm, VirtualMachine } } - private void updateVolumesAfterMigration(Map volumeToPool) { + private void updateVolumesAfterMigration(Map volumeToPool, List volumeTos) { for (Map.Entry entry : volumeToPool.entrySet()) { + boolean updated = false; VolumeInfo volume = entry.getKey(); StoragePool pool = (StoragePool)entry.getValue(); - - VolumeVO volumeVO = volDao.findById(volume.getId()); - Long oldPoolId = volumeVO.getPoolId(); - volumeVO.setLastPoolId(oldPoolId); - volumeVO.setFolder(pool.getPath()); - volumeVO.setPodId(pool.getPodId()); - volumeVO.setPoolId(pool.getId()); - - volDao.update(volume.getId(), volumeVO); - s_logger.debug("Volume path was successfully updated for volume " + volume.getName() + " after it was migrated."); + for (VolumeObjectTO volumeTo : volumeTos) { + if (volume.getId() == volumeTo.getId()) { + VolumeVO volumeVO = volDao.findById(volume.getId()); + Long oldPoolId = volumeVO.getPoolId(); + volumeVO.setPath(volumeTo.getPath()); + volumeVO.setLastPoolId(oldPoolId); + volumeVO.setFolder(pool.getPath()); + volumeVO.setPodId(pool.getPodId()); + volumeVO.setPoolId(pool.getId()); + volDao.update(volume.getId(), volumeVO); + updated = true; + break; + } + } + if (!updated) { + s_logger.error("Volume path wasn't updated for volume " + volume + " after it was migrated."); + } } } } diff --git a/plugins/hypervisors/xen/pom.xml b/plugins/hypervisors/xen/pom.xml index 66b6b1d58031..da942c78948f 100644 --- a/plugins/hypervisors/xen/pom.xml +++ b/plugins/hypervisors/xen/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java index 6dd6f3fb4226..47ab90a1e525 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java @@ -16,19 +16,59 @@ // under the License. package com.cloud.hypervisor; +import java.util.ArrayList; +import java.util.List; + import javax.ejb.Local; import javax.inject.Inject; -import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.to.*; +import com.cloud.host.HostInfo; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.GuestOSVO; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.template.VirtualMachineTemplate.BootloaderType; +import com.cloud.utils.Pair; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.UserVmDao; +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.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.framework.config.Configurable; +import org.apache.cloudstack.storage.command.CopyCommand; +import org.apache.cloudstack.storage.command.DettachCommand; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.framework.config.ConfigKey; + @Local(value=HypervisorGuru.class) -public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru { +public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru, Configurable{ @Inject GuestOSDao _guestOsDao; + @Inject + EndPointSelector endPointSelector; + @Inject + HostDao hostDao; + @Inject + VolumeDao _volumeDao; + @Inject + PrimaryDataStoreDao _storagePoolDao; + @Inject + VolumeDataFactory _volFactory; + @Inject + UserVmDao _userVmDao; + + static final ConfigKey MaxNumberOfVCPUSPerVM = new ConfigKey("Advanced", Integer.class, "xen.vm.vcpu.max", "16", + "Maximum number of VCPUs that VM can get in XenServer.", true, ConfigKey.Scope.Cluster); protected XenServerGuru() { super(); @@ -46,6 +86,14 @@ public VirtualMachineTO implement(VirtualMachineProfile vm) { bt = vm.getBootLoaderType(); } VirtualMachineTO to = toVirtualMachineTO(vm); + UserVmVO userVmVO = _userVmDao.findById(vm.getId()); + if (userVmVO != null) { + HostVO host = hostDao.findById(userVmVO.getHostId()); + if (host != null) { + to.setVcpuMaxLimit(MaxNumberOfVCPUSPerVM.valueIn(host.getClusterId())); + } + } + to.setBootloader(bt); // Determine the VM's OS description @@ -59,4 +107,76 @@ public VirtualMachineTO implement(VirtualMachineProfile vm) { public boolean trackVmHostChange() { return true; } + + @Override + public List finalizeExpungeVolumes(VirtualMachine vm) { + List commands = new ArrayList(); + + List volumes = _volumeDao.findByInstance(vm.getId()); + + if (volumes != null) { + for (VolumeVO volume : volumes) { + if (volume.getVolumeType() == Volume.Type.DATADISK) { + StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); + + // storagePool should be null if we are expunging a volume that was never + // attached to a VM that was started (the "trick" for storagePool to be null + // is that none of the VMs this volume may have been attached to were ever started, + // so the volume was never assigned to a storage pool) + if (storagePool != null && storagePool.isManaged()) { + DataTO volTO = _volFactory.getVolume(volume.getId()).getTO(); + DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), volume.getPath(), volume.getVolumeType()); + + DettachCommand cmd = new DettachCommand(disk, vm.getInstanceName()); + + cmd.setManaged(true); + + cmd.setStorageHost(storagePool.getHostAddress()); + cmd.setStoragePort(storagePool.getPort()); + + cmd.set_iScsiName(volume.get_iScsiName()); + + commands.add(cmd); + } + } + } + } + + return commands; + } + + @Override + public Pair getCommandHostDelegation(long hostId, Command cmd) { + if (cmd instanceof CopyCommand) { + CopyCommand cpyCommand = (CopyCommand)cmd; + DataTO srcData = cpyCommand.getSrcTO(); + DataTO destData = cpyCommand.getDestTO(); + + if (srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.TEMPLATE) { + DataStoreTO srcStore = srcData.getDataStore(); + DataStoreTO destStore = destData.getDataStore(); + if (srcStore instanceof NfsTO && destStore instanceof NfsTO) { + HostVO host = hostDao.findById(hostId); + EndPoint ep = endPointSelector.selectHypervisorHost(new ZoneScope(host.getDataCenterId())); + host = hostDao.findById(ep.getId()); + hostDao.loadDetails(host); + boolean snapshotHotFix = Boolean.parseBoolean(host.getDetail(HostInfo.XS620_SNAPSHOT_HOTFIX)); + if (snapshotHotFix) { + return new Pair(Boolean.TRUE, new Long(ep.getId())); + } + } + } + } + return new Pair(Boolean.FALSE, new Long(hostId)); + } + + @Override + public String getConfigComponentName() { + return XenServerGuru.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[] {MaxNumberOfVCPUSPerVM}; + } } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java index 688488d071a2..86686a192c9b 100755 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java @@ -34,13 +34,6 @@ import org.apache.log4j.Logger; import org.apache.xmlrpc.XmlRpcException; -import com.xensource.xenapi.Connection; -import com.xensource.xenapi.Host; -import com.xensource.xenapi.Pool; -import com.xensource.xenapi.Session; -import com.xensource.xenapi.Types.SessionAuthenticationFailed; -import com.xensource.xenapi.Types.XenAPIException; - import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; import com.cloud.agent.api.AgentControlAnswer; @@ -82,6 +75,7 @@ import com.cloud.hypervisor.xen.resource.XenServer610Resource; import com.cloud.hypervisor.xen.resource.XenServer620Resource; import com.cloud.hypervisor.xen.resource.XenServerConnectionPool; +import com.cloud.hypervisor.xen.resource.Xenserver625Resource; import com.cloud.resource.Discoverer; import com.cloud.resource.DiscovererBase; import com.cloud.resource.ResourceManager; @@ -98,6 +92,12 @@ import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.HypervisorVersionChangedException; +import com.xensource.xenapi.Connection; +import com.xensource.xenapi.Host; +import com.xensource.xenapi.Pool; +import com.xensource.xenapi.Session; +import com.xensource.xenapi.Types.SessionAuthenticationFailed; +import com.xensource.xenapi.Types.XenAPIException; @Local(value=Discoverer.class) public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, Listener, ResourceStateAdapter { @@ -112,6 +112,7 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L protected String _guestNic; protected boolean _setupMultipath; protected String _instance; + private String xs620snapshothotfix = "Xenserver-Vdi-Copy-HotFix"; @Inject protected AlertManager _alertMgr; @Inject protected AgentManager _agentMgr; @@ -143,6 +144,11 @@ void setClusterGuid(ClusterVO cluster, String guid) { } } + protected boolean xenserverHotFixEnabled() { + //temporary fix, we should call xenserver api to get the hot fix is enabled or not. + return Boolean.parseBoolean(_configDao.getValue(Config.XenServerHotFix.name())); + } + @Override public Map> find(long dcId, Long podId, Long clusterId, URI url, String username, String password, List hostTags) throws DiscoveryException { Map> resources = new HashMap>(); @@ -182,8 +188,7 @@ public Map> find(long dcId, Long p String hostIp = ia.getHostAddress(); Queue pass=new LinkedList(); pass.add(password); - String masterIp = _connPool.getMasterIp(hostIp, username, pass); - conn = _connPool.masterConnect(masterIp, username, pass); + conn = _connPool.getConnect(hostIp, username, pass); if (conn == null) { String msg = "Unable to get a connection to " + url; s_logger.debug(msg); @@ -247,7 +252,7 @@ public Map> find(long dcId, Long p } if( !support_hvm ) { String msg = "Unable to add host " + record.address + " because it doesn't support hvm"; - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, msg, msg); + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, dcId, podId, msg, msg); s_logger.debug(msg); throw new RuntimeException(msg); } @@ -268,6 +273,8 @@ public Map> find(long dcId, Long p hostOS = record.softwareVersion.get("platform_name"); } + //Boolean xs620hotfix = record.tags.contains(xs620snapshothotfix); + Boolean xs620hotfix = xenserverHotFixEnabled(); String hostOSVer = prodVersion; String hostKernelVer = record.softwareVersion.get("linux"); @@ -297,6 +304,7 @@ public Map> find(long dcId, Long p details.put(HostInfo.HOST_OS_VERSION, hostOSVer); details.put(HostInfo.HOST_OS_KERNEL_VERSION, hostKernelVer); details.put(HostInfo.HYPERVISOR_VERSION, xenVersion); + details.put(HostInfo.XS620_SNAPSHOT_HOTFIX, xs620hotfix.toString()); String privateNetworkLabel = _networkMgr.getDefaultManagementTrafficLabel(dcId, HypervisorType.XenServer); String storageNetworkLabel = _networkMgr.getDefaultStorageTrafficLabel(dcId, HypervisorType.XenServer); @@ -325,7 +333,7 @@ public Map> find(long dcId, Long p try { resource.configure("Xen Server", params); } catch (ConfigurationException e) { - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, "Unable to add " + record.address, "Error is " + e.getMessage()); + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, dcId, podId, "Unable to add " + record.address, "Error is " + e.getMessage()); s_logger.warn("Unable to instantiate " + record.address, e); continue; } @@ -383,7 +391,7 @@ protected boolean addHostsToPool(Connection conn, String hostIp, Long clusterId) password = host.getDetail("password"); pass.add(password); String address = host.getPrivateIpAddress(); - Connection hostConn = _connPool.slaveConnect(address, username, pass); + Connection hostConn = _connPool.getConnect(address, username, pass); if (hostConn == null) { continue; } @@ -397,7 +405,7 @@ protected boolean addHostsToPool(Connection conn, String hostIp, Long clusterId) s_logger.warn("Can not get master ip address from host " + address); } finally { try{ - Session.localLogout(hostConn); + Session.logout(hostConn); } catch (Exception e ) { } hostConn.dispose(); @@ -451,9 +459,21 @@ else if (prodBrand.equals("XenServer") && prodVersion.equals("6.0.2")) return new XenServer602Resource(); else if (prodBrand.equals("XenServer") && prodVersion.equals("6.1.0")) return new XenServer610Resource(); - else if (prodBrand.equals("XenServer") && prodVersion.equals("6.2.0")) - return new XenServer620Resource(); - else if (prodBrand.equals("XenServer") && prodVersion.equals("5.6.100")) { + else if (prodBrand.equals("XenServer") && prodVersion.equals("6.2.0")) { + /* + Set tags =record.tags; + if (tags.contains(xs620snapshothotfix)) { + return new Xenserver625Resource(); + } else { + return new XenServer620Resource(); + }*/ + boolean hotfix = xenserverHotFixEnabled(); + if (hotfix) { + return new Xenserver625Resource(); + } else { + return new XenServer620Resource(); + } + } else if (prodBrand.equals("XenServer") && prodVersion.equals("5.6.100")) { String prodVersionTextShort = record.softwareVersion.get("product_version_text_short").trim(); if ("5.6 SP2".equals(prodVersionTextShort)) { return new XenServer56SP2Resource(); @@ -465,7 +485,7 @@ else if (prodBrand.equals("XenServer") && prodVersion.equals("5.6.100")) { } String msg = "Only support XCP 1.0.0, 1.1.0, 1.4.x, 1.5 beta, 1.6.x; XenServer 5.6, XenServer 5.6 FP1, XenServer 5.6 SP2, Xenserver 6.0, 6.0.2, 6.1.0, 6.2.0 but this one is " + prodBrand + " " + prodVersion; - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, msg, msg); + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, dcId, podId, msg, msg); s_logger.debug(msg); throw new RuntimeException(msg); } @@ -604,7 +624,12 @@ public void processConnect(com.cloud.host.Host agent, StartupCommand cmd, boolea } else if (prodBrand.equals("XenServer") && prodVersion.equals("6.1.0")) { resource = XenServer610Resource.class.getName(); } else if (prodBrand.equals("XenServer") && prodVersion.equals("6.2.0")) { - resource = XenServer620Resource.class.getName(); + String hotfix = details.get("Xenserer620HotFix"); + if (hotfix != null && hotfix.equalsIgnoreCase("Xenserver-Vdi-Copy-HotFix")) { + resource = Xenserver625Resource.class.getName(); + } else { + resource = XenServer620Resource.class.getName(); + } } else if (prodBrand.equals("XenServer") && prodVersion.equals("5.6.100")) { String prodVersionTextShort = details.get("product_version_text_short").trim(); if ("5.6 SP2".equals(prodVersionTextShort)) { @@ -737,13 +762,24 @@ public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForc String msg = "Unable to eject host " + host.getGuid() + " due to there is no host up in this cluster, please execute xe pool-eject host-uuid=" + host.getGuid() + "in this host " + host.getPrivateIpAddress(); s_logger.warn(msg); - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "Unable to eject host " + host.getGuid(), msg); + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "Unable to eject host " + host.getGuid(), msg); } } return new DeleteHostAnswer(true); } + @Override + protected HashMap buildConfigParams(HostVO host){ + HashMap params = super.buildConfigParams(host); + DataCenterVO zone = _dcDao.findById(host.getDataCenterId()); + if ( zone != null ) { + boolean securityGroupEnabled = zone.isSecurityGroupEnabled(); + params.put("securitygroupenabled", Boolean.toString(securityGroupEnabled)); + } + return params; + } + @Override public boolean stop() { _resourceMgr.unregisterResourceStateAdapter(this.getClass().getSimpleName()); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixHelper.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixHelper.java index ed890efffa96..c7e39382272f 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixHelper.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixHelper.java @@ -11,16 +11,16 @@ // 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 +// KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package com.cloud.hypervisor.xen.resource; -import org.apache.log4j.Logger; - import java.util.ArrayList; import java.util.HashMap; +import org.apache.log4j.Logger; + /** * Reduce bloat inside CitrixResourceBase * @@ -31,12 +31,14 @@ public class CitrixHelper { private static final HashMap _xcp160GuestOsMap = new HashMap(70); private static final HashMap _xenServerGuestOsMap = new HashMap(70); private static final HashMap _xenServer56FP1GuestOsMap = new HashMap(70); + private static final HashMap _xenServer602GuestOsMap = new HashMap(70); private static final HashMap _xenServer56FP2GuestOsMap = new HashMap(70); private static final HashMap _xenServer600GuestOsMap = new HashMap(70); - private static final HashMap _xenServer602GuestOsMap = new HashMap(70); private static final HashMap _xenServer610GuestOsMap = new HashMap(70); private static final HashMap _xenServer620GuestOsMap = new HashMap(70); + private static final HashMap _xenServer625GuestOsMap = new HashMap(70); private static final HashMap _xenServer620GuestOsMemoryMap = new HashMap(70); + private static final HashMap _xenServer625GuestOsMemoryMap = new HashMap(70); private static final HashMap _xenServer610GuestOsMemoryMap = new HashMap(70); private static final HashMap _xenServer602GuestOsMemoryMap = new HashMap(70); private static final HashMap _xenServer600GuestOsMemoryMap = new HashMap(70); @@ -1532,6 +1534,168 @@ public class CitrixHelper { _xenServer620GuestOsMap.put("Other PV (64-bit)", "CentOS 5 (64-bit)"); } + static { + _xenServer625GuestOsMap.put("CentOS 4.5 (32-bit)", "CentOS 4.5 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 4.6 (32-bit)", "CentOS 4.6 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 4.7 (32-bit)", "CentOS 4.7 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 4.8 (32-bit)", "CentOS 4.8 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.0 (32-bit)", "CentOS 5 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.0 (64-bit)", "CentOS 5 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.1 (32-bit)", "CentOS 5 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.1 (64-bit)", "CentOS 5 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.2 (32-bit)", "CentOS 5 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.2 (64-bit)", "CentOS 5 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.3 (32-bit)", "CentOS 5 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.3 (64-bit)", "CentOS 5 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.4 (32-bit)", "CentOS 5 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.4 (64-bit)", "CentOS 5 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.5 (32-bit)", "CentOS 5 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.5 (64-bit)", "CentOS 5 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.6 (32-bit)", "CentOS 5 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.6 (64-bit)", "CentOS 5 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.7 (32-bit)", "CentOS 5 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.7 (64-bit)", "CentOS 5 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.8 (32-bit)", "CentOS 5 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.8 (64-bit)", "CentOS 5 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.9 (32-bit)", "CentOS 5 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 5.9 (64-bit)", "CentOS 5 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 6.0 (32-bit)", "CentOS 6 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 6.0 (64-bit)", "CentOS 6 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 6.1 (32-bit)", "CentOS 6 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 6.1 (64-bit)", "CentOS 6 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 6.2 (32-bit)", "CentOS 6 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 6.2 (64-bit)", "CentOS 6 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 6.3 (32-bit)", "CentOS 6 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 6.3 (64-bit)", "CentOS 6 (64-bit)"); + _xenServer625GuestOsMap.put("CentOS 6.4 (32-bit)", "CentOS 6 (32-bit)"); + _xenServer625GuestOsMap.put("CentOS 6.4 (64-bit)", "CentOS 6 (64-bit)"); + _xenServer625GuestOsMap.put("Debian GNU/Linux 6(32-bit)", "Debian Squeeze 6.0 (32-bit)"); + _xenServer625GuestOsMap.put("Debian GNU/Linux 6(64-bit)", "Debian Squeeze 6.0 (64-bit)"); + _xenServer625GuestOsMap.put("Debian GNU/Linux 7(32-bit)", "Debian Wheezy 7.0 (32-bit)"); + _xenServer625GuestOsMap.put("Debian GNU/Linux 7(64-bit)", "Debian Wheezy 7.0 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.0 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.0 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.1 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.1 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.2 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.2 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.3 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.3 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.4 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.4 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.5 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.5 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.6 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.6 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.7 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.7 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.8 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.8 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.9 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 5.9 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 6.0 (32-bit)", "Oracle Enterprise Linux 6 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 6.0 (64-bit)", "Oracle Enterprise Linux 6 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 6.1 (32-bit)", "Oracle Enterprise Linux 6 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 6.1 (64-bit)", "Oracle Enterprise Linux 6 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 6.2 (32-bit)", "Oracle Enterprise Linux 6 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 6.2 (64-bit)", "Oracle Enterprise Linux 6 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 6.3 (32-bit)", "Oracle Enterprise Linux 6 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 6.3 (64-bit)", "Oracle Enterprise Linux 6 (64-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 6.4 (32-bit)", "Oracle Enterprise Linux 6 (32-bit)"); + _xenServer625GuestOsMap.put("Oracle Enterprise Linux 6.4 (64-bit)", "Oracle Enterprise Linux 6 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 4.5 (32-bit)", "Red Hat Enterprise Linux 4.5 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 4.6 (32-bit)", "Red Hat Enterprise Linux 4.6 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 4.7 (32-bit)", "Red Hat Enterprise Linux 4.7 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 4.8 (32-bit)", "Red Hat Enterprise Linux 4.8 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.0 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.0 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.1 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.1 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.2 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.2 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.3 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.3 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.4 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.4 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.5 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.5 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.6 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.6 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.7 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.7 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.8 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.8 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.9 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 5.9 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 6.0 (32-bit)", "Red Hat Enterprise Linux 6 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 6.0 (64-bit)", "Red Hat Enterprise Linux 6 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 6.1 (32-bit)", "Red Hat Enterprise Linux 6 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 6.1 (64-bit)", "Red Hat Enterprise Linux 6 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 6.2 (32-bit)", "Red Hat Enterprise Linux 6 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 6.2 (64-bit)", "Red Hat Enterprise Linux 6 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 6.3 (32-bit)", "Red Hat Enterprise Linux 6 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 6.3 (64-bit)", "Red Hat Enterprise Linux 6 (64-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 6.4 (32-bit)", "Red Hat Enterprise Linux 6 (32-bit)"); + _xenServer625GuestOsMap.put("Red Hat Enterprise Linux 6.4 (64-bit)", "Red Hat Enterprise Linux 6 (64-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 10 SP1 (32-bit)", "SUSE Linux Enterprise Server 10 SP1 (32-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 10 SP1 (64-bit)", "SUSE Linux Enterprise Server 10 SP1 (64-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 10 SP2 (32-bit)", "SUSE Linux Enterprise Server 10 SP2 (32-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 10 SP2 (64-bit)", "SUSE Linux Enterprise Server 10 SP2 (64-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 10 SP3 (32-bit)", "SUSE Linux Enterprise Server 10 SP3 (32-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 10 SP3 (64-bit)", "SUSE Linux Enterprise Server 10 SP3 (64-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 10 SP4 (32-bit)", "SUSE Linux Enterprise Server 10 SP4 (32-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 10 SP4 (64-bit)", "SUSE Linux Enterprise Server 10 SP4 (64-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 11 (32-bit)", "SUSE Linux Enterprise Server 11 (32-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 11 (64-bit)", "SUSE Linux Enterprise Server 11 (64-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 11 SP1 (32-bit)", "SUSE Linux Enterprise Server 11 SP1 (32-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 11 SP1 (64-bit)", "SUSE Linux Enterprise Server 11 SP1 (64-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 11 SP2 (32-bit)", "SUSE Linux Enterprise Server 11 SP2 (32-bit)"); + _xenServer625GuestOsMap.put("SUSE Linux Enterprise Server 11 SP2 (64-bit)", "SUSE Linux Enterprise Server 11 SP2 (64-bit)"); + _xenServer625GuestOsMap.put("Windows 7 (32-bit)", "Windows 7 (32-bit)"); + _xenServer625GuestOsMap.put("Windows 7 (64-bit)", "Windows 7 (64-bit)"); + _xenServer625GuestOsMap.put("Windows 7 SP1 (32-bit)", "Windows 7 (32-bit)"); + _xenServer625GuestOsMap.put("Windows 7 SP1 (64-bit)", "Windows 7 (64-bit)"); + _xenServer625GuestOsMap.put("Windows 8 (32-bit)", "Windows 8 (32-bit)"); + _xenServer625GuestOsMap.put("Windows 8 (64-bit)", "Windows 8 (64-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2003 SP2 (32-bit)", "Windows Server 2003 (32-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2003 SP2 (64-bit)", "Windows Server 2003 (64-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2003 PAE (32-bit)", "Windows Server 2003 (32-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2003 Enterprise Edition(32-bit)", "Windows Server 2003 (32-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2003 Enterprise Edition(64-bit)", "Windows Server 2003 (64-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2003 DataCenter Edition(32-bit)", "Windows Server 2003 (32-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2003 DataCenter Edition(64-bit)", "Windows Server 2003 (64-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2003 Standard Edition(32-bit)", "Windows Server 2003 (32-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2003 Standard Edition(64-bit)", "Windows Server 2003 (64-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2008 SP2 (32-bit)", "Windows Server 2008 (34-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2008 SP2 (64-bit)", "Windows Server 2008 (64-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2008 R2 (64-bit)", "Windows Server 2008 R2 (64-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2008 R2 SP1 (64-bit)", "Windows Server 2008 R2 (64-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2012 (64-bit)", "Windows Server 2012 (64-bit)"); + _xenServer625GuestOsMap.put("Windows Server 2012 R2 (64-bit)", "Windows Server 2012 (64-bit)"); + _xenServer625GuestOsMap.put("Windows Vista SP2 (32-bit)", "Windows Vista (32-bit)"); + _xenServer625GuestOsMap.put("Windows XP SP3 (32-bit)", "Windows XP SP3 (32-bit)"); + _xenServer625GuestOsMap.put("Ubuntu 10.04 (32-bit)", "Ubuntu Lucid Lynx 10.04 (32-bit)"); + _xenServer625GuestOsMap.put("Ubuntu 10.04 (64-bit)", "Ubuntu Lucid Lynx 10.04 (64-bit)"); + _xenServer625GuestOsMap.put("Ubuntu 10.10 (32-bit)", "Ubuntu Maverick Meerkat 10.10 (32-bit) (experimental)"); + _xenServer625GuestOsMap.put("Ubuntu 10.10 (64-bit)", "Ubuntu Maverick Meerkat 10.10 (64-bit) (experimental)"); + _xenServer625GuestOsMap.put("Ubuntu 12.04 (32-bit)", "Ubuntu Precise Pangolin 12.04 (32-bit)"); + _xenServer625GuestOsMap.put("Ubuntu 12.04 (64-bit)", "Ubuntu Precise Pangolin 12.04 (64-bit)"); + _xenServer625GuestOsMap.put("Ubuntu 11.04 (32-bit)", "Other install media"); + _xenServer625GuestOsMap.put("Ubuntu 11.04 (64-bit)", "Other install media"); + _xenServer625GuestOsMap.put("Other Linux (32-bit)", "Other install media"); + _xenServer625GuestOsMap.put("Other Linux (64-bit)", "Other install media"); + _xenServer625GuestOsMap.put("Other (32-bit)", "Other install media"); + _xenServer625GuestOsMap.put("Other (64-bit)", "Other install media"); + _xenServer625GuestOsMap.put("Other CentOS (32-bit)", "Other install media"); + _xenServer625GuestOsMap.put("Other CentOS (64-bit)", "Other install media"); + _xenServer625GuestOsMap.put("Other Ubuntu (32-bit)", "Other install media"); + _xenServer625GuestOsMap.put("Other Ubuntu (64-bit)", "Other install media"); + _xenServer625GuestOsMap.put("Other SUSE Linux(32-bit)", "Other install media"); + _xenServer625GuestOsMap.put("Other SUSE Linux(64-bit)", "Other install media"); + _xenServer625GuestOsMap.put("Other PV (32-bit)", "CentOS 5 (32-bit)"); + _xenServer625GuestOsMap.put("Other PV (64-bit)", "CentOS 5 (64-bit)"); + } + public static class MemoryValues { long max; long min; @@ -1823,6 +1987,147 @@ public long getMin() { _xenServer620GuestOsMemoryMap.put("Ubuntu 12.04 (64-bit)", new MemoryValues(128l, 128*1024l)); } + static { + _xenServer625GuestOsMemoryMap.put("CentOS 4.5 (32-bit)", new MemoryValues(256l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 4.6 (32-bit)", new MemoryValues(256l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 4.7 (32-bit)", new MemoryValues(256l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 4.8 (32-bit)", new MemoryValues(256l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.0 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.0 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.1 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.1 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.2 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.2 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.3 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.3 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.4 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.4 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.5 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.5 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.6 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.6 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.7 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.7 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.8 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.8 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.9 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 5.9 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 6.0 (32-bit)", new MemoryValues(512l, 8 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 6.0 (64-bit)", new MemoryValues(512l, 32 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 6.1 (32-bit)", new MemoryValues(512l, 8 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 6.1 (64-bit)", new MemoryValues(512l, 32 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 6.2 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 6.2 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 6.3 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 6.3 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 6.4 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("CentOS 6.4 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Debian GNU/Linux 6(32-bit)", new MemoryValues(128l, 32 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Debian GNU/Linux 6(64-bit)", new MemoryValues(128l, 32 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Debian GNU/Linux 7(32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Debian GNU/Linux 7(64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.0 (32-bit)", new MemoryValues(512l, 64 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.0 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.1 (32-bit)", new MemoryValues(512l, 64 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.1 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.2 (32-bit)", new MemoryValues(512l, 64 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.2 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.3 (32-bit)", new MemoryValues(512l, 64 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.3 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.4 (32-bit)", new MemoryValues(512l, 64 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.4 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.5 (32-bit)", new MemoryValues(512l, 64 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.5 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.6 (32-bit)", new MemoryValues(512l, 64 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.6 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.7 (32-bit)", new MemoryValues(512l, 64 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.7 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.8 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.8 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.9 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 5.9 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 6.0 (32-bit)", new MemoryValues(512l, 8 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 6.0 (64-bit)", new MemoryValues(512l, 32 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 6.1 (32-bit)", new MemoryValues(512l, 8 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 6.1 (64-bit)", new MemoryValues(512l, 32 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 6.2 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 6.2 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 6.3 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 6.3 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 6.4 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Oracle Enterprise Linux 6.4 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 4.5 (32-bit)", new MemoryValues(256l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 4.6 (32-bit)", new MemoryValues(256l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 4.7 (32-bit)", new MemoryValues(256l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 4.8 (32-bit)", new MemoryValues(256l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.0 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.0 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.1 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.1 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.2 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.2 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.3 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.3 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.4 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.4 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.5 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.5 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.6 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.6 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.7 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.7 (64-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.8 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.8 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.9 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 5.9 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 6.0 (32-bit)", new MemoryValues(512l, 8 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 6.0 (64-bit)", new MemoryValues(512l, 32 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 6.1 (32-bit)", new MemoryValues(512l, 8 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 6.1 (64-bit)", new MemoryValues(512l, 32 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 6.2 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 6.2 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 6.3 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 6.3 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 6.4 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Red Hat Enterprise Linux 6.4 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 10 SP1 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 10 SP1 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 10 SP2 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 10 SP2 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 10 SP3 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 10 SP3 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 10 SP4 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 10 SP4 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 11 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 11 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 11 SP1 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 11 SP1 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 11 SP2 (32-bit)", new MemoryValues(512l, 16 * 1024l)); + _xenServer625GuestOsMemoryMap.put("SUSE Linux Enterprise Server 11 SP2 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + + _xenServer625GuestOsMemoryMap.put("Windows 7 (32-bit)", new MemoryValues(1024l, 4 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows 7 (64-bit)", new MemoryValues(2 * 1024l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows 7 SP1 (32-bit)", new MemoryValues(1024l, 4 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows 7 SP1 (64-bit)", new MemoryValues(2 * 1024l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows 8 (32-bit)", new MemoryValues(1024l, 4 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows 8 (64-bit)", new MemoryValues(2 * 1024l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows Server 2003 SP2 (32-bit)", new MemoryValues(256l, 64 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows Server 2003 SP2 (64-bit)", new MemoryValues(256l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows Server 2008 SP2 (32-bit)", new MemoryValues(512l, 64 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows Server 2008 SP2 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows Server 2008 R2 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows Server 2008 R2 SP1 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows Server 2012 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows Server 2012 R2 (64-bit)", new MemoryValues(512l, 128 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows Vista SP2 (32-bit)", new MemoryValues(1024l, 4 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Windows XP SP3 (32-bit)", new MemoryValues(256l, 4 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Ubuntu 10.04 (32-bit)", new MemoryValues(128l, 512l)); + _xenServer625GuestOsMemoryMap.put("Ubuntu 10.04 (64-bit)", new MemoryValues(128l, 32 * 1024l)); + //_xenServer620GuestOsMemoryMap.put("Ubuntu 10.10 (32-bit)", new MemoryValues(512l, 16*1024l));//? + //_xenServer620GuestOsMemoryMap.put("Ubuntu 10.10 (64-bit)", new MemoryValues(512l, 16*1024l)); //? + _xenServer625GuestOsMemoryMap.put("Ubuntu 12.04 (32-bit)", new MemoryValues(128l, 32 * 1024l)); + _xenServer625GuestOsMemoryMap.put("Ubuntu 12.04 (64-bit)", new MemoryValues(128l, 128 * 1024l)); + } public static String getXcpGuestOsType(String stdType) { String guestOS = _xcp100GuestOsMap.get(stdType); @@ -1857,7 +2162,7 @@ public static String getXenServerGuestOsType(String stdType, boolean bootFromCD) return guestOS; } - public static String getXenServer56FP1GuestOsType(String stdType, boolean bootFromCD) { + public static String getXenServer56FP1GuestOsType(String stdType, boolean bootFromCD) { String guestOS = _xenServer56FP1GuestOsMap.get(stdType); if (guestOS == null) { if ( !bootFromCD ) { @@ -2023,6 +2328,20 @@ public static String getXenServer620GuestOsType(String stdType, boolean bootFrom return guestOS; } + public static String getXenServer625GuestOsType(String stdType, boolean bootFromCD) { + String guestOS = _xenServer625GuestOsMap.get(stdType); + if (guestOS == null) { + if (!bootFromCD) { + s_logger.debug("Can't find the guest os: " + stdType + " mapping into XenServer 6.2.5 guestOS type, start it as HVM guest"); + guestOS = "Other install media"; + } else { + String msg = "XenServer 6.2.5 DOES NOT support Guest OS type " + stdType; + s_logger.warn(msg); + } + } + return guestOS; + } + public static long getXenServer620StaticMax(String stdType, boolean bootFromCD) { MemoryValues recommendedMaxMinMemory = _xenServer620GuestOsMemoryMap.get(stdType); if (recommendedMaxMinMemory == null) { @@ -2038,4 +2357,20 @@ public static long getXenServer620StaticMin(String stdType, boolean bootFromCD) } return recommendedMaxMinMemory.getMin(); } + + public static long getXenServer625StaticMax(String stdType, boolean bootFromCD) { + MemoryValues recommendedMaxMinMemory = _xenServer625GuestOsMemoryMap.get(stdType); + if (recommendedMaxMinMemory == null) { + return 0l; + } + return recommendedMaxMinMemory.getMax(); + } + + public static long getXenServer625StaticMin(String stdType, boolean bootFromCD) { + MemoryValues recommendedMaxMinMemory = _xenServer625GuestOsMemoryMap.get(stdType); + if (recommendedMaxMinMemory == null) { + return 0l; + } + return recommendedMaxMinMemory.getMin(); + } } \ No newline at end of file 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 69b7c9e07c75..7199d287ac01 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 @@ -16,13 +16,51 @@ // under the License. package com.cloud.hypervisor.xen.resource; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Queue; +import java.util.Random; +import java.util.Set; +import java.util.UUID; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.cloudstack.storage.command.StorageSubSystemCommand; +import org.apache.cloudstack.storage.to.TemplateObjectTO; +import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; +import org.apache.xmlrpc.XmlRpcException; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; import com.cloud.agent.api.AttachIsoCommand; import com.cloud.agent.api.AttachVolumeAnswer; import com.cloud.agent.api.AttachVolumeCommand; -import com.cloud.agent.api.BackupSnapshotAnswer; -import com.cloud.agent.api.BackupSnapshotCommand; import com.cloud.agent.api.BumpUpPriorityCommand; import com.cloud.agent.api.CheckHealthAnswer; import com.cloud.agent.api.CheckHealthCommand; @@ -40,13 +78,9 @@ import com.cloud.agent.api.ClusterSyncAnswer; import com.cloud.agent.api.ClusterSyncCommand; import com.cloud.agent.api.Command; -import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand; -import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand; import com.cloud.agent.api.CreateStoragePoolCommand; import com.cloud.agent.api.CreateVMSnapshotAnswer; import com.cloud.agent.api.CreateVMSnapshotCommand; -import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer; -import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; import com.cloud.agent.api.DeleteStoragePoolCommand; import com.cloud.agent.api.DeleteVMSnapshotAnswer; import com.cloud.agent.api.DeleteVMSnapshotCommand; @@ -63,10 +97,9 @@ 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; -import com.cloud.agent.api.ManageSnapshotCommand; import com.cloud.agent.api.MigrateAnswer; import com.cloud.agent.api.MigrateCommand; import com.cloud.agent.api.ModifySshKeysCommand; @@ -118,12 +151,37 @@ import com.cloud.agent.api.proxy.CheckConsoleProxyLoadCommand; import com.cloud.agent.api.proxy.ConsoleProxyLoadAnswer; import com.cloud.agent.api.proxy.WatchConsoleProxyLoadCommand; -import com.cloud.agent.api.routing.*; -import com.cloud.agent.api.storage.CopyVolumeAnswer; -import com.cloud.agent.api.storage.CopyVolumeCommand; +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.IpAssocAnswer; +import com.cloud.agent.api.routing.IpAssocCommand; +import com.cloud.agent.api.routing.IpAssocVpcCommand; +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.SetFirewallRulesAnswer; +import com.cloud.agent.api.routing.SetFirewallRulesCommand; +import com.cloud.agent.api.routing.SetMonitorServiceCommand; +import com.cloud.agent.api.routing.SetNetworkACLAnswer; +import com.cloud.agent.api.routing.SetNetworkACLCommand; +import com.cloud.agent.api.routing.SetPortForwardingRulesAnswer; +import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; +import com.cloud.agent.api.routing.SetPortForwardingRulesVpcCommand; +import com.cloud.agent.api.routing.SetSourceNatAnswer; +import com.cloud.agent.api.routing.SetSourceNatCommand; +import com.cloud.agent.api.routing.SetStaticNatRulesAnswer; +import com.cloud.agent.api.routing.SetStaticNatRulesCommand; +import com.cloud.agent.api.routing.SetStaticRouteAnswer; +import com.cloud.agent.api.routing.SetStaticRouteCommand; +import com.cloud.agent.api.routing.Site2SiteVpnCfgCommand; +import com.cloud.agent.api.routing.VmDataCommand; +import com.cloud.agent.api.routing.VpnUsersCfgCommand; import com.cloud.agent.api.storage.CreateAnswer; import com.cloud.agent.api.storage.CreateCommand; -import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer; import com.cloud.agent.api.storage.DestroyCommand; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; @@ -138,16 +196,13 @@ import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.PortForwardingRuleTO; -import com.cloud.agent.api.to.S3TO; import com.cloud.agent.api.to.StaticNatRuleTO; import com.cloud.agent.api.to.StorageFilerTO; -import com.cloud.agent.api.to.SwiftTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.api.to.VolumeTO; import com.cloud.exception.InternalErrorException; import com.cloud.host.Host.Type; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.hypervisor.xen.resource.CitrixHelper; import com.cloud.network.HAProxyConfigurator; import com.cloud.network.LoadBalancerConfigurator; import com.cloud.network.Networks; @@ -171,7 +226,6 @@ import com.cloud.resource.ServerResource; import com.cloud.resource.hypervisor.HypervisorResource; import com.cloud.storage.Storage; -import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; @@ -181,13 +235,14 @@ import com.cloud.template.VirtualMachineTemplate.BootloaderType; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; -import com.cloud.utils.Ternary; -import com.cloud.utils.S3Utils; import com.cloud.utils.StringUtils; +import com.cloud.utils.Ternary; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; +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.cloud.vm.snapshot.VMSnapshot; import com.google.gson.Gson; @@ -225,48 +280,6 @@ 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; -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; -import org.apache.xmlrpc.XmlRpcException; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -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; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringReader; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Queue; -import java.util.Random; -import java.util.Set; -import java.util.UUID; - -import static com.cloud.utils.ReflectUtil.flattenProperties; -import static com.google.common.collect.Lists.newArrayList; /** * CitrixResourceBase encapsulates the calls to the XenServer Xapi process @@ -347,6 +360,17 @@ public boolean equals(String type) { } } + 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 +380,7 @@ public boolean equals(String type) { s_statesTable.put(Types.VmPowerState.SUSPENDED, State.Running); s_statesTable.put(Types.VmPowerState.UNRECOGNIZED, State.Unknown); } + // TODO vmsync } public XsHost getHost() { return _host; @@ -405,23 +430,12 @@ protected boolean pingdomr(Connection conn, String host, String port) { } protected boolean pingXenServer() { - Session slaveSession = null; - Connection slaveConn = null; + Connection conn = getConnection(); try { - URL slaveUrl = null; - slaveUrl = _connPool.getURL(_host.ip); - slaveConn = new Connection(slaveUrl, 10); - slaveSession = _connPool.slaveLocalLoginWithPassword(slaveConn, _username, _password); + callHostPlugin(conn, "echo", "main"); return true; } catch (Exception e) { - } finally { - if( slaveSession != null ){ - try{ - Session.localLogout(slaveConn); - } catch (Exception e) { - } - slaveConn.dispose(); - } + s_logger.debug("cannot ping host " + _host.ip + " due to " + e.toString(), e); } return false; } @@ -490,24 +504,12 @@ public Answer executeRequest(Command cmd) { return execute((ModifyStoragePoolCommand) cmd); } else if (clazz == DeleteStoragePoolCommand.class) { return execute((DeleteStoragePoolCommand) cmd); - } else if (clazz == CopyVolumeCommand.class) { - return execute((CopyVolumeCommand) cmd); - } else if (clazz == ResizeVolumeCommand.class) { + }else if (clazz == ResizeVolumeCommand.class) { return execute((ResizeVolumeCommand) cmd); } else if (clazz == AttachVolumeCommand.class) { return execute((AttachVolumeCommand) cmd); } else if (clazz == AttachIsoCommand.class) { return execute((AttachIsoCommand) cmd); - } else if (clazz == ManageSnapshotCommand.class) { - return execute((ManageSnapshotCommand) cmd); - } else if (clazz == BackupSnapshotCommand.class) { - return execute((BackupSnapshotCommand) cmd); - } else if (clazz == CreateVolumeFromSnapshotCommand.class) { - return execute((CreateVolumeFromSnapshotCommand) cmd); - } else if (clazz == CreatePrivateTemplateFromVolumeCommand.class) { - return execute((CreatePrivateTemplateFromVolumeCommand) cmd); - } else if (clazz == CreatePrivateTemplateFromSnapshotCommand.class) { - return execute((CreatePrivateTemplateFromSnapshotCommand) cmd); } else if (clazz == UpgradeSnapshotCommand.class) { return execute((UpgradeSnapshotCommand) cmd); } else if (clazz == GetStorageStatsCommand.class) { @@ -641,12 +643,12 @@ protected void scaleVM(Connection conn, VM vm, VirtualMachineTO vmSpec, Host hos if (vmSpec.getLimitCpuUse()) { long utilization = 0; // max CPU cap, default is unlimited - utilization = (int) ((speed * 0.99 * vmSpec.getCpus()) / _host.speed * 100); + utilization = (int) ((vmSpec.getMaxSpeed() * 0.99 * vmSpec.getCpus()) / _host.speed * 100); //vm.addToVCPUsParamsLive(conn, "cap", Long.toString(utilization)); currently xenserver doesnot support Xapi to add VCPUs params live. - callHostPlugin(conn, "vmops", "add_to_VCPUs_params_live", "key", "cap", "value", Long.toString(utilization), "vmname", vmSpec.getName() ); + callHostPlugin(conn, "vmops", "add_to_VCPUs_params_live", "key", "cap", "value", Long.toString(utilization), "vmname", vmSpec.getName()); } //vm.addToVCPUsParamsLive(conn, "weight", Integer.toString(cpuWeight)); - callHostPlugin(conn, "vmops", "add_to_VCPUs_params_live", "key", "weight", "value", Integer.toString(cpuWeight), "vmname", vmSpec.getName() ); + callHostPlugin(conn, "vmops", "add_to_VCPUs_params_live", "key", "weight", "value", Integer.toString(cpuWeight), "vmname", vmSpec.getName()); } } @@ -844,7 +846,7 @@ private void enableXenServerNetwork(Connection conn, Network nw, Set dom0Vifs = dom0.getVIFs(conn); for (VIF vif:dom0Vifs) { vif.getRecord(conn); - if (vif.getNetwork(conn).getUuid(conn) == nw.getUuid(conn)) { + if (vif.getNetwork(conn).getUuid(conn).equals(nw.getUuid(conn))) { dom0vif = vif; s_logger.debug("A VIF for dom0 has already been found - No need to create one"); } @@ -868,7 +870,12 @@ private void enableXenServerNetwork(Connection conn, Network nw, dom0vif = VIF.create(conn, vifr); } // At this stage we surely have a VIF - dom0vif.plug(conn); + try { + dom0vif.plug(conn); + } catch (Exception e) { + // though wierd exception is thrown, VIF actually gets plugged-in to dom0, so just ignore exception + s_logger.info("Ignoring the benign error thrown while plugging VIF to dom0"); + } dom0vif.unplug(conn); synchronized(_tmpDom0Vif) { _tmpDom0Vif.add(dom0vif); @@ -966,7 +973,7 @@ private synchronized Network configureTunnelNetwork(Connection conn, long networ String result = callHostPlugin(conn, "ovstunnel", "setup_ovs_bridge", "bridge", bridge, "key", String.valueOf(key), "xs_nw_uuid", nw.getUuid(conn), - "cs_host_id", ((Long)hostId).toString()); + "cs_host_id", ((Long) hostId).toString()); //Note down the fact that the ovs bridge has been setup String[] res = result.split(":"); if (res.length != 2 || !res[0].equalsIgnoreCase("SUCCESS")) { @@ -1065,8 +1072,7 @@ protected VIF createVif(Connection conn, String vmName, VM vm, VirtualMachineTO // Provide XAPI with the cloudstack vm and nic uids. vifr.otherConfig.put("cloudstack-nic-id", nic.getUuid()); if (vmSpec != null) { - vifr.otherConfig.put("cloudstack-vm-id", vmSpec.getUuid()); - } + vifr.otherConfig.put("cloudstack-vm-id", vmSpec.getUuid()); } vifr.network = getNetwork(conn, nic); @@ -1188,6 +1194,10 @@ protected VBD createVbd(Connection conn, DiskTO volume, String vmName, VM vm, Bo } if ( vdi != null ) { + if ("detached".equals(vdi.getNameLabel(conn))) { + vdi.setNameLabel(conn, vmName + "-DATA"); + } + Map smConfig = vdi.getSmConfig(conn); for (String key : smConfig.keySet()) { if (key.startsWith("host_")) { @@ -1230,7 +1240,7 @@ protected VBD createVbd(Connection conn, DiskTO volume, String vmName, VM vm, Bo return vbd; } - + public long getStaticMax(String os, boolean b, long dynamicMinRam, long dynamicMaxRam){ return dynamicMaxRam; @@ -1255,6 +1265,8 @@ protected VM createVmFromTemplate(Connection conn, VirtualMachineTO vmSpec, Host vmr.nameLabel = vmSpec.getName(); vmr.actionsAfterCrash = Types.OnCrashBehaviour.DESTROY; vmr.actionsAfterShutdown = Types.OnNormalExit.DESTROY; + vmr.VCPUsMax = (long) vmSpec.getCpus(); // FIX ME: In case of dynamic scaling this VCPU max should be the minumum of + // recommended value for that template and capacity remaining on host if (isDmcEnabled(conn, host) && vmSpec.isEnableDynamicallyScaleVm()) { //scaling is allowed @@ -1262,6 +1274,14 @@ protected VM createVmFromTemplate(Connection conn, VirtualMachineTO vmSpec, Host vmr.memoryStaticMax = getStaticMax(vmSpec.getOs(), vmSpec.getBootloader() == BootloaderType.CD, vmSpec.getMinRam(), vmSpec.getMaxRam()); vmr.memoryDynamicMin = vmSpec.getMinRam(); vmr.memoryDynamicMax = vmSpec.getMaxRam(); + + if (guestOsTypeName.toLowerCase().contains("windows")) { + vmr.VCPUsMax = (long) vmSpec.getCpus(); + } else { + if (vmSpec.getVcpuMaxLimit() != null) { + vmr.VCPUsMax = (long) vmSpec.getVcpuMaxLimit(); + } + } } else { //scaling disallowed, set static memory target if (vmSpec.isEnableDynamicallyScaleVm() && !isDmcEnabled(conn, host)) { @@ -1271,29 +1291,8 @@ protected VM createVmFromTemplate(Connection conn, VirtualMachineTO vmSpec, Host vmr.memoryStaticMax = vmSpec.getMaxRam(); vmr.memoryDynamicMin = vmSpec.getMinRam(); vmr.memoryDynamicMax = vmSpec.getMaxRam(); - } - if (guestOsTypeName.toLowerCase().contains("windows")) { vmr.VCPUsMax = (long) vmSpec.getCpus(); - } else { - vmr.VCPUsMax = 32L; - } - - Map details = vmSpec.getDetails(); - if ( details != null ) { - String timeoffset = details.get("timeoffset"); - if (timeoffset != null) { - Map platform = vmr.platform; - platform.put("timeoffset", timeoffset); - vmr.platform = platform; - } - - String coresPerSocket = details.get("cpu.corespersocket"); - if (coresPerSocket != null) { - Map platform = vmr.platform; - platform.put("cores-per-socket", coresPerSocket); - vmr.platform = platform; - } } vmr.VCPUsAtStartup = (long) vmSpec.getCpus(); @@ -1320,7 +1319,7 @@ protected VM createVmFromTemplate(Connection conn, VirtualMachineTO vmSpec, Host if (vmSpec.getLimitCpuUse()) { // CPU cap is per VM, so need to assign cap based on the number of vcpus - utilization = (int) ((speed * 0.99 * vmSpec.getCpus()) / _host.speed * 100); + utilization = (int) ((vmSpec.getMaxSpeed() * 0.99 * vmSpec.getCpus()) / _host.speed * 100); } vcpuParams.put("weight", Integer.toString(cpuWeight)); @@ -1377,12 +1376,43 @@ protected VM createVmFromTemplate(Connection conn, VirtualMachineTO vmSpec, Host } return vm; } - - + + protected void finalizeVmMetaData(VM vm, Connection conn, VirtualMachineTO vmSpec) throws Exception { + + Map details = vmSpec.getDetails(); + if ( details != null ) { + String platformstring = details.get("platform"); + if (platformstring != null && !platformstring.isEmpty() ) { + Map platform = StringUtils.stringToMap(platformstring); + vm.setPlatform(conn, platform); + } else { + String timeoffset = details.get("timeoffset"); + if (timeoffset != null) { + Map platform = vm.getPlatform(conn); + platform.put("timeoffset", timeoffset); + vm.setPlatform(conn, platform); + } + String coresPerSocket = details.get("cpu.corespersocket"); + if (coresPerSocket != null) { + Map platform = vm.getPlatform(conn); + platform.put("cores-per-socket", coresPerSocket); + vm.setPlatform(conn, platform); + } + + String xentoolsversion = details.get("hypervisortoolsversion"); + if ( xentoolsversion == null || !xentoolsversion.equalsIgnoreCase("xenserver61") ) { + Map platform = vm.getPlatform(conn); + platform.remove("device_id"); + vm.setPlatform(conn, platform); + } + + } + } } + protected String handleVmStartFailure(Connection conn, String vmName, VM vm, String message, Throwable th) { String msg = "Unable to start " + vmName + " due to " + message; s_logger.warn(msg, th); @@ -1658,37 +1688,15 @@ public StartAnswer execute(StartCommand cmd) { vm = createVmFromTemplate(conn, vmSpec, host); for (DiskTO disk : vmSpec.getDisks()) { - VDI vdi = null; - - if (disk.getData() instanceof VolumeObjectTO) { - Map details = disk.getDetails(); - boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - - if (isManaged) { - String iScsiName = details.get(DiskTO.IQN); - String storageHost = details.get(DiskTO.STORAGE_HOST); - String chapInitiatorUsername = disk.getDetails().get(DiskTO.CHAP_INITIATOR_USERNAME); - String chapInitiatorSecret = disk.getDetails().get(DiskTO.CHAP_INITIATOR_SECRET); - Long volumeSize = Long.parseLong(details.get(DiskTO.VOLUME_SIZE)); - String vdiNameLabel = vmName + "-DATA"; + VDI newVdi = prepareManagedDisk(conn, disk, vmName); - SR sr = getIscsiSR(conn, iScsiName, storageHost, iScsiName, - chapInitiatorUsername, chapInitiatorSecret, true); + if (newVdi != null) { + String path = newVdi.getUuid(conn); - vdi = getVDIbyUuid(conn, disk.getPath(), false); - - if (vdi == null) { - vdi = createVdi(sr, vdiNameLabel, volumeSize); - - iqnToPath.put(iScsiName, vdi.getUuid(conn)); - } - else { - vdi.setNameLabel(conn, vdiNameLabel); - } - } + iqnToPath.put(disk.getDetails().get(DiskTO.IQN), path); } - createVbd(conn, disk, vmName, vm, vmSpec.getBootloader(), vdi); + createVbd(conn, disk, vmName, vm, vmSpec.getBootloader(), newVdi); } if (vmSpec.getType() != VirtualMachine.Type.User) { @@ -1795,47 +1803,54 @@ public StartAnswer execute(StartCommand cmd) { s_logger.debug("The VM is in stopped state, detected problem during startup : " + vmName); } } - - if (state != State.Running) { - disconnectManagedVolumes(conn, vm); - } } } - private void disconnectManagedVolumes(Connection conn, VM vm) { - try { - Set vbds = vm.getVBDs(conn); + // the idea here is to see if the DiskTO in question is from managed storage and + // does not yet have an SR + // if no SR, create it and create a VDI in it + private VDI prepareManagedDisk(Connection conn, DiskTO disk, String vmName) throws Exception { + Map details = disk.getDetails(); - for (VBD vbd : vbds) { - VDI vdi = vbd.getVDI(conn); - SR sr = null; + if (details == null) { + return null; + } - try { - sr = vdi.getSR(conn); - } - catch (Exception ex) { - continue; - } + boolean isManaged = new Boolean(details.get(DiskTO.MANAGED)).booleanValue(); - if (sr.getNameLabel(conn).startsWith("/iqn.")) { - VBD.Record vbdr = vbd.getRecord(conn); + if (!isManaged) { + return null; + } - if (vbdr.currentlyAttached) { - vbd.unplug(conn); - } + String iqn = details.get(DiskTO.IQN); - vbd.destroy(conn); + Set srNameLabels = SR.getByNameLabel(conn, iqn); + + if (srNameLabels.size() != 0) { + return null; + } - vdi.setNameLabel(conn, "detached"); + String vdiNameLabel = vmName + "-DATA"; - umount(conn, vdi); + return prepareManagedStorage(conn, details, null, vdiNameLabel); + } - handleSrAndVdiDetach(sr.getNameLabel(conn)); - } - } - } catch (Exception ex) { - s_logger.debug(ex.getMessage()); + protected VDI prepareManagedStorage(Connection conn, Map details, String path, String vdiNameLabel) throws Exception { + String iScsiName = details.get(DiskTO.IQN); + String storageHost = details.get(DiskTO.STORAGE_HOST); + String chapInitiatorUsername = details.get(DiskTO.CHAP_INITIATOR_USERNAME); + String chapInitiatorSecret = details.get(DiskTO.CHAP_INITIATOR_SECRET); + Long volumeSize = Long.parseLong(details.get(DiskTO.VOLUME_SIZE)); + + SR sr = getIscsiSR(conn, iScsiName, storageHost, iScsiName, chapInitiatorUsername, chapInitiatorSecret, true); + + VDI vdi = getVDIbyUuid(conn, path, false); + + if (vdi == null) { + vdi = createVdi(sr, vdiNameLabel, volumeSize); } + + return vdi; } protected Answer execute(ModifySshKeysCommand cmd) { @@ -1931,7 +1946,7 @@ private Answer execute(BumpUpPriorityCommand cmd) { protected MaintainAnswer execute(MaintainCommand cmd) { Connection conn = getConnection(); try { - + Host host = Host.getByUuid(conn, _host.uuid); // remove all tags cloud stack Host.Record hr = host.getRecord(conn); @@ -2357,7 +2372,8 @@ protected Answer execute(final SavePasswordCommand cmd) { protected void assignPublicIpAddress(Connection conn, String vmName, String privateIpAddress, String publicIpAddress, boolean add, boolean firstIP, - boolean sourceNat, String vlanId, String vlanGateway, String vlanNetmask, String vifMacAddress, Integer networkRate, TrafficType trafficType, String name) throws InternalErrorException { + boolean sourceNat, String vlanId, String vlanGateway, String vlanNetmask, String vifMacAddress, Integer networkRate, TrafficType trafficType, String name, + int numOfips) throws InternalErrorException { try { VM router = getVM(conn, vmName); @@ -2448,6 +2464,11 @@ protected void assignPublicIpAddress(Connection conn, String vmName, String priv throw new InternalErrorException("Xen plugin \"ipassoc\" failed."); } + //there is only only ip in public subnet and it is deleted so unplug the vif + if (numOfips == 1 && !add) { + removeVif = true; + } + if (removeVif) { network = correctVif.getNetwork(conn); @@ -2549,14 +2570,19 @@ protected Answer execute(IpAssocCommand cmd) { Connection conn = getConnection(); String[] results = new String[cmd.getIpAddresses().length]; int i = 0; + int numOfIps = 0; String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP); try { IpAddressTO[] ips = cmd.getIpAddresses(); + if (ips != null) { + numOfIps = ips.length; + } + for (IpAddressTO ip : ips) { assignPublicIpAddress(conn, routerName, routerIp, ip.getPublicIp(), ip.isAdd(), ip.isFirstIP(), ip.isSourceNat(), ip.getBroadcastUri(), - ip.getVlanGateway(), ip.getVlanNetmask(), ip.getVifMacAddress(), ip.getNetworkRate(), ip.getTrafficType(), ip.getNetworkName()); + ip.getVlanGateway(), ip.getVlanNetmask(), ip.getVifMacAddress(), ip.getNetworkRate(), ip.getTrafficType(), ip.getNetworkName(), numOfIps); results[i++] = ip.getPublicIp() + " - success"; } } catch (InternalErrorException e) { @@ -2612,7 +2638,7 @@ protected long[] getNetworkStats(Connection conn, String privateIP) { /** * This is the method called for getting the HOST stats - * + * * @param cmd * @return */ @@ -2976,6 +3002,60 @@ protected State convertToState(Types.VmPowerState 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; @@ -3007,7 +3087,7 @@ protected HashMap> getAllVms(Connection c s_logger.trace("VM " + record.nameLabel + ": powerstate = " + ps + "; vm state=" + state.toString()); } Host host = record.residentOn; - String xstoolsversion = getVMXenToolsVersion(record.platform); + String platformstring = StringUtils.mapToString(record.platform); String host_uuid = null; if( ! isRefNull(host) ) { try { @@ -3019,12 +3099,13 @@ protected HashMap> getAllVms(Connection c } catch (XmlRpcException e) { s_logger.error("Failed to get host uuid for host " + host.toWireString(), e); } - vmStates.put(record.nameLabel, new Ternary(host_uuid, state, xstoolsversion)); + vmStates.put(record.nameLabel, new Ternary(host_uuid, state, platformstring)); } } return vmStates; } + // TODO vmsync } protected State getVmState(Connection conn, final String vmName) { int retry = 3; @@ -3368,7 +3449,7 @@ protected MigrateAnswer execute(final MigrateCommand cmd) { Set vbds = vm.getVBDs(conn); for( VBD vbd : vbds) { VBD.Record vbdRec = vbd.getRecord(conn); - if( vbdRec.type.equals(Types.VbdType.CD.toString()) && !vbdRec.empty ) { + if( vbdRec.type.equals(Types.VbdType.CD) && !vbdRec.empty ) { vbd.eject(conn); break; } @@ -3437,13 +3518,21 @@ protected Pair getControlDomain(Connection conn) throws XenAPIExc } + protected void umountSnapshotDir(Connection conn, Long dcId) { + try { + callHostPlugin(conn, "vmopsSnapshot", "unmountSnapshotsDir", "dcId", dcId.toString()); + } catch (Exception e) { + s_logger.debug("Failed to umount snapshot dir",e); + } + } + protected ReadyAnswer execute(ReadyCommand cmd) { Connection conn = getConnection(); Long dcId = cmd.getDataCenterId(); // Ignore the result of the callHostPlugin. Even if unmounting the // snapshots dir fails, let Ready command // succeed. - callHostPlugin(conn, "vmopsSnapshot", "unmountSnapshotsDir", "dcId", dcId.toString()); + umountSnapshotDir(conn, dcId); setupLinkLocalNetwork(conn); // try to destroy CD-ROM device for all system VMs on this host @@ -3853,113 +3942,6 @@ protected VDI cloudVDIcopy(Connection conn, VDI vdi, SR sr, int wait) throws Xen } } - boolean swiftDownload(Connection conn, SwiftTO swift, String container, String rfilename, String dir, String lfilename, Boolean remote) { - String result = null; - try { - result = callHostPluginAsync(conn, "swiftxen", "swift", 60 * 60, - "op", "download", "url", swift.getUrl(), "account", swift.getAccount(), - "username", swift.getUserName(), "key", swift.getKey(), "rfilename", rfilename, - "dir", dir, "lfilename", lfilename, "remote", remote.toString()); - if( result != null && result.equals("true")) { - return true; - } - } catch (Exception e) { - s_logger.warn("swift download failed due to ", e); - } - return false; - } - - boolean swiftUpload(Connection conn, SwiftTO swift, String container, String ldir, String lfilename, Boolean isISCSI, int wait) { - String result = null; - try { - result = callHostPluginAsync(conn, "swiftxen", "swift", wait, - "op", "upload", "url", swift.getUrl(), "account", swift.getAccount(), - "username", swift.getUserName(), "key", swift.getKey(), "container", container, - "ldir", ldir, "lfilename", lfilename, "isISCSI", isISCSI.toString()); - if( result != null && result.equals("true")) { - return true; - } - } catch (Exception e) { - s_logger.warn("swift upload failed due to " + e.toString(), e); - } - return false; - } - - boolean swiftDelete(Connection conn, SwiftTO swift, String rfilename) { - String result = null; - try { - result = callHostPlugin(conn, "swiftxen", "swift", - "op", "delete", "url", swift.getUrl(), "account", swift.getAccount(), - "username", swift.getUserName(), "key", swift.getKey(), "rfilename", rfilename); - if( result != null && result.equals("true")) { - return true; - } - } catch (Exception e) { - s_logger.warn("swift download failed due to ", e); - } - return false; - } - - public String swiftBackupSnapshot(Connection conn, SwiftTO swift, String srUuid, String snapshotUuid, String container, Boolean isISCSI, int wait) { - String lfilename; - String ldir; - if ( isISCSI ) { - ldir = "/dev/VG_XenStorage-" + srUuid; - lfilename = "VHD-" + snapshotUuid; - } else { - ldir = "/var/run/sr-mount/" + srUuid; - lfilename = snapshotUuid + ".vhd"; - } - swiftUpload(conn, swift, container, ldir, lfilename, isISCSI, wait); - return lfilename; - } - - - protected String backupSnapshot(Connection conn, String primaryStorageSRUuid, Long dcId, Long accountId, - Long volumeId, String secondaryStorageMountPath, String snapshotUuid, String prevBackupUuid, Boolean isISCSI, int wait, Long secHostId) { - String backupSnapshotUuid = null; - - if (prevBackupUuid == null) { - prevBackupUuid = ""; - } - - // Each argument is put in a separate line for readability. - // Using more lines does not harm the environment. - String backupUuid = UUID.randomUUID().toString(); - String results = callHostPluginAsync(conn, "vmopsSnapshot", "backupSnapshot", wait, - "primaryStorageSRUuid", primaryStorageSRUuid, "dcId", dcId.toString(), "accountId", accountId.toString(), - "volumeId", volumeId.toString(), "secondaryStorageMountPath", secondaryStorageMountPath, - "snapshotUuid", snapshotUuid, "prevBackupUuid", prevBackupUuid, "backupUuid", backupUuid, "isISCSI", isISCSI.toString(), "secHostId", secHostId.toString()); - String errMsg = null; - if (results == null || results.isEmpty()) { - errMsg = "Could not copy backupUuid: " + backupSnapshotUuid + " of volumeId: " + volumeId - + " from primary storage " + primaryStorageSRUuid + " to secondary storage " - + secondaryStorageMountPath + " due to null"; - } else { - - String[] tmp = results.split("#"); - String status = tmp[0]; - backupSnapshotUuid = tmp[1]; - // status == "1" if and only if backupSnapshotUuid != null - // So we don't rely on status value but return backupSnapshotUuid as an - // indicator of success. - if (status != null && status.equalsIgnoreCase("1") && backupSnapshotUuid != null) { - s_logger.debug("Successfully copied backupUuid: " + backupSnapshotUuid + " of volumeId: " + volumeId - + " to secondary storage"); - return backupSnapshotUuid; - } else { - errMsg = "Could not copy backupUuid: " + backupSnapshotUuid + " of volumeId: " + volumeId - + " from primary storage " + primaryStorageSRUuid + " to secondary storage " - + secondaryStorageMountPath + " due to " + tmp[1]; - } - } - String source = backupUuid + ".vhd"; - killCopyProcess(conn, source); - s_logger.warn(errMsg); - return null; - - } - protected String callHostPluginAsync(Connection conn, String plugin, String cmd, int wait, String... params) { int timeout = wait * 1000; Map args = new HashMap(); @@ -4005,6 +3987,7 @@ protected String callHostPluginAsync(Connection conn, String plugin, String cmd, @Override public StopAnswer execute(StopCommand cmd) { String vmName = cmd.getVmName(); + String platformstring = null; try { Connection conn = getConnection(); Set vms = VM.getByNameLabel(conn, vmName); @@ -4034,7 +4017,7 @@ public StopAnswer execute(StopCommand cmd) { } for (VM vm : vms) { VM.Record vmr = vm.getRecord(conn); - + platformstring = StringUtils.mapToString(vmr.platform); if (vmr.isControlDomain) { String msg = "Tring to Shutdown control domain"; s_logger.warn(msg); @@ -4044,7 +4027,7 @@ public StopAnswer execute(StopCommand cmd) { if (vmr.powerState == VmPowerState.RUNNING && !isRefNull(vmr.residentOn) && !vmr.residentOn.getUuid(conn).equals(_host.uuid)) { String msg = "Stop Vm " + vmName + " failed due to this vm is not running on this host: " + _host.uuid + " but host:" + vmr.residentOn.getUuid(conn); s_logger.warn(msg); - return new StopAnswer(cmd, msg, false); + return new StopAnswer(cmd, msg, platformstring, false); } State state = s_vms.getState(_cluster, vmName); @@ -4073,24 +4056,11 @@ public StopAnswer execute(StopCommand cmd) { } catch (Exception e) { String msg = "Catch exception " + e.getClass().getName() + " when stop VM:" + cmd.getVmName() + " due to " + e.toString(); s_logger.debug(msg); - return new StopAnswer(cmd, msg, false); + return new StopAnswer(cmd, msg, platformstring, false); } finally { try { if (vm.getPowerState(conn) == VmPowerState.HALTED) { - disconnectManagedVolumes(conn, vm); - - Map platform = vm.getPlatform(conn); - Integer timeoffset = null; - try { - if (platform.containsKey("timeoffset")) { - timeoffset = Integer.valueOf(platform.get("timeoffset")); - } - } catch (NumberFormatException e) { - s_logger.error("Error while reading the platform:timeoffset field of the instance", e); - } - String xentoolsversion = getVMXenToolsVersion(platform); - Set vifs = vm.getVIFs(conn); List networks = new ArrayList(); for (VIF vif : vifs) { @@ -4111,11 +4081,8 @@ public StopAnswer execute(StopCommand cmd) { // network might be destroyed by other host } } - return new StopAnswer(cmd, "Stop VM " + vmName + " Succeed", xentoolsversion, timeoffset, true); + return new StopAnswer(cmd, "Stop VM " + vmName + " Succeed", platformstring ,true); } - } catch (XenAPIException e) { - String msg = "VM destroy failed in Stop " + vmName + " Command due to " + e.toString(); - s_logger.warn(msg, e); } catch (Exception e) { String msg = "VM destroy failed in Stop " + vmName + " Command due to " + e.getMessage(); s_logger.warn(msg, e); @@ -4128,28 +4095,21 @@ public StopAnswer execute(StopCommand cmd) { } } - } catch (XenAPIException e) { + } catch (Exception e) { String msg = "Stop Vm " + vmName + " fail due to " + e.toString(); s_logger.warn(msg, e); - return new StopAnswer(cmd, msg, false); - } catch (XmlRpcException e) { - String msg = "Stop Vm " + vmName + " fail due to " + e.getMessage(); - s_logger.warn(msg, e); - return new StopAnswer(cmd, msg, false); - } catch (Exception e) { - s_logger.warn("Unable to stop " + vmName + " due to ", e); - return new StopAnswer(cmd, e); + return new StopAnswer(cmd, msg, platformstring, false); } - return new StopAnswer(cmd, "Stop VM failed", false); + return new StopAnswer(cmd, "Stop VM failed", platformstring, false); } - + /*Override by subclass*/ protected String getVMXenToolsVersion(Map platform) { return "xenserver56"; } - + private List getVdis(Connection conn, VM vm) { List vdis = new ArrayList(); try { @@ -4417,14 +4377,14 @@ protected VDI mount(Connection conn, StoragePoolType poolType, String volumeFold * used to talk to retrieve a network by the name. The reason is * because of the problems in using the name label as the way to find * the Network. - * + * * To see how we are working around these problems, take a look at * enableVlanNetwork(). The following description assumes you have looked * at the description on that method. - * + * * In order to understand this, we have to see what type of networks are * within a XenServer that's under CloudStack control. - * + * * - Native Networks: these are networks that are untagged on the * XenServer and are used to crate VLAN networks on. These are * created by the user and is assumed to be one per cluster. @@ -4433,7 +4393,7 @@ protected VDI mount(Connection conn, StoragePoolType poolType, String volumeFold * - LinkLocal Networks: these are dynamically created by CloudStack and * can also have problems with duplicated names but these don't have * actual PIFs. - * + * * In order to speed to retrieval of a network, we do the following: * - We retrieve by the name. If only one network is retrieved, we * assume we retrieved the right network. @@ -4441,13 +4401,13 @@ protected VDI mount(Connection conn, StoragePoolType poolType, String volumeFold * has the pif for the local host and use that. * - If a pif is not found, then we look at the tags and find the * one with the lowest timestamp. (See enableVlanNetwork()) - * + * * @param conn Xapi connection * @param name name of the network * @return XsNic an object that contains network, network record, pif, and pif record. * @throws XenAPIException * @throws XmlRpcException - * + * * @see CitrixResourceBase#enableVlanNetwork */ protected XsLocalNetwork getNetworkByName(Connection conn, String name) throws XenAPIException, XmlRpcException { @@ -4511,13 +4471,13 @@ protected Pair parseTimestamp(String timeStampStr) { /** * enableVlanNetwork creates a Network object, Vlan object, and thereby * a tagged PIF object in Xapi. - * + * * In XenServer, VLAN is added by * - Create a network, which is unique cluster wide. * - Find the PIF that you want to create the VLAN on. * - Create a VLAN using the network and the PIF. As a result of this * operation, a tagged PIF object is also created. - * + * * Here is a list of problems with clustered Xapi implementation that * we are trying to circumvent. * - There can be multiple Networks with the same name-label so searching @@ -4532,9 +4492,9 @@ protected Pair parseTimestamp(String timeStampStr) { * problems in migration because the VMs are logically attached * to different networks in Xapi's database but in reality, they * are attached to the same network. - * + * * To work around these problems, we do the following. - * + * * - When creating the VLAN network, we name it as VLAN-UUID of the * Network it is created on-VLAN Tag. Because VLAN tags is unique with * one particular network, this is a unique name-label to quickly @@ -4546,10 +4506,10 @@ protected Pair parseTimestamp(String timeStampStr) { * lowest random number as the VLAN network. This allows VLAN creation * to happen on multiple hosts concurrently but even if two VLAN * networks were created with the same name, only one of them is used. - * + * * One cavaet about this approach is that it relies on the timestamp to * be relatively accurate among different hosts. - * + * * @param conn Xapi Connection * @param tag VLAN tag * @param network network on this host to create the VLAN on. @@ -4749,13 +4709,13 @@ public PingCommand getCurrentStatus(long id) { } 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 +4970,7 @@ public StartupCommand[] initialize() throws IllegalArgumentException{ cmd.setHypervisorType(HypervisorType.XenServer); cmd.setCluster(_cluster); cmd.setPoolSync(false); + cmd.setHostVmStateReport(this.getHostVmStateReport(conn)); Pool pool; try { @@ -5077,11 +5038,11 @@ protected SetupAnswer execute(SetupCommand cmd) { s_logger.warn("set xenserver Iptable failed"); return null; } - + if (_securityGroupEnabled) { _canBridgeFirewall = can_bridge_firewall(conn); } - + String result = callHostPluginPremium(conn, "heartbeat", "host", _host.uuid, "interval", Integer .toString(_heartbeatInterval)); if (result == null || !result.contains("> DONE <")) { @@ -5229,6 +5190,12 @@ protected boolean setupServer(Connection conn) { } com.trilead.ssh2.Session session = sshConnection.openSession(); + + String cmd = "mkdir -p /opt/cloud/bin /var/log/cloud"; + if (!SSHCmdHelper.sshExecuteCmd(sshConnection, cmd)) { + throw new CloudRuntimeException("Cannot create directory /opt/cloud/bin on XenServer hosts"); + } + SCPClient scp = new SCPClient(sshConnection); List files = getPatchFiles(); @@ -5935,7 +5902,6 @@ protected void fillHostInfo(Connection conn, StartupRoutingCommand cmd) { details.put("private.network.device", _privateNetworkName); } - details.put("can_bridge_firewall", Boolean.toString(_canBridgeFirewall)); cmd.setHostDetails(details); cmd.setName(hr.nameLabel); cmd.setGuid(_host.uuid); @@ -6109,9 +6075,9 @@ protected StorageSubsystemCommandHandler getStorageHandler() { } private void CheckXenHostInfo() throws ConfigurationException { - Connection conn = _connPool.slaveConnect(_host.ip, _username, _password); + Connection conn = _connPool.getConnect(_host.ip, _username, _password); if( conn == null ) { - throw new ConfigurationException("Can not create slave connection to " + _host.ip); + throw new ConfigurationException("Can not create connection to " + _host.ip); } try { Host.Record hostRec = null; @@ -6131,20 +6097,12 @@ private void CheckXenHostInfo() throws ConfigurationException { } } finally { try { - Session.localLogout(conn); + Session.logout(conn); } catch (Exception e) { } } } - void destroyVDI(Connection conn, VDI vdi) { - try { - vdi.destroy(conn); - } catch (Exception e) { - String msg = "destroy VDI failed due to " + e.toString(); - s_logger.warn(msg); - } - } public CreateAnswer execute(CreateCommand cmd) { Connection conn = getConnection(); @@ -6573,53 +6531,6 @@ public Answer execute(DestroyCommand cmd) { return new Answer(cmd, true, "Success"); } - public CopyVolumeAnswer execute(final CopyVolumeCommand cmd) { - Connection conn = getConnection(); - String volumeUUID = cmd.getVolumePath(); - StorageFilerTO poolTO = cmd.getPool(); - String secondaryStorageURL = cmd.getSecondaryStorageURL(); - boolean toSecondaryStorage = cmd.toSecondaryStorage(); - int wait = cmd.getWait(); - try { - URI uri = new URI(secondaryStorageURL); - String remoteVolumesMountPath = uri.getHost() + ":" + uri.getPath() + "/volumes/"; - String volumeFolder = String.valueOf(cmd.getVolumeId()) + "/"; - String mountpoint = remoteVolumesMountPath + volumeFolder; - SR primaryStoragePool = getStorageRepository(conn, poolTO.getUuid()); - String srUuid = primaryStoragePool.getUuid(conn); - if (toSecondaryStorage) { - // Create the volume folder - if (!createSecondaryStorageFolder(conn, remoteVolumesMountPath, volumeFolder)) { - throw new InternalErrorException("Failed to create the volume folder."); - } - SR secondaryStorage = null; - try { - // Create a SR for the volume UUID folder - secondaryStorage = createNfsSRbyURI(conn, new URI(secondaryStorageURL + "/volumes/" + volumeFolder), false); - // Look up the volume on the source primary storage pool - VDI srcVolume = getVDIbyUuid(conn, volumeUUID); - // Copy the volume to secondary storage - VDI destVolume = cloudVDIcopy(conn, srcVolume, secondaryStorage, wait); - String destVolumeUUID = destVolume.getUuid(conn); - return new CopyVolumeAnswer(cmd, true, null, null, destVolumeUUID); - } finally { - removeSR(conn, secondaryStorage); - } - } else { - try { - String volumePath = mountpoint + "/" + volumeUUID + ".vhd"; - String uuid = copy_vhd_from_secondarystorage(conn, volumePath, srUuid, wait ); - return new CopyVolumeAnswer(cmd, true, null, srUuid, uuid); - } finally { - deleteSecondaryStorageFolder(conn, remoteVolumesMountPath, volumeFolder); - } - } - } catch (Exception e) { - String msg = "Catch Exception " + e.getClass().getName() + " due to " + e.toString(); - s_logger.warn(msg, e); - return new CopyVolumeAnswer(cmd, false, msg, null, null); - } - } protected VDI createVdi(SR sr, String vdiNameLabel, Long volumeSize) throws Types.XenAPIException, XmlRpcException { VDI vdi = null; @@ -6661,9 +6572,7 @@ protected VDI createVdi(SR sr, String vdiNameLabel, Long volumeSize) throws Type return vdi; } - protected void handleSrAndVdiDetach(String iqn) throws Exception { - Connection conn = getConnection(); - + protected void handleSrAndVdiDetach(String iqn, Connection conn) throws Exception { SR sr = getStorageRepository(conn, iqn); removeSR(conn, sr); @@ -6771,7 +6680,7 @@ protected AttachVolumeAnswer execute(final AttachVolumeCommand cmd) { vdi.setNameLabel(conn, "detached"); if (cmd.isManaged()) { - handleSrAndVdiDetach(cmd.get_iScsiName()); + handleSrAndVdiDetach(cmd.get_iScsiName(), conn); } return new AttachVolumeAnswer(cmd); @@ -6844,7 +6753,7 @@ private long getVMSnapshotChainSize(Connection conn, VolumeObjectTO volumeTo, St } return size; } - + protected Answer execute(final CreateVMSnapshotCommand cmd) { String vmName = cmd.getVmName(); @@ -6933,7 +6842,7 @@ protected Answer execute(final CreateVMSnapshotCommand cmd) { long size = getVMSnapshotChainSize(conn,volumeTo,cmd.getVmName()); volumeTo.setSize(size); } - + success = true; return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), cmd.getVolumeTOs()); } catch (Exception e) { @@ -7061,7 +6970,7 @@ protected Answer execute(final DeleteVMSnapshotCommand cmd) { long size = getVMSnapshotChainSize(conn,volumeTo,cmd.getVmName()); volumeTo.setSize(size); } - + return new DeleteVMSnapshotAnswer(cmd, cmd.getVolumeTOs()); } catch (Exception e) { s_logger.warn("Catch Exception: " + e.getClass().toString() @@ -7165,139 +7074,6 @@ boolean IsISCSI(String type) { return SRType.LVMOHBA.equals(type) || SRType.LVMOISCSI.equals(type) || SRType.LVM.equals(type) ; } - protected ManageSnapshotAnswer execute(final ManageSnapshotCommand cmd) { - Connection conn = getConnection(); - long snapshotId = cmd.getSnapshotId(); - String snapshotName = cmd.getSnapshotName(); - - // By default assume failure - boolean success = false; - String cmdSwitch = cmd.getCommandSwitch(); - String snapshotOp = "Unsupported snapshot command." + cmdSwitch; - if (cmdSwitch.equals(ManageSnapshotCommand.CREATE_SNAPSHOT)) { - snapshotOp = "create"; - } else if (cmdSwitch.equals(ManageSnapshotCommand.DESTROY_SNAPSHOT)) { - snapshotOp = "destroy"; - } - String details = "ManageSnapshotCommand operation: " + snapshotOp + " Failed for snapshotId: " + snapshotId; - String snapshotUUID = null; - - try { - if (cmdSwitch.equals(ManageSnapshotCommand.CREATE_SNAPSHOT)) { - // Look up the volume - String volumeUUID = cmd.getVolumePath(); - VDI volume = VDI.getByUuid(conn, volumeUUID); - - // Create a snapshot - VDI snapshot = volume.snapshot(conn, new HashMap()); - - if (snapshotName != null) { - snapshot.setNameLabel(conn, snapshotName); - } - // Determine the UUID of the snapshot - - snapshotUUID = snapshot.getUuid(conn); - String preSnapshotUUID = cmd.getSnapshotPath(); - //check if it is a empty snapshot - if( preSnapshotUUID != null) { - SR sr = volume.getSR(conn); - String srUUID = sr.getUuid(conn); - String type = sr.getType(conn); - Boolean isISCSI = IsISCSI(type); - String snapshotParentUUID = getVhdParent(conn, srUUID, snapshotUUID, isISCSI); - - String preSnapshotParentUUID = getVhdParent(conn, srUUID, preSnapshotUUID, isISCSI); - if( snapshotParentUUID != null && snapshotParentUUID.equals(preSnapshotParentUUID)) { - // this is empty snapshot, remove it - snapshot.destroy(conn); - snapshotUUID = preSnapshotUUID; - } - - } - success = true; - details = null; - } else if (cmd.getCommandSwitch().equals(ManageSnapshotCommand.DESTROY_SNAPSHOT)) { - // Look up the snapshot - snapshotUUID = cmd.getSnapshotPath(); - VDI snapshot = getVDIbyUuid(conn, snapshotUUID); - - snapshot.destroy(conn); - snapshotUUID = null; - success = true; - details = null; - } - } catch (XenAPIException e) { - details += ", reason: " + e.toString(); - s_logger.warn(details, e); - } catch (Exception e) { - details += ", reason: " + e.toString(); - s_logger.warn(details, e); - } - return new ManageSnapshotAnswer(cmd, snapshotId, snapshotUUID, success, details); - } - - protected CreatePrivateTemplateAnswer execute(final CreatePrivateTemplateFromVolumeCommand cmd) { - Connection conn = getConnection(); - String secondaryStoragePoolURL = cmd.getSecondaryStorageUrl(); - String volumeUUID = cmd.getVolumePath(); - Long accountId = cmd.getAccountId(); - String userSpecifiedName = cmd.getTemplateName(); - Long templateId = cmd.getTemplateId(); - int wait = cmd.getWait(); - String details = null; - SR tmpltSR = null; - boolean result = false; - String secondaryStorageMountPath = null; - String installPath = null; - try { - URI uri = new URI(secondaryStoragePoolURL); - secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath(); - installPath = "template/tmpl/" + accountId + "/" + templateId; - if( !createSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath)) { - details = " Filed to create folder " + installPath + " in secondary storage"; - s_logger.warn(details); - return new CreatePrivateTemplateAnswer(cmd, false, details); - } - - VDI volume = getVDIbyUuid(conn, volumeUUID); - // create template SR - URI tmpltURI = new URI(secondaryStoragePoolURL + "/" + installPath); - tmpltSR = createNfsSRbyURI(conn, tmpltURI, false); - - // copy volume to template SR - VDI tmpltVDI = cloudVDIcopy(conn, volume, tmpltSR, wait); - // scan makes XenServer pick up VDI physicalSize - tmpltSR.scan(conn); - if (userSpecifiedName != null) { - tmpltVDI.setNameLabel(conn, userSpecifiedName); - } - - String tmpltUUID = tmpltVDI.getUuid(conn); - String tmpltFilename = tmpltUUID + ".vhd"; - long virtualSize = tmpltVDI.getVirtualSize(conn); - long physicalSize = tmpltVDI.getPhysicalUtilisation(conn); - // create the template.properties file - String templatePath = secondaryStorageMountPath + "/" + installPath; - result = postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize, templateId); - if (!result) { - throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + tmpltURI); - } - installPath = installPath + "/" + tmpltFilename; - removeSR(conn, tmpltSR); - tmpltSR = null; - return new CreatePrivateTemplateAnswer(cmd, true, null, installPath, virtualSize, physicalSize, tmpltUUID, ImageFormat.VHD); - } catch (Exception e) { - if (tmpltSR != null) { - removeSR(conn, tmpltSR); - } - if ( secondaryStorageMountPath != null) { - deleteSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath); - } - details = "Creating template from volume " + volumeUUID + " failed due to " + e.toString(); - s_logger.error(details, e); - } - return new CreatePrivateTemplateAnswer(cmd, result, details); - } protected Answer execute(final UpgradeSnapshotCommand cmd) { @@ -7328,59 +7104,6 @@ protected Answer execute(final UpgradeSnapshotCommand cmd) { return new Answer(cmd, false, "failure"); } - protected CreatePrivateTemplateAnswer execute(final CreatePrivateTemplateFromSnapshotCommand cmd) { - Connection conn = getConnection(); - Long accountId = cmd.getAccountId(); - Long volumeId = cmd.getVolumeId(); - String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); - String backedUpSnapshotUuid = cmd.getSnapshotUuid(); - Long newTemplateId = cmd.getNewTemplateId(); - String userSpecifiedName = cmd.getTemplateName(); - int wait = cmd.getWait(); - // By default, assume failure - String details = null; - boolean result = false; - String secondaryStorageMountPath = null; - String installPath = null; - try { - URI uri = new URI(secondaryStorageUrl); - secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath(); - installPath = "template/tmpl/" + accountId + "/" + newTemplateId; - if( !createSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath)) { - details = " Filed to create folder " + installPath + " in secondary storage"; - s_logger.warn(details); - return new CreatePrivateTemplateAnswer(cmd, false, details); - } - String templatePath = secondaryStorageMountPath + "/" + installPath; - // create snapshot SR - String filename = backedUpSnapshotUuid; - if ( !filename.startsWith("VHD-") && !filename.endsWith(".vhd")) { - filename = backedUpSnapshotUuid + ".vhd"; - } - String snapshotPath = secondaryStorageMountPath + "/snapshots/" + accountId + "/" + volumeId + "/" + filename; - String results = createTemplateFromSnapshot(conn, templatePath, snapshotPath, wait); - String[] tmp = results.split("#"); - String tmpltUuid = tmp[1]; - long physicalSize = Long.parseLong(tmp[2]); - long virtualSize = Long.parseLong(tmp[3]) * 1024 * 1024; - String tmpltFilename = tmpltUuid + ".vhd"; - - // create the template.properties file - result = postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUuid, userSpecifiedName, null, physicalSize, virtualSize, newTemplateId); - if (!result) { - throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + templatePath); - } - installPath = installPath + "/" + tmpltFilename; - return new CreatePrivateTemplateAnswer(cmd, true, null, installPath, virtualSize, physicalSize, tmpltUuid, ImageFormat.VHD); - } catch (Exception e) { - if (secondaryStorageMountPath != null) { - deleteSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath); - } - details = "Creating template from snapshot " + backedUpSnapshotUuid + " failed due to " + e.toString(); - s_logger.error(details, e); - } - return new CreatePrivateTemplateAnswer(cmd, result, details); - } private boolean destroySnapshotOnPrimaryStorageExceptThis(Connection conn, String volumeUuid, String avoidSnapshotUuid){ try { @@ -7412,211 +7135,6 @@ private boolean destroySnapshotOnPrimaryStorageExceptThis(Connection conn, Strin return false; } - protected BackupSnapshotAnswer execute(final BackupSnapshotCommand cmd) { - Connection conn = getConnection(); - String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel(); - Long dcId = cmd.getDataCenterId(); - Long accountId = cmd.getAccountId(); - Long volumeId = cmd.getVolumeId(); - String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); - String snapshotUuid = cmd.getSnapshotUuid(); // not null: Precondition. - String prevBackupUuid = cmd.getPrevBackupUuid(); - String prevSnapshotUuid = cmd.getPrevSnapshotUuid(); - int wait = cmd.getWait(); - Long secHostId = cmd.getSecHostId(); - // By default assume failure - String details = null; - boolean success = false; - String snapshotBackupUuid = null; - boolean fullbackup = true; - try { - SR primaryStorageSR = getSRByNameLabelandHost(conn, primaryStorageNameLabel); - if (primaryStorageSR == null) { - throw new InternalErrorException("Could not backup snapshot because the primary Storage SR could not be created from the name label: " + primaryStorageNameLabel); - } - String psUuid = primaryStorageSR.getUuid(conn); - Boolean isISCSI = IsISCSI(primaryStorageSR.getType(conn)); - URI uri = new URI(secondaryStorageUrl); - String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath(); - VDI snapshotVdi = getVDIbyUuid(conn, snapshotUuid); - String snapshotPaUuid = null; - if ( prevBackupUuid != null ) { - try { - snapshotPaUuid = getVhdParent(conn, psUuid, snapshotUuid, isISCSI); - if( snapshotPaUuid != null ) { - String snashotPaPaPaUuid = getVhdParent(conn, psUuid, snapshotPaUuid, isISCSI); - String prevSnashotPaUuid = getVhdParent(conn, psUuid, prevSnapshotUuid, isISCSI); - if (snashotPaPaPaUuid != null && prevSnashotPaUuid!= null && prevSnashotPaUuid.equals(snashotPaPaPaUuid)) { - fullbackup = false; - } - } - } catch (Exception e) { - } - } - - if (fullbackup) { - // the first snapshot is always a full snapshot - String folder = "snapshots/" + accountId + "/" + volumeId; - if( !createSecondaryStorageFolder(conn, secondaryStorageMountPath, folder)) { - details = " Filed to create folder " + folder + " in secondary storage"; - s_logger.warn(details); - return new BackupSnapshotAnswer(cmd, false, details, null, false); - } - String snapshotMountpoint = secondaryStorageUrl + "/" + folder; - SR snapshotSr = null; - try { - snapshotSr = createNfsSRbyURI(conn, new URI(snapshotMountpoint), false); - VDI backedVdi = cloudVDIcopy(conn, snapshotVdi, snapshotSr, wait); - snapshotBackupUuid = backedVdi.getUuid(conn); - if( cmd.getSwift() != null ) { - try { - swiftBackupSnapshot(conn, cmd.getSwift(), snapshotSr.getUuid(conn), snapshotBackupUuid, "S-" + volumeId.toString(), false, wait); - snapshotBackupUuid = snapshotBackupUuid + ".vhd"; - } finally { - deleteSnapshotBackup(conn, dcId, accountId, volumeId, secondaryStorageMountPath, snapshotBackupUuid); - } - } else if (cmd.getS3() != null) { - try { - backupSnapshotToS3(conn, cmd.getS3(), snapshotSr.getUuid(conn), snapshotBackupUuid, isISCSI, wait); - snapshotBackupUuid = snapshotBackupUuid + ".vhd"; - } finally { - deleteSnapshotBackup(conn, dcId, accountId, volumeId, secondaryStorageMountPath, snapshotBackupUuid); - } - } - success = true; - } finally { - if( snapshotSr != null) { - removeSR(conn, snapshotSr); - } - } - } else { - String primaryStorageSRUuid = primaryStorageSR.getUuid(conn); - if( cmd.getSwift() != null ) { - swiftBackupSnapshot(conn, cmd.getSwift(), primaryStorageSRUuid, snapshotPaUuid, "S-" + volumeId.toString(), isISCSI, wait); - if ( isISCSI ) { - snapshotBackupUuid = "VHD-" + snapshotPaUuid; - } else { - snapshotBackupUuid = snapshotPaUuid + ".vhd"; - } - success = true; - } else if (cmd.getS3() != null) { - backupSnapshotToS3(conn, cmd.getS3(), primaryStorageSRUuid, snapshotPaUuid, isISCSI, wait); - } else { - snapshotBackupUuid = backupSnapshot(conn, primaryStorageSRUuid, dcId, accountId, volumeId, secondaryStorageMountPath, snapshotUuid, prevBackupUuid, isISCSI, wait, secHostId); - success = (snapshotBackupUuid != null); - } - } - String volumeUuid = cmd.getVolumePath(); - destroySnapshotOnPrimaryStorageExceptThis(conn, volumeUuid, snapshotUuid); - if (success) { - details = "Successfully backedUp the snapshotUuid: " + snapshotUuid + " to secondary storage."; - - } - } catch (XenAPIException e) { - details = "BackupSnapshot Failed due to " + e.toString(); - s_logger.warn(details, e); - } catch (Exception e) { - details = "BackupSnapshot Failed due to " + e.getMessage(); - s_logger.warn(details, e); - } - - return new BackupSnapshotAnswer(cmd, success, details, snapshotBackupUuid, fullbackup); - } - - private boolean backupSnapshotToS3(final Connection connection, - final S3TO s3, final String srUuid, final String snapshotUuid, - final Boolean iSCSIFlag, final int wait) { - - final String filename = iSCSIFlag ? "VHD-" + snapshotUuid - : snapshotUuid + ".vhd"; - final String dir = (iSCSIFlag ? "/dev/VG_XenStorage-" - : "/var/run/sr-mount/") + srUuid; - final String key = String.format("/snapshots/%1$s", snapshotUuid); - - try { - - final List parameters = newArrayList(flattenProperties(s3, - S3Utils.ClientOptions.class)); - // https workaround for Introspector bug that does not - // recognize Boolean accessor methods ... - parameters.addAll(Arrays.asList("operation", "put", "filename", - dir + "/" + filename, "iSCSIFlag", iSCSIFlag.toString(), - "bucket", s3.getBucketName(), "key", key, "https", - s3.isHttps() != null ? s3.isHttps().toString() - : "null")); - final String result = callHostPluginAsync(connection, "s3xen", - "s3", wait, - parameters.toArray(new String[parameters.size()])); - - if (result != null && result.equals("true")) { - return true; - } - - } catch (Exception e) { - s_logger.error(String.format( - "S3 upload failed of snapshot %1$s due to %2$s.", - snapshotUuid, e.toString()), e); - } - - return false; - - } - - protected CreateVolumeFromSnapshotAnswer execute(final CreateVolumeFromSnapshotCommand cmd) { - Connection conn = getConnection(); - String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel(); - Long accountId = cmd.getAccountId(); - Long volumeId = cmd.getVolumeId(); - String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); - String backedUpSnapshotUuid = cmd.getSnapshotUuid(); - int wait = cmd.getWait(); - boolean result = false; - // Generic error message. - String details = null; - String volumeUUID = null; - SR snapshotSR = null; - - if (secondaryStorageUrl == null) { - details += " because the URL passed: " + secondaryStorageUrl + " is invalid."; - return new CreateVolumeFromSnapshotAnswer(cmd, result, details, volumeUUID); - } - try { - SR primaryStorageSR = getSRByNameLabelandHost(conn, primaryStorageNameLabel); - if (primaryStorageSR == null) { - throw new InternalErrorException("Could not create volume from snapshot because the primary Storage SR could not be created from the name label: " - + primaryStorageNameLabel); - } - // Get the absolute path of the snapshot on the secondary storage. - URI snapshotURI = new URI(secondaryStorageUrl + "/snapshots/" + accountId + "/" + volumeId); - String filename = backedUpSnapshotUuid; - if ( !filename.startsWith("VHD-") && !filename.endsWith(".vhd")) { - filename = backedUpSnapshotUuid + ".vhd"; - } - String snapshotPath = snapshotURI.getHost() + ":" + snapshotURI.getPath() + "/" + filename; - String srUuid = primaryStorageSR.getUuid(conn); - volumeUUID = copy_vhd_from_secondarystorage(conn, snapshotPath, srUuid, wait); - result = true; - } catch (XenAPIException e) { - details += " due to " + e.toString(); - s_logger.warn(details, e); - } catch (Exception e) { - details += " due to " + e.getMessage(); - s_logger.warn(details, e); - } finally { - // In all cases, if the temporary SR was created, forget it. - if (snapshotSR != null) { - removeSR(conn, snapshotSR); - } - } - if (!result) { - // Is this logged at a higher level? - s_logger.error(details); - } - - // In all cases return something. - return new CreateVolumeFromSnapshotAnswer(cmd, result, details, volumeUUID); - } - protected VM getVM(Connection conn, String vmName) { // Look up VMs with the specified name @@ -7815,27 +7333,6 @@ protected String getVhdParent(Connection conn, String primaryStorageSRUuid, Stri return parentUuid; } - protected boolean destroySnapshotOnPrimaryStorage(Connection conn, String snapshotUuid) { - // Precondition snapshotUuid != null - try { - VDI snapshot = getVDIbyUuid(conn, snapshotUuid); - if (snapshot == null) { - throw new InternalErrorException("Could not destroy snapshot " + snapshotUuid + " because the snapshot VDI was null"); - } - snapshot.destroy(conn); - s_logger.debug("Successfully destroyed snapshotUuid: " + snapshotUuid + " on primary storage"); - return true; - } catch (XenAPIException e) { - String msg = "Destroy snapshotUuid: " + snapshotUuid + " on primary storage failed due to " + e.toString(); - s_logger.error(msg, e); - } catch (Exception e) { - String msg = "Destroy snapshotUuid: " + snapshotUuid + " on primary storage failed due to " + e.getMessage(); - s_logger.warn(msg, e); - } - - return false; - } - protected String deleteSnapshotBackup(Connection conn, Long dcId, Long accountId, Long volumeId, String secondaryStorageMountPath, String backupUUID) { // If anybody modifies the formatting below again, I'll skin them @@ -7845,10 +7342,6 @@ protected String deleteSnapshotBackup(Connection conn, Long dcId, Long accountId return result; } - protected boolean deleteSnapshotsDir(Connection conn, Long dcId, Long accountId, Long volumeId, String secondaryStorageMountPath) { - return deleteSecondaryStorageFolder(conn, secondaryStorageMountPath, "snapshots" + "/" + accountId.toString() + "/" + volumeId.toString()); - } - @Override public boolean start() { @@ -7900,38 +7393,14 @@ protected Answer execute(PoolEjectCommand cmd) { Host.Record hostr = poolr.master.getRecord(conn); if (_host.uuid.equals(hostr.uuid)) { - boolean mastermigrated = false; Map hostMap = Host.getAllRecords(conn); - if (hostMap.size() != 1) { - Host newMaster = null; - Host.Record newMasterRecord = null; - for (Map.Entry entry : hostMap.entrySet()) { - if (_host.uuid.equals(entry.getValue().uuid)) { - continue; - } - newMaster = entry.getKey(); - newMasterRecord = entry.getValue(); - s_logger.debug("New master for the XenPool is " + newMasterRecord.uuid + " : " + newMasterRecord.address); - try { - _connPool.switchMaster(_host.ip, _host.pool, conn, newMaster, _username, _password, _wait); - mastermigrated = true; - break; - } catch (Exception e) { - s_logger.warn("Unable to switch the new master to " + newMasterRecord.uuid + ": " + newMasterRecord.address + " due to " + e.toString()); - } - } - } else { - s_logger.debug("This is last host to eject, so don't need to eject: " + hostuuid); - return new Answer(cmd); - } - if ( !mastermigrated ) { - String msg = "this host is master, and cannot designate a new master"; + if (hostMap.size() > 1) { + String msg = "This host is XS master, please designate a new XS master throught XenCenter before you delete this host from CS"; s_logger.debug(msg); return new Answer(cmd, false, msg); - } } - + // eject from pool try { Pool.eject(conn, host); @@ -7957,7 +7426,7 @@ private Answer execute(CleanupNetworkRulesCmd cmd) { return new Answer(cmd, true, null); } Connection conn = getConnection(); - String result = callHostPlugin(conn, "vmops","cleanup_rules", "instance", _instance); + String result = callHostPlugin(conn, "vmops", "cleanup_rules", "instance", _instance); int numCleaned = Integer.parseInt(result); if (result == null || result.isEmpty() || (numCleaned < 0)) { s_logger.warn("Failed to cleanup rules for host " + _host.ip); @@ -8103,6 +7572,7 @@ private Answer execute(SetMonitorServiceCommand cmd) { Connection conn = getConnection(); String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP); + String disable = cmd.getAccessDetail(NetworkElementCommand.ROUTER_MONITORING_DISABLE); if (routerIp == null) { return new Answer(cmd); @@ -8110,6 +7580,10 @@ private Answer execute(SetMonitorServiceCommand cmd) { String args = "monitor_service.sh " + routerIp; args += " -c " + config; + if (disable != null) { + args += " -d "; + } + String result = callHostPlugin(conn, "vmops", "routerProxy", "args", args); if (result == null || result.isEmpty()) { @@ -8181,7 +7655,7 @@ protected Answer execute(final ClusterSyncCommand cmd) { } catch (Throwable e) { s_logger.warn("Check for master failed, failing the Cluster sync command"); return new Answer(cmd); - } + } HashMap> newStates = deltaClusterSync(conn); return new ClusterSyncAnswer(cmd.getClusterId(), newStates); } @@ -8200,13 +7674,12 @@ protected HashMap> fullClusterSync(Connec String vm_name = record.nameLabel; VmPowerState ps = record.powerState; final State state = convertToState(ps); - String xstoolsversion = getVMXenToolsVersion(record.platform); Host host = record.residentOn; String host_uuid = null; if( ! isRefNull(host) ) { host_uuid = host.getUuid(conn); synchronized (_cluster.intern()) { - s_vms.put(_cluster, host_uuid, vm_name, state, xstoolsversion); + s_vms.put(_cluster, host_uuid, vm_name, state, null); } } if (s_logger.isTraceEnabled()) { @@ -8237,19 +7710,19 @@ protected HashMap> deltaClusterSync(Conne for (final Map.Entry> entry : newStates.entrySet()) { final String vm = entry.getKey(); - String xstoolsversion = entry.getValue().third(); + String platform = entry.getValue().third(); State newState = entry.getValue().second(); String host_uuid = entry.getValue().first(); final Ternary oldState = oldStates.remove(vm); - - // check if xstoolsversion changed - if (xstoolsversion != null && oldState != null){ - if (xstoolsversion != oldState.third() && newState != State.Stopped && newState != State.Stopping){ - s_logger.warn("Detecting a change in xstoolsversion for " + vm); - changes.put(vm, new Ternary(host_uuid, newState, xstoolsversion)); + + // check if platform changed + if (platform != null && oldState != null){ + if (!platform.equals(oldState.third()) && newState != State.Stopped && newState != State.Stopping){ + s_logger.warn("Detecting a change in platform for " + vm); + changes.put(vm, new Ternary(host_uuid, newState, platform)); s_logger.debug("11. The VM " + vm + " is in " + newState + " state"); - s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); + s_vms.put(_cluster, host_uuid, vm, newState, platform); continue; } } @@ -8257,10 +7730,10 @@ protected HashMap> deltaClusterSync(Conne if (host_uuid != null && oldState != null){ if (!host_uuid.equals(oldState.first()) && newState != State.Stopped && newState != State.Stopping){ s_logger.warn("Detecting a change in host for " + vm); - changes.put(vm, new Ternary(host_uuid, newState, null)); + changes.put(vm, new Ternary(host_uuid, newState, platform)); s_logger.debug("11. The VM " + vm + " is in " + newState + " state"); - s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); + s_vms.put(_cluster, host_uuid, vm, newState, platform); continue; } } @@ -8279,31 +7752,31 @@ protected HashMap> deltaClusterSync(Conne continue; } if (oldState == null) { - s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); + s_vms.put(_cluster, host_uuid, vm, newState, platform); s_logger.warn("Detecting a new state but couldn't find a old state so adding it to the changes: " + vm); - changes.put(vm, new Ternary(host_uuid, newState, null)); + changes.put(vm, new Ternary(host_uuid, newState, platform)); } else if (oldState.second() == State.Starting) { if (newState == State.Running) { s_logger.debug("12. The VM " + vm + " is in " + State.Running + " state"); - s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); + s_vms.put(_cluster, host_uuid, vm, newState, platform); } else if (newState == State.Stopped) { s_logger.warn("Ignoring vm " + vm + " because of a lag in starting the vm."); } } else if (oldState.second() == State.Migrating) { if (newState == State.Running) { s_logger.debug("Detected that an migrating VM is now running: " + vm); - s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); + s_vms.put(_cluster, host_uuid, vm, newState, platform); } } else if (oldState.second() == State.Stopping) { if (newState == State.Stopped) { s_logger.debug("13. The VM " + vm + " is in " + State.Stopped + " state"); - s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); + s_vms.put(_cluster, host_uuid, vm, newState, platform); } else if (newState == State.Running) { s_logger.warn("Ignoring vm " + vm + " because of a lag in stopping the vm. "); } } else if (oldState.second() != newState) { s_logger.debug("14. The VM " + vm + " is in " + newState + " state was " + oldState.second()); - s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); + s_vms.put(_cluster, host_uuid, vm, newState, platform); if (newState == State.Stopped) { /* * if (s_vmsKilled.remove(vm)) { s_logger.debug("VM " + vm + " has been killed for storage. "); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XcpOssResource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XcpOssResource.java index 5261ca046e7d..5260c55bcc27 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XcpOssResource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XcpOssResource.java @@ -27,24 +27,22 @@ import org.apache.log4j.Logger; import org.apache.xmlrpc.XmlRpcException; - import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; import com.cloud.agent.api.NetworkUsageAnswer; import com.cloud.agent.api.NetworkUsageCommand; -import com.cloud.agent.api.StartAnswer; -import com.cloud.agent.api.StartCommand; import com.cloud.agent.api.StartupRoutingCommand; +import com.cloud.agent.api.StartupStorageCommand; import com.cloud.agent.api.StopAnswer; import com.cloud.agent.api.StopCommand; -import com.cloud.agent.api.to.NicTO; -import com.cloud.agent.api.to.VirtualMachineTO; -import com.cloud.network.Networks.TrafficType; +import com.cloud.agent.api.StoragePoolInfo; import com.cloud.resource.ServerResource; +import com.cloud.storage.Storage; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; -import com.cloud.vm.VirtualMachine; import com.xensource.xenapi.Connection; +import com.xensource.xenapi.Host; +import com.xensource.xenapi.SR; import com.xensource.xenapi.Types; import com.xensource.xenapi.Types.XenAPIException; import com.xensource.xenapi.VBD; @@ -76,16 +74,50 @@ protected void fillHostInfo(Connection conn, StartupRoutingCommand cmd) { cmd.setCaps(cmd.getCapabilities() + " , hvm"); } + protected StartupStorageCommand initializeLocalSR(Connection conn) { + SR extsr = getLocalEXTSR(conn); + if (extsr != null) { + try { + String extuuid = extsr.getUuid(conn); + _host.localSRuuid = extuuid; + long cap = extsr.getPhysicalSize(conn); + if (cap > 0) { + long avail = cap - extsr.getPhysicalUtilisation(conn); + String name = "Cloud Stack Local EXT Storage Pool for " + _host.uuid; + extsr.setNameDescription(conn, name); + Host host = Host.getByUuid(conn, _host.uuid); + String address = host.getAddress(conn); + StoragePoolInfo pInfo = new StoragePoolInfo(extsr.getNameLabel(conn), address, SRType.EXT.toString(), SRType.EXT.toString(), Storage.StoragePoolType.EXT, cap, avail); + StartupStorageCommand cmd = new StartupStorageCommand(); + cmd.setPoolInfo(pInfo); + cmd.setGuid(_host.uuid); + cmd.setDataCenter(Long.toString(_dcId)); + cmd.setResourceType(Storage.StorageResourceType.STORAGE_POOL); + return cmd; + } + } catch (XenAPIException e) { + String msg = "build local EXT info err in host:" + _host.uuid + e.toString(); + s_logger.warn(msg); + } catch (XmlRpcException e) { + String msg = "build local EXT info err in host:" + _host.uuid + e.getMessage(); + s_logger.warn(msg); + } + } + return null; + } + @Override protected String getGuestOsType(String stdType, boolean bootFromCD) { if (stdType.equalsIgnoreCase("Debian GNU/Linux 6(64-bit)")) { return "Debian Squeeze 6.0 (64-bit)"; - } else { + } else if (stdType.equalsIgnoreCase("CentOS 5.6 (64-bit)")) { + return "CentOS 5 (64-bit)"; + } else { return CitrixHelper.getXcpGuestOsType(stdType); } } - protected VBD createPatchVbd(Connection conn, String vmName, VM vm) throws XmlRpcException, XenAPIException { + protected synchronized VBD createPatchVbd(Connection conn, String vmName, VM vm) throws XmlRpcException, XenAPIException { if (_host.localSRuuid != null) { //create an iso vdi on it String result = callHostPlugin(conn, "vmops", "createISOVHD", "uuid", _host.localSRuuid); @@ -141,25 +173,6 @@ public Answer executeRequest(Command cmd) { } } - @Override - public StartAnswer execute(StartCommand cmd) { - StartAnswer answer = super.execute(cmd); - - VirtualMachineTO vmSpec = cmd.getVirtualMachine(); - if (vmSpec.getType() == VirtualMachine.Type.ConsoleProxy) { - Connection conn = getConnection(); - String publicIp = null; - for (NicTO nic : vmSpec.getNics()) { - if (nic.getType() == TrafficType.Guest) { - publicIp = nic.getIp(); - } - } - callHostPlugin(conn, "vmops", "setDNATRule", "ip", publicIp, "port", "8443", "add", "true"); - } - - return answer; - } - @Override public StopAnswer execute(StopCommand cmd) { StopAnswer answer = super.execute(cmd); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java index 2603922fd181..69c45f07c111 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java @@ -462,17 +462,4 @@ protected String getVMXenToolsVersion(Map platform) { return "xenserver56"; } - @Override - protected void finalizeVmMetaData(VM vm, Connection conn, VirtualMachineTO vmSpec) throws Exception { - Map details = vmSpec.getDetails(); - if ( details!= null ) { - String xentoolsversion = details.get("hypervisortoolsversion"); - if ( xentoolsversion == null || !xentoolsversion.equalsIgnoreCase("xenserver61") ) { - Map platform = vm.getPlatform(conn); - platform.remove("device_id"); - vm.setPlatform(conn, platform); - } - } - } - } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerConnectionPool.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerConnectionPool.java index cb188d5ee035..5014b9b02052 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerConnectionPool.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerConnectionPool.java @@ -54,7 +54,6 @@ public class XenServerConnectionPool { protected HashMap _conns = new HashMap(); protected int _retries; protected int _interval; - protected static boolean s_managePool = true; protected static long s_sleepOnError = 10 * 1000; // in ms static { File file = PropertiesUtil.findConfigFile("environment.properties"); @@ -67,15 +66,11 @@ public class XenServerConnectionPool { final Properties props = new Properties(); props.load(finputstream); finputstream.close(); - String search = props.getProperty("manage.xenserver.pool.master"); - if (search != null) { - s_managePool = Boolean.parseBoolean(search); - } - search = props.getProperty("sleep.interval.on.error"); + String search = props.getProperty("sleep.interval.on.error"); if (search != null) { s_sleepOnError = NumbersUtil.parseInterval(search, 10) * 1000; } - s_logger.info("XenServer Connection Pool Configs: manage.xenserver.pool.master=" + s_managePool + "; sleep.interval.on.error=" + s_sleepOnError); + s_logger.info("XenServer Connection Pool Configs: sleep.interval.on.error=" + s_sleepOnError); } catch (FileNotFoundException e) { s_logger.debug("File is not found", e); } catch (IOException e) { @@ -212,301 +207,29 @@ public boolean joinPool(Connection conn, String hostIp, String masterIp, String return false; } - public void switchMaster(String slaveIp, String poolUuid, - Connection conn, Host host, String username, Queue password, - int wait) throws XmlRpcException, XenAPIException { - synchronized (poolUuid.intern()) { - String masterIp = host.getAddress(conn); - s_logger.debug("Designating the new master to " + masterIp); - Pool.designateNewMaster(conn, host); - Connection slaveConn = null; - Connection masterConn = null; - int retry = 30; - for (int i = 0; i < retry; i++) { - forceSleep(5); - try { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Logging on as the slave to " + slaveIp); - } - slaveConn = null; - masterConn = null; - Session slaveSession = null; - - slaveConn = new Connection(getURL(slaveIp), 10); - slaveSession = slaveLocalLoginWithPassword(slaveConn, username, password); - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Slave logon successful. session= " - + slaveSession); - } - - Pool.Record pr = getPoolRecord(slaveConn); - Host master = pr.master; - String ma = master.getAddress(slaveConn); - if (!ma.trim().equals(masterIp.trim())) { - continue; - } - s_logger.debug("Logging on as the master to " + masterIp); - masterConn = new Connection(getURL(masterIp), 10); - loginWithPassword(masterConn, username, password, APIVersion.latest().toString()); - removeConnect(poolUuid); - ensurePoolIntegrity(masterConn, masterIp, username, password, wait); - return; - } catch (Types.HostIsSlave e) { - s_logger.debug("HostIsSlaveException: Still waiting for the conversion to the master"); - } catch (XmlRpcException e) { - s_logger.debug("XmlRpcException: Still waiting for the conversion to the master " + e.getMessage()); - } catch (Exception e) { - s_logger.debug("Exception: Still waiting for the conversion to the master" + e.getMessage()); - } finally { - if (masterConn != null) { - try { - Session.logout(masterConn); - } catch (Exception e) { - s_logger.debug("Unable to log out of session: " - + e.getMessage()); - } - masterConn.dispose(); - masterConn = null; - } - localLogout(slaveConn); - slaveConn = null; - } - } - throw new CloudRuntimeException( - "Unable to logon to the new master after " + retry + " retries"); - } - } - - private void localLogout(Connection conn) { - if ( conn == null ) - return; + + public Connection getConnect(String ip, String username, Queue password) { + Connection conn = new Connection(getURL(ip), 10); try { - if( s_logger.isTraceEnabled()) { - s_logger.trace("Logging out of the session " - + conn.getSessionReference()); - } - Session.localLogout(conn); - } catch (Exception e) { - s_logger.debug("localLogout has problem " + e.getMessage()); - } finally { - conn.dispose(); - conn = null; - } - } - - public Connection slaveConnect(String ip, String username, Queue password) { - Connection conn = null; - try{ - conn = new Connection(getURL(ip), 10); - slaveLocalLoginWithPassword(conn, username, password); - return conn; - }catch ( Exception e){ - s_logger.debug("Failed to slave local login to " + ip); - } - return null; - } - - public Connection masterConnect(String ip, String username, Queue password) { - Connection conn = null; - try{ - conn = new Connection(getURL(ip), 10); - s_logger.debug("Logging on as the master to " + ip); loginWithPassword(conn, username, password, APIVersion.latest().toString()); - return conn; - }catch ( Exception e){ - s_logger.debug("Failed to slave local login to " + ip); - } - throw new RuntimeException("can not log in to master " + ip); - } - - - public String getMasterIp(String ip, String username, Queue password) throws XenAPIException { - Connection slaveConn = null; - try{ - slaveConn = new Connection(getURL(ip), 10); - slaveLocalLoginWithPassword(slaveConn, username, password); - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Slave logon to " + ip); - } - String masterIp = null; - Pool.Record pr = getPoolRecord(slaveConn); - Host master = pr.master; - masterIp = master.getAddress(slaveConn); - return masterIp; - }catch(Types.SessionAuthenticationFailed e){ - s_logger.debug("Failed to slave local login to " + ip + " due to " + e.toString()); - throw e; - }catch ( Exception e){ - s_logger.debug("Failed to slave local login to " + ip + " due to " + e.toString()); - } finally { - localLogout(slaveConn); - slaveConn = null; - } - throw new RuntimeException("can not get master ip"); - } - - - void PoolEmergencyTransitionToMaster(String slaveIp, String username, Queue password) { - if (!s_managePool) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Don't manage pool on error so sleeping for " + s_sleepOnError); - try { - Thread.sleep(s_sleepOnError); - } catch (InterruptedException ie) { - } - } - return; - } - - Connection slaveConn = null; - Connection c = null; - try{ - s_logger.debug("Trying to transition master to " + slaveIp); - slaveConn = new Connection(getURL(slaveIp), 10); - slaveLocalLoginWithPassword(slaveConn, username, password); - Pool.emergencyTransitionToMaster(slaveConn); - // restart xapi in 10 sec - forceSleep(10); - // check if the master of this host is set correctly. - c = new Connection(getURL(slaveIp), 10); - for (int i = 0; i < 30; i++) { - try { - loginWithPassword(c, username, password, APIVersion.latest().toString()); - s_logger.debug("Succeeded to transition master to " + slaveIp); - return; - } catch (Types.HostIsSlave e) { - s_logger.debug("HostIsSlave: Still waiting for the conversion to the master " + slaveIp); - } catch (Exception e) { - s_logger.debug("Exception: Still waiting for the conversion to the master"); - } - forceSleep(2); - } - throw new RuntimeException("EmergencyTransitionToMaster failed after retry 30 times"); - } catch (Exception e) { - throw new RuntimeException("EmergencyTransitionToMaster failed due to " + e.getMessage()); - } finally { - localLogout(slaveConn); - slaveConn = null; - if(c != null) { - try { - Session.logout(c); - c.dispose(); - } catch (Exception e) { - } - } - } - - } - - private void PoolEmergencyResetMaster(String slaveIp, String masterIp, String username, Queue password) { - if (!s_managePool) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Don't manage pool on error so sleeping for " + s_sleepOnError); - try { - Thread.sleep(s_sleepOnError); - } catch (InterruptedException ie) { - } - } - return; - } - - Connection slaveConn = null; - try { - s_logger.debug("Trying to reset master of slave " + slaveIp - + " to " + masterIp); - slaveConn = new Connection(getURL(slaveIp), 10); - slaveLocalLoginWithPassword(slaveConn, username, password); - Pool.emergencyResetMaster(slaveConn, masterIp); - forceSleep(10); - for (int i = 0; i < 30; i++) { - try { - slaveLocalLoginWithPassword(slaveConn, username, password); - Pool.Record pr = getPoolRecord(slaveConn); - String mIp = pr.master.getAddress(slaveConn); - if (mIp.trim().equals(masterIp.trim())) { - s_logger.debug("Succeeded to reset master of slave " + slaveIp + " to " + masterIp); - return; - } - } catch (Exception e) { - } finally { - localLogout(slaveConn); - slaveConn = null; - } - // wait 2 second - forceSleep(2); - } - throw new CloudRuntimeException("Unable to reset master of slave " + slaveIp - + " to " + masterIp + "after 30 retry"); - } catch (Exception e) { - throw new CloudRuntimeException("Unable to reset master of slave " + slaveIp - + " to " + masterIp + " due to " + e.toString()); - } finally { - localLogout(slaveConn); - slaveConn = null; - } - } - - protected void ensurePoolIntegrity(Connection conn, - String masterIp, String username, Queue password, int wait) { - try { - // try recoverSlave first - Set rcSlaves = Pool.recoverSlaves(conn); - // wait 10 second - forceSleep(10); - for(Host slave : rcSlaves ) { - for (int i = 0; i < 30; i++) { - Connection slaveConn = null; - try { - - String slaveIp = slave.getAddress(conn); - s_logger.debug("Logging on as the slave to " + slaveIp); - slaveConn = new Connection(getURL(slaveIp), 10); - slaveLocalLoginWithPassword(slaveConn, username, password); - Pool.Record pr = getPoolRecord(slaveConn); - String mIp = pr.master.getAddress(slaveConn); - if (mIp.trim().equals(masterIp.trim())) { - break; - } - } catch (Exception e) { - } finally { - localLogout(slaveConn); - slaveConn = null; - } - // wait 2 second - forceSleep(2); - } - } - // then try emergency reset master - Set slaves = Host.getAll(conn); - for (Host slave : slaves) { - String slaveIp = slave.getAddress(conn); - Connection slaveConn = null; - try { - s_logger.debug("Logging on as the slave to " + slaveIp); - - slaveConn = new Connection(getURL(slaveIp), 10); - slaveLocalLoginWithPassword(slaveConn, username, password); - Pool.Record slavePoolr = getPoolRecord(slaveConn); - String ip = slavePoolr.master.getAddress(slaveConn); - if (!masterIp.trim().equals(ip.trim())) { - PoolEmergencyResetMaster(slaveIp, masterIp, username, password); - } - } catch (Exception e) { - s_logger.debug("Unable to login to slave " + slaveIp + " error " + e.getMessage()); - } finally { - localLogout(slaveConn); - slaveConn = null; - } + } catch (Types.HostIsSlave e) { + String maddress = e.masterIPAddress; + conn = new Connection(getURL(maddress), 10); + try { + loginWithPassword(conn, username, password, APIVersion.latest().toString()); + } catch (Exception e1) { + String msg = "Unable to create master connection to host(" + maddress +") , due to " + e1.toString(); + s_logger.debug(msg); + throw new CloudRuntimeException(msg, e1); } } catch (Exception e) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Catch " + e.getClass().getName() + " due to " + e.toString()); - } + String msg = "Unable to create master connection to host(" + ip +") , due to " + e.toString(); + s_logger.debug(msg); + throw new CloudRuntimeException(msg, e); } + return conn; } - + public URL getURL(String ip){ try { return new URL("https://" + ip); @@ -522,39 +245,18 @@ public URL getURL(String ip){ public Connection connect(String hostUuid, String poolUuid, String ipAddress, String username, Queue password, int wait) { XenServerConnection mConn = null; - Connection sConn = null; - String masterIp = null; if (hostUuid == null || poolUuid == null || ipAddress == null || username == null || password == null) { String msg = "Connect some parameter are null hostUuid:" + hostUuid + " ,poolUuid:" + poolUuid + " ,ipAddress:" + ipAddress; s_logger.debug(msg); throw new CloudRuntimeException(msg); } - Host host = null; synchronized (poolUuid.intern()) { // Let's see if it is an existing connection. mConn = getConnect(poolUuid); if (mConn != null){ try{ - host = Host.getByUuid(mConn, hostUuid); - } catch (Types.SessionInvalid e) { - s_logger.debug("Session thgrough ip " + mConn.getIp() + " is invalid for pool(" + poolUuid + ") due to " + e.toString()); - try { - loginWithPassword(mConn, mConn.getUsername(), mConn.getPassword(), APIVersion.latest().toString()); - } catch (Exception e1) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("connect through IP(" + mConn.getIp() + " for pool(" + poolUuid + ") is broken due to " + e.toString()); - } - removeConnect(poolUuid); - mConn = null; - } - } catch (UuidInvalid e) { - String msg = "Host(" + hostUuid + ") doesn't belong to pool(" + poolUuid + "), please execute 'xe pool-join master-address=" + mConn.getIp() - + " master-username=" + mConn.getUsername(); - if (s_logger.isDebugEnabled()) { - s_logger.debug(msg); - } - throw new CloudRuntimeException(msg, e); + Host.getByUuid(mConn, hostUuid); } catch (Exception e) { if (s_logger.isDebugEnabled()) { s_logger.debug("connect through IP(" + mConn.getIp() + " for pool(" + poolUuid + ") is broken due to " + e.toString()); @@ -565,113 +267,29 @@ public Connection connect(String hostUuid, String poolUuid, String ipAddress, } if ( mConn == null ) { + mConn = new XenServerConnection(getURL(ipAddress), ipAddress, username, password, _retries, _interval, wait); try { + loginWithPassword(mConn, username, password, APIVersion.latest().toString()); + } catch (Types.HostIsSlave e) { + String maddress = e.masterIPAddress; + mConn = new XenServerConnection(getURL(maddress), maddress, username, password, _retries, _interval, wait); try { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Logging on as the slave to " + ipAddress); - } - sConn = new Connection(getURL(ipAddress), 5); - slaveLocalLoginWithPassword(sConn, username, password); - } catch (Exception e){ - String msg = "Unable to create slave connection to host(" + hostUuid +") due to " + e.toString(); - if (s_logger.isDebugEnabled()) { - s_logger.debug(msg); - } - throw new CloudRuntimeException(msg, e); - } - Pool.Record pr = null; - try { - pr = getPoolRecord(sConn); - } catch (Exception e) { - PoolEmergencyTransitionToMaster(ipAddress, username, password); - mConn = new XenServerConnection(getURL(ipAddress), ipAddress, username, password, _retries, _interval, wait); - try { - loginWithPassword(mConn, username, password, APIVersion.latest().toString()); - pr = getPoolRecord(mConn); - } catch (Exception e1) { - String msg = "Unable to create master connection to host(" + hostUuid +") after transition it to master, due to " + e1.toString(); - if (s_logger.isDebugEnabled()) { - s_logger.debug(msg); - } - throw new CloudRuntimeException(msg, e1); - } - if ( !pr.uuid.equals(poolUuid) ) { - String msg = "host(" + hostUuid +") should be in pool(" + poolUuid + "), but it is actually in pool(" + pr.uuid + ")"; - if (s_logger.isDebugEnabled()) { - s_logger.debug(msg); - } - throw new CloudRuntimeException(msg); - } else { - if (s_managePool) { - ensurePoolIntegrity(mConn, ipAddress, username, password, wait); - } - addConnect(poolUuid, mConn); - return mConn; - } - } - if ( !pr.uuid.equals(poolUuid) ) { - String msg = "host(" + hostUuid +") should be in pool(" + poolUuid + "), but it is actually in pool(" + pr.uuid + ")"; - if (s_logger.isDebugEnabled()) { - s_logger.debug(msg); - } - throw new CloudRuntimeException(msg); - } - try { - masterIp = pr.master.getAddress(sConn); - mConn = new XenServerConnection(getURL(masterIp), masterIp, username, password, _retries, _interval, wait); loginWithPassword(mConn, username, password, APIVersion.latest().toString()); - addConnect(poolUuid, mConn); - return mConn; - } catch (Exception e) { - String msg = "Unable to logon in " + masterIp + " as master in pool(" + poolUuid + ")"; - if (s_logger.isDebugEnabled()) { - s_logger.debug(msg); - } - throw new CloudRuntimeException(msg); - } - } finally { - localLogout(sConn); - sConn = null; - } - } - } - - if ( mConn != null ) { - if (s_managePool) { - try { - Map args = new HashMap(); - host.callPlugin(mConn, "echo", "main", args); - } catch (Types.SessionInvalid e) { - if (s_logger.isDebugEnabled()) { - String msg = "Catch Exception: " + e.getClass().getName() + " Can't connect host " + ipAddress + " due to " + e.toString(); - s_logger.debug(msg); - } - PoolEmergencyResetMaster(ipAddress, mConn.getIp(), mConn.getUsername(), mConn.getPassword()); - } catch (Types.CannotContactHost e ) { - if (s_logger.isDebugEnabled()) { - String msg = "Catch Exception: " + e.getClass().getName() + " Can't connect host " + ipAddress + " due to " + e.toString(); + } catch (Exception e1) { + String msg = "Unable to create master connection to host(" + maddress +") , due to " + e1.toString(); s_logger.debug(msg); - } - PoolEmergencyResetMaster(ipAddress, mConn.getIp(), mConn.getUsername(), mConn.getPassword()); - } catch (Types.HostOffline e ) { - if (s_logger.isDebugEnabled()) { - String msg = "Catch Exception: " + e.getClass().getName() + " Host is offline " + ipAddress + " due to " + e.toString(); - s_logger.debug(msg); - } - PoolEmergencyResetMaster(ipAddress, mConn.getIp(), mConn.getUsername(), mConn.getPassword()); - } catch (Types.HostNotLive e ) { - String msg = "Catch Exception: " + e.getClass().getName() + " Host Not Live " + ipAddress + " due to " + e.toString(); - if (s_logger.isDebugEnabled()) { - s_logger.debug(msg); - } - PoolEmergencyResetMaster(ipAddress, mConn.getIp(), mConn.getUsername(), mConn.getPassword()); + throw new CloudRuntimeException(msg, e1); + + } } catch (Exception e) { - String msg = "Echo test failed on host " + hostUuid + " IP " + ipAddress; - s_logger.warn(msg, e); - throw new CloudRuntimeException(msg, e); + String msg = "Unable to create master connection to host(" + ipAddress +") , due to " + e.toString(); + s_logger.debug(msg); + throw new CloudRuntimeException(msg, e); } + addConnect(poolUuid, mConn); } } + return mConn; } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerPoolVms.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerPoolVms.java index f22fb286c8af..d25602414906 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerPoolVms.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerPoolVms.java @@ -50,11 +50,15 @@ public State getState(String clusterId, String name){ Ternary pv = vms.get(name); return pv == null ? State.Stopped : pv.second(); // if a VM is absent on the cluster, it is effectively in stopped state. } - - public void put(String clusterId, String hostUuid, String name, State state, String xstoolsversion){ + public Ternary get(String clusterId, String name) { + HashMap> vms = getClusterVmState(clusterId); + return vms.get(name); + } + + public void put(String clusterId, String hostUuid, String name, State state, String platform){ HashMap> vms= getClusterVmState(clusterId); - vms.put(name, new Ternary(hostUuid, state, xstoolsversion)); + vms.put(name, new Ternary(hostUuid, state, platform)); } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java index 5a19aee2468f..430dcb8e36b7 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java @@ -22,7 +22,6 @@ import static com.cloud.utils.ReflectUtil.flattenProperties; import static com.google.common.collect.Lists.newArrayList; - import java.io.File; import java.net.URI; import java.util.Arrays; @@ -81,6 +80,7 @@ import com.xensource.xenapi.SR; import com.xensource.xenapi.Types; import com.xensource.xenapi.Types.BadServerResponse; +import com.xensource.xenapi.Types.VmPowerState; import com.xensource.xenapi.Types.XenAPIException; import com.xensource.xenapi.VBD; import com.xensource.xenapi.VDI; @@ -90,10 +90,10 @@ public class XenServerStorageProcessor implements StorageProcessor { private static final Logger s_logger = Logger.getLogger(XenServerStorageProcessor.class); protected CitrixResourceBase hypervisorResource; - private String BaseMountPointOnHost = "/var/run/cloud_mount"; + protected String BaseMountPointOnHost = "/var/run/cloud_mount"; public XenServerStorageProcessor(CitrixResourceBase resource) { - this.hypervisorResource = resource; + hypervisorResource = resource; } @Override @@ -117,14 +117,14 @@ public AttachAnswer attachIso(AttachCommand cmd) { String vmName = cmd.getVmName(); try { - Connection conn = this.hypervisorResource.getConnection(); + Connection conn = hypervisorResource.getConnection(); VBD isoVBD = null; // Find the VM - VM vm = this.hypervisorResource.getVM(conn, vmName); + VM vm = hypervisorResource.getVM(conn, vmName); // Find the ISO VDI - VDI isoVDI = this.hypervisorResource.getIsoVDIByURL(conn, vmName, isoURL); + VDI isoVDI = hypervisorResource.getIsoVDIByURL(conn, vmName, isoURL); // Find the VM's CD-ROM VBD Set vbds = vm.getVBDs(conn); @@ -142,7 +142,7 @@ public AttachAnswer attachIso(AttachCommand cmd) { throw new CloudRuntimeException("Unable to find CD-ROM VBD for VM: " + vmName); } else { // If an ISO is already inserted, eject it - if (isoVBD.getEmpty(conn) == false) { + if (!isoVBD.getEmpty(conn)) { isoVBD.eject(conn); } @@ -163,76 +163,92 @@ public AttachAnswer attachIso(AttachCommand cmd) { @Override public AttachAnswer attachVolume(AttachCommand cmd) { - String vmName = cmd.getVmName(); - String vdiNameLabel = vmName + "-DATA"; DiskTO disk = cmd.getDisk(); DataTO data = disk.getData(); try { + String vmName = cmd.getVmName(); + String vdiNameLabel = vmName + "-DATA"; + Connection conn = this.hypervisorResource.getConnection(); + VM vm = null; - VDI vdi = null; + boolean vmNotRunning = true; - Map details = cmd.getDisk().getDetails(); + try { + vm = this.hypervisorResource.getVM(conn, vmName); + + VM.Record vmr = vm.getRecord(conn); + + vmNotRunning = vmr.powerState != VmPowerState.RUNNING; + } + catch (CloudRuntimeException ex) { + } + + Map details = disk.getDetails(); boolean isManaged = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - if (isManaged) { - String iScsiName = details.get(DiskTO.IQN); - String storageHost = details.get(DiskTO.STORAGE_HOST); - String chapInitiatorUsername = disk.getDetails().get(DiskTO.CHAP_INITIATOR_USERNAME); - String chapInitiatorSecret = disk.getDetails().get(DiskTO.CHAP_INITIATOR_SECRET); - Long volumeSize = Long.parseLong(details.get(DiskTO.VOLUME_SIZE)); + // if the VM is not running and we're not dealing with managed storage, just return success (nothing to do here) + // this should probably never actually happen + if (vmNotRunning && !isManaged) { + return new AttachAnswer(disk); + } + + VDI vdi = null; - SR sr = this.hypervisorResource.getIscsiSR(conn, iScsiName, storageHost, iScsiName, - chapInitiatorUsername, chapInitiatorSecret, true); + if (isManaged) { + vdi = hypervisorResource.prepareManagedStorage(conn, details, data.getPath(), vdiNameLabel); - vdi = this.hypervisorResource.getVDIbyUuid(conn, data.getPath(), false); + if (vmNotRunning) { + DiskTO newDisk = new DiskTO(disk.getData(), disk.getDiskSeq(), vdi.getUuid(conn), disk.getType()); - if (vdi == null) { - vdi = this.hypervisorResource.createVdi(sr, vdiNameLabel, volumeSize); + return new AttachAnswer(newDisk); } } else { - vdi = this.hypervisorResource.mount(conn, null, null, data.getPath()); + vdi = hypervisorResource.mount(conn, null, null, data.getPath()); } - // Look up the VM - VM vm = this.hypervisorResource.getVM(conn, vmName); /* For HVM guest, if no pv driver installed, no attach/detach */ - boolean isHVM; - if (vm.getPVBootloader(conn).equalsIgnoreCase("")) { - isHVM = true; - } else { - isHVM = false; - } + boolean isHVM = vm.getPVBootloader(conn).equalsIgnoreCase(""); + VMGuestMetrics vgm = vm.getGuestMetrics(conn); boolean pvDrvInstalled = false; + if (!this.hypervisorResource.isRefNull(vgm) && vgm.getPVDriversUpToDate(conn)) { pvDrvInstalled = true; } + if (isHVM && !pvDrvInstalled) { s_logger.warn(": You attempted an operation on a VM which requires PV drivers to be installed but the drivers were not detected"); + return new AttachAnswer("You attempted an operation that requires PV drivers to be installed on the VM. Please install them by inserting xen-pv-drv.iso."); } // Figure out the disk number to attach the VM to String diskNumber = null; Long deviceId = disk.getDiskSeq(); - if( deviceId != null ) { - if( deviceId.longValue() == 3 ) { + + if (deviceId != null) { + if (deviceId.longValue() == 3) { String msg = "Device 3 is reserved for CD-ROM, choose other device"; + return new AttachAnswer(msg); } - if(this.hypervisorResource.isDeviceUsed(conn, vm, deviceId)) { + + if (this.hypervisorResource.isDeviceUsed(conn, vm, deviceId)) { String msg = "Device " + deviceId + " is used in VM " + vmName; + return new AttachAnswer(msg); } + diskNumber = deviceId.toString(); } else { - diskNumber = this.hypervisorResource.getUnusedDeviceNum(conn, vm); + diskNumber = hypervisorResource.getUnusedDeviceNum(conn, vm); } - // Create a new VBD + VBD.Record vbdr = new VBD.Record(); + vbdr.VM = vm; vbdr.VDI = vdi; vbdr.bootable = false; @@ -240,6 +256,7 @@ public AttachAnswer attachVolume(AttachCommand cmd) { vbdr.mode = Types.VbdMode.RW; vbdr.type = Types.VbdType.DISK; vbdr.unpluggable = true; + VBD vbd = VBD.create(conn, vbdr); // Attach the VBD to the VM @@ -247,9 +264,10 @@ public AttachAnswer attachVolume(AttachCommand cmd) { // Update the VDI's label to include the VM name vdi.setNameLabel(conn, vdiNameLabel); + DiskTO newDisk = new DiskTO(disk.getData(), Long.parseLong(diskNumber), vdi.getUuid(conn), disk.getType()); - return new AttachAnswer(newDisk); + return new AttachAnswer(newDisk); } catch (XenAPIException e) { String msg = "Failed to attach volume" + " for uuid: " + data.getPath() + " due to " + e.toString(); s_logger.warn(msg, e); @@ -281,13 +299,13 @@ public Answer dettachIso(DettachCommand cmd) { } try { - Connection conn = this.hypervisorResource.getConnection(); + Connection conn = hypervisorResource.getConnection(); // Find the VM - VM vm = this.hypervisorResource.getVM(conn, cmd.getVmName()); + VM vm = hypervisorResource.getVM(conn, cmd.getVmName()); String vmUUID = vm.getUuid(conn); // Find the ISO VDI - VDI isoVDI = this.hypervisorResource.getIsoVDIByURL(conn, cmd.getVmName(), isoURL); + VDI isoVDI = hypervisorResource.getIsoVDIByURL(conn, cmd.getVmName(), isoURL); SR sr = isoVDI.getSR(conn); @@ -310,7 +328,7 @@ public Answer dettachIso(DettachCommand cmd) { } if (!sr.getNameLabel(conn).startsWith("XenServer Tools")) { - this.hypervisorResource.removeSR(conn, sr); + hypervisorResource.removeSR(conn, sr); } return new DettachAnswer(disk); @@ -325,57 +343,75 @@ public Answer dettachIso(DettachCommand cmd) { } } - @Override public Answer dettachVolume(DettachCommand cmd) { - String vmName = cmd.getVmName(); DiskTO disk = cmd.getDisk(); DataTO data = disk.getData(); + try { Connection conn = this.hypervisorResource.getConnection(); - // Look up the VDI - VDI vdi = this.hypervisorResource.mount(conn, null, null, data.getPath()); - // Look up the VM - VM vm = this.hypervisorResource.getVM(conn, vmName); - /* For HVM guest, if no pv driver installed, no attach/detach */ - boolean isHVM; - if (vm.getPVBootloader(conn).equalsIgnoreCase("")) { - isHVM = true; - } else { - isHVM = false; + + String vmName = cmd.getVmName(); + VM vm = null; + + boolean vmNotRunning = true; + + try { + vm = this.hypervisorResource.getVM(conn, vmName); + + VM.Record vmr = vm.getRecord(conn); + + vmNotRunning = vmr.powerState != VmPowerState.RUNNING; } - VMGuestMetrics vgm = vm.getGuestMetrics(conn); - boolean pvDrvInstalled = false; - if (!this.hypervisorResource.isRefNull(vgm) && vgm.getPVDriversUpToDate(conn)) { - pvDrvInstalled = true; + catch (CloudRuntimeException ex) { } - if (isHVM && !pvDrvInstalled) { - s_logger.warn(": You attempted an operation on a VM which requires PV drivers to be installed but the drivers were not detected"); - return new DettachAnswer("You attempted an operation that requires PV drivers to be installed on the VM. Please install them by inserting xen-pv-drv.iso."); + + // if the VM is not running and we're not dealing with managed storage, just return success (nothing to do here) + // this should probably never actually happen + if (vmNotRunning && !cmd.isManaged()) { + return new DettachAnswer(disk); } + if (!vmNotRunning) { + /* For HVM guest, if no pv driver installed, no attach/detach */ + boolean isHVM = vm.getPVBootloader(conn).equalsIgnoreCase(""); - // Look up all VBDs for this VDI - Set vbds = vdi.getVBDs(conn); + VMGuestMetrics vgm = vm.getGuestMetrics(conn); + boolean pvDrvInstalled = false; - // Detach each VBD from its VM, and then destroy it - for (VBD vbd : vbds) { - VBD.Record vbdr = vbd.getRecord(conn); + if (!this.hypervisorResource.isRefNull(vgm) && vgm.getPVDriversUpToDate(conn)) { + pvDrvInstalled = true; + } - if (vbdr.currentlyAttached) { - vbd.unplug(conn); + if (isHVM && !pvDrvInstalled) { + s_logger.warn(": You attempted an operation on a VM which requires PV drivers to be installed but the drivers were not detected"); + return new DettachAnswer("You attempted an operation that requires PV drivers to be installed on the VM. Please install them by inserting xen-pv-drv.iso."); } - vbd.destroy(conn); - } + VDI vdi = this.hypervisorResource.mount(conn, null, null, data.getPath()); + + // Look up all VBDs for this VDI + Set vbds = vdi.getVBDs(conn); - // Update the VDI's label to be "detached" - vdi.setNameLabel(conn, "detached"); + // Detach each VBD from its VM, and then destroy it + for (VBD vbd : vbds) { + VBD.Record vbdr = vbd.getRecord(conn); - this.hypervisorResource.umount(conn, vdi); + if (vbdr.currentlyAttached) { + vbd.unplug(conn); + } + + vbd.destroy(conn); + } + + // Update the VDI's label to be "detached" + vdi.setNameLabel(conn, "detached"); + + this.hypervisorResource.umount(conn, vdi); + } if (cmd.isManaged()) { - this.hypervisorResource.handleSrAndVdiDetach(cmd.get_iScsiName()); + hypervisorResource.handleSrAndVdiDetach(cmd.get_iScsiName(), conn); } return new DettachAnswer(disk); @@ -385,7 +421,6 @@ public Answer dettachVolume(DettachCommand cmd) { } } - protected SR getSRByNameLabel(Connection conn, String nameLabel) throws BadServerResponse, XenAPIException, XmlRpcException { Set srs = SR.getByNameLabel(conn, nameLabel); if (srs.size() != 1) { @@ -439,11 +474,15 @@ public Answer createSnapshot(CreateObjectCommand cmd) { Boolean isISCSI = IsISCSI(type); String snapshotParentUUID = getVhdParent(conn, srUUID, snapshotUUID, isISCSI); - String preSnapshotParentUUID = getVhdParent(conn, srUUID, preSnapshotUUID, isISCSI); - if( snapshotParentUUID != null && snapshotParentUUID.equals(preSnapshotParentUUID)) { - // this is empty snapshot, remove it - snapshot.destroy(conn); - snapshotUUID = preSnapshotUUID; + try { + String preSnapshotParentUUID = getVhdParent(conn, srUUID, preSnapshotUUID, isISCSI); + if( snapshotParentUUID != null && snapshotParentUUID.equals(preSnapshotParentUUID)) { + // this is empty snapshot, remove it + snapshot.destroy(conn); + snapshotUUID = preSnapshotUUID; + } + } catch(Exception e) { + s_logger.debug("Failed to get parent snapshot", e); } } SnapshotObjectTO newSnapshot = new SnapshotObjectTO(); @@ -581,13 +620,13 @@ protected SR getIscsiSR(Connection conn, StorageFilerTO pool) { } if (target.equals(dc.get("target")) && targetiqn.equals(dc.get("targetIQN")) && lunid.equals(dc.get("lunid"))) { throw new CloudRuntimeException("There is a SR using the same configuration target:" + dc.get("target") + ", targetIQN:" - + dc.get("targetIQN") + ", lunid:" + dc.get("lunid") + " for pool " + pool.getUuid() + "on host:" + this.hypervisorResource.getHost().uuid); + + dc.get("targetIQN") + ", lunid:" + dc.get("lunid") + " for pool " + pool.getUuid() + "on host:" + hypervisorResource.getHost().uuid); } } deviceConfig.put("target", target); deviceConfig.put("targetIQN", targetiqn); - Host host = Host.getByUuid(conn, this.hypervisorResource.getHost().uuid); + Host host = Host.getByUuid(conn, hypervisorResource.getHost().uuid); Map smConfig = new HashMap(); String type = SRType.LVMOISCSI.toString(); String poolId = Long.toString(pool.getId()); @@ -660,7 +699,7 @@ protected SR getIscsiSR(Connection conn, StorageFilerTO pool) { } } protected Answer execute(CreateStoragePoolCommand cmd) { - Connection conn = this.hypervisorResource.getConnection(); + Connection conn = hypervisorResource.getConnection(); StorageFilerTO pool = cmd.getPool(); try { if (pool.getType() == StoragePoolType.NetworkFilesystem) { @@ -673,7 +712,7 @@ protected Answer execute(CreateStoragePoolCommand cmd) { } return new Answer(cmd, true, "success"); } catch (Exception e) { - String msg = "Catch Exception " + e.getClass().getName() + ", create StoragePool failed due to " + e.toString() + " on host:" + this.hypervisorResource.getHost().uuid + " pool: " + pool.getHost() + pool.getPath(); + String msg = "Catch Exception " + e.getClass().getName() + ", create StoragePool failed due to " + e.toString() + " on host:" + hypervisorResource.getHost().uuid + " pool: " + pool.getHost() + pool.getPath(); s_logger.warn(msg, e); return new Answer(cmd, false, msg); } @@ -781,7 +820,7 @@ protected Answer execute(AttachPrimaryDataStoreCmd cmd) { } } - private boolean IsISCSI(String type) { + protected boolean IsISCSI(String type) { return SRType.LVMOHBA.equals(type) || SRType.LVMOISCSI.equals(type) || SRType.LVM.equals(type) ; } @@ -1078,7 +1117,7 @@ public String swiftBackupSnapshot(Connection conn, SwiftTO swift, String srUuid, return lfilename; } - private String backupSnapshotToS3(final Connection connection, final S3TO s3, final String srUuid, final String folder, final String snapshotUuid, + protected String backupSnapshotToS3(final Connection connection, final S3TO s3, final String srUuid, final String folder, final String snapshotUuid, final Boolean iSCSIFlag, final int wait) { final String filename = iSCSIFlag ? "VHD-" + snapshotUuid @@ -1118,6 +1157,16 @@ private String backupSnapshotToS3(final Connection connection, final S3TO s3, fi } + protected Long getSnapshotSize(Connection conn, String primaryStorageSRUuid, String snapshotUuid, Boolean isISCSI, int wait) { + String physicalSize = hypervisorResource.callHostPluginAsync(conn, "vmopsSnapshot", "getSnapshotSize", wait, + "primaryStorageSRUuid", primaryStorageSRUuid, "snapshotUuid", snapshotUuid, "isISCSI", isISCSI.toString()); + if (physicalSize == null || physicalSize.isEmpty()) { + return (long) 0; + } else { + return Long.parseLong(physicalSize); + } + } + protected String backupSnapshot(Connection conn, String primaryStorageSRUuid, String localMountPoint, String path, String secondaryStorageMountPath, String snapshotUuid, String prevBackupUuid, Boolean isISCSI, int wait) { String backupSnapshotUuid = null; @@ -1147,7 +1196,7 @@ protected String backupSnapshot(Connection conn, String primaryStorageSRUuid, St if (status != null && status.equalsIgnoreCase("1") && backupSnapshotUuid != null) { s_logger.debug("Successfully copied backupUuid: " + backupSnapshotUuid + " to secondary storage"); - return backupSnapshotUuid; + return results; } else { errMsg = "Could not copy backupUuid: " + backupSnapshotUuid + " from primary storage " + primaryStorageSRUuid + " to secondary storage " @@ -1160,7 +1209,7 @@ protected String backupSnapshot(Connection conn, String primaryStorageSRUuid, St throw new CloudRuntimeException(errMsg); } - private boolean destroySnapshotOnPrimaryStorageExceptThis(Connection conn, String volumeUuid, String avoidSnapshotUuid){ + protected boolean destroySnapshotOnPrimaryStorageExceptThis(Connection conn, String volumeUuid, String avoidSnapshotUuid){ try { VDI volume = getVDIbyUuid(conn, volumeUuid); if (volume == null) { @@ -1169,7 +1218,7 @@ private boolean destroySnapshotOnPrimaryStorageExceptThis(Connection conn, Strin Set snapshots = volume.getSnapshots(conn); for( VDI snapshot : snapshots ) { try { - if(! snapshot.getUuid(conn).equals(avoidSnapshotUuid)) { + if (!snapshot.getUuid(conn).equals(avoidSnapshotUuid)) { snapshot.destroy(conn); } } catch (Exception e) { @@ -1190,6 +1239,26 @@ private boolean destroySnapshotOnPrimaryStorageExceptThis(Connection conn, Strin return false; } + private boolean destroySnapshotOnPrimaryStorage(Connection conn, String lastSnapshotUuid) { + try { + VDI snapshot = getVDIbyUuid(conn, lastSnapshotUuid); + if (snapshot == null) { + // since this is just used to cleanup leftover bad snapshots, no need to throw exception + s_logger.warn("Could not destroy snapshot " + lastSnapshotUuid + " due to can not find it"); + return false; + } + snapshot.destroy(conn); + return true; + } catch (XenAPIException e) { + String msg = "Destroying snapshot: " + lastSnapshotUuid + " failed due to " + e.toString(); + s_logger.error(msg, e); + } catch (Exception e) { + String msg = "Destroying snapshot: " + lastSnapshotUuid + " failed due to " + e.toString(); + s_logger.warn(msg, e); + } + return false; + } + @Override public Answer backupSnapshot(CopyCommand cmd) { Connection conn = hypervisorResource.getConnection(); @@ -1214,6 +1283,7 @@ public Answer backupSnapshot(CopyCommand cmd) { SnapshotObjectTO snapshotTO = (SnapshotObjectTO)srcData; SnapshotObjectTO snapshotOnImage = (SnapshotObjectTO)destData; String snapshotUuid = snapshotTO.getPath(); + String volumeUuid = snapshotTO.getVolume().getPath(); String prevBackupUuid = snapshotOnImage.getParentSnapshotPath(); String prevSnapshotUuid = snapshotTO.getParentSnapshotPath(); @@ -1221,7 +1291,10 @@ public Answer backupSnapshot(CopyCommand cmd) { // By default assume failure String details = null; String snapshotBackupUuid = null; - boolean fullbackup = true; + Long physicalSize = null; + Map options = cmd.getOptions(); + boolean fullbackup = Boolean.parseBoolean(options.get("fullSnapshot")); + boolean result = false; try { SR primaryStorageSR = hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel); if (primaryStorageSR == null) { @@ -1232,7 +1305,7 @@ public Answer backupSnapshot(CopyCommand cmd) { VDI snapshotVdi = getVDIbyUuid(conn, snapshotUuid); String snapshotPaUuid = null; - if ( prevBackupUuid != null ) { + if ( prevSnapshotUuid != null && !fullbackup) { try { snapshotPaUuid = getVhdParent(conn, psUuid, snapshotUuid, isISCSI); if( snapshotPaUuid != null ) { @@ -1240,9 +1313,13 @@ public Answer backupSnapshot(CopyCommand cmd) { String prevSnashotPaUuid = getVhdParent(conn, psUuid, prevSnapshotUuid, isISCSI); if (snashotPaPaPaUuid != null && prevSnashotPaUuid!= null && prevSnashotPaUuid.equals(snashotPaPaPaUuid)) { fullbackup = false; + } else { + fullbackup = true; } } } catch (Exception e) { + s_logger.debug("Failed to get parent snapshots, take full snapshot", e); + fullbackup = true; } } @@ -1267,6 +1344,8 @@ public Answer backupSnapshot(CopyCommand cmd) { snapshotSr = hypervisorResource.createNfsSRbyURI(conn, new URI(snapshotMountpoint), false); VDI backedVdi = hypervisorResource.cloudVDIcopy(conn, snapshotVdi, snapshotSr, wait); snapshotBackupUuid = backedVdi.getUuid(conn); + String primarySRuuid = snapshotSr.getUuid(conn); + physicalSize = getSnapshotSize(conn, primarySRuuid, snapshotBackupUuid, isISCSI, wait); if( destStore instanceof SwiftTO) { try { @@ -1317,22 +1396,27 @@ public Answer backupSnapshot(CopyCommand cmd) { throw new CloudRuntimeException("S3 upload of snapshots " + snapshotPaUuid + " failed"); } } else { - snapshotBackupUuid = backupSnapshot(conn, primaryStorageSRUuid, localMountPoint, folder, + String results = backupSnapshot(conn, primaryStorageSRUuid, localMountPoint, folder, secondaryStorageMountPath, snapshotUuid, prevBackupUuid, isISCSI, wait); + String[] tmp = results.split("#"); + snapshotBackupUuid = tmp[1]; + physicalSize = Long.parseLong(tmp[2]); finalPath = folder + File.separator + snapshotBackupUuid; } } - String volumeUuid = snapshotTO.getVolume().getPath(); + // delete primary snapshots with only the last one left destroySnapshotOnPrimaryStorageExceptThis(conn, volumeUuid, snapshotUuid); SnapshotObjectTO newSnapshot = new SnapshotObjectTO(); newSnapshot.setPath(finalPath); + newSnapshot.setPhysicalSize(physicalSize); if (fullbackup) { newSnapshot.setParentSnapshotPath(null); } else { newSnapshot.setParentSnapshotPath(prevBackupUuid); } + result = true; return new CopyCmdAnswer(newSnapshot); } catch (XenAPIException e) { details = "BackupSnapshot Failed due to " + e.toString(); @@ -1340,6 +1424,15 @@ public Answer backupSnapshot(CopyCommand cmd) { } catch (Exception e) { details = "BackupSnapshot Failed due to " + e.getMessage(); s_logger.warn(details, e); + } finally { + if (!result) { + // remove last bad primary snapshot when exception happens + try { + destroySnapshotOnPrimaryStorage(conn, snapshotUuid); + } catch (Exception e) { + s_logger.debug("clean up snapshot failed", e); + } + } } return new CopyCmdAnswer(details); @@ -1347,7 +1440,7 @@ public Answer backupSnapshot(CopyCommand cmd) { @Override public Answer createTemplateFromVolume(CopyCommand cmd) { - Connection conn = this.hypervisorResource.getConnection(); + Connection conn = hypervisorResource.getConnection(); VolumeObjectTO volume = (VolumeObjectTO)cmd.getSrcTO(); TemplateObjectTO template = (TemplateObjectTO)cmd.getDestTO(); NfsTO destStore = (NfsTO)cmd.getDestTO().getDataStore(); @@ -1368,7 +1461,7 @@ public Answer createTemplateFromVolume(CopyCommand cmd) { URI uri = new URI(secondaryStoragePoolURL); secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath(); installPath = template.getPath(); - if( !this.hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath)) { + if( !hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath)) { details = " Filed to create folder " + installPath + " in secondary storage"; s_logger.warn(details); return new CopyCmdAnswer(details); @@ -1377,10 +1470,10 @@ public Answer createTemplateFromVolume(CopyCommand cmd) { VDI vol = getVDIbyUuid(conn, volumeUUID); // create template SR URI tmpltURI = new URI(secondaryStoragePoolURL + "/" + installPath); - tmpltSR = this.hypervisorResource.createNfsSRbyURI(conn, tmpltURI, false); + tmpltSR = hypervisorResource.createNfsSRbyURI(conn, tmpltURI, false); // copy volume to template SR - VDI tmpltVDI = this.hypervisorResource.cloudVDIcopy(conn, vol, tmpltSR, wait); + VDI tmpltVDI = hypervisorResource.cloudVDIcopy(conn, vol, tmpltSR, wait); // scan makes XenServer pick up VDI physicalSize tmpltSR.scan(conn); if (userSpecifiedName != null) { @@ -1393,12 +1486,12 @@ public Answer createTemplateFromVolume(CopyCommand cmd) { long physicalSize = tmpltVDI.getPhysicalUtilisation(conn); // create the template.properties file String templatePath = secondaryStorageMountPath + "/" + installPath; - result = this.hypervisorResource.postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize, template.getId()); + result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize, template.getId()); if (!result) { throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + tmpltURI); } installPath = installPath + "/" + tmpltFilename; - this.hypervisorResource.removeSR(conn, tmpltSR); + hypervisorResource.removeSR(conn, tmpltSR); tmpltSR = null; TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(installPath); @@ -1410,10 +1503,10 @@ public Answer createTemplateFromVolume(CopyCommand cmd) { return answer; } catch (Exception e) { if (tmpltSR != null) { - this.hypervisorResource.removeSR(conn, tmpltSR); + hypervisorResource.removeSR(conn, tmpltSR); } if ( secondaryStorageMountPath != null) { - this.hypervisorResource.deleteSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath); + hypervisorResource.deleteSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath); } details = "Creating template from volume " + volumeUUID + " failed due to " + e.toString(); s_logger.error(details, e); @@ -1428,7 +1521,7 @@ public Answer createTemplateFromSnapshot(CopyCommand cmd) { @Override public Answer createVolumeFromSnapshot(CopyCommand cmd) { - Connection conn = this.hypervisorResource.getConnection(); + Connection conn = hypervisorResource.getConnection(); DataTO srcData = cmd.getSrcTO(); SnapshotObjectTO snapshot = (SnapshotObjectTO)srcData; DataTO destData = cmd.getDestTO(); @@ -1452,7 +1545,7 @@ public Answer createVolumeFromSnapshot(CopyCommand cmd) { return new CopyCmdAnswer(details); } try { - SR primaryStorageSR = this.hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel); + SR primaryStorageSR = hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel); if (primaryStorageSR == null) { throw new InternalErrorException("Could not create volume from snapshot because the primary Storage SR could not be created from the name label: " + primaryStorageNameLabel); @@ -1497,14 +1590,14 @@ public Answer deleteSnapshot(DeleteCommand cmd) { SnapshotObjectTO snapshot = (SnapshotObjectTO)cmd.getData(); DataStoreTO store = snapshot.getDataStore(); if (store.getRole() == DataStoreRole.Primary) { - Connection conn = this.hypervisorResource.getConnection(); + Connection conn = hypervisorResource.getConnection(); VDI snapshotVdi = getVDIbyUuid(conn, snapshot.getPath()); if (snapshotVdi == null) { return new Answer(null); } String errMsg = null; try { - this.deleteVDI(conn, snapshotVdi); + deleteVDI(conn, snapshotVdi); } catch (BadServerResponse e) { s_logger.debug("delete snapshot failed:" + e.toString()); errMsg = e.toString(); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/Xenserver625Resource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/Xenserver625Resource.java new file mode 100644 index 000000000000..a085e2de0005 --- /dev/null +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/Xenserver625Resource.java @@ -0,0 +1,113 @@ +/* + * 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.hypervisor.xen.resource; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; + +import org.apache.log4j.Logger; + +import com.xensource.xenapi.Connection; + +import org.apache.cloudstack.hypervisor.xenserver.XenServerResourceNewBase; + +import com.cloud.agent.api.StartupRoutingCommand; +import com.cloud.resource.ServerResource; +import com.cloud.storage.resource.StorageSubsystemCommandHandler; +import com.cloud.storage.resource.StorageSubsystemCommandHandlerBase; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; + +@Local(value=ServerResource.class) +public class Xenserver625Resource extends XenServerResourceNewBase { + private static final Logger s_logger = Logger.getLogger(Xenserver625Resource.class); + + public Xenserver625Resource() { + super(); + } + + @Override + protected void fillHostInfo(Connection conn, StartupRoutingCommand cmd) { + super.fillHostInfo(conn, cmd); + Map details = cmd.getHostDetails(); + details.put("Xenserer620HotFix", "Xenserver-Vdi-Copy-HotFix"); + } + + @Override + protected String getGuestOsType(String stdType, boolean bootFromCD) { + return CitrixHelper.getXenServer625GuestOsType(stdType, bootFromCD); + } + + @Override + protected List getPatchFiles() { + List files = new ArrayList(); + String patch = "scripts/vm/hypervisor/xenserver/xenserver62/patch"; + String patchfilePath = Script.findScript("", patch); + if (patchfilePath == null) { + throw new CloudRuntimeException("Unable to find patch file " + patch); + } + File file = new File(patchfilePath); + files.add(file); + return files; + } + + @Override + public long getStaticMax(String os, boolean b, long dynamicMinRam, long dynamicMaxRam){ + long recommendedValue = CitrixHelper.getXenServer625StaticMax(os, b); + if(recommendedValue == 0){ + s_logger.warn("No recommended value found for dynamic max, setting static max and dynamic max equal"); + return dynamicMaxRam; + } + long staticMax = Math.min(recommendedValue, 4l * dynamicMinRam); // XS constraint for stability + if (dynamicMaxRam > staticMax){ // XS contraint that dynamic max <= static max + s_logger.warn("dynamixMax " + dynamicMaxRam + " cant be greater than static max " + staticMax + ", can lead to stability issues. Setting static max as much as dynamic max "); + return dynamicMaxRam; + } + return staticMax; + } + + @Override + public long getStaticMin(String os, boolean b, long dynamicMinRam, long dynamicMaxRam){ + long recommendedValue = CitrixHelper.getXenServer625StaticMin(os, b); + if(recommendedValue == 0){ + s_logger.warn("No recommended value found for dynamic min"); + return dynamicMinRam; + } + + if(dynamicMinRam < recommendedValue){ // XS contraint that dynamic min > static min + s_logger.warn("Vm is set to dynamixMin " + dynamicMinRam + " less than the recommended static min " + recommendedValue + ", could lead to stability issues"); + } + return dynamicMinRam; + } + + @Override + protected StorageSubsystemCommandHandler getStorageHandler() { + XenServerStorageProcessor processor = new Xenserver625StorageProcessor(this); + return new StorageSubsystemCommandHandlerBase(processor); + } + + @Override + protected void umountSnapshotDir(Connection conn, Long dcId) { + + } +} \ No newline at end of file diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/Xenserver625StorageProcessor.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/Xenserver625StorageProcessor.java new file mode 100644 index 000000000000..dad3d145fae5 --- /dev/null +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/Xenserver625StorageProcessor.java @@ -0,0 +1,822 @@ +/* + * 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.hypervisor.xen.resource; + +import java.io.File; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.apache.cloudstack.storage.command.CopyCmdAnswer; +import org.apache.cloudstack.storage.command.CopyCommand; +import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; +import org.apache.cloudstack.storage.to.SnapshotObjectTO; +import org.apache.cloudstack.storage.to.TemplateObjectTO; +import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.to.DataObjectType; +import com.cloud.agent.api.to.DataStoreTO; +import com.cloud.agent.api.to.DataTO; +import com.cloud.agent.api.to.NfsTO; +import com.cloud.agent.api.to.S3TO; +import com.cloud.agent.api.to.SwiftTO; +import com.cloud.exception.InternalErrorException; +import com.cloud.storage.Storage; +import com.cloud.utils.exception.CloudRuntimeException; +import com.xensource.xenapi.Connection; +import com.xensource.xenapi.Host; +import com.xensource.xenapi.PBD; +import com.xensource.xenapi.SR; +import com.xensource.xenapi.Task; +import com.xensource.xenapi.Types; +import com.xensource.xenapi.VDI; + +public class Xenserver625StorageProcessor extends XenServerStorageProcessor { + private static final Logger s_logger = Logger.getLogger(XenServerStorageProcessor.class); + + public Xenserver625StorageProcessor(CitrixResourceBase resource) { + super(resource); + } + protected boolean mountNfs(Connection conn, String remoteDir, String localDir) { + if (localDir == null) { + localDir = "/var/cloud_mount/" + UUID.nameUUIDFromBytes(remoteDir.getBytes()); + } + String results = hypervisorResource.callHostPluginAsync(conn, "cloud-plugin-storage", "mountNfsSecondaryStorage", 100 * 1000, + "localDir", localDir, "remoteDir", remoteDir); + if (results == null || results.isEmpty()) { + String errMsg = "Could not mount secondary storage " + remoteDir + " on host "; + s_logger.warn(errMsg); + throw new CloudRuntimeException(errMsg); + } + return true; + } + + protected boolean makeDirectory(Connection conn, String path) { + String result = hypervisorResource.callHostPlugin(conn, "cloud-plugin-storage", "makeDirectory", "path", path); + if (result == null || result.isEmpty()) { + return false; + } + return true; + } + + protected SR createFileSR(Connection conn, String path) { + SR sr = null; + PBD pbd = null; + try { + Map smConfig = new HashMap(); + Host host = Host.getByUuid(conn, hypervisorResource.getHost().uuid); + String uuid = UUID.randomUUID().toString(); + + sr = SR.introduce(conn,uuid, uuid, uuid, "file", "file", false, smConfig); + PBD.Record record = new PBD.Record(); + record.host = host; + record.SR = sr; + smConfig.put("location", path); + record.deviceConfig = smConfig; + pbd = PBD.create(conn, record); + pbd.plug(conn); + sr.scan(conn); + return sr; + } catch (Exception e) { + try { + if (pbd != null) { + pbd.destroy(conn); + } + } catch (Exception e1) { + s_logger.debug("Failed to destroy pbd", e); + } + try { + if (sr != null) { + sr.forget(conn); + } + } catch (Exception e2) { + s_logger.error("Failed to forget sr", e); + } + String msg = "createFileSR failed! due to " + e.toString(); + s_logger.warn(msg, e); + throw new CloudRuntimeException(msg, e); + } + } + + protected SR createFileSr(Connection conn, String remotePath, String dir) { + String localDir = "/var/cloud_mount/" + UUID.nameUUIDFromBytes(remotePath.getBytes()); + mountNfs(conn, remotePath, localDir); + SR sr = createFileSR(conn, localDir + "/" + dir); + return sr; + } + + @Override + public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { + DataTO srcData = cmd.getSrcTO(); + DataTO destData = cmd.getDestTO(); + int wait = cmd.getWait(); + DataStoreTO srcStore = srcData.getDataStore(); + Connection conn = hypervisorResource.getConnection(); + SR srcSr = null; + try { + if ((srcStore instanceof NfsTO) && (srcData.getObjectType() == DataObjectType.TEMPLATE)) { + NfsTO srcImageStore = (NfsTO)srcStore; + TemplateObjectTO srcTemplate = (TemplateObjectTO)srcData; + String storeUrl = srcImageStore.getUrl(); + URI uri = new URI(storeUrl); + String volumePath = srcData.getPath(); + volumePath = StringUtils.stripEnd(volumePath, "/"); + String[] splits = volumePath.split("/"); + String volumeDirectory = volumePath; + if (splits.length > 4) { + //"template/tmpl/dcid/templateId/templatename" + int index = volumePath.lastIndexOf("/"); + volumeDirectory = volumePath.substring(0, index); + } + srcSr = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), volumeDirectory); + Set vdis = srcSr.getVDIs(conn); + if (vdis.size() != 1) { + return new CopyCmdAnswer("Can't find template VDI under: " + uri.getHost() + ":" + uri.getPath() + "/" + volumeDirectory); + } + + VDI srcVdi = vdis.iterator().next(); + + PrimaryDataStoreTO destStore = (PrimaryDataStoreTO)destData.getDataStore(); + String poolName = destStore.getUuid(); + + + SR poolsr = null; + Set srs = SR.getByNameLabel(conn, poolName); + if (srs.size() != 1) { + String msg = "There are " + srs.size() + " SRs with same name: " + poolName; + s_logger.warn(msg); + return new CopyCmdAnswer(msg); + } else { + poolsr = srs.iterator().next(); + } + String pUuid = poolsr.getUuid(conn); + boolean isISCSI = IsISCSI(poolsr.getType(conn)); + Task task = srcVdi.copyAsync2(conn, poolsr, null, null); + // poll every 1 seconds , + hypervisorResource.waitForTask(conn, task, 1000, wait * 1000); + hypervisorResource.checkForSuccess(conn, task); + VDI tmpl = Types.toVDI(task, conn); + VDI snapshotvdi = tmpl.snapshot(conn, new HashMap()); + snapshotvdi.setNameLabel(conn, "Template " + srcTemplate.getName()); + tmpl.destroy(conn); + poolsr.scan(conn); + try{ + Thread.sleep(5000); + } catch (Exception e) { + } + + TemplateObjectTO newVol = new TemplateObjectTO(); + newVol.setUuid(snapshotvdi.getUuid(conn)); + newVol.setPath(newVol.getUuid()); + newVol.setFormat(Storage.ImageFormat.VHD); + return new CopyCmdAnswer(newVol); + } + }catch (Exception e) { + String msg = "Catch Exception " + e.getClass().getName() + " for template + " + " due to " + e.toString(); + s_logger.warn(msg, e); + return new CopyCmdAnswer(msg); + } finally { + if (srcSr != null) { + hypervisorResource.removeSR(conn, srcSr); + } + } + return new CopyCmdAnswer("not implemented yet"); + } + + protected String backupSnapshot(Connection conn, String primaryStorageSRUuid, String localMountPoint, String path, String secondaryStorageMountPath, String snapshotUuid, String prevBackupUuid, String prevSnapshotUuid, Boolean isISCSI, int wait) { + String errMsg = null; + boolean mounted = false; + boolean filesrcreated = false; + boolean copied = false; + if (prevBackupUuid == null) { + prevBackupUuid = ""; + } + SR ssSR = null; + + String remoteDir = secondaryStorageMountPath; + + try { + ssSR = createFileSr(conn, remoteDir, path); + filesrcreated = true; + + VDI snapshotvdi = VDI.getByUuid(conn, snapshotUuid); + Task task = null; + if (wait == 0) { + wait = 2 * 60 * 60; + } + VDI dvdi = null; + try { + VDI previousSnapshotVdi = null; + if (prevSnapshotUuid != null) { + previousSnapshotVdi = VDI.getByUuid(conn,prevSnapshotUuid); + } + task = snapshotvdi.copyAsync2(conn, ssSR, previousSnapshotVdi, null); + // poll every 1 seconds , + hypervisorResource.waitForTask(conn, task, 1000, wait * 1000); + hypervisorResource.checkForSuccess(conn, task); + dvdi = Types.toVDI(task, conn); + copied = true; + } finally { + if (task != null) { + try { + task.destroy(conn); + } catch (Exception e1) { + s_logger.warn("unable to destroy task(" + task.toString() + ") on host(" + + ") due to ", e1); + } + } + } + String backupUuid = dvdi.getUuid(conn); + return backupUuid; + } catch (Exception e) { + String msg = "Exception in backupsnapshot stage due to " + e.toString(); + s_logger.debug(msg); + throw new CloudRuntimeException(msg, e); + } finally { + try { + if (filesrcreated && ssSR != null) { + hypervisorResource.removeSR(conn, ssSR); + } + } catch (Exception e) { + s_logger.debug("Exception in backupsnapshot cleanup stage due to " + e.toString()); + } + } + } + + @Override + protected String getVhdParent(Connection conn, String primaryStorageSRUuid, String snapshotUuid, Boolean isISCSI) { + String parentUuid = hypervisorResource.callHostPlugin(conn, "cloud-plugin-storage", "getVhdParent", "primaryStorageSRUuid", primaryStorageSRUuid, + "snapshotUuid", snapshotUuid, "isISCSI", isISCSI.toString()); + + if (parentUuid == null || parentUuid.isEmpty() || parentUuid.equalsIgnoreCase("None")) { + s_logger.debug("Unable to get parent of VHD " + snapshotUuid + " in SR " + primaryStorageSRUuid); + // errString is already logged. + return null; + } + return parentUuid; + } + + @Override + public Answer backupSnapshot(CopyCommand cmd) { + Connection conn = hypervisorResource.getConnection(); + DataTO srcData = cmd.getSrcTO(); + DataTO cacheData = cmd.getCacheTO(); + DataTO destData = cmd.getDestTO(); + int wait = cmd.getWait(); + PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)srcData.getDataStore(); + String primaryStorageNameLabel = primaryStore.getUuid(); + String secondaryStorageUrl = null; + NfsTO cacheStore = null; + String destPath = null; + if (cacheData != null) { + cacheStore = (NfsTO)cacheData.getDataStore(); + secondaryStorageUrl = cacheStore.getUrl(); + destPath = cacheData.getPath(); + } else { + cacheStore = (NfsTO)destData.getDataStore(); + secondaryStorageUrl = cacheStore.getUrl(); + destPath = destData.getPath(); + } + + SnapshotObjectTO snapshotTO = (SnapshotObjectTO)srcData; + SnapshotObjectTO snapshotOnImage = (SnapshotObjectTO)destData; + String snapshotUuid = snapshotTO.getPath(); + + String prevBackupUuid = snapshotOnImage.getParentSnapshotPath(); + String prevSnapshotUuid = snapshotTO.getParentSnapshotPath(); + Map options = cmd.getOptions(); + // By default assume failure + String details = null; + String snapshotBackupUuid = null; + boolean fullbackup = Boolean.parseBoolean(options.get("fullSnapshot")); + try { + SR primaryStorageSR = hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel); + if (primaryStorageSR == null) { + throw new InternalErrorException("Could not backup snapshot because the primary Storage SR could not be created from the name label: " + primaryStorageNameLabel); + } + String psUuid = primaryStorageSR.getUuid(conn); + Boolean isISCSI = IsISCSI(primaryStorageSR.getType(conn)); + + VDI snapshotVdi = getVDIbyUuid(conn, snapshotUuid); + String snapshotPaUuid = null; + + URI uri = new URI(secondaryStorageUrl); + String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath(); + DataStoreTO destStore = destData.getDataStore(); + String folder = destPath; + String finalPath = null; + + String localMountPoint = BaseMountPointOnHost + File.separator + UUID.nameUUIDFromBytes(secondaryStorageUrl.getBytes()).toString(); + if (fullbackup) { + SR snapshotSr = null; + try { + String localDir = "/var/cloud_mount/" + UUID.nameUUIDFromBytes(secondaryStorageMountPath.getBytes()); + mountNfs(conn, secondaryStorageMountPath, localDir); + boolean result = makeDirectory(conn, localDir + "/" + folder); + if (!result) { + details = " Filed to create folder " + folder + " in secondary storage"; + s_logger.warn(details); + return new CopyCmdAnswer(details); + } + + snapshotSr = createFileSr(conn, secondaryStorageMountPath, folder); + + Task task = snapshotVdi.copyAsync2(conn, snapshotSr, null, null); + // poll every 1 seconds , + hypervisorResource.waitForTask(conn, task, 1000, wait * 1000); + hypervisorResource.checkForSuccess(conn, task); + VDI backedVdi = Types.toVDI(task, conn); + snapshotBackupUuid = backedVdi.getUuid(conn); + + if( destStore instanceof SwiftTO) { + try { + String container = "S-" + snapshotTO.getVolume().getVolumeId().toString(); + String destSnapshotName = swiftBackupSnapshot(conn, (SwiftTO)destStore, snapshotSr.getUuid(conn), snapshotBackupUuid, container, false, wait); + String swiftPath = container + File.separator + destSnapshotName; + finalPath = swiftPath; + } finally { + try { + deleteSnapshotBackup(conn, localMountPoint, folder, secondaryStorageMountPath, snapshotBackupUuid); + } catch (Exception e) { + s_logger.debug("Failed to delete snapshot on cache storages" ,e); + } + } + + } else if (destStore instanceof S3TO) { + try { + finalPath = backupSnapshotToS3(conn, (S3TO) destStore, snapshotSr.getUuid(conn), folder, snapshotBackupUuid, isISCSI, wait); + if (finalPath == null) { + throw new CloudRuntimeException("S3 upload of snapshots " + snapshotBackupUuid + " failed"); + } + } finally { + try { + deleteSnapshotBackup(conn, localMountPoint, folder, secondaryStorageMountPath, snapshotBackupUuid); + } catch (Exception e) { + s_logger.debug("Failed to delete snapshot on cache storages" ,e); + } + } + // finalPath = folder + File.separator + snapshotBackupUuid; + } else { + finalPath = folder + File.separator + snapshotBackupUuid; + } + + } finally { + if( snapshotSr != null) { + hypervisorResource.removeSR(conn, snapshotSr); + } + } + } else { + String primaryStorageSRUuid = primaryStorageSR.getUuid(conn); + if( destStore instanceof SwiftTO ) { + String container = "S-" + snapshotTO.getVolume().getVolumeId().toString(); + snapshotBackupUuid = swiftBackupSnapshot(conn, (SwiftTO)destStore, primaryStorageSRUuid, snapshotPaUuid, "S-" + snapshotTO.getVolume().getVolumeId().toString(), isISCSI, wait); + finalPath = container + File.separator + snapshotBackupUuid; + } else if (destStore instanceof S3TO ) { + finalPath = backupSnapshotToS3(conn, (S3TO) destStore, primaryStorageSRUuid, folder, snapshotPaUuid, isISCSI, wait); + if (finalPath == null) { + throw new CloudRuntimeException("S3 upload of snapshots " + snapshotPaUuid + " failed"); + } + } else { + snapshotBackupUuid = backupSnapshot(conn, primaryStorageSRUuid, localMountPoint, folder, + secondaryStorageMountPath, snapshotUuid, prevBackupUuid, prevSnapshotUuid, isISCSI, wait); + + finalPath = folder + File.separator + snapshotBackupUuid; + } + } + String volumeUuid = snapshotTO.getVolume().getPath(); + destroySnapshotOnPrimaryStorageExceptThis(conn, volumeUuid, snapshotUuid); + + SnapshotObjectTO newSnapshot = new SnapshotObjectTO(); + newSnapshot.setPath(finalPath); + if (fullbackup) { + newSnapshot.setParentSnapshotPath(null); + } else { + newSnapshot.setParentSnapshotPath(prevBackupUuid); + } + return new CopyCmdAnswer(newSnapshot); + } catch (Types.XenAPIException e) { + details = "BackupSnapshot Failed due to " + e.toString(); + s_logger.warn(details, e); + } catch (Exception e) { + details = "BackupSnapshot Failed due to " + e.getMessage(); + s_logger.warn(details, e); + } + + return new CopyCmdAnswer(details); + } + + @Override + public Answer createTemplateFromVolume(CopyCommand cmd) { + Connection conn = hypervisorResource.getConnection(); + VolumeObjectTO volume = (VolumeObjectTO)cmd.getSrcTO(); + TemplateObjectTO template = (TemplateObjectTO)cmd.getDestTO(); + NfsTO destStore = (NfsTO)cmd.getDestTO().getDataStore(); + int wait = cmd.getWait(); + + String secondaryStoragePoolURL = destStore.getUrl(); + String volumeUUID = volume.getPath(); + + String userSpecifiedName = template.getName(); + + + String details = null; + SR tmpltSR = null; + boolean result = false; + String secondaryStorageMountPath = null; + String installPath = null; + try { + URI uri = new URI(secondaryStoragePoolURL); + secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath(); + installPath = template.getPath(); + if( !hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath)) { + details = " Filed to create folder " + installPath + " in secondary storage"; + s_logger.warn(details); + return new CopyCmdAnswer(details); + } + + VDI vol = getVDIbyUuid(conn, volumeUUID); + // create template SR + tmpltSR = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), installPath); + + // copy volume to template SR + Task task = vol.copyAsync2(conn, tmpltSR, null, null); + // poll every 1 seconds , + hypervisorResource.waitForTask(conn, task, 1000, wait * 1000); + hypervisorResource.checkForSuccess(conn, task); + VDI tmpltVDI = Types.toVDI(task, conn); + // scan makes XenServer pick up VDI physicalSize + tmpltSR.scan(conn); + if (userSpecifiedName != null) { + tmpltVDI.setNameLabel(conn, userSpecifiedName); + } + + String tmpltUUID = tmpltVDI.getUuid(conn); + String tmpltFilename = tmpltUUID + ".vhd"; + long virtualSize = tmpltVDI.getVirtualSize(conn); + long physicalSize = tmpltVDI.getPhysicalUtilisation(conn); + // create the template.properties file + String templatePath = secondaryStorageMountPath + "/" + installPath; + result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize, template.getId()); + if (!result) { + throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir"); + } + installPath = installPath + "/" + tmpltFilename; + hypervisorResource.removeSR(conn, tmpltSR); + tmpltSR = null; + TemplateObjectTO newTemplate = new TemplateObjectTO(); + newTemplate.setPath(installPath); + newTemplate.setFormat(Storage.ImageFormat.VHD); + newTemplate.setSize(virtualSize); + newTemplate.setPhysicalSize(physicalSize); + newTemplate.setName(tmpltUUID); + CopyCmdAnswer answer = new CopyCmdAnswer(newTemplate); + return answer; + } catch (Exception e) { + if (tmpltSR != null) { + hypervisorResource.removeSR(conn, tmpltSR); + } + if ( secondaryStorageMountPath != null) { + hypervisorResource.deleteSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath); + } + details = "Creating template from volume " + volumeUUID + " failed due to " + e.toString(); + s_logger.error(details, e); + } + return new CopyCmdAnswer(details); + } + + protected String getSnapshotUuid(String snapshotPath) { + int index = snapshotPath.lastIndexOf(File.separator); + String snapshotUuid = snapshotPath.substring(index + 1); + index = snapshotUuid.lastIndexOf("."); + if (index != -1) { + snapshotUuid = snapshotUuid.substring(0, index); + } + return snapshotUuid; + } + + @Override + public Answer createVolumeFromSnapshot(CopyCommand cmd) { + Connection conn = hypervisorResource.getConnection(); + DataTO srcData = cmd.getSrcTO(); + SnapshotObjectTO snapshot = (SnapshotObjectTO)srcData; + DataTO destData = cmd.getDestTO(); + PrimaryDataStoreTO pool = (PrimaryDataStoreTO)destData.getDataStore(); + VolumeObjectTO volume = (VolumeObjectTO)destData; + DataStoreTO imageStore = srcData.getDataStore(); + + if (!(imageStore instanceof NfsTO)) { + return new CopyCmdAnswer("unsupported protocol"); + } + + NfsTO nfsImageStore = (NfsTO)imageStore; + String primaryStorageNameLabel = pool.getUuid(); + String secondaryStorageUrl = nfsImageStore.getUrl(); + int wait = cmd.getWait(); + boolean result = false; + // Generic error message. + String details = null; + String volumeUUID = null; + + if (secondaryStorageUrl == null) { + details += " because the URL passed: " + secondaryStorageUrl + " is invalid."; + return new CopyCmdAnswer(details); + } + SR srcSr = null; + VDI destVdi = null; + try { + SR primaryStorageSR = hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel); + if (primaryStorageSR == null) { + throw new InternalErrorException("Could not create volume from snapshot because the primary Storage SR could not be created from the name label: " + + primaryStorageNameLabel); + } + String nameLabel = "cloud-" + UUID.randomUUID().toString(); + destVdi = createVdi(conn, nameLabel, primaryStorageSR, volume.getSize()); + volumeUUID = destVdi.getUuid(conn); + String snapshotInstallPath = snapshot.getPath(); + int index = snapshotInstallPath.lastIndexOf(File.separator); + String snapshotDirectory = snapshotInstallPath.substring(0, index); + String snapshotUuid = getSnapshotUuid(snapshotInstallPath); + + URI uri = new URI(secondaryStorageUrl); + srcSr = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), snapshotDirectory); + + String[] parents = snapshot.getParents(); + List snapshotChains = new ArrayList(); + if (parents != null) { + for(int i = 0; i < parents.length; i++) { + String snChainPath = parents[i]; + String uuid = getSnapshotUuid(snChainPath); + VDI chain = VDI.getByUuid(conn, uuid); + snapshotChains.add(chain); + } + } + + VDI snapshotVdi = VDI.getByUuid(conn, snapshotUuid); + snapshotChains.add(snapshotVdi); + + for(VDI snapChain : snapshotChains) { + Task task = snapChain.copyAsync2(conn, null, null, destVdi); + // poll every 1 seconds , + hypervisorResource.waitForTask(conn, task, 1000, wait * 1000); + hypervisorResource.checkForSuccess(conn, task); + } + + result = true; + destVdi = VDI.getByUuid(conn, volumeUUID); + VDI.Record vdir = destVdi.getRecord(conn); + VolumeObjectTO newVol = new VolumeObjectTO(); + newVol.setPath(volumeUUID); + newVol.setSize(vdir.virtualSize); + return new CopyCmdAnswer(newVol); + } catch (Types.XenAPIException e) { + details += " due to " + e.toString(); + s_logger.warn(details, e); + } catch (Exception e) { + details += " due to " + e.getMessage(); + s_logger.warn(details, e); + } finally { + if (srcSr != null) { + hypervisorResource.removeSR(conn, srcSr); + } + if (!result && destVdi != null) { + try { + destVdi.destroy(conn); + } catch (Exception e) { + s_logger.debug("destroy dest vdi failed", e); + } + } + } + if (!result) { + // Is this logged at a higher level? + s_logger.error(details); + } + + // In all cases return something. + return new CopyCmdAnswer(details); + } + + @Override + public Answer copyVolumeFromPrimaryToSecondary(CopyCommand cmd) { + Connection conn = hypervisorResource.getConnection(); + VolumeObjectTO srcVolume = (VolumeObjectTO)cmd.getSrcTO(); + VolumeObjectTO destVolume = (VolumeObjectTO)cmd.getDestTO(); + int wait = cmd.getWait(); + DataStoreTO destStore = destVolume.getDataStore(); + + if (destStore instanceof NfsTO) { + SR secondaryStorage = null; + try { + NfsTO nfsStore = (NfsTO)destStore; + URI uri = new URI(nfsStore.getUrl()); + // Create the volume folder + if (!hypervisorResource.createSecondaryStorageFolder(conn, uri.getHost() + ":" + uri.getPath(), destVolume.getPath())) { + throw new InternalErrorException("Failed to create the volume folder."); + } + + // Create a SR for the volume UUID folder + secondaryStorage = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), destVolume.getPath()); + // Look up the volume on the source primary storage pool + VDI srcVdi = getVDIbyUuid(conn, srcVolume.getPath()); + // Copy the volume to secondary storage + Task task = srcVdi.copyAsync2(conn, secondaryStorage, null, null); + // poll every 1 seconds , + hypervisorResource.waitForTask(conn, task, 1000, wait * 1000); + hypervisorResource.checkForSuccess(conn, task); + VDI destVdi = Types.toVDI(task, conn); + String destVolumeUUID = destVdi.getUuid(conn); + + VolumeObjectTO newVol = new VolumeObjectTO(); + newVol.setPath(destVolume.getPath() + File.separator + destVolumeUUID + ".vhd"); + newVol.setSize(srcVolume.getSize()); + return new CopyCmdAnswer(newVol); + } catch (Exception e) { + s_logger.debug("Failed to copy volume to secondary: " + e.toString()); + return new CopyCmdAnswer("Failed to copy volume to secondary: " + e.toString()); + } finally { + hypervisorResource.removeSR(conn, secondaryStorage); + } + } + return new CopyCmdAnswer("unsupported protocol"); + } + + @Override + public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd) { + Connection conn = hypervisorResource.getConnection(); + DataTO srcData = cmd.getSrcTO(); + DataTO destData = cmd.getDestTO(); + int wait = cmd.getWait(); + VolumeObjectTO srcVolume = (VolumeObjectTO)srcData; + VolumeObjectTO destVolume = (VolumeObjectTO)destData; + PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)destVolume.getDataStore(); + DataStoreTO srcStore = srcVolume.getDataStore(); + + if (srcStore instanceof NfsTO) { + NfsTO nfsStore = (NfsTO)srcStore; + String volumePath = srcVolume.getPath(); + int index = volumePath.lastIndexOf("/"); + String volumeDirectory = volumePath.substring(0, index); + String volumeUuid = volumePath.substring(index + 1); + index = volumeUuid.indexOf("."); + if (index != -1) { + volumeUuid = volumeUuid.substring(0, index); + } + URI uri = null; + try { + uri = new URI(nfsStore.getUrl()); + } catch (Exception e) { + return new CopyCmdAnswer(e.toString()); + } + SR srcSr = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), volumeDirectory); + try { + SR primaryStoragePool = hypervisorResource.getStorageRepository(conn, primaryStore.getUuid()); + VDI srcVdi = VDI.getByUuid(conn, volumeUuid); + Task task = srcVdi.copyAsync2(conn, primaryStoragePool, null, null); + // poll every 1 seconds , + hypervisorResource.waitForTask(conn, task, 1000, wait * 1000); + hypervisorResource.checkForSuccess(conn, task); + VDI destVdi = Types.toVDI(task, conn); + VolumeObjectTO newVol = new VolumeObjectTO(); + newVol.setPath(destVdi.getUuid(conn)); + newVol.setSize(srcVolume.getSize()); + + return new CopyCmdAnswer(newVol); + } catch (Exception e) { + String msg = "Catch Exception " + e.getClass().getName() + " due to " + e.toString(); + s_logger.warn(msg, e); + return new CopyCmdAnswer(e.toString()); + } finally { + if (srcSr != null) { + hypervisorResource.removeSR(conn, srcSr); + } + } + } + + s_logger.debug("unsupported protocol"); + return new CopyCmdAnswer("unsupported protocol"); + } + + @Override + public Answer createTemplateFromSnapshot(CopyCommand cmd) { + Connection conn = hypervisorResource.getConnection(); + DataTO srcData = cmd.getSrcTO(); + DataTO destData = cmd.getDestTO(); + int wait = cmd.getWait(); + SnapshotObjectTO srcObj = (SnapshotObjectTO)srcData; + TemplateObjectTO destObj = (TemplateObjectTO)destData; + NfsTO srcStore = (NfsTO)srcObj.getDataStore(); + NfsTO destStore = (NfsTO)destObj.getDataStore(); + + URI srcUri = null; + URI destUri = null; + try { + srcUri = new URI(srcStore.getUrl()); + destUri = new URI(destStore.getUrl()); + } catch (Exception e) { + s_logger.debug("incorrect url", e); + return new CopyCmdAnswer("incorrect url" + e.toString()); + } + + String srcPath = srcObj.getPath(); + int index = srcPath.lastIndexOf("/"); + String srcDir = srcPath.substring(0, index); + String destDir = destObj.getPath(); + SR srcSr = null; + SR destSr = null; + VDI destVdi = null; + boolean result = false; + try { + srcSr = createFileSr(conn, srcUri.getHost() + ":" + srcUri.getPath(), srcDir); + + String destNfsPath = destUri.getHost() + ":" + destUri.getPath(); + String localDir = "/var/cloud_mount/" + UUID.nameUUIDFromBytes(destNfsPath.getBytes()); + mountNfs(conn, destUri.getHost() + ":" + destUri.getPath(), localDir); + makeDirectory(conn, localDir + "/" + destDir); + destSr = createFileSR(conn, localDir + "/" + destDir); + + String nameLabel = "cloud-" + UUID.randomUUID().toString(); + + String[] parents = srcObj.getParents(); + List snapshotChains = new ArrayList(); + if (parents != null) { + for(int i = 0; i < parents.length; i++) { + String snChainPath = parents[i]; + String uuid = getSnapshotUuid(snChainPath); + VDI chain = VDI.getByUuid(conn, uuid); + snapshotChains.add(chain); + } + } + String snapshotUuid = getSnapshotUuid(srcPath); + VDI snapshotVdi = VDI.getByUuid(conn, snapshotUuid); + snapshotChains.add(snapshotVdi); + + long templateVirtualSize = snapshotChains.get(0).getVirtualSize(conn); + destVdi = createVdi(conn, nameLabel, destSr, templateVirtualSize); + String destVdiUuid = destVdi.getUuid(conn); + + for(VDI snapChain : snapshotChains) { + Task task = snapChain.copyAsync2(conn, null, null, destVdi); + // poll every 1 seconds , + hypervisorResource.waitForTask(conn, task, 1000, wait * 1000); + hypervisorResource.checkForSuccess(conn, task); + } + + destVdi = VDI.getByUuid(conn, destVdiUuid); + String templatePath = destDir + "/" + destVdiUuid + ".vhd"; + templatePath = templatePath.replaceAll("//","/"); + TemplateObjectTO newTemplate = new TemplateObjectTO(); + newTemplate.setPath(templatePath); + newTemplate.setFormat(Storage.ImageFormat.VHD); + newTemplate.setSize(destVdi.getVirtualSize(conn)); + newTemplate.setPhysicalSize(destVdi.getPhysicalUtilisation(conn)); + newTemplate.setName(destVdiUuid); + + result = true; + return new CopyCmdAnswer(newTemplate); + } catch (Exception e) { + s_logger.error("Failed create template from snapshot", e); + return new CopyCmdAnswer("Failed create template from snapshot " + e.toString()); + } finally { + if (!result) { + if (destVdi != null) { + try { + destVdi.destroy(conn); + } catch (Exception e) { + s_logger.debug("Clean up left over on dest storage failed: ", e); + } + } + } + + if (destSr != null) { + hypervisorResource.removeSR(conn, destSr); + } + + if (srcSr != null) { + hypervisorResource.removeSR(conn, srcSr); + } + } + } + +} diff --git a/plugins/hypervisors/xen/src/org/apache/cloudstack/hypervisor/xenserver/XenServerResourceNewBase.java b/plugins/hypervisors/xen/src/org/apache/cloudstack/hypervisor/xenserver/XenServerResourceNewBase.java new file mode 100644 index 000000000000..2ee45a3f4a89 --- /dev/null +++ b/plugins/hypervisors/xen/src/org/apache/cloudstack/hypervisor/xenserver/XenServerResourceNewBase.java @@ -0,0 +1,340 @@ +// 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.hypervisor.xenserver; + + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeoutException; + +import org.apache.log4j.Logger; +import org.apache.xmlrpc.XmlRpcException; + +import com.xensource.xenapi.Connection; +import com.xensource.xenapi.Event; +import com.xensource.xenapi.Host; +import com.xensource.xenapi.Pool; +import com.xensource.xenapi.Task; +import com.xensource.xenapi.Types; +import com.xensource.xenapi.Types.XenAPIException; +import com.xensource.xenapi.VM; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.ClusterSyncAnswer; +import com.cloud.agent.api.ClusterSyncCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.hypervisor.xen.resource.XenServer610Resource; +import com.cloud.utils.Ternary; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineName; + +/** + * + * XenServerResourceNewBase is an abstract base class that encapsulates how + * CloudStack should interact with XenServer after a special XenServer + * 6.2 hotfix. From here on, every Resource for future versions of + * XenServer should use this as the base class. This base class lessens + * the amount of load CloudStack places on Xapi because it doesn't use + * polling as a means to collect data and figure out task completion. + * + * This base class differs from CitrixResourceBase in the following ways: + * - VM states are detected using Event.from instead of polling. This + * increases the number of threads CloudStack uses but the threads + * are mostly idle just waiting for events from XenServer. + * - stats are collected through the http interface rather than Xapi plugin. + * This change may be promoted to CitrixResourceBase as it's also possible + * in previous versions of XenServer. + * - Asynchronous task completion is done throught Event.from rather than + * polling. + * + */ +public class XenServerResourceNewBase extends XenServer610Resource { + private static final Logger s_logger = Logger.getLogger(XenServerResourceNewBase.class); + protected VmEventListener _listener = null; + + @Override + public StartupCommand[] initialize() throws IllegalArgumentException { + StartupCommand[] cmds = super.initialize(); + + Connection conn = getConnection(); + Pool pool; + try { + pool = Pool.getByUuid(conn, _host.pool); + Pool.Record poolr = pool.getRecord(conn); + + Host.Record masterRecord = poolr.master.getRecord(conn); + if (_host.uuid.equals(masterRecord.uuid)) { + _listener = new VmEventListener(true); + _listener.start(); + } else { + _listener = new VmEventListener(false); + } + } catch (XenAPIException e) { + throw new CloudRuntimeException("Unable to determine who is the master", e); + } catch (XmlRpcException e) { + throw new CloudRuntimeException("Unable to determine who is the master", e); + } + return cmds; + } + + protected void waitForTask2(Connection c, Task task, long pollInterval, long timeout) throws XenAPIException, XmlRpcException, TimeoutException { + long beginTime = System.currentTimeMillis(); + if (s_logger.isTraceEnabled()) { + s_logger.trace("Task " + task.getNameLabel(c) + " (" + task.getType(c) + ") sent to " + c.getSessionReference() + " is pending completion with a " + timeout + + "ms timeout"); + } + Set classes = new HashSet(); + classes.add("Task/" + task.toString()); + String token = ""; + Double t = new Double(timeout / 1000); + while (true) { + Map map = Event.properFrom(c, classes, token, t); + token = (String)map.get("token"); + @SuppressWarnings("unchecked") + Set events = (Set)map.get("events"); + if (events.size() == 0) { + String msg = "Async " + timeout / 1000 + " seconds timeout for task " + task.toString(); + s_logger.warn(msg); + task.cancel(c); + throw new TimeoutException(msg); + } + for (Event.Record rec : events) { + if (!(rec.snapshot instanceof Task.Record)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Skipping over " + rec); + } + continue; + } + + Task.Record taskRecord = (Task.Record)rec.snapshot; + + if (taskRecord.status != Types.TaskStatusType.PENDING) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Task is done " + taskRecord.status); + } + return; + } else { + s_logger.debug("Task is not done " + taskRecord); + } + } + } + } + + @Override + protected Answer execute(final ClusterSyncCommand cmd) { + if (!_listener.isListening()) { + return new Answer(cmd); + } + + HashMap> newStates = _listener.getChanges(); + return new ClusterSyncAnswer(cmd.getClusterId(), newStates); + } + + protected class VmEventListener extends Thread { + boolean _stop = false; + HashMap> _changes = new HashMap>(); + boolean _isMaster; + Set _classes; + String _token = ""; + + public VmEventListener(boolean isMaster) { + _isMaster = isMaster; + _classes = new HashSet(); + _classes.add("VM"); + } + + @Override + public void run() { + setName("XS-Listener-" + _host.ip); + while (!_stop) { + try { + Connection conn = getConnection(); + Map results; + try { + results = Event.properFrom(conn, _classes, _token, new Double(30)); + } catch (Exception e) { + s_logger.error("Retrying the waiting on VM events due to: ", e); + continue; + } + + _token = (String)results.get("token"); + @SuppressWarnings("unchecked") + Set events = (Set)results.get("events"); + for (Event.Record event : events) { + try { + if (!(event.snapshot instanceof VM.Record)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("The snapshot is not a VM: " + event); + } + continue; + } + VM.Record vm = (VM.Record)event.snapshot; + + String hostUuid = null; + if (vm.residentOn != null && !vm.residentOn.toWireString().contains("OpaqueRef:NULL")) { + hostUuid = vm.residentOn.getUuid(conn); + } + recordChanges(conn, vm, hostUuid); + } catch (Exception e) { + s_logger.error("Skipping over " + event, e); + } + } + } catch (Throwable th) { + s_logger.error("Exception caught in eventlistener thread: ", th); + } + } + } + + protected void recordChanges(Connection conn, VM.Record rec, String hostUuid) { + String vm = rec.nameLabel; + if (!VirtualMachineName.isValidCloudStackVmName(vm, _instance)) { + s_logger.debug("Skipping over VMs that does not conform to CloudStack naming convention: " + vm); + return; + } + + VirtualMachine.State currentState = convertToState(rec.powerState); + if (vm.startsWith("migrating")) { + s_logger.warn("Skipping " + vm + " because it is migrating."); + return; + } + + if (currentState == VirtualMachine.State.Stopped) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Double check the power state to make sure we got the correct state for " + vm); + } + currentState = getRealPowerState(conn, vm); + } + + boolean updateMap = false; + boolean reportChange = false; + + // NOTE: For now we only record change when the VM is stopped. We don't find out any VMs starting for now. + synchronized (_cluster.intern()) { + Ternary oldState = s_vms.get(_cluster, vm); + if (oldState == null) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Unable to find " + vm + " from previous map. Assuming it was in Stopped state."); + } + oldState = new Ternary(null, VirtualMachine.State.Stopped, null); + } + + if (s_logger.isTraceEnabled()) { + s_logger.trace(vm + ": current state=" + currentState + ", previous state=" + oldState); + } + + if (oldState.second() == VirtualMachine.State.Starting) { + if (currentState == VirtualMachine.State.Running) { + updateMap = true; + reportChange = false; + } else if (currentState == VirtualMachine.State.Stopped) { + updateMap = false; + reportChange = false; + } + } else if (oldState.second() == VirtualMachine.State.Migrating) { + updateMap = true; + reportChange = false; + } else if (oldState.second() == VirtualMachine.State.Stopping) { + if (currentState == VirtualMachine.State.Stopped) { + updateMap = true; + reportChange = false; + } else if (currentState == VirtualMachine.State.Running) { + updateMap = false; + reportChange = false; + } + } else if (oldState.second() != currentState) { + updateMap = true; + reportChange = true; + } else if (hostUuid != null && !hostUuid.equals(oldState.first())) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Detecting " + vm + " moved from " + oldState.first() + " to " + hostUuid); + } + reportChange = true; + updateMap = true; + } + + if (updateMap) { + s_vms.put(_cluster, hostUuid, vm, currentState); + if (s_logger.isTraceEnabled()) { + s_logger.trace("Updated " + vm + " to [" + hostUuid + ", " + currentState); + } + } + if (reportChange) { + Ternary change = _changes.get(vm); + if (hostUuid == null) { + // This is really strange code. It looks like the sync + // code wants this to be set, which is extremely weird + // for VMs that are dead. Why would I want to set the + // hostUuid if the VM is stopped. + hostUuid = oldState.first(); + if (hostUuid == null) { + hostUuid = _host.uuid; + } + } + if (change == null) { + change = new Ternary(hostUuid, currentState, null); + } else { + change.first(hostUuid); + change.second(currentState); + } + _changes.put(vm, change); + } + } + } + + @Override + public void start() { + if (_isMaster) { + // Throw away the initial set of events because they're history + Connection conn = getConnection(); + Map results; + try { + results = Event.properFrom(conn, _classes, _token, new Double(30)); + } catch (Exception e) { + s_logger.error("Retrying the waiting on VM events due to: ", e); + throw new CloudRuntimeException("Unable to start a listener thread to listen to VM events", e); + } + _token = (String)results.get("token"); + s_logger.debug("Starting the event listener thread for " + _host.uuid); + super.start(); + } + } + + public boolean isListening() { + return _isMaster; + } + + public HashMap> getChanges() { + synchronized (_cluster.intern()) { + if (_changes.size() == 0) { + return null; + } + HashMap> diff = _changes; + _changes = new HashMap>(); + return diff; + } + } + + public void signalStop() { + _stop = true; + interrupt(); + } + } + +} diff --git a/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java b/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java index 3dc7dd86cbcb..8d1194075263 100644 --- a/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java +++ b/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java @@ -103,7 +103,7 @@ public Void copyAsync(Map volumeMap, VirtualMachineTO vmT try { VMInstanceVO instance = instanceDao.findById(vmTo.getId()); if (instance != null) { - if (srcHost.getClusterId() == destHost.getClusterId()) { + if (srcHost.getClusterId().equals(destHost.getClusterId())) { answer = migrateVmWithVolumesWithinCluster(instance, vmTo, srcHost, destHost, volumeMap); } else { answer = migrateVmWithVolumesAcrossCluster(instance, vmTo, srcHost, destHost, volumeMap); diff --git a/plugins/hypervisors/xen/test/com/cloud/hypervisor/xen/resource/CitrixResourceBaseTest.java b/plugins/hypervisors/xen/test/com/cloud/hypervisor/xen/resource/CitrixResourceBaseTest.java index 920d6d24e627..be0548c51b38 100644 --- a/plugins/hypervisors/xen/test/com/cloud/hypervisor/xen/resource/CitrixResourceBaseTest.java +++ b/plugins/hypervisors/xen/test/com/cloud/hypervisor/xen/resource/CitrixResourceBaseTest.java @@ -144,6 +144,7 @@ public void testScaleVMF3() throws Types.XenAPIException, XmlRpcException { doReturn(1).when(vmSpec).getCpus(); doNothing().when(vm).setVCPUsNumberLive(conn, 1L); doReturn(500).when(vmSpec).getMinSpeed(); + doReturn(500).when(vmSpec).getMaxSpeed(); doReturn(true).when(vmSpec).getLimitCpuUse(); doReturn(null).when(_resource).callHostPlugin(conn, "vmops", "add_to_VCPUs_params_live", "key", "cap", "value", "99", "vmname", "i-2-3-VM"); Map args = (Map)mock(HashMap.class); diff --git a/plugins/network-elements/bigswitch-vns/pom.xml b/plugins/network-elements/bigswitch-vns/pom.xml index bd42806c9de8..b0e9b9f711b7 100644 --- a/plugins/network-elements/bigswitch-vns/pom.xml +++ b/plugins/network-elements/bigswitch-vns/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/network-elements/cisco-vnmc/pom.xml b/plugins/network-elements/cisco-vnmc/pom.xml index ec2f2f86be24..0b00f012b9d8 100644 --- a/plugins/network-elements/cisco-vnmc/pom.xml +++ b/plugins/network-elements/cisco-vnmc/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/network-elements/cisco-vnmc/resources/META-INF/cloudstack/cisco-vnmc/module.properties b/plugins/network-elements/cisco-vnmc/resources/META-INF/cloudstack/cisco-vnmc/module.properties new file mode 100644 index 000000000000..69ffb6fe1d03 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/resources/META-INF/cloudstack/cisco-vnmc/module.properties @@ -0,0 +1,18 @@ +# 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. +name=cisco-vnmc +parent=network \ No newline at end of file diff --git a/plugins/network-elements/cisco-vnmc/resources/META-INF/cloudstack/cisco-vnmc/spring-cisco-vnmc-context.xml b/plugins/network-elements/cisco-vnmc/resources/META-INF/cloudstack/cisco-vnmc/spring-cisco-vnmc-context.xml new file mode 100644 index 000000000000..62e2ef088e38 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/resources/META-INF/cloudstack/cisco-vnmc/spring-cisco-vnmc-context.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java index fbda707fce20..f03fd05b9c12 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java @@ -27,6 +27,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import javax.persistence.EntityExistsException; import org.apache.log4j.Logger; import org.apache.cloudstack.context.CallContext; @@ -887,8 +888,12 @@ public CiscoAsa1000vDevice addCiscoAsa1000vResource( throw new InvalidParameterValueException("Could not find phyical network with ID: " + physicalNetworkId); } - ciscoAsa1000vResource = new CiscoAsa1000vDeviceVO(physicalNetworkId, cmd.getManagementIp(), cmd.getInPortProfile(), cmd.getClusterId()); - _ciscoAsa1000vDao.persist((CiscoAsa1000vDeviceVO)ciscoAsa1000vResource); + ciscoAsa1000vResource = new CiscoAsa1000vDeviceVO(physicalNetworkId, cmd.getManagementIp().trim(), cmd.getInPortProfile(), cmd.getClusterId()); + try { + _ciscoAsa1000vDao.persist((CiscoAsa1000vDeviceVO)ciscoAsa1000vResource); + } catch (EntityExistsException e) { + throw new InvalidParameterValueException("An ASA 1000v appliance already exists with same configuration"); + } return ciscoAsa1000vResource; } diff --git a/plugins/network-elements/dns-notifier/pom.xml b/plugins/network-elements/dns-notifier/pom.xml index 8c63ebf809cb..ec63d9d804a4 100644 --- a/plugins/network-elements/dns-notifier/pom.xml +++ b/plugins/network-elements/dns-notifier/pom.xml @@ -22,7 +22,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml cloud-plugin-example-dns-notifier diff --git a/plugins/network-elements/elastic-loadbalancer/pom.xml b/plugins/network-elements/elastic-loadbalancer/pom.xml index 968debc5f54c..f599979c4d05 100644 --- a/plugins/network-elements/elastic-loadbalancer/pom.xml +++ b/plugins/network-elements/elastic-loadbalancer/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java index e049cece0581..c60b3ca7756c 100644 --- a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java +++ b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java @@ -17,6 +17,7 @@ package com.cloud.network.lb; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -34,13 +35,13 @@ 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.loadbalancer.CreateLoadBalancerRuleCmd; 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.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; @@ -97,8 +98,8 @@ import com.cloud.network.dao.VirtualRouterProviderDao; 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.dao.ElasticLbVmMapDao; import com.cloud.network.router.VirtualRouter; import com.cloud.network.router.VirtualRouter.RedundantState; @@ -124,8 +125,6 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; 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.exception.CloudRuntimeException; @@ -500,11 +499,11 @@ public DomainRouterVO deployELBVm(Network guestNetwork, DeployDestination dest, NetworkOffering controlOffering = offerings.get(0); Network controlConfig = _networkMgr.setupNetwork(_systemAcct, controlOffering, plan, null, null, false).get(0); - LinkedHashMap networks = new LinkedHashMap(2); + LinkedHashMap> networks = new LinkedHashMap>(2); NicProfile guestNic = new NicProfile(); guestNic.setDefaultNic(true); - networks.put(controlConfig, null); - networks.put(guestNetwork, guestNic); + networks.put(controlConfig, new ArrayList()); + networks.put(guestNetwork, new ArrayList(Arrays.asList(guestNic))); VMTemplateVO template = _templateDao.findSystemVMTemplate(dcId); diff --git a/plugins/network-elements/f5/pom.xml b/plugins/network-elements/f5/pom.xml index 760b610a8371..895bf461fb7a 100644 --- a/plugins/network-elements/f5/pom.xml +++ b/plugins/network-elements/f5/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml @@ -36,5 +36,10 @@ org.apache.axis axis + + commons-discovery + commons-discovery + 0.5 + diff --git a/plugins/network-elements/f5/resources/META-INF/cloudstack/f5/module.properties b/plugins/network-elements/f5/resources/META-INF/cloudstack/f5/module.properties new file mode 100644 index 000000000000..efdb64a89e7f --- /dev/null +++ b/plugins/network-elements/f5/resources/META-INF/cloudstack/f5/module.properties @@ -0,0 +1,18 @@ +# 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. +name=f5 +parent=network \ No newline at end of file diff --git a/plugins/network-elements/f5/resources/META-INF/cloudstack/f5/spring-f5-context.xml b/plugins/network-elements/f5/resources/META-INF/cloudstack/f5/spring-f5-context.xml new file mode 100644 index 000000000000..6472d689c4f9 --- /dev/null +++ b/plugins/network-elements/f5/resources/META-INF/cloudstack/f5/spring-f5-context.xml @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java index fc2256b2a565..77916ddafd70 100644 --- a/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java +++ b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java @@ -320,7 +320,7 @@ public Host addExternalLoadBalancer(AddExternalLoadBalancerCmd cmd) { String deviceType = NetworkDevice.F5BigIpLoadBalancer.getName(); lbDeviceVO = addExternalLoadBalancer(pNetwork.getId(), cmd.getUrl(), cmd.getUsername(), cmd.getPassword(), - deviceType, new F5BigIpResource(), false, null, null); + deviceType, new F5BigIpResource(), false, false, null, null); if (lbDeviceVO != null) { lbHost = _hostDao.findById(lbDeviceVO.getHostId()); @@ -374,7 +374,7 @@ public ExternalLoadBalancerDeviceVO addF5LoadBalancer(AddF5LoadBalancerCmd cmd) } return addExternalLoadBalancer(cmd.getPhysicalNetworkId(), cmd.getUrl(), cmd.getUsername(), cmd.getPassword(), - deviceName, new F5BigIpResource(), false, null, null); + deviceName, new F5BigIpResource(), false, false, null, null); } diff --git a/plugins/network-elements/internal-loadbalancer/pom.xml b/plugins/network-elements/internal-loadbalancer/pom.xml index 2002728776d0..d76345d47c90 100644 --- a/plugins/network-elements/internal-loadbalancer/pom.xml +++ b/plugins/network-elements/internal-loadbalancer/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java index b9482b5a490c..02e872b3facc 100644 --- a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java +++ b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.network.lb; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; @@ -26,12 +27,11 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.log4j.Logger; - import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; @@ -77,7 +77,6 @@ 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.LoadBalancingRulesManager; import com.cloud.network.router.VirtualNetworkApplianceManager; import com.cloud.network.router.VirtualRouter; @@ -610,7 +609,7 @@ protected List findOrDeployInternalLbVm(Network guestNetwork, Ip return internalLbVms; } - LinkedHashMap networks = createInternalLbVmNetworks(guestNetwork, plan, requestedGuestIp); + LinkedHashMap> networks = createInternalLbVmNetworks(guestNetwork, plan, requestedGuestIp); //Pass startVm=false as we are holding the network lock that needs to be released at the end of vm allocation DomainRouterVO internalLbVm = deployInternalLbVm(owner, dest, plan, params, internalLbProviderId, _internalLbVmOfferingId, guestNetwork.getVpcId(), networks, false); @@ -646,11 +645,11 @@ protected long getInternalLbProviderId(Network guestNetwork) { return internalLbProvider.getId(); } - protected LinkedHashMap createInternalLbVmNetworks(Network guestNetwork, DeploymentPlan plan, Ip guestIp) throws ConcurrentOperationException, + protected LinkedHashMap> createInternalLbVmNetworks(Network guestNetwork, DeploymentPlan plan, Ip guestIp) throws ConcurrentOperationException, InsufficientAddressCapacityException { //Form networks - LinkedHashMap networks = new LinkedHashMap(3); + LinkedHashMap> networks = new LinkedHashMap>(3); //1) Guest network - default if (guestNetwork != null) { @@ -669,7 +668,7 @@ protected LinkedHashMap createInternalLbVmNetworks(Network String gatewayCidr = guestNetwork.getCidr(); guestNic.setNetmask(NetUtils.getCidrNetmask(gatewayCidr)); guestNic.setDefaultNic(true); - networks.put(guestNetwork, guestNic); + networks.put(guestNetwork, new ArrayList(Arrays.asList(guestNic))); } //2) Control network @@ -677,7 +676,7 @@ protected LinkedHashMap createInternalLbVmNetworks(Network List offerings = _ntwkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemControlNetwork); NetworkOffering controlOffering = offerings.get(0); Network controlConfig = _ntwkMgr.setupNetwork(_accountMgr.getSystemAccount(), controlOffering, plan, null, null, false).get(0); - networks.put(controlConfig, null); + networks.put(controlConfig, new ArrayList()); return networks; } @@ -711,7 +710,7 @@ public List findInternalLbVms(long guestNetworkId, Ip requestedG protected DomainRouterVO deployInternalLbVm(Account owner, DeployDestination dest, DeploymentPlan plan, Map params, long internalLbProviderId, long svcOffId, Long vpcId, - LinkedHashMap networks, + LinkedHashMap> networks, boolean startVm) throws ConcurrentOperationException, InsufficientAddressCapacityException, InsufficientServerCapacityException, InsufficientCapacityException, StorageUnavailableException, ResourceUnavailableException { diff --git a/plugins/network-elements/juniper-contrail/pom.xml b/plugins/network-elements/juniper-contrail/pom.xml index 22167fed199e..5227878da909 100644 --- a/plugins/network-elements/juniper-contrail/pom.xml +++ b/plugins/network-elements/juniper-contrail/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailElementImpl.java b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailElementImpl.java index dfbe7d34dbb1..896ae8c69354 100644 --- a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailElementImpl.java +++ b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailElementImpl.java @@ -52,12 +52,8 @@ import com.cloud.network.element.NetworkACLServiceProvider; import com.cloud.network.element.SourceNatServiceProvider; import com.cloud.network.element.StaticNatServiceProvider; -import com.cloud.network.element.VpcProvider; import com.cloud.network.rules.StaticNat; import com.cloud.network.vpc.NetworkACLItem; -import com.cloud.network.vpc.PrivateGateway; -import com.cloud.network.vpc.StaticRouteProfile; -import com.cloud.network.vpc.Vpc; import com.cloud.offering.NetworkOffering; import com.cloud.utils.component.AdapterBase; import com.cloud.vm.NicProfile; @@ -68,14 +64,22 @@ import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.NicDao; import com.cloud.network.IpAddress; +import com.cloud.server.ConfigurationServer; +import com.cloud.server.ConfigurationServerImpl; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.resource.ResourceManager; @Component -@Local(value = {ContrailElement.class, StaticNatServiceProvider.class}) +@Local(value = {ContrailElement.class, StaticNatServiceProvider.class, IpDeployer.class, SourceNatServiceProvider.class}) public class ContrailElementImpl extends AdapterBase - implements ContrailElement, IpDeployer, StaticNatServiceProvider { + implements ContrailElement, StaticNatServiceProvider, IpDeployer, SourceNatServiceProvider, DhcpServiceProvider { private static final Map> _capabilities = InitCapabilities(); + @Inject ResourceManager _resourceMgr; + @Inject ConfigurationServer _configServer; + @Inject NetworkDao _networksDao; @Inject ContrailManager _manager; @Inject NicDao _nicDao; @Inject ServerDBSync _dbSync; @@ -99,7 +103,7 @@ public List> getCommands() { // NetworkElement API @Override public Provider getProvider() { - return Provider.JuniperContrail; + return Provider.JuniperContrailRouter; } private static Map> InitCapabilities() { @@ -281,6 +285,32 @@ public boolean destroy(Network network, ReservationContext context) @Override public boolean isReady(PhysicalNetworkServiceProvider provider) { + Map serviceMap = ((ConfigurationServerImpl)_configServer).getServicesAndProvidersForNetwork( _manager.getRouterOffering().getId()); + List types = new ArrayList(); + types.add(TrafficType.Control); + types.add(TrafficType.Management); + types.add(TrafficType.Storage); + List systemNets = _manager.findSystemNetworks(types); + if (systemNets != null && !systemNets.isEmpty()) { + for (NetworkVO net: systemNets) { + s_logger.debug("update system network service: " + net.getName() + "; service provider: " + serviceMap); + _networksDao.update(net.getId(), net, serviceMap); + } + } else { + s_logger.debug("no system networks created yet"); + } + serviceMap = ((ConfigurationServerImpl)_configServer).getServicesAndProvidersForNetwork( _manager.getPublicRouterOffering().getId()); + types = new ArrayList(); + types.add(TrafficType.Public); + systemNets = _manager.findSystemNetworks(types); + if (systemNets != null && !systemNets.isEmpty()) { + for (NetworkVO net: systemNets) { + s_logger.debug("update system network service: " + net.getName() + "; service provider: " + serviceMap); + _networksDao.update(net.getId(), net, serviceMap); + } + } else { + s_logger.debug("no system networks created yet"); + } return true; } @@ -346,4 +376,28 @@ private boolean isFloatingIpCreate(PublicIpAddress ip) { } return false; } + + @Override + public boolean addDhcpEntry(Network network, NicProfile nic, + VirtualMachineProfile vm, + DeployDestination dest, ReservationContext context) + throws ConcurrentOperationException, InsufficientCapacityException, + ResourceUnavailableException { + return false; + } + + @Override + public boolean configDhcpSupportForSubnet(Network network, NicProfile nic, + VirtualMachineProfile vm, + DeployDestination dest, ReservationContext context) + throws ConcurrentOperationException, InsufficientCapacityException, + ResourceUnavailableException { + return false; + } + + @Override + public boolean removeDhcpSupportForSubnet(Network network) + throws ResourceUnavailableException { + return false; + } } diff --git a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailGuru.java b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailGuru.java index ca53f416f899..4e8083b6cd2a 100644 --- a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailGuru.java +++ b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailGuru.java @@ -19,8 +19,11 @@ import java.io.IOException; +import java.net.URI; +import java.util.List; import javax.inject.Inject; +import javax.ejb.Local; import net.juniper.contrail.api.types.MacAddressesType; import net.juniper.contrail.api.types.VirtualMachineInterface; @@ -37,6 +40,9 @@ import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.dao.DataCenterDao; import com.cloud.network.Network; import com.cloud.network.Network.State; import com.cloud.network.NetworkProfile; @@ -47,6 +53,10 @@ import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.guru.NetworkGuru; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetwork.IsolationMethod; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.offering.NetworkOffering; import com.cloud.user.Account; import com.cloud.utils.component.AdapterBase; @@ -60,20 +70,36 @@ import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.NicDao; import com.cloud.vm.NicVO; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.addr.PublicIp; +import com.cloud.user.AccountManager; +import com.cloud.network.IpAddressManager; -@Component +@Local(value = {NetworkGuru.class}) public class ContrailGuru extends AdapterBase implements NetworkGuru { @Inject NetworkDao _networkDao; @Inject ContrailManager _manager; @Inject NicDao _nicDao; + @Inject PhysicalNetworkDao _physicalNetworkDao; + @Inject DataCenterDao _dcDao; + @Inject IPAddressDao _ipAddressDao; + @Inject AccountManager _accountMgr; + @Inject IpAddressManager _ipAddrMgr; private static final Logger s_logger = Logger.getLogger(ContrailGuru.class); private static final TrafficType[] _trafficTypes = {TrafficType.Guest}; - private boolean canHandle(NetworkOffering offering) { - return (offering.getName().equals(ContrailManager.offeringName)); - } + private boolean canHandle(NetworkOffering offering, NetworkType networkType, PhysicalNetwork physicalNetwork) { + if (networkType == NetworkType.Advanced + && isMyTrafficType(offering.getTrafficType()) + && offering.getGuestType() == Network.GuestType.Isolated + && physicalNetwork.getIsolationMethods().contains("L3VPN")) + return true; + return false; + } + @Override public String getName() { return "ContrailGuru"; @@ -82,7 +108,11 @@ public String getName() { @Override public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { - if (!canHandle(offering)) { + // Check of the isolation type of the related physical network is L3VPN + PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId()); + DataCenter dc = _dcDao.findById(plan.getDataCenterId()); + if (!canHandle(offering, dc.getNetworkType(),physnet)) { + s_logger.debug("Refusing to design this network"); return null; } NetworkVO network = new NetworkVO(offering.getTrafficType(), Mode.Dhcp, BroadcastDomainType.Lswitch, @@ -142,7 +172,13 @@ public NicProfile allocate(Network network, NicProfile profile, } profile.setStrategy(ReservationStrategy.Start); - + URI broadcastUri = null; + try { + broadcastUri = new URI("vlan://untagged"); + } catch (Exception e) { + s_logger.warn("unable to instantiate broadcast URI: " + e); + } + profile.setBroadcastUri(broadcastUri); return profile; } @@ -225,7 +261,9 @@ public void reserve(NicProfile nic, Network network, if (nic.getIp4Address() == null) { s_logger.debug("Allocated IP address " + ipModel.getAddress()); nic.setIp4Address(ipModel.getAddress()); - nic.setNetmask(NetUtils.cidr2Netmask(network.getCidr())); + if (network.getCidr() != null) { + nic.setNetmask(NetUtils.cidr2Netmask(network.getCidr())); + } nic.setGateway(network.getGateway()); nic.setFormat(AddressFormat.Ip4); } @@ -296,6 +334,7 @@ public void shutdown(NetworkProfile network, NetworkOffering offering) { return; } try { + _manager.getDatabase().getVirtualNetworks().remove(vnModel); vnModel.delete(_manager.getModelController()); } catch (IOException e) { s_logger.warn("virtual-network delete", e); diff --git a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailManager.java b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailManager.java index b96b00c9e96c..6489da9d042a 100644 --- a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailManager.java +++ b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailManager.java @@ -25,6 +25,9 @@ import net.juniper.contrail.api.ApiConnector; import net.juniper.contrail.api.types.FloatingIp; +import net.juniper.contrail.api.types.NetworkPolicy; +import net.juniper.contrail.api.types.Project; + import net.juniper.contrail.api.types.VirtualNetwork; import com.cloud.network.Network; @@ -36,17 +39,22 @@ import com.cloud.network.dao.NetworkVO; import com.cloud.domain.DomainVO; import com.cloud.projects.ProjectVO; +import com.cloud.network.vpc.NetworkACLVO; public interface ContrailManager { - public static final String offeringName = "Juniper Contrail offering"; - public static final String offeringDisplayText = "Juniper Contrail network offering"; + public static final String routerOfferingName = "Juniper Contrail Network Offering"; + public static final String routerOfferingDisplayText = "Juniper Contrail Network Offering"; + public static final String routerPublicOfferingName = "Juniper Contrail Public Network Offering"; + public static final String routerPublicOfferingDisplayText = "Juniper Contrail Public Network Offering"; public static final int DB_SYNC_INTERVAL_DEFAULT = 600000; public static final String VNC_ROOT_DOMAIN = "default-domain"; public static final String VNC_DEFAULT_PROJECT = "default-project"; public static final String managementNetworkName = "ip-fabric"; - public NetworkOffering getOffering(); - public void syncNetworkDB(short syncMode) throws IOException; + public NetworkOffering getRouterOffering(); + public NetworkOffering getPublicRouterOffering(); + + public void syncNetworkDB(short syncMode) throws Exception; public boolean isManagedPhysicalNetwork(Network network); @@ -68,6 +76,7 @@ public interface ContrailManager { public String getDefaultPublicNetworkFQN(); public String getProjectId(long domainId, long accountId) throws IOException; public net.juniper.contrail.api.types.Project getVncProject(long domainId, long accountId) throws IOException; + public net.juniper.contrail.api.types.Project getDefaultVncProject() throws IOException; public boolean isSystemRootDomain(net.juniper.contrail.api.types.Domain vnc); public boolean isSystemRootDomain(DomainVO domain); public boolean isSystemDefaultProject(net.juniper.contrail.api.types.Project project); @@ -80,14 +89,16 @@ public interface ContrailManager { public ApiConnector getApiConnector(); public ModelDatabase getDatabase(); public ModelController getModelController(); - public List findJuniperManagedNetworks(List types); - public List findJuniperManagedPublicIps(); + public List findManagedNetworks(List types); + public List findSystemNetworks(List types); + public List findManagedPublicIps(); + public List findManagedACLs(); public VirtualNetwork findDefaultVirtualNetwork(TrafficType trafficType) throws IOException; public List getFloatingIps(); public VirtualNetworkModel lookupPublicNetworkModel(); - public void createPublicNetworks(); public boolean createFloatingIp(PublicIpAddress ip); public boolean deleteFloatingIp(PublicIpAddress ip); + public boolean isSystemDefaultNetworkPolicy(NetworkPolicy policy); } diff --git a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java index 4eaafca17cf0..466e0434597d 100644 --- a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java +++ b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -31,6 +30,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import javax.ejb.Local; import net.juniper.contrail.api.ApiConnector; import net.juniper.contrail.api.ApiConnectorFactory; @@ -38,6 +38,8 @@ import net.juniper.contrail.api.ObjectReference; import net.juniper.contrail.api.types.FloatingIp; import net.juniper.contrail.api.types.FloatingIpPool; +import net.juniper.contrail.api.types.NetworkPolicy; +import net.juniper.contrail.api.types.Project; import net.juniper.contrail.api.types.VirtualNetwork; import org.apache.cloudstack.network.contrail.model.FloatingIpModel; @@ -50,13 +52,14 @@ import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.ConfigurationService; +import com.cloud.server.ConfigurationServer; +import com.cloud.server.ConfigurationServerImpl; import com.cloud.dc.DataCenter; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.VlanDao; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; -import com.cloud.exception.InternalErrorException; import com.cloud.projects.ProjectVO; import com.cloud.user.dao.AccountDao; import com.cloud.user.Account; @@ -72,11 +75,12 @@ import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.PhysicalNetworkVO; -import com.cloud.offering.NetworkOffering.State; import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.network.vpc.dao.NetworkACLDao; +import com.cloud.network.vpc.NetworkACLVO; import com.cloud.projects.dao.ProjectDao; import com.cloud.utils.component.ComponentLifecycle; import com.cloud.utils.component.ManagerBase; @@ -96,9 +100,10 @@ import java.io.File; import java.io.FileInputStream; -@Component +@Local(value = { ContrailManager.class}) public class ContrailManagerImpl extends ManagerBase implements ContrailManager { @Inject public ConfigurationService _configService; + @Inject ConfigurationServer _configServer; @Inject NetworkOfferingDao _networkOfferingDao; @Inject DomainDao _domainDao; @@ -115,12 +120,15 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager @Inject IPAddressDao _ipAddressDao; @Inject VlanDao _vlanDao; @Inject UserVmDao _vmDao; + @Inject NetworkACLDao _networkAclDao; private static final Logger s_logger = Logger.getLogger(ContrailManager.class); private ApiConnector _api; private NetworkOffering _offering; + private NetworkOffering _routerOffering; + private NetworkOffering _routerPublicOffering; private Timer _dbSyncTimer; private int _dbSyncInterval = DB_SYNC_INTERVAL_DEFAULT; private final String configuration = "contrail.properties"; @@ -128,7 +136,6 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager private ModelController _controller; ContrailManagerImpl() { - setRunLevel(ComponentLifecycle.RUN_LEVEL_COMPONENT); _database = new ModelDatabase(); } @@ -153,21 +160,56 @@ public boolean stop() { public ModelDatabase getDatabase() { return _database; } - - private NetworkOffering LocateOffering() { + + private NetworkOffering LocatePublicNetworkOffering(String offeringName, + String offeringDisplayText, Provider provider) { + List offerList = _configService.listNetworkOfferings(TrafficType.Public, false); + for (NetworkOffering offer: offerList) { + if (offer.getName().equals(offeringName)) { + if (offer.getState() != NetworkOffering.State.Enabled) { + return EnableNetworkOffering(offer.getId()); + } + return offer; + } + } + Map> serviceProviderMap = new HashMap>(); + Set providerSet = new HashSet(); + providerSet.add(provider); + final Service[] services = { + Service.Connectivity, + Service.Dhcp, + Service.NetworkACL, + Service.StaticNat, + Service.SourceNat + }; + for (Service svc: services) { + serviceProviderMap.put(svc, providerSet); + } + ConfigurationManager configMgr = (ConfigurationManager) _configService; + NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, + TrafficType.Public, null, true, Availability.Optional, null, serviceProviderMap, true, + Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false); + + voffer.setState(NetworkOffering.State.Enabled); + long id = voffer.getId(); + _networkOfferingDao.update(id, voffer); + return _networkOfferingDao.findById(id); + } + + private NetworkOffering LocateNetworkOffering(String offeringName, + String offeringDisplayText, Provider provider) { List offerList = _configService.listNetworkOfferings(TrafficType.Guest, false); for (NetworkOffering offer: offerList) { if (offer.getName().equals(offeringName)) { - if (offer.getState() != State.Enabled) { + if (offer.getState() != NetworkOffering.State.Enabled) { return EnableNetworkOffering(offer.getId()); } return offer; } } Map> serviceProviderMap = new HashMap>(); - // Map> serviceCapabilityMap = new HashMap>(); Set providerSet = new HashSet(); - providerSet.add(Provider.JuniperContrail); + providerSet.add(provider); final Service[] services = { Service.Connectivity, Service.Dhcp, @@ -183,7 +225,7 @@ private NetworkOffering LocateOffering() { TrafficType.Guest, null, false, Availability.Optional, null, serviceProviderMap, true, Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false); - voffer.setState(State.Enabled); + voffer.setState(NetworkOffering.State.Enabled); long id = voffer.getId(); _networkOfferingDao.update(id, voffer); return _networkOfferingDao.findById(id); @@ -191,7 +233,7 @@ private NetworkOffering LocateOffering() { private NetworkOffering EnableNetworkOffering(long id) { NetworkOfferingVO offering = _networkOfferingDao.createForUpdate(id); - offering.setState(State.Enabled); + offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(id, offering); return _networkOfferingDao.findById(id); } @@ -200,29 +242,41 @@ private NetworkOffering EnableNetworkOffering(long id) { public boolean configure(String name, Map params) throws ConfigurationException { File configFile = PropertiesUtil.findConfigFile(configuration); - final Properties configProps = new Properties(); try { - configProps.load(new FileInputStream(configFile)); - String value = configProps.getProperty("management.db_sync_interval"); - if (value != null) { - _dbSyncInterval = Integer.valueOf(value); - } - - String hostname = configProps.getProperty("api.hostname"); - String portStr = configProps.getProperty("api.port"); + String hostname = null; int port = 0; - if (portStr != null && portStr.length() > 0) { - port = Integer.parseInt(portStr); + if (configFile == null) { + hostname = "localhost"; + port = 8082; + } else { + final Properties configProps = new Properties(); + configProps.load(new FileInputStream(configFile)); + String value = configProps.getProperty("management.db_sync_interval"); + if (value != null) { + _dbSyncInterval = Integer.valueOf(value); + } + hostname = configProps.getProperty("api.hostname"); + String portStr = configProps.getProperty("api.port"); + if (portStr != null && portStr.length() > 0) { + port = Integer.parseInt(portStr); + } } _api = ApiConnectorFactory.build(hostname, port); } catch (IOException ex) { s_logger.warn("Unable to read " + configuration, ex); throw new ConfigurationException(); + } catch (Exception ex) { + s_logger.debug("Exception in configure: " + ex); + ex.printStackTrace(); + throw new ConfigurationException(); } _controller = new ModelController(this, _api, _vmDao, _networksDao, _nicDao, _vlanDao, _ipAddressDao); - _offering = LocateOffering(); + _routerOffering = LocateNetworkOffering(routerOfferingName, routerOfferingDisplayText, + Provider.JuniperContrailRouter); + _routerPublicOffering = LocatePublicNetworkOffering(routerPublicOfferingName, routerPublicOfferingDisplayText, + Provider.JuniperContrailRouter); _eventHandler.subscribe(); @@ -232,8 +286,13 @@ public boolean configure(String name, Map params) throws Configu } @Override - public NetworkOffering getOffering() { - return _offering; + public NetworkOffering getPublicRouterOffering() { + return _routerPublicOffering; + } + + @Override + public NetworkOffering getRouterOffering() { + return _routerOffering; } @Override @@ -329,12 +388,19 @@ public String getProjectId(long domainId, long accountId) throws IOException { public net.juniper.contrail.api.types.Project getVncProject(long domainId, long accountId) throws IOException { String projectId = getProjectId(domainId, accountId); if (projectId == null) { - return null; + return getDefaultVncProject(); } return (net.juniper.contrail.api.types.Project) _api.findById(net.juniper.contrail.api.types.Project.class, projectId); } + @Override + public net.juniper.contrail.api.types.Project getDefaultVncProject() throws IOException { + net.juniper.contrail.api.types.Project project = null; + project = (net.juniper.contrail.api.types.Project)_api.findByFQN(net.juniper.contrail.api.types.Project.class, VNC_ROOT_DOMAIN + ":" + VNC_DEFAULT_PROJECT); + return project; + } + @Override public String getFQN(Network net) { // domain, project, name @@ -359,7 +425,7 @@ public void findInfrastructureNetworks(PhysicalNetworkVO phys, List d } - public void syncNetworkDB(short syncMode) throws IOException { + public void syncNetworkDB(short syncMode) throws Exception { if (_dbSync.syncAll(syncMode) == ServerDBSync.SYNC_STATE_OUT_OF_SYNC) { if (syncMode == DBSyncGeneric.SYNC_MODE_CHECK) { s_logger.info("# Cloudstack DB & VNC are out of sync #"); @@ -383,6 +449,7 @@ public void run() { } catch (Exception ex) { s_logger.debug(ex); s_logger.info("Unable to sync network db"); + //resync will be done after _dbSyncInterval seconds since _syncMode is still set to SYNC_MODE_UPDATE } } } @@ -392,7 +459,7 @@ public void run() { public boolean isManagedPhysicalNetwork(Network network) { List net_list = _physicalNetworkDao.listByZone(network.getDataCenterId()); for (PhysicalNetworkVO phys : net_list) { - if(_physProviderDao.findByServiceProvider(phys.getId(), Network.Provider.JuniperContrail.getName()) != null) { + if(_physProviderDao.findByServiceProvider(phys.getId(), Network.Provider.JuniperContrailRouter.getName()) != null) { return true; } } @@ -415,7 +482,54 @@ public String findVirtualNetworkId(Network net) throws IOException { List fqn = ImmutableList.copyOf(StringUtils.split(netname, ':')); return _api.findByName(VirtualNetwork.class, fqn); } - + + @Override + public List findSystemNetworks(List types) { + SearchBuilder searchBuilder = _networksDao.createSearchBuilder(); + searchBuilder.and("trafficType", searchBuilder.entity().getTrafficType(), Op.IN); + SearchCriteria sc = searchBuilder.create(); + if (types == null || types.isEmpty()) { + types = new ArrayList(); + types.add(TrafficType.Control); + types.add(TrafficType.Management); + types.add(TrafficType.Public); + types.add(TrafficType.Storage); + } + sc.setParameters("trafficType", types.toArray()); + List dbNets = _networksDao.search(sc, null); + if (dbNets == null) { + s_logger.debug("no system networks for the given traffic types: " + types.toString()); + dbNets = new ArrayList(); + } + + List phys_list = _physicalNetworkDao.listAll(); + final String provider = Provider.JuniperContrailRouter.getName(); + for (Iterator iter = phys_list.iterator(); iter.hasNext(); ) { + PhysicalNetworkVO phys = iter.next(); + if (_physProviderDao.findByServiceProvider(phys.getId(), provider) != null) { + List infraNets = new ArrayList(); + findInfrastructureNetworks(phys, infraNets); + for (NetworkVO net:infraNets) { + if (types == null || types.isEmpty()) { + if (!dbNets.contains(net)) { + dbNets.add(net); + } + continue; + } + for(TrafficType type:types) { + if (net.getTrafficType() == type) { + if (!dbNets.contains(net)) { + dbNets.add(net); + } + break; + } + } + } + } + } + return dbNets; + } + @Override public VirtualNetwork findDefaultVirtualNetwork(TrafficType trafficType) throws IOException { if (trafficType == TrafficType.Guest || @@ -435,14 +549,17 @@ public VirtualNetwork findDefaultVirtualNetwork(TrafficType trafficType) throws * Returns list of networks managed by Juniper VRouter filtered by traffic types */ @Override - public List findJuniperManagedNetworks(List types) { + public List findManagedNetworks(List types) { SearchBuilder searchBuilder = _networksDao.createSearchBuilder(); searchBuilder.and("trafficType", searchBuilder.entity().getTrafficType(), Op.IN); - searchBuilder.and("networkOfferingId", searchBuilder.entity().getNetworkOfferingId(), Op.EQ); + searchBuilder.and("networkOfferingId", searchBuilder.entity().getNetworkOfferingId(), Op.IN); SearchCriteria sc = searchBuilder.create(); - sc.setParameters("networkOfferingId", getOffering().getId()); + List offerings = new ArrayList(); + offerings.add(getRouterOffering().getId()); + offerings.add(getPublicRouterOffering().getId()); + sc.setParameters("networkOfferingId", offerings.toArray()); if (types == null || types.isEmpty()) { types = new ArrayList(); @@ -461,7 +578,7 @@ public List findJuniperManagedNetworks(List types) { } List phys_list = _physicalNetworkDao.listAll(); - final String provider = Network.Provider.JuniperContrail.getName(); + final String provider = Network.Provider.JuniperContrailRouter.getName(); for (Iterator iter = phys_list.iterator(); iter.hasNext(); ) { PhysicalNetworkVO phys = iter.next(); if (_physProviderDao.findByServiceProvider(phys.getId(), provider) != null) { @@ -469,12 +586,16 @@ public List findJuniperManagedNetworks(List types) { findInfrastructureNetworks(phys, infraNets); for (NetworkVO net:infraNets) { if (types == null || types.isEmpty()) { - dbNets.add(net); + if (!dbNets.contains(net)) { + dbNets.add(net); + } continue; } for(TrafficType type:types) { if (net.getTrafficType() == type) { - dbNets.add(net); + if (!dbNets.contains(net)) { + dbNets.add(net); + } break; } } @@ -484,13 +605,19 @@ public List findJuniperManagedNetworks(List types) { return dbNets; } + @Override + public List findManagedACLs() { + /* contrail vpc is not yet implemented */ + return null; + } + /* * Returns list of public ip addresses managed by Juniper VRouter */ @Override - public List findJuniperManagedPublicIps() { + public List findManagedPublicIps() { - List dbNets = findJuniperManagedNetworks(null); + List dbNets = findManagedNetworks(null); if (dbNets == null || dbNets.isEmpty()) { s_logger.debug("Juniper managed networks is empty"); @@ -528,7 +655,7 @@ private void initializeDefaultVirtualNetworkModels() { types.add(TrafficType.Storage); types.add(TrafficType.Control); - List dbNets = findJuniperManagedNetworks(types); + List dbNets = findManagedNetworks(types); for (NetworkVO net:dbNets) { VirtualNetworkModel vnModel = getDatabase().lookupVirtualNetwork(null, getCanonicalName(net), net.getTrafficType()); @@ -638,47 +765,26 @@ public ApiConnector getApiConnector() { public VirtualNetworkModel lookupPublicNetworkModel() { List types = new ArrayList(); types.add(TrafficType.Public); - List dbNets = findJuniperManagedNetworks(types); + List dbNets = findManagedNetworks(types); if (dbNets == null) { return null; } - NetworkVO net = dbNets.get(0); - - VirtualNetworkModel vnModel = getDatabase().lookupVirtualNetwork(net.getUuid(), getCanonicalName(net), TrafficType.Public); - return vnModel; - } - - @Override - public void createPublicNetworks() { - List types = new ArrayList(Arrays.asList(TrafficType.Public)); - List dbNets = findJuniperManagedNetworks(types); - if (dbNets == null) { - return; - } - for (NetworkVO net: dbNets) { - VirtualNetworkModel vnModel = _database.lookupVirtualNetwork(net.getUuid(), getCanonicalName(net), - TrafficType.Public); - if (vnModel != null) { - continue; - } - vnModel = new VirtualNetworkModel(net, net.getUuid(), getCanonicalName(net), net.getTrafficType()); - vnModel.build(_controller, net); - try { - vnModel.update(_controller); - } catch (InternalErrorException ex) { - s_logger.warn("virtual-network update", ex); - continue; - } catch (IOException ex) { - s_logger.warn("virtual-network update", ex); - continue; + NetworkVO network = dbNets.get(0); + VirtualNetworkModel vnModel = getDatabase().lookupVirtualNetwork(network.getUuid(), getCanonicalName(network), TrafficType.Public); + if (vnModel == null) { + vnModel = new VirtualNetworkModel(network, network.getUuid(), + getCanonicalName(network), network.getTrafficType()); + vnModel.setProperties(getModelController(), network); + } + try { + if (!vnModel.verify(getModelController())) { + vnModel.update(getModelController()); } - _database.getVirtualNetworks().add(vnModel); - - // Add the Contrail NetworkElement to the Public network. - Map providerMap = new HashMap(); - providerMap.put(Service.Connectivity.getName(), Provider.JuniperContrail.getName()); - _networksDao.update(net.getId(), net, providerMap); - } + getDatabase().getVirtualNetworks().add(vnModel); + } catch (Exception ex) { + s_logger.warn("virtual-network update: ", ex); + } + return vnModel; } public boolean createFloatingIp(PublicIpAddress ip) { @@ -765,4 +871,13 @@ public List getFloatingIps() { } return null; } + + @Override + public boolean isSystemDefaultNetworkPolicy(NetworkPolicy policy) { + if (policy.getName().equals("default-network-policy")) { + return true; + } + return false; + } + } diff --git a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ModelDatabase.java b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ModelDatabase.java index f705f076df73..3eb66bfcb596 100644 --- a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ModelDatabase.java +++ b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ModelDatabase.java @@ -20,6 +20,7 @@ import java.util.TreeSet; import org.apache.cloudstack.network.contrail.model.ModelObjectBase; +import org.apache.cloudstack.network.contrail.model.NetworkPolicyModel; import org.apache.cloudstack.network.contrail.model.ServiceInstanceModel; import org.apache.cloudstack.network.contrail.model.VirtualMachineModel; import org.apache.cloudstack.network.contrail.model.VirtualNetworkModel; @@ -30,8 +31,9 @@ public class ModelDatabase { TreeSet _serviceInstanceTable; TreeSet _vmTable; TreeSet _vnTable; + TreeSet _policyTable; - ModelDatabase() { + public ModelDatabase() { initDb(); } @@ -39,16 +41,17 @@ public void initDb() { _serviceInstanceTable = new TreeSet(new ModelObjectBase.UuidComparator()); _vmTable = new TreeSet(new ModelObjectBase.UuidComparator()); _vnTable = new TreeSet(new ModelObjectBase.UuidComparator()); + _policyTable = new TreeSet(new ModelObjectBase.UuidComparator()); } public TreeSet getServiceInstances() { return _serviceInstanceTable; } - public ServiceInstanceModel lookupServiceInstance(String uuid) { - ServiceInstanceModel siKey = new ServiceInstanceModel(uuid); + public ServiceInstanceModel lookupServiceInstance(String fqn) { + ServiceInstanceModel siKey = new ServiceInstanceModel(fqn); ServiceInstanceModel current = _serviceInstanceTable.ceiling(siKey); - if (current != null && current.getUuid().equals(uuid)) { + if (current != null && current.getQualifiedName().equals(fqn)) { return current; } return null; @@ -86,4 +89,17 @@ public VirtualNetworkModel lookupVirtualNetwork(String uuid, String name, Traffi } return null; } + + public TreeSet getNetworkPolicys() { + return _policyTable; + } + + public NetworkPolicyModel lookupNetworkPolicy(String uuid) { + NetworkPolicyModel vmKey = new NetworkPolicyModel(uuid, null); + NetworkPolicyModel current = _policyTable.ceiling(vmKey); + if (current != null && current.getUuid().equals(uuid)) { + return current; + } + return null; + } } diff --git a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServerDBSync.java b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServerDBSync.java index fea9a951e68e..68319774c9f2 100644 --- a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServerDBSync.java +++ b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServerDBSync.java @@ -32,7 +32,7 @@ public interface ServerDBSync { * API for syncing all classes of vnc objects with cloudstack * Sync cloudstack and vnc objects. */ - public short syncAll(short syncMode); + public short syncAll(short syncMode) throws Exception; public void syncClass(Class cls); public void createProject(ProjectVO project, StringBuffer syncLogMesg) throws IOException; public void createDomain(DomainVO domain, StringBuffer logMesg)throws IOException; diff --git a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServerDBSyncImpl.java b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServerDBSyncImpl.java index 7a77040e0c9b..22c726abc850 100644 --- a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServerDBSyncImpl.java +++ b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServerDBSyncImpl.java @@ -27,6 +27,7 @@ import net.juniper.contrail.api.types.FloatingIp; import net.juniper.contrail.api.types.FloatingIpPool; +import net.juniper.contrail.api.types.NetworkPolicy; import net.juniper.contrail.api.types.ServiceInstance; import net.juniper.contrail.api.types.VirtualNetwork; import net.juniper.contrail.api.types.VirtualMachine; @@ -39,6 +40,7 @@ import org.apache.cloudstack.network.contrail.model.FloatingIpModel; import org.apache.cloudstack.network.contrail.model.FloatingIpPoolModel; +import org.apache.cloudstack.network.contrail.model.NetworkPolicyModel; import org.apache.cloudstack.network.contrail.model.ServiceInstanceModel; import org.apache.cloudstack.network.contrail.model.VMInterfaceModel; import org.apache.cloudstack.network.contrail.model.VirtualMachineModel; @@ -65,6 +67,10 @@ import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.vpc.NetworkACLItemDao; +import com.cloud.network.vpc.NetworkACLItemVO; +import com.cloud.network.vpc.NetworkACLVO; +import com.cloud.network.vpc.dao.NetworkACLDao; import javax.inject.Inject; @@ -80,6 +86,9 @@ public class ServerDBSyncImpl implements ServerDBSync { @Inject PhysicalNetworkDao _physicalNetworkDao; @Inject PhysicalNetworkServiceProviderDao _physProviderDao; @Inject ContrailManager _manager; + @Inject NetworkACLItemDao _networkACLItemDao; + @Inject NetworkACLDao _networkACLDao; + DBSyncGeneric _dbSync; Class[] _vncClasses; // Read-Write (true) or Read-Only mode. @@ -90,6 +99,7 @@ public class ServerDBSyncImpl implements ServerDBSync { _vncClasses = new Class[] { net.juniper.contrail.api.types.Domain.class, net.juniper.contrail.api.types.Project.class, + NetworkPolicy.class, VirtualNetwork.class, VirtualMachine.class, ServiceInstance.class, @@ -107,7 +117,7 @@ public class ServerDBSyncImpl implements ServerDBSync { * Order has to be maintained */ @Override - public short syncAll(short syncMode) { + public short syncAll(short syncMode) throws Exception { short syncState = SYNC_STATE_IN_SYNC; /* vnc classes need to be synchronized with cloudstack */ @@ -148,6 +158,7 @@ public short syncAll(short syncMode) { if (_lockSyncMode.isLocked()) { _lockSyncMode.unlock(); } + throw ex; } return syncState; @@ -437,7 +448,7 @@ public boolean syncVirtualNetwork() throws Exception { List types = new ArrayList(); types.add(TrafficType.Public); types.add(TrafficType.Guest); - List dbNets = _manager.findJuniperManagedNetworks(types); + List dbNets = _manager.findManagedNetworks(types); List vList = (List) api.list(VirtualNetwork.class, null); List vncList = new ArrayList(); @@ -498,6 +509,16 @@ public void createVirtualNetwork(NetworkVO dbNet, StringBuffer syncLogMesg) thro VirtualNetworkModel vnModel = new VirtualNetworkModel(dbNet, dbNet.getUuid(), _manager.getCanonicalName(dbNet), dbNet.getTrafficType()); + if (dbNet.getTrafficType() == TrafficType.Guest && dbNet.getNetworkACLId() != null) { + NetworkACLVO acl = _networkACLDao.findById(dbNet.getNetworkACLId()); + NetworkPolicyModel policyModel = _manager.getDatabase().lookupNetworkPolicy(acl.getUuid()); + if (policyModel == null) { + s_logger.error("Network(" + dbNet.getName() + ") has ACL but policy model not created: " + + acl.getUuid() + ", name: " + acl.getName()); + } else { + vnModel.addToNetworkPolicy(policyModel); + } + } vnModel.build(_manager.getModelController(), dbNet); if (_rw_mode) { @@ -573,6 +594,17 @@ public Boolean equalVirtualNetwork(NetworkVO dbn, VirtualNetwork vnet, StringBuf VirtualNetworkModel vnModel = new VirtualNetworkModel(dbn, vnet.getUuid(), _manager.getCanonicalName(dbn), dbn.getTrafficType()); + + if (dbn.getTrafficType() == TrafficType.Guest && dbn.getNetworkACLId() != null) { + NetworkACLVO acl = _networkACLDao.findById(dbn.getNetworkACLId()); + NetworkPolicyModel policyModel = _manager.getDatabase().lookupNetworkPolicy(acl.getUuid()); + if (policyModel == null) { + s_logger.error("Network(" + dbn.getName() + ") has ACL but policy model not created: " + + acl.getUuid() + ", name: " + acl.getName()); + } else { + vnModel.addToNetworkPolicy(policyModel); + } + } vnModel.build(_manager.getModelController(), dbn); if (_rw_mode) { @@ -593,6 +625,23 @@ public Boolean equalVirtualNetwork(NetworkVO dbn, VirtualNetwork vnet, StringBuf } catch (Exception ex) { s_logger.warn("update virtual-network", ex); } + if (current != null) { + NetworkPolicyModel oldPolicyModel = current.getNetworkPolicyModel(); + if (oldPolicyModel != vnModel.getNetworkPolicyModel()) { + /* + * if no other VNs are associated with the old policy, + * we could delete it from the Contrail VNC + */ + if (oldPolicyModel != null && !oldPolicyModel.hasDescendents()) { + try { + oldPolicyModel.delete(_manager.getModelController()); + _manager.getDatabase().getNetworkPolicys().remove(oldPolicyModel); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } } else { //compare if (current != null && current.compare(_manager.getModelController(), vnModel) == false) { @@ -786,7 +835,7 @@ public Boolean equalVirtualMachine(VMInstanceVO dbVm, VirtualMachine vncVm, Stri public boolean syncFloatingIp() throws Exception { - List ipList = _manager.findJuniperManagedPublicIps(); + List ipList = _manager.findManagedPublicIps(); List vncList = _manager.getFloatingIps(); if (ipList == null) { ipList = new ArrayList(); @@ -962,5 +1011,164 @@ public boolean syncServiceInstance() { } return inSync; } + + /* + * Network Policy Synchronization methods + */ + @SuppressWarnings({ "unchecked" }) + public boolean syncNetworkPolicy() throws Exception { + final ApiConnector api = _manager.getApiConnector(); + try { + + List dbAcls = _manager.findManagedACLs(); + if (dbAcls == null) { + dbAcls = new ArrayList(); + } + + List pList = (List) api.list(NetworkPolicy.class, null); + List vncList = new ArrayList(); + + for (NetworkPolicy policy:pList) { + if (!_manager.isSystemDefaultNetworkPolicy(policy)) { + vncList.add(policy); + } + } + s_logger.debug("sync Network Policy - DB size: " + dbAcls.size() + " VNC Size: " + vncList.size()); + return _dbSync.syncGeneric(NetworkPolicy.class, dbAcls, vncList); + } catch (Exception ex) { + s_logger.warn("sync network-policys", ex); + throw ex; + } + } + + public Comparator dbComparatorNetworkPolicy() { + Comparator comparator = new Comparator() { + public int compare(NetworkACLVO u1, NetworkACLVO u2) { + return u1.getUuid().compareTo(u2.getUuid()); + } + }; + return comparator; + } + + public Comparator vncComparatorNetworkPolicy() { + Comparator comparator = new Comparator() { + public int compare(NetworkPolicy u1, NetworkPolicy u2) { + return u1.getUuid().compareTo(u2.getUuid()); + } + }; + return comparator; + } + + public void createNetworkPolicy(NetworkACLVO db, StringBuffer syncLogMesg) throws IOException { + syncLogMesg.append("Policy# DB: " + db.getName() + + "(" + db.getUuid() + "); VNC: none; action: create\n"); + + if (_manager.getDatabase().lookupNetworkPolicy(db.getUuid()) != null) { + s_logger.warn("Policy model object is already present in DB: " + + db.getUuid() + ", name: " + db.getName()); + } + NetworkPolicyModel policyModel = new NetworkPolicyModel(db.getUuid(), db.getName()); + net.juniper.contrail.api.types.Project project = null; + try { + project = _manager.getDefaultVncProject(); + } catch (IOException ex) { + s_logger.warn("read project", ex); + throw ex; + } + policyModel.setProject(project); + List rules = _networkACLItemDao.listByACL(db.getId()); + try { + policyModel.build(_manager.getModelController(), rules); + } catch (Exception e) { + e.printStackTrace(); + } + + if (_rw_mode) { + try { + if (!policyModel.verify(_manager.getModelController())) { + policyModel.update(_manager.getModelController()); + } + } catch (Exception ex) { + s_logger.warn("create network-policy", ex); + syncLogMesg.append("Error: Policy# VNC : Unable to create network policy " + + db.getName() + "\n"); + return; + } + s_logger.debug("add model " + policyModel.getName()); + _manager.getDatabase().getNetworkPolicys().add(policyModel); + syncLogMesg.append("Policy# VNC: " + db.getUuid() + ", " + policyModel.getName() + " created\n"); + } else { + syncLogMesg.append("Policy# VNC: " + policyModel.getName() + " created \n"); + } + } + + public void deleteNetworkPolicy(NetworkPolicy policy, StringBuffer syncLogMesg) throws IOException { + final ApiConnector api = _manager.getApiConnector(); + if (_manager.isSystemDefaultNetworkPolicy(policy)) { + syncLogMesg.append("Policy# System default Network Policy# VNC: " + policy.getName() + " can not be deleted\n"); + return; + } + syncLogMesg.append("Policy# DB: none; VNC: " + policy.getName() + "(" + policy.getUuid() + "); action: delete\n"); + api.delete(policy); + syncLogMesg.append("Policy# VNC: " + policy.getName() + " deleted\n"); + } + + public Integer compareNetworkPolicy(NetworkACLVO dbn, NetworkPolicy policy, StringBuffer syncLogMesg) { + if (_manager.isSystemDefaultNetworkPolicy(policy)) { + return 1; + } + return dbn.getUuid().compareTo(policy.getUuid()); + } + + public Boolean filterNetworkPolicy(NetworkPolicy policy, StringBuffer syncLogMesg) { + if (_manager.isSystemDefaultNetworkPolicy(policy)) { + syncLogMesg.append("Policy# VNC: " + policy.getName() + " filtered; action: don't delete\n"); + return true; + } + return false; + } + + public Boolean equalNetworkPolicy(NetworkACLVO db, NetworkPolicy policy, StringBuffer syncLogMesg) { + syncLogMesg.append("Policy# DB: " + db.getName() + + "; VNC: " + policy.getName() + "; action: equal\n"); + NetworkPolicyModel current = _manager.getDatabase().lookupNetworkPolicy(policy.getUuid()); + NetworkPolicyModel policyModel = new NetworkPolicyModel(db.getUuid(), db.getName()); + net.juniper.contrail.api.types.Project project = null; + try { + project = _manager.getDefaultVncProject(); + } catch (IOException ex) { + s_logger.warn("read project", ex); + } + policyModel.setProject(project); + List rules = _networkACLItemDao.listByACL(db.getId()); + try { + policyModel.build(_manager.getModelController(), rules); + } catch (Exception e) { + e.printStackTrace(); + } + if (_rw_mode) { + if (current != null) { + _manager.getDatabase().getNetworkPolicys().remove(current); + } + s_logger.debug("add policy model " + policyModel.getName()); + _manager.getDatabase().getNetworkPolicys().add(policyModel); + try { + if (!policyModel.verify(_manager.getModelController())) { + policyModel.update(_manager.getModelController()); + } + } catch (Exception ex) { + s_logger.warn("update network-policy", ex); + } + } else { + //compare + if (current != null && current.compare(_manager.getModelController(), policyModel) == false) { + syncLogMesg.append("Policy# DB: " + db.getName() + + "; VNC: " + policy.getName() + "; attributes differ\n"); + return false; + } + } + return true; + } + } diff --git a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServerEventHandlerImpl.java b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServerEventHandlerImpl.java index ec374409fc07..4ebce591bca2 100644 --- a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServerEventHandlerImpl.java +++ b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServerEventHandlerImpl.java @@ -81,14 +81,6 @@ private void setClassMap() { public void defaultMessageHandler(String subject, String topic, Object args) { s_logger.info("DB Event Received - topic: " + topic + "; subject: " + subject); - if (subject.equals("VLAN.IP.RANGE.CREATE")) { - _manager.createPublicNetworks(); - return; - } else if (subject.equals("VLAN.IP.RANGE.DELETE")) { - // TODO - return; - } - org.apache.cloudstack.framework.events.Event event = (org.apache.cloudstack.framework.events.Event)args; /* Method name should be on for example: onDomainCreate */ @@ -240,8 +232,6 @@ public void subscribe() { _messageBus.subscribe(EventTypes.EVENT_PROJECT_DELETE, MessageDispatcher.getDispatcher(this)); _messageBus.subscribe(EventTypes.EVENT_DOMAIN_CREATE, MessageDispatcher.getDispatcher(this)); _messageBus.subscribe(EventTypes.EVENT_DOMAIN_DELETE, MessageDispatcher.getDispatcher(this)); - _messageBus.subscribe(EventTypes.EVENT_VLAN_IP_RANGE_CREATE, MessageDispatcher.getDispatcher(this)); - _messageBus.subscribe(EventTypes.EVENT_VLAN_IP_RANGE_DELETE, MessageDispatcher.getDispatcher(this)); } } diff --git a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServiceManagerImpl.java b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServiceManagerImpl.java index 47fc99e371a0..71dad2988698 100644 --- a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServiceManagerImpl.java +++ b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/management/ServiceManagerImpl.java @@ -27,6 +27,14 @@ import javax.ejb.Local; import javax.inject.Inject; +import net.juniper.contrail.api.ApiConnector; +import net.juniper.contrail.api.types.ServiceInstance; + +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.network.contrail.api.response.ServiceInstanceResponse; +import org.apache.cloudstack.network.contrail.model.ServiceInstanceModel; +import org.apache.cloudstack.network.contrail.model.VirtualMachineModel; +import org.apache.cloudstack.network.contrail.model.VirtualNetworkModel; import org.apache.log4j.Logger; import com.cloud.api.ApiDBUtils; @@ -36,22 +44,16 @@ import com.cloud.event.EventTypes; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; import com.cloud.network.NetworkModel; import com.cloud.network.Networks.TrafficType; import com.cloud.network.dao.NetworkVO; import com.cloud.offering.ServiceOffering; import com.cloud.projects.Project; -import com.cloud.service.ServiceOfferingVO; -import com.cloud.storage.VMTemplateVO; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.user.AccountService; -import com.cloud.user.User; -import com.cloud.user.UserVO; import com.cloud.user.dao.UserDao; -import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.NicProfile; import com.cloud.vm.UserVmVO; @@ -60,15 +62,6 @@ import com.cloud.vm.dao.UserVmDao; import com.google.gson.Gson; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.network.contrail.api.response.ServiceInstanceResponse; -import org.apache.cloudstack.network.contrail.model.ServiceInstanceModel; -import org.apache.cloudstack.network.contrail.model.VirtualMachineModel; - -import net.juniper.contrail.api.ApiConnector; -import net.juniper.contrail.api.types.ServiceInstance; -import net.juniper.contrail.api.types.VirtualNetwork; - @Local(value = {ServiceManager.class}) public class ServiceManagerImpl implements ServiceManager { private static final Logger s_logger = Logger.getLogger(ServiceManager.class); @@ -105,12 +98,12 @@ private ServiceVirtualMachine createServiceVM(DataCenter zone, Account owner, Vi DataCenterDeployment plan = new DataCenterDeployment(zone.getId()); - LinkedHashMap networks = new LinkedHashMap(); + LinkedHashMap> networks = new LinkedHashMap>(); NetworkVO linklocal = (NetworkVO) _networkModel.getSystemNetworkByZoneAndTrafficType(zone.getId(), TrafficType.Management); - networks.put(linklocal, null); - networks.put((NetworkVO) left, null); - networks.put((NetworkVO) right, null); + networks.put(linklocal, new ArrayList()); + networks.put((NetworkVO)left, new ArrayList()); + networks.put((NetworkVO)right, new ArrayList()); String instanceName = VirtualMachineName.getVmName(id, owner.getId(), "SRV"); ServiceVirtualMachine svm = new ServiceVirtualMachine(id, instanceName, name, template.getId(), @@ -148,17 +141,15 @@ public ServiceVirtualMachine createServiceInstance(DataCenter zone, Account owne } final ApiConnector api = _manager.getApiConnector(); - final VirtualNetwork netLeft; - try { - netLeft = (VirtualNetwork) api.findById(VirtualNetwork.class, left.getUuid()); - } catch (IOException ex) { - throw new CloudRuntimeException("Unable to read virtual-network object", ex); + VirtualNetworkModel leftModel = _manager.getDatabase().lookupVirtualNetwork(left.getUuid(), + _manager.getCanonicalName(left), left.getTrafficType()); + if (leftModel == null) { + throw new CloudRuntimeException("Unable to read virtual-network object"); } - final VirtualNetwork netRight; - try { - netRight = (VirtualNetwork) api.findById(VirtualNetwork.class, right.getUuid()); - } catch (IOException ex) { - throw new CloudRuntimeException("Unable to read virtual-network object", ex); + VirtualNetworkModel rightModel = _manager.getDatabase().lookupVirtualNetwork(right.getUuid(), + _manager.getCanonicalName(right), right.getTrafficType()); + if (rightModel == null) { + throw new CloudRuntimeException("Unable to read virtual-network object"); } net.juniper.contrail.api.types.Project project; @@ -181,7 +172,7 @@ public ServiceVirtualMachine createServiceInstance(DataCenter zone, Account owne // 1. Create service-instance. ServiceInstanceModel serviceModel = new ServiceInstanceModel(project, name, template, serviceOffering, - netLeft, netRight); + leftModel, rightModel); try { serviceModel.update(_manager.getModelController()); diff --git a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/NetworkPolicyModel.java b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/NetworkPolicyModel.java new file mode 100644 index 000000000000..aefc36bbeafb --- /dev/null +++ b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/NetworkPolicyModel.java @@ -0,0 +1,308 @@ +// 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.network.contrail.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import com.cloud.network.Networks; + +import net.juniper.contrail.api.types.NetworkPolicy; +import net.juniper.contrail.api.types.PolicyEntriesType; +import net.juniper.contrail.api.types.PolicyEntriesType.PolicyRuleType; +import net.juniper.contrail.api.types.Project; +import net.juniper.contrail.api.ApiConnector; +import org.apache.cloudstack.network.contrail.management.ContrailManager; + +import com.cloud.exception.InternalErrorException; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.network.vpc.NetworkACLItem.Action; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.exception.CloudRuntimeException; + +public class NetworkPolicyModel extends ModelObjectBase { + private static final Logger s_logger = Logger.getLogger(NetworkPolicyModel.class); + + private String _uuid; + private String _fq_name; + private String _name; + private Project _project; + private NetworkPolicy _policy; + PolicyEntriesType _policyMap; + + public NetworkPolicyModel(String uuid, String name) { + _uuid = uuid; + _name = name; + } + + public String getQualifiedName() { + return _fq_name; + } + + public String getName() { + return _name; + } + + public NetworkVO cidrToNetwork(ModelController controller, String cidr) { + SearchBuilder searchBuilder = controller.getNetworkDao().createSearchBuilder(); + searchBuilder.and("trafficType", searchBuilder.entity().getTrafficType(), Op.EQ); + searchBuilder.and("cidr", searchBuilder.entity().getCidr(), Op.EQ); + searchBuilder.and("networkOfferingId", searchBuilder.entity().getNetworkOfferingId(), Op.EQ); + + SearchCriteria sc = searchBuilder.create(); + + sc.setParameters("networkOfferingId", controller.getManager().getRouterOffering().getId()); + sc.setParameters("cidr", cidr); + sc.setParameters("trafficType", Networks.TrafficType.Guest); + + List dbNets = controller.getNetworkDao().search(sc, null); + if (dbNets == null || dbNets.size() == 0) { + return null; + } + if (dbNets.size() > 1) { + s_logger.warn("more than one network found with cidr: " + cidr); + } + return dbNets.get(0); + } + + public void build(ModelController controller, List rules) throws Exception { + String projectName = null; + if (_project != null) { + _fq_name = StringUtils.join(_project.getQualifiedName(), ':') + ":" + _name; + projectName = StringUtils.join(_project.getQualifiedName(), ':'); + } else { + _fq_name = ContrailManager.VNC_ROOT_DOMAIN + ":" + ContrailManager.VNC_DEFAULT_PROJECT + ":" + _name; + projectName = ContrailManager.VNC_ROOT_DOMAIN + ":" + ContrailManager.VNC_DEFAULT_PROJECT; + } + + PolicyEntriesType policyMap = new PolicyEntriesType(); + + for (NetworkACLItem rule:rules) { + if (rule.getState() != NetworkACLItem.State.Active && + rule.getState() != NetworkACLItem.State.Add) { + continue; + } + + String action = null; + if (rule.getAction() == Action.Allow) { + action = "pass"; + } else if (rule.getAction() == Action.Deny) { + action = "deny"; + } + List cidrList = rule.getSourceCidrList(); + String protocol = rule.getProtocol(); + if (protocol == null || protocol.equalsIgnoreCase("ALL") || protocol.isEmpty()) { + protocol = "any"; + } else { + protocol = protocol.toLowerCase(); + } + + Integer portStart = rule.getSourcePortStart(); + Integer portEnd = rule.getSourcePortEnd(); + if (portStart == null) { + portStart = 0; + } + if (portEnd == null) { + portEnd = 65535; + } + + List srcList = new ArrayList(); + List dstList = new ArrayList(); + + List srcPorts = new ArrayList(); + List dstPorts = new ArrayList(); + + if (rule.getTrafficType() == NetworkACLItem.TrafficType.Egress){ + for (String cidr: cidrList) { + NetworkVO net = cidrToNetwork(controller, cidr); + /*String[] maskInfo = StringUtils.splitByWholeSeparator(cidr, "/"); + SubnetType subnet = new SubnetType(); + subnet.setIpPrefix(maskInfo[0]); + subnet.setIpPrefixLen(Integer.parseInt(maskInfo[1])); + */ + String netName = projectName + ":" + controller.getManager().getCanonicalName(net); + dstList.add(new PolicyRuleType.AddressType(null, netName, null)); + } + dstPorts.add(new PolicyRuleType.PortType(portStart, portEnd)); + srcList.add(new PolicyRuleType.AddressType(null, "local", null)); + srcPorts.add(new PolicyRuleType.PortType(0, 65535)); + } else { + for (String cidr: cidrList) { + NetworkVO net = cidrToNetwork(controller, cidr); + String netName = projectName + ":" + controller.getManager().getCanonicalName(net); + dstList.add(new PolicyRuleType.AddressType(null, netName, null)); + } + dstPorts.add(new PolicyRuleType.PortType(portStart, portEnd)); + + srcList.add(new PolicyRuleType.AddressType(null, "any", null)); + srcPorts.add(new PolicyRuleType.PortType(0, 65535)); + } + + PolicyRuleType vnRule = new PolicyRuleType( + new PolicyRuleType.SequenceType(1, 0), rule.getUuid(), "<>", protocol, + srcList, srcPorts, null, dstList, dstPorts, + new PolicyRuleType.ActionListType(action, null, null, null)); + policyMap.addPolicyRule(vnRule); + } + _policyMap = policyMap; + } + + /* for service instance policy */ + public void build(ModelController modelController, String leftVn, String rightVn, String gatewayName, + List siList, String action) { + if (_project != null) { + _fq_name = StringUtils.join(_project.getQualifiedName(), ':') + ":" + _name; + } else { + _fq_name = ContrailManager.VNC_ROOT_DOMAIN + ":" + ContrailManager.VNC_DEFAULT_PROJECT + ":" + _name; + } + + PolicyEntriesType policyMap = new PolicyEntriesType(); + List srcList = new ArrayList(); + srcList.add(new PolicyRuleType.AddressType(null, leftVn, null)); + List dstList = new ArrayList(); + dstList.add(new PolicyRuleType.AddressType(null, rightVn, null)); + + List portAny = new ArrayList(); + portAny.add(new PolicyRuleType.PortType(0, 65535)); + + PolicyRuleType rule = new PolicyRuleType( + new PolicyRuleType.SequenceType(1, 0), null, "<>", "any", + srcList, portAny, null, dstList, portAny, + new PolicyRuleType.ActionListType(action, gatewayName, siList, null)); + policyMap.addPolicyRule(rule); + _policyMap = policyMap; + } + + + public boolean hasPolicyRules() { + if (_policyMap != null && _policyMap.getPolicyRule() != null && _policyMap.getPolicyRule().size() > 0) { + return true; + } + return false; + } + + @Override + public int compareTo(ModelObject o) { + NetworkPolicyModel other; + try { + other = (NetworkPolicyModel) o; + } catch (ClassCastException ex) { + String clsname = o.getClass().getName(); + return NetworkPolicyModel.class.getName().compareTo(clsname); + } + return _uuid.compareTo(other._uuid); + } + + @Override + public void delete(ModelController controller) throws IOException { + ApiConnector api = controller.getApiAccessor(); + if (_policy != null) { + api.delete(_policy); + _policy = null; + } + } + + @Override + public void destroy(ModelController controller) throws IOException { + } + + + public String getUuid() { + return _uuid; + } + + @Override + public void update(ModelController controller) throws InternalErrorException, IOException { + ApiConnector api = controller.getApiAccessor(); + if (_project == null) { + s_logger.debug("Project is null for the policy: " + _name); + throw new IOException("Project is null for the policy: " + _name); + } + + NetworkPolicy policy = _policy; + + if (policy == null) { + try { + String policyId = api.findByName(NetworkPolicy.class, _project, _name); + if (policyId != null) { + policy = _policy = (NetworkPolicy) api.findById(NetworkPolicy.class, policyId); + } + if (policy == null) { + policy = new NetworkPolicy(); + policy.setUuid(_uuid); + policy.setName(_name); + policy.setParent(_project); + } + } catch (IOException ex) { + s_logger.warn("network-policy read", ex); + return; + } + } + + policy.setEntries(_policyMap); + if (_policy == null) { + try { + api.create(policy); + } catch (Exception ex) { + s_logger.debug("network policy create", ex); + throw new CloudRuntimeException("Failed to create network policy", ex); + } + _policy = policy; + } else { + try { + api.update(policy); + } catch (IOException ex) { + s_logger.warn("network policy update", ex); + throw new CloudRuntimeException("Unable to update network policy", ex); + } + } + for (ModelObject successor: successors()) { + successor.update(controller); + } + } + + @Override + public boolean verify(ModelController controller) { + return false; + } + + @Override + public boolean compare(ModelController controller, ModelObject current) { + return true; + } + + public void setProperties(ModelController controller, List rules) { + + } + + public void setProject(Project project) { + _project = project; + } + + public NetworkPolicy getPolicy() { + return _policy; + } + +} diff --git a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/ServiceInstanceModel.java b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/ServiceInstanceModel.java index 20b80bead4c0..31c052c4a239 100644 --- a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/ServiceInstanceModel.java +++ b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/ServiceInstanceModel.java @@ -20,10 +20,10 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import javax.inject.Inject; -import org.apache.cloudstack.network.contrail.management.ContrailManager; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -39,6 +39,7 @@ import net.juniper.contrail.api.types.VirtualNetwork; import net.juniper.contrail.api.types.VirtualNetworkPolicyType; import net.juniper.contrail.api.ApiConnector; +import org.apache.cloudstack.network.contrail.management.ContrailManager; import com.cloud.offering.ServiceOffering; import com.cloud.template.VirtualMachineTemplate; @@ -57,11 +58,11 @@ public class ServiceInstanceModel extends ModelObjectBase { private String _templateName; private String _templateId; private String _templateUrl; - private VirtualNetwork _left; - private VirtualNetwork _right; + private VirtualNetworkModel _left; + private VirtualNetworkModel _right; private ServiceTemplate _tmpl; private ServiceInstance _serviceInstance; - private NetworkPolicy _policy; + private NetworkPolicyModel _policy; /** * Create a ServiceInstance as result of an API call. @@ -74,7 +75,7 @@ public class ServiceInstanceModel extends ModelObjectBase { * @param right */ public ServiceInstanceModel(Project project, String name, VirtualMachineTemplate template, - ServiceOffering serviceOffering, VirtualNetwork left, VirtualNetwork right) { + ServiceOffering serviceOffering, VirtualNetworkModel left, VirtualNetworkModel right) { String parent_name; if (project != null) { parent_name = StringUtils.join(project.getQualifiedName(), ':'); @@ -87,8 +88,8 @@ public ServiceInstanceModel(Project project, String name, VirtualMachineTemplate + ContrailManager.managementNetworkName; _left = left; _right = right; - _leftName = StringUtils.join(left.getQualifiedName(), ":"); - _rightName = StringUtils.join(right.getQualifiedName(), ":"); + _leftName = StringUtils.join(left.getVirtualNetwork().getQualifiedName(), ":"); + _rightName = StringUtils.join(right.getVirtualNetwork().getQualifiedName(), ":"); _templateName = template.getName(); _templateId = template.getUuid(); @@ -113,31 +114,6 @@ public String getName() { return _fq_name.substring(_fq_name.lastIndexOf(':') + 1); } - private void applyNetworkPolicy(ModelController controller, NetworkPolicy policy, - VirtualNetwork left, VirtualNetwork right) { - left.setNetworkPolicy(policy, new VirtualNetworkPolicyType( - new VirtualNetworkPolicyType.SequenceType(1, 0), null)); - // TODO: network_ipam_refs attr is missing - left.clearNetworkIpam(); - try { - ApiConnector api = controller.getApiAccessor(); - api.update(left); - } catch (IOException ex) { - throw new CloudRuntimeException("Unable to update virtual-network", ex); - } - - right.setNetworkPolicy(policy, new VirtualNetworkPolicyType( - new VirtualNetworkPolicyType.SequenceType(1, 0), null)); - // TODO: network_ipam_refs attr is missing - right.clearNetworkIpam(); - try { - ApiConnector api = controller.getApiAccessor(); - api.update(right); - } catch (IOException ex) { - throw new CloudRuntimeException("Unable to update virtual-network", ex); - } - } - /** * Recreate the model object from the Contrail API which is the master for this type of object. * @param siObj @@ -157,18 +133,6 @@ public void build(ModelController controller, ServiceInstance siObj) { s_logger.warn("service-template read", ex); } } - try { - Project project = (Project) api.findById(Project.class, siObj.getParentUuid()); - if (project != null) { - _projectId = project.getUuid(); - } - String policyId = api.findByName(NetworkPolicy.class, project, siObj.getName()); - if (policyId != null) { - _policy = (NetworkPolicy) api.findById(NetworkPolicy.class, policyId); - } - } catch (IOException ex) { - s_logger.warn("network-policy read", ex); - } } @Override @@ -213,42 +177,53 @@ private ServiceInstance createServiceInstance(ModelController controller) { return si_obj; } - - private NetworkPolicy createServicePolicy(ModelController controller) { - NetworkPolicy policy = new NetworkPolicy(); - policy.setParent(_serviceInstance.getParent()); - policy.setName(_serviceInstance.getName()); - PolicyEntriesType policy_map = new PolicyEntriesType(); - List srcList = new ArrayList(); - srcList.add(new PolicyRuleType.AddressType(null, _leftName, null)); - List dstList = new ArrayList(); - dstList.add(new PolicyRuleType.AddressType(null, _rightName, null)); + + private void clearServicePolicy(ModelController controller) { + _left.addToNetworkPolicy(null); + _right.addToNetworkPolicy(null); + try { + controller.getManager().getDatabase().getNetworkPolicys().remove(_policy); + _policy.delete(controller.getManager().getModelController()); + _policy = null; + } catch (Exception e) { + s_logger.error(e); + } + try { + _left.update(controller.getManager().getModelController()); + _right.update(controller.getManager().getModelController()); + } catch (Exception ex) { + s_logger.error("virtual-network update for policy delete: ", ex); + } + } + + private NetworkPolicyModel setServicePolicy(ModelController controller) { + NetworkPolicyModel policyModel = new NetworkPolicyModel(UUID.randomUUID().toString(), _serviceInstance.getName()); + policyModel.setProject((Project)_serviceInstance.getParent()); + _left.addToNetworkPolicy(policyModel); + _right.addToNetworkPolicy(policyModel); List siList = new ArrayList(); siList.add(StringUtils.join(_serviceInstance.getQualifiedName(), ':')); - List portAny = new ArrayList(); - portAny.add(new PolicyRuleType.PortType(0, 65535)); - - PolicyRuleType rule = new PolicyRuleType( - new PolicyRuleType.SequenceType(1, 0), /* uuid */ null, "<>", "any", - srcList, portAny, /* application */ null, dstList, portAny, - new PolicyRuleType.ActionListType("pass", "in-network", siList, null)); - policy_map.addPolicyRule(rule); - policy.setEntries(policy_map); - - try { - ApiConnector api = controller.getApiAccessor(); - if (!api.create(policy)) { - throw new CloudRuntimeException("Unable to create network-policy"); + try { + policyModel.build(controller.getManager().getModelController(), _leftName, _rightName, "in-network", siList, "pass"); + } catch (Exception e) { + s_logger.error(e); + return null; + } + try { + if (!policyModel.verify(controller.getManager().getModelController())) { + policyModel.update(controller.getManager().getModelController()); } - } catch (IOException ex) { - throw new CloudRuntimeException("Unable to create network-policy", ex); + controller.getManager().getDatabase().getNetworkPolicys().add(policyModel); + } catch (Exception ex) { + s_logger.error("network-policy update: ", ex); } - return policy; + return policyModel; } @Override public void delete(ModelController controller) throws IOException { ApiConnector api = controller.getApiAccessor(); + clearServicePolicy(controller); if (_serviceInstance != null) { api.delete(_serviceInstance); } @@ -299,9 +274,7 @@ public void update(ModelController controller) { } _uuid = _serviceInstance.getUuid(); if (_policy == null) { - _policy = createServicePolicy(controller); - // TODO: update the network model objects and call update - applyNetworkPolicy(controller, _policy, _left, _right); + _policy = setServicePolicy(controller); } } diff --git a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/VirtualMachineModel.java b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/VirtualMachineModel.java index ec20a9417ecd..ec28798455c0 100644 --- a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/VirtualMachineModel.java +++ b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/VirtualMachineModel.java @@ -22,8 +22,8 @@ import java.util.Map; import java.util.TreeSet; -import org.apache.cloudstack.network.contrail.management.ContrailManager; import org.apache.log4j.Logger; +import org.apache.commons.lang.StringUtils; import com.cloud.exception.InternalErrorException; import com.cloud.network.dao.NetworkDao; @@ -40,6 +40,7 @@ import net.juniper.contrail.api.types.ServiceInstance; import net.juniper.contrail.api.types.VirtualMachine; import net.juniper.contrail.api.ApiConnector; +import org.apache.cloudstack.network.contrail.management.ContrailManager; public class VirtualMachineModel extends ModelObjectBase { private static final Logger s_logger = Logger.getLogger(VirtualMachineModel.class); @@ -101,18 +102,27 @@ private void buildServiceInstance(ModelController controller, String serviceUuid ApiConnector api = controller.getApiAccessor(); _serviceUuid = serviceUuid; - ServiceInstanceModel siModel = manager.getDatabase().lookupServiceInstance(serviceUuid); - if (siModel == null) { - ServiceInstance siObj; - try { - siObj = (ServiceInstance) api.findById(ServiceInstance.class, serviceUuid); - } catch (IOException ex) { - s_logger.warn("service-instance read", ex); - throw new CloudRuntimeException("Unable to read service-instance object", ex); - } - if (siObj == null) { - siModel = new ServiceInstanceModel(serviceUuid); - siModel.build(controller, siObj); + ServiceInstance siObj; + try { + siObj = (ServiceInstance) api.findById(ServiceInstance.class, serviceUuid); + } catch (IOException ex) { + s_logger.warn("service-instance read", ex); + throw new CloudRuntimeException("Unable to read service-instance object", ex); + } + ServiceInstanceModel siModel; + if (siObj == null) { + siModel = new ServiceInstanceModel(serviceUuid); + siModel.build(controller, siObj); + manager.getDatabase().getServiceInstances().add(siModel); + } else { + String fqn = StringUtils.join(siObj.getQualifiedName(), ':'); + siModel = manager.getDatabase().lookupServiceInstance(fqn); + if (siModel == null) { + if (siObj == null) { + siModel = new ServiceInstanceModel(serviceUuid); + siModel.build(controller, siObj); + manager.getDatabase().getServiceInstances().add(siModel); + } } } _serviceModel = siModel; @@ -337,8 +347,23 @@ public void update(ModelController controller) throws InternalErrorException, IO @Override public boolean verify(ModelController controller) { - // TODO Auto-generated method stub - return false; + assert _initialized : "initialized is false"; + assert _uuid != null : "uuid is not set"; + ApiConnector api = controller.getApiAccessor(); + try { + _vm = (VirtualMachine) api.findById(VirtualMachine.class, _uuid); + } catch (IOException e) { + e.printStackTrace(); + } + if (_vm == null) { + return false; + } + for (ModelObject successor: successors()) { + if (!successor.verify(controller)) { + return false; + } + } + return true; } @Override diff --git a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/VirtualNetworkModel.java b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/VirtualNetworkModel.java index b4968ac78058..f05517f70193 100644 --- a/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/VirtualNetworkModel.java +++ b/plugins/network-elements/juniper-contrail/src/org/apache/cloudstack/network/contrail/model/VirtualNetworkModel.java @@ -23,7 +23,6 @@ import java.util.List; import java.util.Set; -import org.apache.cloudstack.network.contrail.management.ContrailManager; import org.apache.log4j.Logger; import com.cloud.dc.VlanVO; @@ -39,8 +38,10 @@ import net.juniper.contrail.api.types.Project; import net.juniper.contrail.api.types.SubnetType; import net.juniper.contrail.api.types.VirtualNetwork; +import net.juniper.contrail.api.types.VirtualNetworkPolicyType; import net.juniper.contrail.api.types.VnSubnetsType; import net.juniper.contrail.api.ApiConnector; +import org.apache.cloudstack.network.contrail.management.ContrailManager; public class VirtualNetworkModel extends ModelObjectBase { private static final Logger s_logger = Logger.getLogger(VirtualNetworkModel.class); @@ -65,6 +66,7 @@ public class VirtualNetworkModel extends ModelObjectBase { private NetworkIpam _ipam; private FloatingIpPoolModel _fipPoolModel; + private NetworkPolicyModel _policyModel; public VirtualNetworkModel(Network network, String uuid, String name, TrafficType trafficType) { _uuid = uuid; @@ -132,6 +134,10 @@ public void delete(ModelController controller) throws IOException { successor.delete(controller); } + if (_policyModel != null) { + _policyModel.removeSuccessor(this); + } + try { api.delete(VirtualNetwork.class, _uuid); } catch (IOException ex) { @@ -180,6 +186,8 @@ public void setProperties(ModelController controller, Network network) { s_logger.warn("Unable to read virtual-network", ex); } } + + _id = network.getId(); try { _projectId = manager.getProjectId(network.getDomainId(), network.getAccountId()); @@ -225,6 +233,16 @@ public void update(ModelController controller) throws InternalErrorException, IO vn.setUuid(_uuid); } } + + if (_policyModel == null) { + vn.clearNetworkPolicy(); + } else if (!_policyModel.hasPolicyRules()) { + vn.clearNetworkPolicy(); + _policyModel.removeSuccessor(this); + } else { + vn.setNetworkPolicy(_policyModel.getPolicy(), new VirtualNetworkPolicyType( + new VirtualNetworkPolicyType.SequenceType(1, 0), null)); + } if (_ipam == null) { NetworkIpam ipam = null; @@ -403,7 +421,23 @@ public boolean verify(ModelController controller) { "; db: " + dbSubnets + ", vnc: " + vncSubnets + ", diff: " + diff); return false; } - + + List> policyRefs = _vn.getNetworkPolicy(); + if ((policyRefs == null || policyRefs.isEmpty()) && _policyModel != null) { + return false; + } + + if ((policyRefs != null && !policyRefs.isEmpty()) && _policyModel == null) { + return false; + } + + if (policyRefs != null && !policyRefs.isEmpty() && _policyModel != null) { + ObjectReference ref = policyRefs.get(0); + if (!ref.getUuid().equals(_policyModel.getUuid())) { + return false; + } + } + for (ModelObject successor: successors()) { if (!successor.verify(controller)) { return false; @@ -415,8 +449,6 @@ public boolean verify(ModelController controller) { @Override public boolean compare(ModelController controller, ModelObject o) { VirtualNetworkModel latest; - ApiConnector api = controller.getApiAccessor(); - assert this._vn != null : "vnc virtual network current is not initialized"; try { @@ -481,14 +513,64 @@ public boolean compare(ModelController controller, ModelObject o) { "; db: " + currentSubnets + ", vnc: " + newSubnets + ", diff: " + diff); return false; } - + + List> currentPolicyRefs = this._vn.getNetworkPolicy(); + List> latestPolicyRefs = latest._vn.getNetworkPolicy(); + + if (currentPolicyRefs == null && latestPolicyRefs == null) { + return true; + } + + if ((currentPolicyRefs == null && latestPolicyRefs != null) || + (currentPolicyRefs != null && latestPolicyRefs == null) || + (currentPolicyRefs.size() != latestPolicyRefs.size())) { + return false; + } + + if (currentPolicyRefs.isEmpty() && latestPolicyRefs.isEmpty()) { + return true; + } + + //both must be non empty lists + ObjectReference ref1 = currentPolicyRefs.get(0); + ObjectReference ref2 = latestPolicyRefs.get(0); + + if ((ref1 != null && ref2 == null) || (ref1 == null && ref2 != null)) { + return false; + } + + if ((ref1.getUuid() != null && ref2.getUuid() == null) || (ref1.getUuid() == null && ref2.getUuid() != null)) { + return false; + } + if (ref1.getUuid() == null && ref2.getUuid() == null) { + return true; + } + if (!ref1.getUuid().equals(ref2.getUuid())) { + return false; + } return true; } public FloatingIpPoolModel getFipPoolModel() { return _fipPoolModel; } + public void setFipPoolModel(FloatingIpPoolModel fipPoolModel) { _fipPoolModel = fipPoolModel; } + + public NetworkPolicyModel getNetworkPolicyModel() { + return _policyModel; + } + + public void addToNetworkPolicy(NetworkPolicyModel policyModel) { + if (_policyModel != null) { + _policyModel.removeSuccessor(this); + } + _policyModel = policyModel; + if (_policyModel != null) { + _policyModel.addSuccessor(this); + } + } + } diff --git a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/ManagementServerMock.java b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/ManagementServerMock.java index 86750ca8d1bb..36b5374187f6 100644 --- a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/ManagementServerMock.java +++ b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/ManagementServerMock.java @@ -315,17 +315,17 @@ private void locatePhysicalNetwork() { _znet = _networkService.getPhysicalNetwork(id); List nets = _physicalNetworkDao.listByZoneAndTrafficType(_zone.getId(), TrafficType.Public); if (nets == null || nets.isEmpty()) { - _networkService.addTrafficTypeToPhysicalNetwork(_znet.getId(), TrafficType.Public.toString(), null, null, null, null, null, null); + _networkService.addTrafficTypeToPhysicalNetwork(_znet.getId(), TrafficType.Public.toString(), "vlan", null, null, null, null, null, null); } } catch (InvalidParameterValueException e) { List isolationMethods = new ArrayList(); - isolationMethods.add("GRE"); + isolationMethods.add("L3VPN"); _znet = _networkService.createPhysicalNetwork(_zone.getId(), null, null, isolationMethods, BroadcastDomainRange.ZONE.toString(), _zone.getDomainId(), null, "znet"); List nets = _physicalNetworkDao.listByZoneAndTrafficType(_zone.getId(), TrafficType.Public); if (nets == null || nets.isEmpty()) { - _networkService.addTrafficTypeToPhysicalNetwork(_znet.getId(), TrafficType.Public.toString(), null, null, null, null, null, null); + _networkService.addTrafficTypeToPhysicalNetwork(_znet.getId(), TrafficType.Public.toString(), "vlan", null, null, null, null, null, null); } } if (_znet.getState() != PhysicalNetwork.State.Enabled) { @@ -343,17 +343,17 @@ private void locatePhysicalNetwork() { } } if (!found) { - _networkService.addTrafficTypeToPhysicalNetwork(_znet.getId(), TrafficType.Guest.toString(), + _networkService.addTrafficTypeToPhysicalNetwork(_znet.getId(), TrafficType.Guest.toString(), "vlan", null, null, null, null, null, null); } Pair, Integer> providers = - _networkService.listNetworkServiceProviders(_znet.getId(), Provider.JuniperContrail.getName(), + _networkService.listNetworkServiceProviders(_znet.getId(), Provider.JuniperContrailRouter.getName(), null, null, null); if (providers.second() == 0) { - s_logger.debug("Add " + Provider.JuniperContrail.getName() + " to network " + _znet.getName()); + s_logger.debug("Add " + Provider.JuniperContrailRouter.getName() + " to network " + _znet.getName()); PhysicalNetworkServiceProvider provider = - _networkService.addProviderToPhysicalNetwork(_znet.getId(), Provider.JuniperContrail.getName(), + _networkService.addProviderToPhysicalNetwork(_znet.getId(), Provider.JuniperContrailRouter.getName(), null, null); _networkService.updateNetworkServiceProvider(provider.getId(), PhysicalNetworkServiceProvider.State.Enabled.toString(), null); @@ -369,7 +369,7 @@ private void locatePhysicalNetwork() { PhysicalNetworkServiceProvider.State.Enabled.toString(), null, null); s_logger.debug(_znet.getName() + " has " + providers.second().toString() + " Enabled providers"); for (PhysicalNetworkServiceProvider provider: providers.first()) { - if (provider.getProviderName().equals(Provider.JuniperContrail.getName())) { + if (provider.getProviderName().equals(Provider.JuniperContrailRouter.getName())) { continue; } s_logger.debug("Disabling " + provider.getProviderName()); diff --git a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/NetworkProviderTest.java b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/NetworkProviderTest.java index 40cd1ea30a88..89294cca0780 100644 --- a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/NetworkProviderTest.java +++ b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/NetworkProviderTest.java @@ -177,7 +177,7 @@ private void purgeTestNetwork() { _networkService.getIsolatedNetworksOwnedByAccountInZone(zone.getId(), system); for (Network net : list) { s_logger.debug("Delete network " + net.getName()); - _networkService.deleteNetwork(net.getId()); + _networkService.deleteNetwork(net.getId(), false); } } @@ -203,7 +203,7 @@ private Network createTestNetwork(String name) { ManagementServerMock.setParameter(cmd, "accountName", BaseCmd.CommandType.STRING, system.getAccountName()); ManagementServerMock.setParameter(cmd, ApiConstants.NAME, BaseCmd.CommandType.STRING, name); ManagementServerMock.setParameter(cmd, "displayText", BaseCmd.CommandType.STRING, "test network"); - ManagementServerMock.setParameter(cmd, "networkOfferingId", BaseCmd.CommandType.LONG, _contrailMgr.getOffering().getId()); + ManagementServerMock.setParameter(cmd, "networkOfferingId", BaseCmd.CommandType.LONG, _contrailMgr.getRouterOffering().getId()); ManagementServerMock.setParameter(cmd, "zoneId", BaseCmd.CommandType.LONG, zone.getId()); ManagementServerMock.setParameter(cmd, ApiConstants.GATEWAY, BaseCmd.CommandType.STRING, "10.0.1.254"); ManagementServerMock.setParameter(cmd, ApiConstants.NETMASK, BaseCmd.CommandType.STRING, "255.255.255.0"); @@ -462,15 +462,19 @@ public void dbSyncTest() { } catch (IOException ex) { fail(ex.getMessage()); } - + //now db sync - if (_dbSync.syncAll(DBSyncGeneric.SYNC_MODE_UPDATE) == ServerDBSync.SYNC_STATE_OUT_OF_SYNC) { - s_logger.info("# Cloudstack DB & VNC are out of sync - resync done"); - } - - if (_dbSync.syncAll(DBSyncGeneric.SYNC_MODE_CHECK) == ServerDBSync.SYNC_STATE_OUT_OF_SYNC) { - s_logger.info("# Cloudstack DB & VNC are still out of sync"); - fail("DB Sync failed"); + try { + if (_dbSync.syncAll(DBSyncGeneric.SYNC_MODE_UPDATE) == ServerDBSync.SYNC_STATE_OUT_OF_SYNC) { + s_logger.info("# Cloudstack DB & VNC are out of sync - resync done"); + } + + if (_dbSync.syncAll(DBSyncGeneric.SYNC_MODE_CHECK) == ServerDBSync.SYNC_STATE_OUT_OF_SYNC) { + s_logger.info("# Cloudstack DB & VNC are still out of sync"); + fail("DB Sync failed"); + } + } catch (Exception ex) { + fail(ex.getMessage()); } } diff --git a/plugins/network-elements/juniper-srx/pom.xml b/plugins/network-elements/juniper-srx/pom.xml index 542a6035cab6..7f66dc070ae0 100644 --- a/plugins/network-elements/juniper-srx/pom.xml +++ b/plugins/network-elements/juniper-srx/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/network-elements/juniper-srx/resources/META-INF/cloudstack/srx/module.properties b/plugins/network-elements/juniper-srx/resources/META-INF/cloudstack/srx/module.properties new file mode 100644 index 000000000000..dde649bf7535 --- /dev/null +++ b/plugins/network-elements/juniper-srx/resources/META-INF/cloudstack/srx/module.properties @@ -0,0 +1,18 @@ +# 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. +name=srx +parent=network \ No newline at end of file diff --git a/plugins/network-elements/juniper-srx/resources/META-INF/cloudstack/srx/spring-srx-context.xml b/plugins/network-elements/juniper-srx/resources/META-INF/cloudstack/srx/spring-srx-context.xml new file mode 100644 index 000000000000..2e17f7cf4ee3 --- /dev/null +++ b/plugins/network-elements/juniper-srx/resources/META-INF/cloudstack/srx/spring-srx-context.xml @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java b/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java index 85210379af73..0a863e8d2f27 100644 --- a/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java +++ b/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java @@ -222,6 +222,14 @@ public boolean applyFWRules(Network config, List rules) return false; } + if (rules != null && rules.size() == 1 ) { + // for SRX no need to add default egress rule to DENY traffic + if (rules.get(0).getTrafficType() == FirewallRule.TrafficType.Egress && rules.get(0).getType() == FirewallRule.FirewallRuleType.System && + ! _networkManager.getNetworkEgressDefaultPolicy(config.getId())) + return true; + } + + return applyFirewallRules(config, rules); } diff --git a/plugins/network-elements/juniper-srx/src/com/cloud/network/resource/JuniperSrxResource.java b/plugins/network-elements/juniper-srx/src/com/cloud/network/resource/JuniperSrxResource.java index 684751cc5d6e..a0278ca5b353 100644 --- a/plugins/network-elements/juniper-srx/src/com/cloud/network/resource/JuniperSrxResource.java +++ b/plugins/network-elements/juniper-srx/src/com/cloud/network/resource/JuniperSrxResource.java @@ -11,7 +11,7 @@ // 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 +// KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package com.cloud.network.resource; @@ -68,7 +68,6 @@ import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; -import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.resource.ServerResource; import com.cloud.utils.NumbersUtil; import com.cloud.utils.exception.ExecutionException; @@ -108,38 +107,38 @@ public class JuniperSrxResource implements ServerResource { private final Logger s_logger = Logger.getLogger(JuniperSrxResource.class); private enum SrxXml { - LOGIN("login.xml"), - PRIVATE_INTERFACE_ADD("private-interface-add.xml"), + LOGIN("login.xml"), + PRIVATE_INTERFACE_ADD("private-interface-add.xml"), PRIVATE_INTERFACE_WITH_FILTERS_ADD("private-interface-with-filters-add.xml"), - PRIVATE_INTERFACE_GETONE("private-interface-getone.xml"), - PROXY_ARP_ADD("proxy-arp-add.xml"), - PROXY_ARP_GETONE("proxy-arp-getone.xml"), + PRIVATE_INTERFACE_GETONE("private-interface-getone.xml"), + PROXY_ARP_ADD("proxy-arp-add.xml"), + PROXY_ARP_GETONE("proxy-arp-getone.xml"), PROXY_ARP_GETALL("proxy-arp-getall.xml"), - ZONE_INTERFACE_ADD("zone-interface-add.xml"), - ZONE_INTERFACE_GETONE("zone-interface-getone.xml"), - SRC_NAT_POOL_ADD("src-nat-pool-add.xml"), - SRC_NAT_POOL_GETONE("src-nat-pool-getone.xml"), - SRC_NAT_RULE_ADD("src-nat-rule-add.xml"), - SRC_NAT_RULE_GETONE("src-nat-rule-getone.xml"), - SRC_NAT_RULE_GETALL("src-nat-rule-getall.xml"), + ZONE_INTERFACE_ADD("zone-interface-add.xml"), + ZONE_INTERFACE_GETONE("zone-interface-getone.xml"), + SRC_NAT_POOL_ADD("src-nat-pool-add.xml"), + SRC_NAT_POOL_GETONE("src-nat-pool-getone.xml"), + SRC_NAT_RULE_ADD("src-nat-rule-add.xml"), + SRC_NAT_RULE_GETONE("src-nat-rule-getone.xml"), + SRC_NAT_RULE_GETALL("src-nat-rule-getall.xml"), DEST_NAT_POOL_ADD("dest-nat-pool-add.xml"), DEST_NAT_POOL_GETONE("dest-nat-pool-getone.xml"), DEST_NAT_POOL_GETALL("dest-nat-pool-getall.xml"), DEST_NAT_RULE_ADD("dest-nat-rule-add.xml"), DEST_NAT_RULE_GETONE("dest-nat-rule-getone.xml"), - DEST_NAT_RULE_GETALL("dest-nat-rule-getall.xml"), - STATIC_NAT_RULE_ADD("static-nat-rule-add.xml"), - STATIC_NAT_RULE_GETONE("static-nat-rule-getone.xml"), + DEST_NAT_RULE_GETALL("dest-nat-rule-getall.xml"), + STATIC_NAT_RULE_ADD("static-nat-rule-add.xml"), + STATIC_NAT_RULE_GETONE("static-nat-rule-getone.xml"), STATIC_NAT_RULE_GETALL("static-nat-rule-getall.xml"), - ADDRESS_BOOK_ENTRY_ADD("address-book-entry-add.xml"), - ADDRESS_BOOK_ENTRY_GETONE("address-book-entry-getone.xml"), + ADDRESS_BOOK_ENTRY_ADD("address-book-entry-add.xml"), + ADDRESS_BOOK_ENTRY_GETONE("address-book-entry-getone.xml"), ADDRESS_BOOK_ENTRY_GETALL("address-book-entry-getall.xml"), - APPLICATION_ADD("application-add.xml"), - APPLICATION_GETONE("application-getone.xml"), - SECURITY_POLICY_ADD("security-policy-add.xml"), - SECURITY_POLICY_GETONE("security-policy-getone.xml"), - SECURITY_POLICY_GETALL("security-policy-getall.xml"), - SECURITY_POLICY_GROUP("security-policy-group.xml"), + APPLICATION_ADD("application-add.xml"), + APPLICATION_GETONE("application-getone.xml"), + SECURITY_POLICY_ADD("security-policy-add.xml"), + SECURITY_POLICY_GETONE("security-policy-getone.xml"), + SECURITY_POLICY_GETALL("security-policy-getall.xml"), + SECURITY_POLICY_GROUP("security-policy-group.xml"), GUEST_VLAN_FILTER_TERM_ADD("guest-vlan-filter-term-add.xml"), PUBLIC_IP_FILTER_TERM_ADD("public-ip-filter-term-add.xml"), FILTER_TERM_GETONE("filter-term-getone.xml"), @@ -168,8 +167,8 @@ private enum SrxXml { TEMPLATE_ENTRY("template-entry.xml"), OPEN_CONFIGURATION("open-configuration.xml"), CLOSE_CONFIGURATION("close-configuration.xml"), - COMMIT("commit.xml"), - ROLLBACK("rollback.xml"), + COMMIT("commit.xml"), + ROLLBACK("rollback.xml"), TEST("test.xml"); private final String scriptsDir = "scripts/network/juniper"; @@ -207,7 +206,7 @@ private String getXml(String filename) { return null; } } - } + } public class UsageFilter { private final String name; @@ -215,7 +214,7 @@ public class UsageFilter { private final String addressType; private UsageFilter(String name, String addressType, String counterIdentifier) { - this.name = name; + this.name = name; this.addressType = addressType; if (_usageInterface != null) { @@ -236,7 +235,7 @@ public String getCounterIdentifier() { public String getAddressType() { return addressType; } - } + } public class FirewallFilterTerm { private final String name; @@ -298,7 +297,7 @@ public String getIcmpCode() { public String getCountName() { return countName; } - } + } private enum SrxCommand { LOGIN, OPEN_CONFIGURATION, CLOSE_CONFIGURATION, COMMIT, ROLLBACK, CHECK_IF_EXISTS, CHECK_IF_IN_USE, ADD, DELETE, GET_ALL; @@ -388,7 +387,7 @@ public boolean configure(String name, Map params) throws Configu _password = (String) params.get("password"); if (_password == null) { throw new ConfigurationException("Unable to find password"); - } + } _publicInterface = (String) params.get("publicinterface"); if (_publicInterface == null) { @@ -447,7 +446,7 @@ public boolean configure(String name, Map params) throws Configu } @Override - public StartupCommand[] initialize() { + public StartupCommand[] initialize() { StartupExternalFirewallCommand cmd = new StartupExternalFirewallCommand(); cmd.setName(_name); cmd.setDataCenter(_zoneId); @@ -508,7 +507,7 @@ private Answer execute(MaintainCommand cmd) { } private ExternalNetworkResourceUsageAnswer execute(ExternalNetworkResourceUsageCommand cmd) { - try { + try { return getUsageAnswer(cmd); } catch (ExecutionException e) { return new ExternalNetworkResourceUsageAnswer(cmd, e); @@ -521,7 +520,7 @@ private ExternalNetworkResourceUsageAnswer execute(ExternalNetworkResourceUsageC private boolean refreshSrxConnection() { if (!(closeSocket() && openSocket())) { - return false; + return false; } try { @@ -557,7 +556,7 @@ private boolean closeSocket() { try { if (_toSrx != null) { _toSrx.close(); - } + } if (_fromSrx != null) { _fromSrx.close(); @@ -571,7 +570,7 @@ private boolean closeSocket() { } /* - * The usage data will be handled on it's own socket, so usage + * The usage data will be handled on it's own socket, so usage * commands will use the following methods... */ private boolean usageLogin() throws ExecutionException { @@ -600,7 +599,7 @@ private boolean closeUsageSocket() { try { if (_UsagetoSrx != null) { _UsagetoSrx.close(); - } + } if (_UsagefromSrx != null) { _UsagefromSrx.close(); @@ -637,7 +636,7 @@ private void closeConfiguration() { try { if (!sendRequestAndCheckResponse(SrxCommand.CLOSE_CONFIGURATION, xml)) { s_logger.error(errorMsg); - } + } } catch (ExecutionException e) { s_logger.error(errorMsg); } @@ -652,7 +651,7 @@ private void commitConfiguration() throws ExecutionException { if (!sendRequestAndCheckResponse(SrxCommand.COMMIT, xml)) { throw new ExecutionException(errorMsg); - } else { + } else { s_logger.debug(successMsg); closeConfiguration(); } @@ -667,7 +666,7 @@ private synchronized Answer execute(IpAssocCommand cmd) { return execute(cmd, _numRetries); } - private Answer execute(IpAssocCommand cmd, int numRetries) { + private Answer execute(IpAssocCommand cmd, int numRetries) { String[] results = new String[cmd.getIpAddresses().length]; int i = 0; try { @@ -676,9 +675,9 @@ private Answer execute(IpAssocCommand cmd, int numRetries) { throw new ExecutionException("Received an invalid number of guest IPs to associate."); } else { ip = cmd.getIpAddresses()[0]; - } + } - String sourceNatIpAddress = null; + String sourceNatIpAddress = null; GuestNetworkType type = GuestNetworkType.INTERFACE_NAT; if (ip.isSourceNat()) { @@ -695,28 +694,28 @@ private Answer execute(IpAssocCommand cmd, int numRetries) { String guestVlanGateway = cmd.getAccessDetail(NetworkElementCommand.GUEST_NETWORK_GATEWAY); String cidr = cmd.getAccessDetail(NetworkElementCommand.GUEST_NETWORK_CIDR); long cidrSize = NetUtils.cidrToLong(cidr)[1]; - String guestVlanSubnet = NetUtils.getCidrSubNet(guestVlanGateway, cidrSize); + String guestVlanSubnet = NetUtils.getCidrSubNet(guestVlanGateway, cidrSize); Long publicVlanTag = null; if (ip.getBroadcastUri() != null && !ip.getBroadcastUri().equals("untagged")) { try { - publicVlanTag = Long.parseLong(ip.getBroadcastUri()); + publicVlanTag = Long.parseLong(BroadcastDomainType.getValue(ip.getBroadcastUri())); } catch (Exception e) { throw new ExecutionException("Could not parse public VLAN tag: " + ip.getBroadcastUri()); } - } + } openConfiguration(); // Remove the guest network: // Remove source, static, and destination NAT rules - // Remove VPN + // Remove VPN shutdownGuestNetwork(type, ip.getAccountId(), publicVlanTag, sourceNatIpAddress, guestVlanTag, guestVlanGateway, guestVlanSubnet, cidrSize); - if (ip.isAdd()) { + if (ip.isAdd()) { // Implement the guest network for this VLAN implementGuestNetwork(type, publicVlanTag, sourceNatIpAddress, guestVlanTag, guestVlanGateway, guestVlanSubnet, cidrSize); - } + } commitConfiguration(); results[i++] = ip.getPublicIp() + " - success"; @@ -744,13 +743,13 @@ private void implementGuestNetwork(GuestNetworkType type, Long publicVlanTag, St manageZoneInterface(SrxCommand.ADD, privateVlanTag); if (type.equals(GuestNetworkType.SOURCE_NAT)) { - manageSourceNatPool(SrxCommand.ADD, publicIp); - manageSourceNatRule(SrxCommand.ADD, publicIp, privateSubnet); - manageProxyArp(SrxCommand.ADD, publicVlanTag, publicIp); + manageSourceNatPool(SrxCommand.ADD, publicIp); + manageSourceNatRule(SrxCommand.ADD, publicIp, privateSubnet); + manageProxyArp(SrxCommand.ADD, publicVlanTag, publicIp); manageUsageFilter(SrxCommand.ADD, _usageFilterIPOutput, privateSubnet, null, genIpFilterTermName(publicIp)); manageUsageFilter(SrxCommand.ADD, _usageFilterIPInput, publicIp, null, genIpFilterTermName(publicIp)); - } else if (type.equals(GuestNetworkType.INTERFACE_NAT)){ - manageUsageFilter(SrxCommand.ADD, _usageFilterVlanOutput, null, privateVlanTag, null); + } else if (type.equals(GuestNetworkType.INTERFACE_NAT)){ + manageUsageFilter(SrxCommand.ADD, _usageFilterVlanOutput, null, privateVlanTag, null); manageUsageFilter(SrxCommand.ADD, _usageFilterVlanInput, null, privateVlanTag, null); } @@ -766,20 +765,20 @@ private void shutdownGuestNetwork(GuestNetworkType type, long accountId, Long pu privateGateway = privateGateway + "/" + privateCidrSize; privateSubnet = privateSubnet + "/" + privateCidrSize; - managePrivateInterface(SrxCommand.DELETE, false, privateVlanTag, privateGateway); - manageZoneInterface(SrxCommand.DELETE, privateVlanTag); + managePrivateInterface(SrxCommand.DELETE, false, privateVlanTag, privateGateway); + manageZoneInterface(SrxCommand.DELETE, privateVlanTag); deleteVpnObjectsForAccount(accountId); - if (type.equals(GuestNetworkType.SOURCE_NAT)) { + if (type.equals(GuestNetworkType.SOURCE_NAT)) { manageSourceNatRule(SrxCommand.DELETE, sourceNatIpAddress, privateSubnet); manageSourceNatPool(SrxCommand.DELETE, sourceNatIpAddress); manageProxyArp(SrxCommand.DELETE, publicVlanTag, sourceNatIpAddress); manageUsageFilter(SrxCommand.DELETE, _usageFilterIPOutput, privateSubnet, null, genIpFilterTermName(sourceNatIpAddress)); manageUsageFilter(SrxCommand.DELETE, _usageFilterIPInput, sourceNatIpAddress, null, genIpFilterTermName(sourceNatIpAddress)); } else if (type.equals(GuestNetworkType.INTERFACE_NAT)) { - manageUsageFilter(SrxCommand.DELETE, _usageFilterVlanOutput, null, privateVlanTag, null); + manageUsageFilter(SrxCommand.DELETE, _usageFilterVlanOutput, null, privateVlanTag, null); manageUsageFilter(SrxCommand.DELETE, _usageFilterVlanInput, null, privateVlanTag, null); - } + } String msg = "Shut down guest network with type " + type +". Guest VLAN tag: " + privateVlanTag + ", guest gateway: " + privateGateway; msg += type.equals(GuestNetworkType.SOURCE_NAT) ? ", source NAT IP: " + sourceNatIpAddress : ""; @@ -842,6 +841,15 @@ private Answer execute(SetFirewallRulesCommand cmd, int numRetries) { FirewallRule.FirewallRuleType type = rules[0].getType(); //getting String guestCidr = rules[0].getGuestCidr(); + List cidrs = new ArrayList(); + cidrs.add(guestCidr); + + List applications = new ArrayList(); + Object[] application = new Object[3]; + application[0] = Protocol.all; + application[1] = NetUtils.PORT_RANGE_MIN; + application[2] = NetUtils.PORT_RANGE_MAX; + applications.add(application); for (String guestVlan : guestVlans) { List activeRulesForGuestNw = activeRules.get(guestVlan); @@ -849,23 +857,23 @@ private Answer execute(SetFirewallRulesCommand cmd, int numRetries) { removeEgressSecurityPolicyAndApplications(SecurityPolicyType.SECURITYPOLICY_EGRESS, guestVlan, extractCidrs(activeRulesForGuestNw), defaultEgressPolicy); if (activeRulesForGuestNw.size() > 0 && type == FirewallRule.FirewallRuleType.User) { addEgressSecurityPolicyAndApplications(SecurityPolicyType.SECURITYPOLICY_EGRESS, guestVlan, extractApplications(activeRulesForGuestNw), extractCidrs(activeRulesForGuestNw), defaultEgressPolicy); + + /* Adding default policy rules are required because the order of rules is important. + * Depending on the rules order the traffic accept/drop is performed + */ + removeEgressSecurityPolicyAndApplications(SecurityPolicyType.SECURITYPOLICY_EGRESS_DEFAULT, guestVlan, cidrs, defaultEgressPolicy); + addEgressSecurityPolicyAndApplications(SecurityPolicyType.SECURITYPOLICY_EGRESS_DEFAULT, guestVlan, applications, cidrs, defaultEgressPolicy); } - List applications = new ArrayList(); - Object[] application = new Object[3]; - application[0] = Protocol.all; - application[1] = NetUtils.PORT_RANGE_MIN; - application[2] = NetUtils.PORT_RANGE_MAX; - applications.add(application); - List cidrs = new ArrayList(); - cidrs.add(guestCidr); //remove required with out comparing default policy because in upgrade network offering we may required to delete // the previously added rule - removeEgressSecurityPolicyAndApplications(SecurityPolicyType.SECURITYPOLICY_EGRESS_DEFAULT, guestVlan, cidrs, false); - if (defaultEgressPolicy == true) { - //add default egress security policy - addEgressSecurityPolicyAndApplications(SecurityPolicyType.SECURITYPOLICY_EGRESS_DEFAULT, guestVlan, applications, cidrs, false); + if (defaultEgressPolicy == true && type == FirewallRule.FirewallRuleType.System) { + removeEgressSecurityPolicyAndApplications(SecurityPolicyType.SECURITYPOLICY_EGRESS_DEFAULT, guestVlan, cidrs, defaultEgressPolicy); + if (activeRulesForGuestNw.size() > 0) { + //add default egress security policy + addEgressSecurityPolicyAndApplications(SecurityPolicyType.SECURITYPOLICY_EGRESS_DEFAULT, guestVlan, applications, cidrs, defaultEgressPolicy); + } } } @@ -914,9 +922,9 @@ private Answer execute(SetFirewallRulesCommand cmd, int numRetries) { private synchronized Answer execute(SetStaticNatRulesCommand cmd) { refreshSrxConnection(); return execute(cmd, _numRetries); - } + } - private Answer execute(SetStaticNatRulesCommand cmd, int numRetries) { + private Answer execute(SetStaticNatRulesCommand cmd, int numRetries) { StaticNatRuleTO[] allRules = cmd.getRules(); Map> activeRules = getActiveRules(allRules); Map vlanTagMap = getVlanTagMap(allRules); @@ -925,12 +933,12 @@ private Answer execute(SetStaticNatRulesCommand cmd, int numRetries) { openConfiguration(); Set ipPairs = activeRules.keySet(); - for (String ipPair : ipPairs) { + for (String ipPair : ipPairs) { String[] ipPairComponents = ipPair.split("-"); String publicIp = ipPairComponents[0]; - String privateIp = ipPairComponents[1]; + String privateIp = ipPairComponents[1]; - List activeRulesForIpPair = activeRules.get(ipPair); + List activeRulesForIpPair = activeRules.get(ipPair); Long publicVlanTag = getVlanTag(vlanTagMap.get(publicIp)); // Delete the existing static NAT rule for this IP pair @@ -939,8 +947,8 @@ private Answer execute(SetStaticNatRulesCommand cmd, int numRetries) { if (activeRulesForIpPair.size() > 0) { // If there are active FirewallRules for this IP pair, add the static NAT rule and open the specified port ranges addStaticNatRule(publicVlanTag, publicIp, privateIp, activeRulesForIpPair); - } - } + } + } commitConfiguration(); return new Answer(cmd); @@ -966,15 +974,15 @@ private void addStaticNatRule(Long publicVlanTag, String publicIp, String privat addSecurityPolicyAndApplications(SecurityPolicyType.STATIC_NAT, privateIp, extractApplications(rules)); s_logger.debug("Added static NAT rule for public IP " + publicIp + ", and private IP " + privateIp); - } + } - private void removeStaticNatRule(Long publicVlanTag, String publicIp, String privateIp) throws ExecutionException { + private void removeStaticNatRule(Long publicVlanTag, String publicIp, String privateIp) throws ExecutionException { manageStaticNatRule(SrxCommand.DELETE, publicIp, privateIp); // Remove any existing security policy and clean up applications removeSecurityPolicyAndApplications(SecurityPolicyType.STATIC_NAT, privateIp); - manageAddressBookEntry(SrxCommand.DELETE, _privateZone, privateIp, null); + manageAddressBookEntry(SrxCommand.DELETE, _privateZone, privateIp, null); s_logger.debug("Removed static NAT rule for public IP " + publicIp + ", and private IP " + privateIp); } @@ -1016,14 +1024,14 @@ private Answer execute(RemoteAccessVpnCfgCommand cmd, int numRetries) { openConfiguration(); // Delete existing VPN objects for this account - deleteVpnObjectsForAccount(accountId); + deleteVpnObjectsForAccount(accountId); if (cmd.isCreate()) { // Add IKE policy manageIkePolicy(SrxCommand.ADD, null, accountId, preSharedKey); // Add address pool - manageAddressPool(SrxCommand.ADD, null, accountId, guestNetworkCidr, ipRange[0], ipRange[1], _primaryDnsAddress); + manageAddressPool(SrxCommand.ADD, null, accountId, guestNetworkCidr, ipRange[0], ipRange[1], _primaryDnsAddress); } commitConfiguration(); @@ -1053,7 +1061,7 @@ private void deleteVpnObjectsForAccount(long accountId) throws ExecutionExceptio // Delete all address pools for (String addressPoolName : getVpnObjectNames(SrxXml.ADDRESS_POOL_GETALL, accountId)) { manageAddressPool(SrxCommand.DELETE, addressPoolName, null, null, null, null, null); - } + } // Delete all IKE gateways for (String ikeGatewayName : getVpnObjectNames(SrxXml.IKE_GATEWAY_GETALL, accountId)) { @@ -1063,24 +1071,24 @@ private void deleteVpnObjectsForAccount(long accountId) throws ExecutionExceptio // Delete all IPsec VPNs for (String ipsecVpnName : getVpnObjectNames(SrxXml.IPSEC_VPN_GETALL, accountId)) { manageIpsecVpn(SrxCommand.DELETE, ipsecVpnName, null, null, null, null); - } + } // Delete all dynamic VPN clients for (String dynamicVpnClientName : getVpnObjectNames(SrxXml.DYNAMIC_VPN_CLIENT_GETALL, accountId)) { manageDynamicVpnClient(SrxCommand.DELETE, dynamicVpnClientName, null, null, null, null); - } + } // Delete all access profiles for (String accessProfileName : getVpnObjectNames(SrxXml.ACCESS_PROFILE_GETALL, accountId)) { manageAccessProfile(SrxCommand.DELETE, accessProfileName, null, null, null, null); - } + } // Delete all security policies for (String securityPolicyName : getVpnObjectNames(SrxXml.SECURITY_POLICY_GETALL, accountId)) { manageSecurityPolicy(SecurityPolicyType.VPN, SrxCommand.DELETE, accountId, null, null, null, null, securityPolicyName, false); } - // Delete all address book entries + // Delete all address book entries for (String addressBookEntryName : getVpnObjectNames(SrxXml.ADDRESS_BOOK_ENTRY_GETALL, accountId)) { manageAddressBookEntry(SrxCommand.DELETE, _privateZone, null, addressBookEntryName); } @@ -1088,9 +1096,9 @@ private void deleteVpnObjectsForAccount(long accountId) throws ExecutionExceptio } public List getVpnObjectNames(SrxXml xmlObj, long accountId) throws ExecutionException { - List vpnObjectNames = new ArrayList(); + List vpnObjectNames = new ArrayList(); - String xmlRequest = xmlObj.getXml(); + String xmlRequest = xmlObj.getXml(); if (xmlObj.equals(SrxXml.SECURITY_POLICY_GETALL)) { xmlRequest = replaceXmlValue(xmlRequest, "from-zone", _publicZone); xmlRequest = replaceXmlValue(xmlRequest, "to-zone", _privateZone); @@ -1098,17 +1106,17 @@ public List getVpnObjectNames(SrxXml xmlObj, long accountId) throws Exec xmlRequest = replaceXmlValue(xmlRequest, "zone", _privateZone); } - String xmlResponse = sendRequest(xmlRequest); + String xmlResponse = sendRequest(xmlRequest); Document doc = getDocument(xmlResponse); NodeList vpnObjectNameNodes = doc.getElementsByTagName("name"); for (int i = 0; i < vpnObjectNameNodes.getLength(); i++) { - NodeList vpnObjectNameEntries = vpnObjectNameNodes.item(i).getChildNodes(); + NodeList vpnObjectNameEntries = vpnObjectNameNodes.item(i).getChildNodes(); for (int j = 0; j < vpnObjectNameEntries.getLength(); j++) { String vpnObjectName = vpnObjectNameEntries.item(j).getNodeValue(); if (vpnObjectName.startsWith(genObjectName(_vpnObjectPrefix, String.valueOf(accountId)))) { vpnObjectNames.add(vpnObjectName); } - } + } } return vpnObjectNames; @@ -1119,7 +1127,7 @@ private synchronized Answer execute(VpnUsersCfgCommand cmd) { return execute(cmd, _numRetries); } - private Answer execute(VpnUsersCfgCommand cmd, int numRetries) { + private Answer execute(VpnUsersCfgCommand cmd, int numRetries) { long accountId = Long.parseLong(cmd.getAccessDetail(NetworkElementCommand.ACCOUNT_ID)); String guestNetworkCidr = cmd.getAccessDetail(NetworkElementCommand.GUEST_NETWORK_CIDR); String ikePolicyName = genIkePolicyName(accountId); @@ -1134,7 +1142,7 @@ private Answer execute(VpnUsersCfgCommand cmd, int numRetries) { String ipsecVpnName = genIpsecVpnName(accountId, user.getUsername()); // IKE gateway - manageIkeGateway(srxCmd, null, accountId, ikePolicyName, _ikeGatewayHostname , user.getUsername()); + manageIkeGateway(srxCmd, null, accountId, ikePolicyName, _ikeGatewayHostname , user.getUsername()); // IPSec VPN manageIpsecVpn(srxCmd, null, accountId, guestNetworkCidr, user.getUsername(), _ipsecPolicyName); @@ -1179,7 +1187,7 @@ private synchronized Answer execute (SetPortForwardingRulesCommand cmd) { return execute(cmd, _numRetries); } - private Answer execute(SetPortForwardingRulesCommand cmd, int numRetries) { + private Answer execute(SetPortForwardingRulesCommand cmd, int numRetries) { PortForwardingRuleTO[] allRules = cmd.getRules(); Map> activeRules = getActiveRules(allRules); @@ -1187,12 +1195,12 @@ private Answer execute(SetPortForwardingRulesCommand cmd, int numRetries) { openConfiguration(); Set ipPairs = activeRules.keySet(); - for (String ipPair : ipPairs) { + for (String ipPair : ipPairs) { String[] ipPairComponents = ipPair.split("-"); String publicIp = ipPairComponents[0]; - String privateIp = ipPairComponents[1]; + String privateIp = ipPairComponents[1]; - List activeRulesForIpPair = activeRules.get(ipPair); + List activeRulesForIpPair = activeRules.get(ipPair); // Get a list of all destination NAT rules for the public/private IP address pair List destNatRules = getDestNatRules(RuleMatchCondition.PUBLIC_PRIVATE_IPS, publicIp, privateIp, null, null); @@ -1205,11 +1213,11 @@ private Answer execute(SetPortForwardingRulesCommand cmd, int numRetries) { for (FirewallRuleTO rule : activeRulesForIpPair) { Long publicVlanTag = getVlanTag(rule.getSrcVlanTag()); PortForwardingRuleTO portForwardingRule = (PortForwardingRuleTO) rule; - addDestinationNatRule(getProtocol(rule.getProtocol()), publicVlanTag, portForwardingRule.getSrcIp(), portForwardingRule.getDstIp(), + addDestinationNatRule(getProtocol(rule.getProtocol()), publicVlanTag, portForwardingRule.getSrcIp(), portForwardingRule.getDstIp(), portForwardingRule.getSrcPortRange()[0], portForwardingRule.getSrcPortRange()[1], portForwardingRule.getDstPortRange()[0], portForwardingRule.getDstPortRange()[1]); } - } + } commitConfiguration(); return new Answer(cmd); @@ -1232,8 +1240,8 @@ private void addDestinationNatRule(Protocol protocol, Long publicVlanTag, String int offset = 0; for (int srcPort = srcPortStart; srcPort <= srcPortEnd; srcPort++) { int destPort = destPortStart + offset; - manageDestinationNatPool(SrxCommand.ADD, privateIp, destPort); - manageDestinationNatRule(SrxCommand.ADD, publicIp, privateIp, srcPort, destPort); + manageDestinationNatPool(SrxCommand.ADD, privateIp, destPort); + manageDestinationNatRule(SrxCommand.ADD, publicIp, privateIp, srcPort, destPort); offset += 1; } @@ -1248,15 +1256,15 @@ private void addDestinationNatRule(Protocol protocol, Long publicVlanTag, String s_logger.debug("Added destination NAT rule for protocol " + protocol + ", public IP " + publicIp + ", private IP " + privateIp + ", source port range " + srcPortRange + ", and dest port range " + destPortRange); } - private void removeDestinationNatRule(Long publicVlanTag, String publicIp, String privateIp, int srcPort, int destPort) throws ExecutionException { + private void removeDestinationNatRule(Long publicVlanTag, String publicIp, String privateIp, int srcPort, int destPort) throws ExecutionException { manageDestinationNatRule(SrxCommand.DELETE, publicIp, privateIp, srcPort, destPort); - manageDestinationNatPool(SrxCommand.DELETE, privateIp, destPort); + manageDestinationNatPool(SrxCommand.DELETE, privateIp, destPort); removeSecurityPolicyAndApplications(SecurityPolicyType.DESTINATION_NAT, privateIp); - manageAddressBookEntry(SrxCommand.DELETE, _privateZone, privateIp, null); + manageAddressBookEntry(SrxCommand.DELETE, _privateZone, privateIp, null); - s_logger.debug("Removed destination NAT rule for public IP " + publicIp + ", private IP " + privateIp + ", source port " + srcPort + ", and dest port " + destPort); + s_logger.debug("Removed destination NAT rule for public IP " + publicIp + ", private IP " + privateIp + ", source port " + srcPort + ", and dest port " + destPort); } @@ -1273,8 +1281,8 @@ private void removeDestinationNatRules(Long privateVlanTag, Map pu } if (privateVlanTag != null) { - s_logger.warn("Found a destination NAT rule (public IP: " + publicIp + ", private IP: " + privateIp + - ", public port: " + srcPort + ", private port: " + destPort + ") for guest VLAN with tag " + + s_logger.warn("Found a destination NAT rule (public IP: " + publicIp + ", private IP: " + privateIp + + ", public port: " + srcPort + ", private port: " + destPort + ") for guest VLAN with tag " + privateVlanTag + " that is active when the guest network is being removed. Removing rule..."); } @@ -1287,11 +1295,11 @@ private void removeDestinationNatRules(Long privateVlanTag, Map pu */ private List getAllStaticAndDestNatRules() throws ExecutionException { - List staticAndDestNatRules = new ArrayList(); + List staticAndDestNatRules = new ArrayList(); staticAndDestNatRules.addAll(getStaticNatRules(RuleMatchCondition.ALL, null, null)); - staticAndDestNatRules.addAll(getDestNatRules(RuleMatchCondition.ALL, null, null, null, null)); + staticAndDestNatRules.addAll(getDestNatRules(RuleMatchCondition.ALL, null, null, null, null)); return staticAndDestNatRules; - } + } private void removeStaticAndDestNatRulesInPrivateVlan(long privateVlanTag, String privateGateway, long privateCidrSize) throws ExecutionException { List staticNatRulesToRemove = getStaticNatRules(RuleMatchCondition.PRIVATE_SUBNET, privateGateway, privateCidrSize); @@ -1305,7 +1313,7 @@ private void removeStaticAndDestNatRulesInPrivateVlan(long privateVlanTag, Strin removeStaticNatRules(privateVlanTag, publicVlanTags, staticNatRulesToRemove); removeDestinationNatRules(privateVlanTag, publicVlanTags, destNatRulesToRemove); - } + } private Map> getActiveRules(FirewallRuleTO[] allRules) { Map> activeRules = new HashMap>(); @@ -1854,19 +1862,19 @@ private Map getPublicVlanTagsForPublicIps(List publicIps) String xmlRequest = SrxXml.PROXY_ARP_GETALL.getXml(); xmlRequest = replaceXmlValue(xmlRequest, "interface-name", ""); - String xmlResponse = sendRequest(xmlRequest); + String xmlResponse = sendRequest(xmlRequest); Document doc = getDocument(xmlResponse); NodeList interfaces = doc.getElementsByTagName("interface"); for (int i = 0; i < interfaces.getLength(); i++) { String interfaceName = null; - NodeList interfaceEntries = interfaces.item(i).getChildNodes(); + NodeList interfaceEntries = interfaces.item(i).getChildNodes(); for (int j = 0; j < interfaceEntries.getLength(); j++) { Node interfaceEntry = interfaceEntries.item(j); if (interfaceEntry.getNodeName().equals("name")) { interfaceName = interfaceEntry.getFirstChild().getNodeValue(); break; - } + } } if (interfaceName != null) { @@ -2048,15 +2056,15 @@ private boolean manageStaticNatRule(SrxCommand command, String publicIp, String } } - private List getStaticNatRules(RuleMatchCondition condition, String privateGateway, Long privateCidrSize) throws ExecutionException { + private List getStaticNatRules(RuleMatchCondition condition, String privateGateway, Long privateCidrSize) throws ExecutionException { List staticNatRules = new ArrayList(); String xmlRequest = SrxXml.STATIC_NAT_RULE_GETALL.getXml(); - String xmlResponse = sendRequest(xmlRequest); + String xmlResponse = sendRequest(xmlRequest); Document doc = getDocument(xmlResponse); NodeList rules = doc.getElementsByTagName("rule"); for (int i = 0; i < rules.getLength(); i++) { - NodeList ruleEntries = rules.item(i).getChildNodes(); + NodeList ruleEntries = rules.item(i).getChildNodes(); for (int j = 0; j < ruleEntries.getLength(); j++) { Node ruleEntry = ruleEntries.item(j); if (ruleEntry.getNodeName().equals("name")) { @@ -2085,7 +2093,7 @@ private List getStaticNatRules(RuleMatchCondition condition, String pr staticNatRules.add(new String[]{rulePublicIp, rulePrivateIp}); } } - } + } } return staticNatRules; @@ -2313,7 +2321,7 @@ private List getDestNatRules(RuleMatchCondition condition, String publ } return destNatRules; - } + } /* * Source NAT pools @@ -2671,10 +2679,10 @@ private List getApplicationsForSecurityPolicy(SecurityPolicyType type, S for (int i = 0; i < applicationNodes.getLength(); i++) { Node applicationNode = applicationNodes.item(i); policyApplications.add(applicationNode.getFirstChild().getNodeValue()); - } + } return policyApplications; - } + } private List extractApplications(List rules) throws ExecutionException { List applications = new ArrayList(); @@ -2722,7 +2730,7 @@ private String genSecurityPolicyName(SecurityPolicyType type, Long accountId, St return genObjectName(_vpnObjectPrefix, String.valueOf(accountId), username); } else { return genObjectName(type.getIdentifier(), fromZone, toZone, genIpIdentifier(translatedIp)); - } + } } private boolean manageSecurityPolicy(SecurityPolicyType type, SrxCommand command, Long accountId, String username, String privateIp, List applicationNames, List cidrs, String ipsecVpnName, boolean defaultEgressAction) throws ExecutionException { @@ -2742,7 +2750,7 @@ private boolean manageSecurityPolicy(SecurityPolicyType type, SrxCommand command } else { securityPolicyName = genSecurityPolicyName(type, accountId, username, fromZone, toZone, privateIp); addressBookEntryName = genAddressBookEntryName(privateIp); - } + } String xml; @@ -2758,7 +2766,7 @@ private boolean manageSecurityPolicy(SecurityPolicyType type, SrxCommand command return sendRequestAndCheckResponse(command, xml, "name", securityPolicyName); case CHECK_IF_IN_USE: - List rulesToCheck = null; + List rulesToCheck = null; if (type.equals(SecurityPolicyType.STATIC_NAT)) { // Check if any static NAT rules rely on this security policy rulesToCheck = getStaticNatRules(RuleMatchCondition.ALL, null, null); @@ -2767,7 +2775,7 @@ private boolean manageSecurityPolicy(SecurityPolicyType type, SrxCommand command rulesToCheck = getDestNatRules(RuleMatchCondition.ALL, null, null, null, null); } else { return false; - } + } for (String[] rule : rulesToCheck) { String rulePrivateIp = rule[1]; @@ -2793,7 +2801,7 @@ private boolean manageSecurityPolicy(SecurityPolicyType type, SrxCommand command if (type.equals(SecurityPolicyType.SECURITYPOLICY_EGRESS) || type.equals(SecurityPolicyType.SECURITYPOLICY_EGRESS_DEFAULT)) { xml = replaceXmlValue(xml, "from-zone", _privateZone); xml = replaceXmlValue(xml, "to-zone", _publicZone); - if (cidrs == null) { + if (cidrs == null || cidrs.size() == 0) { srcAddrs = "any"; } else { for (String cidr : cidrs) { @@ -2803,12 +2811,24 @@ private boolean manageSecurityPolicy(SecurityPolicyType type, SrxCommand command xml = replaceXmlValue(xml, "src-address", srcAddrs); dstAddrs = "any"; xml = replaceXmlValue(xml, "dst-address", dstAddrs); - if (defaultEgressAction == true) { - //configure block rules and default allow the traffic - action = ""; + + + if (type.equals(SecurityPolicyType.SECURITYPOLICY_EGRESS_DEFAULT)) { + if (defaultEgressAction == false) { + //for default policy is false add default deny rules + action = ""; + } else { + action = ""; + } } else { - action = ""; + if (defaultEgressAction == true) { + //configure egress rules to deny the traffic when default egress is allow + action = ""; + } else { + action = ""; + } } + xml = replaceXmlValue(xml, "action", action); } else { xml = replaceXmlValue(xml, "from-zone", fromZone); @@ -2821,7 +2841,7 @@ private boolean manageSecurityPolicy(SecurityPolicyType type, SrxCommand command if (type.equals(SecurityPolicyType.VPN) && ipsecVpnName != null) { xml = replaceXmlValue(xml, "tunnel", "" + ipsecVpnName + ""); - } else { + } else { xml = replaceXmlValue(xml, "tunnel", ""); if (!(type.equals(SecurityPolicyType.SECURITYPOLICY_EGRESS_DEFAULT) || type.equals(SecurityPolicyType.SECURITYPOLICY_EGRESS))) { action = ""; @@ -2837,7 +2857,7 @@ private boolean manageSecurityPolicy(SecurityPolicyType type, SrxCommand command for (String applicationName : applicationNames) { applications += "" + applicationName + ""; } - } + } xml = replaceXmlValue(xml, "applications", applications); @@ -2872,7 +2892,7 @@ private boolean manageSecurityPolicy(SecurityPolicyType type, SrxCommand command if (getAllResponseXml == null) { throw new ExecutionException("Deleted security policy, but failed to delete security policy group."); - } + } if (!getAllResponseXml.contains(fromZone) || !getAllResponseXml.contains(toZone)) { return true; @@ -2898,12 +2918,12 @@ private boolean manageSecurityPolicy(SecurityPolicyType type, SrxCommand command return false; } - } + } private boolean addSecurityPolicyAndApplications(SecurityPolicyType type, String privateIp, List applications) throws ExecutionException { // Add all necessary applications List applicationNames = new ArrayList(); - for (Object[] application : applications) { + for (Object[] application : applications) { Protocol protocol = (Protocol) application[0]; int startPort = application[1] != null ? ((Integer) application[1]) : -1; int endPort = application[2] != null ? ((Integer) application[2]) : -1; @@ -3031,19 +3051,19 @@ private String genIpFilterTermName(String ipAddress) { return genIpIdentifier(ipAddress); } - private boolean manageUsageFilter(SrxCommand command, UsageFilter filter, String ip, Long guestVlanTag, String filterTermName) throws ExecutionException { + private boolean manageUsageFilter(SrxCommand command, UsageFilter filter, String ip, Long guestVlanTag, String filterTermName) throws ExecutionException { String filterName; String filterDescription; String xml; if (filter.equals(_usageFilterIPInput) || filter.equals(_usageFilterIPOutput)) { - assert (ip != null && guestVlanTag == null); + assert (ip != null && guestVlanTag == null); filterName = filter.getName(); filterDescription = filter.toString() + ", public IP = " + ip; xml = SrxXml.PUBLIC_IP_FILTER_TERM_ADD.getXml(); } else if (filter.equals(_usageFilterVlanInput) || filter.equals(_usageFilterVlanOutput)) { - assert (ip == null && guestVlanTag != null); - filterName = filter.getName() + "-" + guestVlanTag; + assert (ip == null && guestVlanTag != null); + filterName = filter.getName() + "-" + guestVlanTag; filterDescription = filter.toString() + ", guest VLAN tag = " + guestVlanTag; filterTermName = filterName; xml = SrxXml.GUEST_VLAN_FILTER_TERM_ADD.getXml(); @@ -3060,7 +3080,7 @@ private boolean manageUsageFilter(SrxCommand command, UsageFilter filter, String xml = replaceXmlValue(xml, "term-name", filterTermName); return sendRequestAndCheckResponse(command, xml, "name", filterTermName); - case ADD: + case ADD: if (manageUsageFilter(SrxCommand.CHECK_IF_EXISTS, filter, ip, guestVlanTag, filterTermName)) { return true; } @@ -3101,7 +3121,7 @@ private boolean manageUsageFilter(SrxCommand command, UsageFilter filter, String return false; } - } + } private String genNameValueEntry(String name, String value) { String xml = SrxXml.TEMPLATE_ENTRY.getXml(); @@ -3141,7 +3161,7 @@ private String genIcmpEntries(String icmpType, String icmpCode) { return result; } - private boolean manageFirewallFilter(SrxCommand command, FirewallFilterTerm term, String filterName) throws ExecutionException { + private boolean manageFirewallFilter(SrxCommand command, FirewallFilterTerm term, String filterName) throws ExecutionException { String xml; switch(command) { @@ -3153,7 +3173,7 @@ private boolean manageFirewallFilter(SrxCommand command, FirewallFilterTerm term xml = replaceXmlValue(xml, "term-name", term.getName()); return sendRequestAndCheckResponse(command, xml, "name", term.getName()); - case ADD: + case ADD: if (manageFirewallFilter(SrxCommand.CHECK_IF_EXISTS, term, filterName)) { return true; } @@ -3203,14 +3223,14 @@ private boolean manageFirewallFilter(SrxCommand command, FirewallFilterTerm term return false; } - } + } /* - * Usage + * Usage */ private ExternalNetworkResourceUsageAnswer getUsageAnswer(ExternalNetworkResourceUsageCommand cmd) throws ExecutionException { - try { + try { String socOpenException = "Failed to open a connection for Usage data."; String socCloseException = "Unable to close connection for Usage data."; if (!openUsageSocket()) { @@ -3220,7 +3240,7 @@ private ExternalNetworkResourceUsageAnswer getUsageAnswer(ExternalNetworkResourc ExternalNetworkResourceUsageAnswer answer = new ExternalNetworkResourceUsageAnswer(cmd); String xml = SrxXml.FIREWALL_FILTER_BYTES_GETALL.getXml(); - String rawUsageData = sendUsageRequest(xml); + String rawUsageData = sendUsageRequest(xml); Document doc = getDocument(rawUsageData); NodeList counters = doc.getElementsByTagName("counter"); @@ -3242,13 +3262,13 @@ private ExternalNetworkResourceUsageAnswer getUsageAnswer(ExternalNetworkResourc s_logger.debug(e); byteCount = 0; } - } + } } if (byteCount >= 0) { - updateUsageAnswer(answer, counterName, byteCount); + updateUsageAnswer(answer, counterName, byteCount); } - } + } } if (!closeUsageSocket()) { throw new ExecutionException(socCloseException); @@ -3259,10 +3279,10 @@ private ExternalNetworkResourceUsageAnswer getUsageAnswer(ExternalNetworkResourc throw new ExecutionException(e.getMessage()); } - } + } private void updateBytesMap(Map bytesMap, UsageFilter filter, String usageAnswerKey, long additionalBytes) { - long[] bytesSentAndReceived = bytesMap.get(usageAnswerKey); + long[] bytesSentAndReceived = bytesMap.get(usageAnswerKey); if (bytesSentAndReceived == null) { bytesSentAndReceived = new long[]{0,0}; } @@ -3306,7 +3326,7 @@ private UsageFilter getUsageFilter(String counterName) { return _usageFilterIPInput; } else if (counterName.contains(_usageFilterIPOutput.getCounterIdentifier())) { return _usageFilterIPOutput; - } + } return null; } @@ -3318,7 +3338,7 @@ private String getUsageAnswerKey(UsageFilter filter, String counterName) { return getIpAddress(counterName); } else { return null; - } + } } private Map getBytesMap(ExternalNetworkResourceUsageAnswer answer, UsageFilter filter, String usageAnswerKey) { @@ -3328,22 +3348,22 @@ private Map getBytesMap(ExternalNetworkResourceUsageAnswer answe return answer.ipBytes; } else { return null; - } + } } private void updateUsageAnswer(ExternalNetworkResourceUsageAnswer answer, String counterName, long byteCount) { if (counterName == null || byteCount <= 0) { - return; - } + return; + } - UsageFilter filter = getUsageFilter(counterName); + UsageFilter filter = getUsageFilter(counterName); if (filter == null) { s_logger.debug("Failed to parse counter name in usage answer: " + counterName); return; } - String usageAnswerKey = getUsageAnswerKey(filter, counterName); + String usageAnswerKey = getUsageAnswerKey(filter, counterName); Map bytesMap = getBytesMap(answer, filter, usageAnswerKey); - updateBytesMap(bytesMap, filter, usageAnswerKey, byteCount); + updateBytesMap(bytesMap, filter, usageAnswerKey, byteCount); } /* @@ -3363,7 +3383,7 @@ private String sendRequestPrim(PrintWriter sendStream, BufferedReader recvStream sendStream.write(xmlRequest); sendStream.flush(); - String line = ""; + String line = ""; while ((line = recvStream.readLine()) != null) { xmlResponseBuffer.append(line); if (line.contains("")) { @@ -3488,48 +3508,48 @@ private boolean sendRequestAndCheckResponse(SrxCommand command, String xmlReques return checkResponse(xmlResponse, errorKeyAndValue, key, value); } - private boolean sendUsageRequestAndCheckResponse(SrxCommand command, String xmlRequest, String... keyAndValue) throws ExecutionException { - boolean errorKeyAndValue = false; - String key; - String value; + private boolean sendUsageRequestAndCheckResponse(SrxCommand command, String xmlRequest, String... keyAndValue) throws ExecutionException { + boolean errorKeyAndValue = false; + String key; + String value; - switch (command) { + switch (command) { - case LOGIN: - key = "status"; - value = "success"; - break; + case LOGIN: + key = "status"; + value = "success"; + break; - case OPEN_CONFIGURATION: - case CLOSE_CONFIGURATION: - errorKeyAndValue = true; - key = "error"; - value = null; - break; + case OPEN_CONFIGURATION: + case CLOSE_CONFIGURATION: + errorKeyAndValue = true; + key = "error"; + value = null; + break; - case COMMIT: - key = "commit-success"; - value = null; - break; + case COMMIT: + key = "commit-success"; + value = null; + break; - case CHECK_IF_EXISTS: - case CHECK_IF_IN_USE: - assert (keyAndValue != null && keyAndValue.length == 2) : "If the SrxCommand is " + command + ", both a key and value must be specified."; + case CHECK_IF_EXISTS: + case CHECK_IF_IN_USE: + assert (keyAndValue != null && keyAndValue.length == 2) : "If the SrxCommand is " + command + ", both a key and value must be specified."; - key = keyAndValue[0]; - value = keyAndValue[1]; - break; + key = keyAndValue[0]; + value = keyAndValue[1]; + break; - default: - key = "load-success"; - value = null; - break; + default: + key = "load-success"; + value = null; + break; - } + } - String xmlResponse = sendUsageRequest(xmlRequest); - return checkResponse(xmlResponse, errorKeyAndValue, key, value); - } + String xmlResponse = sendUsageRequest(xmlRequest); + return checkResponse(xmlResponse, errorKeyAndValue, key, value); + } /* @@ -3576,14 +3596,14 @@ private String setDelete(String xml, boolean delete) { /* * Misc - */ + */ private Long getVlanTag(String vlan) throws ExecutionException { Long publicVlanTag = null; if (!vlan.equals("untagged")) { try { // make sure this vlan is numeric - publicVlanTag = Long.parseLong(BroadcastDomainType.getValue(vlan)); + publicVlanTag = Long.parseLong(BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlan))); } catch (Exception e) { throw new ExecutionException("Unable to parse VLAN tag: " + vlan); } @@ -3602,7 +3622,7 @@ private String genObjectName(String... args) { } } - return objectName; + return objectName; } @@ -3617,13 +3637,13 @@ private Protocol getProtocol(String protocolName) throws ExecutionException { return Protocol.valueOf(protocolName); } catch (Exception e) { throw new ExecutionException("Invalid protocol: " + protocolName); - } + } } private Document getDocument(String xml) throws ExecutionException { StringReader srcNatRuleReader = new StringReader(xml); InputSource srcNatRuleSource = new InputSource(srcNatRuleReader); - Document doc = null; + Document doc = null; try { doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(srcNatRuleSource); @@ -3667,6 +3687,6 @@ public int getRunLevel() { public void setRunLevel(int level) { // TODO Auto-generated method stub - } + } } diff --git a/plugins/network-elements/midonet/pom.xml b/plugins/network-elements/midonet/pom.xml index 19103e0c5a03..012d5967f108 100644 --- a/plugins/network-elements/midonet/pom.xml +++ b/plugins/network-elements/midonet/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/network-elements/netscaler/pom.xml b/plugins/network-elements/netscaler/pom.xml index 3e56d16824d2..35d88d2186e3 100644 --- a/plugins/network-elements/netscaler/pom.xml +++ b/plugins/network-elements/netscaler/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/network-elements/netscaler/resources/META-INF/cloudstack/netscaler/module.properties b/plugins/network-elements/netscaler/resources/META-INF/cloudstack/netscaler/module.properties new file mode 100644 index 000000000000..2f1b641ae1d3 --- /dev/null +++ b/plugins/network-elements/netscaler/resources/META-INF/cloudstack/netscaler/module.properties @@ -0,0 +1,18 @@ +# 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. +name=netscaler +parent=network \ No newline at end of file diff --git a/plugins/network-elements/netscaler/resources/META-INF/cloudstack/netscaler/spring-netscaler-context.xml b/plugins/network-elements/netscaler/resources/META-INF/cloudstack/netscaler/spring-netscaler-context.xml new file mode 100644 index 000000000000..b70398cd9e06 --- /dev/null +++ b/plugins/network-elements/netscaler/resources/META-INF/cloudstack/netscaler/spring-netscaler-context.xml @@ -0,0 +1,35 @@ + + + + + + + + + diff --git a/plugins/network-elements/netscaler/src/com/cloud/api/commands/AddNetscalerLoadBalancerCmd.java b/plugins/network-elements/netscaler/src/com/cloud/api/commands/AddNetscalerLoadBalancerCmd.java index d04a183139ae..155247fc9204 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/api/commands/AddNetscalerLoadBalancerCmd.java +++ b/plugins/network-elements/netscaler/src/com/cloud/api/commands/AddNetscalerLoadBalancerCmd.java @@ -59,7 +59,7 @@ public class AddNetscalerLoadBalancerCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.GSLB_PROVIDER, type = CommandType.BOOLEAN, required = false, description = "true if NetScaler device being added is for providing GSLB service") - private boolean isGslbProvider; + private Boolean isGslbProvider; @Parameter(name = ApiConstants.GSLB_PROVIDER_PUBLIC_IP, type = CommandType.STRING, required = false, description = "public IP of the site") @@ -69,6 +69,12 @@ public class AddNetscalerLoadBalancerCmd extends BaseAsyncCmd { description = "public IP of the site") private String gslbSitePrivateIp; + @Parameter(name = ApiConstants.EXCLUSIVE_GSLB_PROVIDER, + type = CommandType.BOOLEAN, + required = false, + description = "true if NetScaler device being added is for providing GSLB service exclusively and can not be used for LB") + private Boolean isExclusiveGslbProvider; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -94,7 +100,19 @@ public String getDeviceType() { } public boolean isGslbProvider() { - return isGslbProvider; + if (isGslbProvider != null) { + return isGslbProvider; + } else { + return false; + } + } + + public boolean isExclusiveGslbProvider() { + if (isExclusiveGslbProvider != null) { + return isExclusiveGslbProvider; + } else { + return false; + } } public String getSitePublicIp() { diff --git a/plugins/network-elements/netscaler/src/com/cloud/api/response/NetscalerLoadBalancerResponse.java b/plugins/network-elements/netscaler/src/com/cloud/api/response/NetscalerLoadBalancerResponse.java index 1348788da25f..6abbc0792d0e 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/api/response/NetscalerLoadBalancerResponse.java +++ b/plugins/network-elements/netscaler/src/com/cloud/api/response/NetscalerLoadBalancerResponse.java @@ -63,7 +63,12 @@ public class NetscalerLoadBalancerResponse extends BaseResponse { @SerializedName(ApiConstants.GSLB_PROVIDER) @Param(description="true if NetScaler device is provisioned to be a GSLB service provider") private Boolean isGslbProvider; - @SerializedName(ApiConstants.GSLB_PROVIDER_PUBLIC_IP) @Param(description="public IP of the NetScaler representing GSLB site") + @SerializedName(ApiConstants.EXCLUSIVE_GSLB_PROVIDER) + @Param(description = "true if NetScaler device is provisioned exclusively to be a GSLB service provider") + private Boolean isExclusiveGslbProvider; + + @SerializedName(ApiConstants.GSLB_PROVIDER_PUBLIC_IP) + @Param(description = "public IP of the NetScaler representing GSLB site") private String gslbSitePublicIp; @SerializedName(ApiConstants.GSLB_PROVIDER_PRIVATE_IP) @Param(description="private IP of the NetScaler representing GSLB site") @@ -122,6 +127,10 @@ public void setGslbProvider(boolean isGslbProvider) { this.isGslbProvider = isGslbProvider; } + public void setExclusiveGslbProvider(boolean isExclusiveGslbProvider) { + this.isExclusiveGslbProvider = isExclusiveGslbProvider; + } + public void setGslbSitePublicIp(String publicIP) { this.gslbSitePublicIp = publicIP; } diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java index de3d7e866657..2ed2605a19f4 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java +++ b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java @@ -381,9 +381,14 @@ public ExternalLoadBalancerDeviceVO addNetscalerLoadBalancer(AddNetscalerLoadBal } - ExternalLoadBalancerDeviceVO lbDeviceVO = addExternalLoadBalancer(cmd.getPhysicalNetworkId(), cmd.getUrl(), - cmd.getUsername(), cmd.getPassword(), deviceName, new NetscalerResource(), cmd.isGslbProvider(), - cmd.getSitePublicIp(), cmd.getSitePrivateIp()); + if (cmd.isExclusiveGslbProvider() && !cmd.isGslbProvider()) { + throw new InvalidParameterValueException("NetScaler can be provisioned to be exclusive GSLB service provider" + + " only if its being configured as GSLB service provider also."); + } + + ExternalLoadBalancerDeviceVO lbDeviceVO = + addExternalLoadBalancer(cmd.getPhysicalNetworkId(), cmd.getUrl(), cmd.getUsername(), cmd.getPassword(), deviceName, new NetscalerResource(), + cmd.isGslbProvider(), cmd.isExclusiveGslbProvider(), cmd.getSitePublicIp(), cmd.getSitePrivateIp()); return lbDeviceVO; } @@ -605,6 +610,7 @@ public NetscalerLoadBalancerResponse createNetscalerLoadBalancerResponse(Externa response.setObjectName("netscalerloadbalancer"); response.setGslbProvider(lbDeviceVO.getGslbProvider()); + response.setExclusiveGslbProvider(lbDeviceVO.getExclusiveGslbProvider()); response.setGslbSitePublicIp(lbDeviceVO.getGslbSitePublicIP()); response.setGslbSitePrivateIp(lbDeviceVO.getGslbSitePrivateIP()); diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java b/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java index e48d31d3f0ab..4cd70cb78847 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java +++ b/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java @@ -16,6 +16,9 @@ // under the License. package com.cloud.network.resource; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.security.cert.Certificate; import java.util.ArrayList; import java.util.Formatter; import java.util.HashMap; @@ -26,9 +29,14 @@ import javax.naming.ConfigurationException; import com.citrix.netscaler.nitro.resource.config.ssl.sslcertkey; +import com.citrix.netscaler.nitro.resource.config.ssl.sslcertkey_sslvserver_binding; +import com.citrix.netscaler.nitro.resource.config.ssl.sslcertlink; import com.citrix.netscaler.nitro.resource.config.ssl.sslvserver_sslcertkey_binding; import com.cloud.network.lb.LoadBalancingRule.LbSslCert; +import com.cloud.utils.security.CertificateHelper; import com.cloud.utils.ssh.SshHelper; +import com.google.common.collect.Lists; +import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.log4j.Logger; import com.citrix.netscaler.nitro.exception.nitro_exception; @@ -119,6 +127,7 @@ import com.cloud.utils.Pair; import com.cloud.utils.exception.ExecutionException; import com.cloud.utils.net.NetUtils; +import org.bouncycastle.openssl.PEMWriter; class NitroError { static final int NS_RESOURCE_EXISTS = 273; @@ -664,25 +673,61 @@ private synchronized Answer execute(LoadBalancerConfigCommand cmd, int numRetrie } - - if(sslCert != null && lbProtocol.equals(NetUtils.SSL_PROTO)) { - if ( sslCert.isRevoked() ){ + if (sslCert != null && lbProtocol.equalsIgnoreCase(NetUtils.SSL_PROTO)) { + if (sslCert.isRevoked()) { deleteCert = true; } else{ - String certName = generateSslCertName(srcIp, srcPort); - String keyName = generateSslKeyName(srcIp, srcPort); - String certKeyName = generateSslCertKeyName(srcIp, srcPort); + // If there is a chain, that should go first to the NS + + String previousCertKeyName = null; + + if ( sslCert.getChain() != null ) { + List chainList = CertificateHelper.parseChain(sslCert.getChain()); + // go from ROOT to intermediate CAs + for ( Certificate intermediateCert : Lists.reverse(chainList)){ + + String fingerPrint=CertificateHelper.generateFingerPrint(intermediateCert); + String intermediateCertKeyName = generateSslCertKeyName(fingerPrint); + String intermediateCertFileName = intermediateCertKeyName + ".pem"; + + if (! SSL.isSslCertKeyPresent(_netscalerService, intermediateCertKeyName)) { + byte[] certData= intermediateCert.getEncoded(); + StringWriter textWriter = new StringWriter(); + PEMWriter pemWriter = new PEMWriter(textWriter); + pemWriter.writeObject(intermediateCert); + pemWriter.flush(); - if ( SSL.isSslCertKeyPresent(_netscalerService, certKeyName)){ - SSL.deleteSslCertKey(_netscalerService, certKeyName); + SSL.uploadCert(_ip, _username, _password, intermediateCertFileName, textWriter.toString().getBytes()); + SSL.createSslCertKey(_netscalerService, intermediateCertFileName, null, intermediateCertKeyName, null); + } + + if ( previousCertKeyName != null && ! SSL.certLinkExists(_netscalerService, intermediateCertKeyName, previousCertKeyName)){ + SSL.linkCerts(_netscalerService, intermediateCertKeyName, previousCertKeyName); + } + + previousCertKeyName = intermediateCertKeyName; + } } + String certFilename = generateSslCertName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files + String keyFilename = generateSslKeyName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files + String certKeyName = generateSslCertKeyName(sslCert.getFingerprint()); - SSL.uploadCert(_ip, _username, _password, certName, sslCert.getCert().getBytes()); - SSL.uploadKey(_ip, _username, _password, keyName, sslCert.getKey().getBytes()); + ByteArrayOutputStream certDataStream = new ByteArrayOutputStream( ); + certDataStream.write(sslCert.getCert().getBytes()); + + if (! SSL.isSslCertKeyPresent(_netscalerService, certKeyName)) { + + SSL.uploadCert(_ip, _username, _password, certFilename, certDataStream.toByteArray()); + SSL.uploadKey(_ip, _username, _password, keyFilename, sslCert.getKey().getBytes()); + SSL.createSslCertKey(_netscalerService, certFilename, keyFilename, certKeyName, sslCert.getPassword()); + } + + if (previousCertKeyName != null && ! SSL.certLinkExists(_netscalerService, certKeyName, previousCertKeyName)){ + SSL.linkCerts(_netscalerService, certKeyName, previousCertKeyName); + } - SSL.createSslCertKey(_netscalerService, certName, keyName, certKeyName, sslCert.getPassword()); SSL.bindCertKeyToVserver(_netscalerService, certKeyName, nsVirtualServerName); } @@ -773,18 +818,50 @@ private synchronized Answer execute(LoadBalancerConfigCommand cmd, int numRetrie } if ( sslCert != null && deleteCert){ - String certName = generateSslCertName(srcIp, srcPort); - String keyName = generateSslKeyName(srcIp, srcPort); - String certKeyName = generateSslCertKeyName(srcIp, srcPort); + String certFilename = generateSslCertName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files + String keyFilename = generateSslKeyName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files + String certKeyName = generateSslCertKeyName(sslCert.getFingerprint()); // unbind before deleting - if ( nsVirtualServerExists(nsVirtualServerName) ){ + if (nsVirtualServerExists(nsVirtualServerName) && + SSL.isSslCertKeyPresent(_netscalerService, certKeyName) && + SSL.isBoundToVserver(_netscalerService, certKeyName, nsVirtualServerName)) { SSL.unbindCertKeyFromVserver(_netscalerService, certKeyName, nsVirtualServerName); } - SSL.deleteSslCertKey(_netscalerService, certKeyName); - SSL.deleteCertFile(_ip, _username, _password, certName); - SSL.deleteKeyFile(_ip, _username, _password, keyName); + if (SSL.isSslCertKeyPresent(_netscalerService, certKeyName)) { + + SSL.deleteSslCertKey(_netscalerService, certKeyName); + SSL.deleteCertFile(_ip, _username, _password, certFilename); + SSL.deleteKeyFile(_ip, _username, _password, keyFilename); + } + + + /* + * Check and delete intermediate certs: + * we can delete an intermediate cert if no other + * cert references it as the athority + */ + + if ( sslCert.getChain() != null ) { + List chainList = CertificateHelper.parseChain(sslCert.getChain()); + //go from intermediate CAs to ROOT + for ( Certificate intermediateCert : chainList){ + + String fingerPrint=CertificateHelper.generateFingerPrint(intermediateCert); + String intermediateCertKeyName = generateSslCertKeyName(fingerPrint); + String intermediateCertFileName = intermediateCertKeyName + ".pem"; + + if (SSL.isSslCertKeyPresent(_netscalerService, intermediateCertKeyName) && + ! SSL.isCaforCerts(_netscalerService, intermediateCertKeyName)) { + SSL.deleteSslCertKey(_netscalerService, intermediateCertKeyName); + SSL.deleteCertFile(_ip, _username, _password, intermediateCertFileName); + }else { + break;// if this cert has another certificate as a child then stop at this point because we need the whole chain + } + + } + } } } @@ -1737,7 +1814,7 @@ private static boolean isSslCertKeyPresent(nitro_service ns, String certKeyName) return false; } - private static void deleteSslCertKey(nitro_service ns, String certKeyName) throws ExecutionException { + private static void deleteSslCertKey(nitro_service ns, String certKeyName) throws ExecutionException { try { sslcertkey certkey = new sslcertkey(); @@ -1752,21 +1829,23 @@ private static void deleteSslCertKey(nitro_service ns, String certKeyName) throw } - private static void deleteCertFile(String nsIp, String username, String password, String certName) throws Exception { - SshHelper.sshExecute(nsIp,SSH_PORT,username,null,password,"shell rm " + SSL_CERT_PATH + certName); + private static void deleteCertFile(String nsIp, String username, String password, String certFilename) throws Exception { + SshHelper.sshExecute(nsIp,SSH_PORT,username,null,password,"shell rm " + SSL_CERT_PATH + certFilename); } - private static void deleteKeyFile(String nsIp, String username, String password, String keyName) throws Exception { - SshHelper.sshExecute(nsIp,SSH_PORT,username,null,password,"shell rm " + SSL_CERT_PATH + keyName); + private static void deleteKeyFile(String nsIp, String username, String password, String keyFilename) throws Exception { + SshHelper.sshExecute(nsIp, SSH_PORT, username, null, password, "shell rm " + SSL_CERT_PATH + keyFilename); } - private static void createSslCertKey(nitro_service ns, String certName, String keyName, String certKeyName, String password) throws ExecutionException { + private static void createSslCertKey(nitro_service ns, String certFilename, String keyFilename, String certKeyName, String password) throws ExecutionException { s_logger.debug("Adding cert to netscaler"); try { sslcertkey certkey = new sslcertkey(); certkey.set_certkey(certKeyName); - certkey.set_cert(SSL_CERT_PATH + certName); - certkey.set_key(SSL_CERT_PATH + keyName); + certkey.set_cert(SSL_CERT_PATH + certFilename); + + if ( keyFilename != null ) + certkey.set_key(SSL_CERT_PATH + keyFilename); if( password != null ) { certkey.set_passplain(password); @@ -1832,19 +1911,18 @@ private static void unbindCertKeyFromVserver(nitro_service ns, String certKeyNam } - - private static void uploadCert(String nsIp, String user, String password, String certName, byte[] certData) throws ExecutionException { + private static void uploadCert(String nsIp, String user, String password, String certFilename, byte[] certData) throws ExecutionException { try { - SshHelper.scpTo(nsIp,SSH_PORT,user,null,password, SSL_CERT_PATH, certData, certName, null); + SshHelper.scpTo(nsIp,SSH_PORT,user,null,password, SSL_CERT_PATH, certData, certFilename, null); } catch (Exception e){ throw new ExecutionException("Failed to copy private key to device " + e.getMessage()); } } - private static void uploadKey(String nsIp, String user, String password, String keyName, byte[] keyData) throws ExecutionException { + private static void uploadKey(String nsIp, String user, String password, String keyFilename, byte[] keyData) throws ExecutionException { try { - SshHelper.scpTo(nsIp, SSH_PORT, user, null, password, SSL_CERT_PATH, keyData, keyName, null); - } catch (Exception e){ + SshHelper.scpTo(nsIp, SSH_PORT, user, null, password, SSL_CERT_PATH, keyData, keyFilename, null); + } catch (Exception e) { throw new ExecutionException("Failed to copy private key to device " + e.getMessage()); } } @@ -1853,7 +1931,7 @@ private static void uploadKey(String nsIp, String user, String password, String private static void enableSslFeature(nitro_service ns) throws ExecutionException { try { base_response result = ns.enable_features(new String[]{"SSL"}); - if( result.errorcode != 0 ) + if (result.errorcode != 0) throw new ExecutionException("Unable to enable SSL on LB"); } catch (nitro_exception e){ throw new ExecutionException("Failed to enable ssl feature on load balancer due to " + e.getMessage()); @@ -1880,7 +1958,80 @@ public static boolean checkSslFeature(nitro_service ns) throws ExecutionExceptio } } + public static boolean certLinkExists(nitro_service ns, String userCertName, String caCertName) throws ExecutionException { + try { + // check if there is a link from userCertName to caCertName + + sslcertkey userCert = sslcertkey.get(ns,userCertName); + String nsCaCert = userCert.get_linkcertkeyname(); + if (nsCaCert != null && nsCaCert.equals(caCertName)) + return true; + + } catch (nitro_exception e) { + throw new ExecutionException("Failed to check cert link on load balancer to " + e.getMessage()); + } catch (Exception e) { + throw new ExecutionException("Failed to check cert link on load balancer due to " + e.getMessage()); + } + return false; + } + + public static void linkCerts(nitro_service ns, String userCertName, String caCertName) throws ExecutionException { + try { + + // the assumption is that that both userCertName and caCertName are present on NS + + sslcertkey caCert = sslcertkey.get(ns, caCertName); + sslcertkey userCert = sslcertkey.get(ns, userCertName); + + sslcertkey linkResource = new sslcertkey(); + + // link user cert to CA cert + linkResource.set_certkey(userCert.get_certkey()); + linkResource.set_linkcertkeyname(caCert.get_certkey()); + sslcertkey.link(ns, linkResource); + + } catch (nitro_exception e) { + throw new ExecutionException("Failed to check cert link on load balancer to " + e.getMessage()); + } catch (Exception e) { + throw new ExecutionException("Failed to check cert link on load balancer due to " + e.getMessage()); + } + + } + + public static boolean isCaforCerts(nitro_service ns, String caCertName) throws ExecutionException { + // check if this certificate serves as a CA for other certificates + try { + sslcertlink[] childLinks = sslcertlink.get_filtered(ns,"linkcertkeyname:" + caCertName); + if(childLinks != null && childLinks.length > 0){ + return true; + } + + } catch (nitro_exception e) { + throw new ExecutionException("Failed to check cert link on load balancer to " + e.getMessage()); + } catch (Exception e) { + throw new ExecutionException("Failed to check cert link on load balancer due to " + e.getMessage()); + } + return false; + + } + + public static boolean isBoundToVserver(nitro_service ns, String certKeyName, String nsVirtualServerName) throws ExecutionException { + try { + + sslcertkey_sslvserver_binding[] cert_vs_binding = sslcertkey_sslvserver_binding.get_filtered(ns, certKeyName, "vservername:" + nsVirtualServerName); + if(cert_vs_binding != null && cert_vs_binding.length > 0){ + return true; + } + + } catch (nitro_exception e) { + throw new ExecutionException("Failed to check cert link on load balancer to " + e.getMessage()); + } catch (Exception e) { + throw new ExecutionException("Failed to check cert link on load balancer due to " + e.getMessage()); + } + return false; + + } } @@ -3624,16 +3775,22 @@ private String generateSnmpMetricName(String counterName) { return counterName.replace(' ', '_'); } - private String generateSslCertName(String srcIp, long srcPort) { + private String generateSslCertName(String fingerPrint) { // maximum length supported by NS is 31 - return genObjectName("Cloud-Cert", srcIp, srcPort); + // the first 20 characters of the SHA-1 checksum are the unique id + String uniqueId = fingerPrint.replace(":","").substring(0,20); + + return genObjectName("Cloud-Cert", uniqueId); } - private String generateSslKeyName(String srcIp, long srcPort) { - return genObjectName("Cloud-Key", srcIp, srcPort); + private String generateSslKeyName(String fingerPrint) { + String uniqueId = fingerPrint.replace(":","").substring(0,20); + return genObjectName("Cloud-Key", uniqueId); } - private String generateSslCertKeyName(String srcIp, long srcPort) { - return genObjectName("Cloud-CertKey", srcIp, srcPort); + + private String generateSslCertKeyName(String fingerPrint){ + String uniqueId = fingerPrint.replace(":","").substring(0,20); + return genObjectName("Cloud-Cert", uniqueId); } private String genObjectName(Object... args) { diff --git a/plugins/network-elements/nicira-nvp/pom.xml b/plugins/network-elements/nicira-nvp/pom.xml index 9341c93c381a..5e227f13dd15 100644 --- a/plugins/network-elements/nicira-nvp/pom.xml +++ b/plugins/network-elements/nicira-nvp/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElement.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElement.java index 3e9e16a8a6fe..bcbcc8290b19 100644 --- a/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElement.java +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElement.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.network.element; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -253,25 +254,29 @@ public boolean implement(Network network, NetworkOffering offering, network.getId(), Service.SourceNat, Provider.NiciraNvp)) { s_logger.debug("Apparently we are supposed to provide SourceNat on this network"); - PublicIp sourceNatIp = _ipAddrMgr - .assignSourceNatIpAddressToGuestNetwork(owner, network); - String publicCidr = sourceNatIp.getAddress().addr() + "/" - + NetUtils.getCidrSize(sourceNatIp.getVlanNetmask()); - String internalCidr = network.getGateway() + "/" - + network.getCidr().split("/")[1]; - long vlanid = (Vlan.UNTAGGED.equals(sourceNatIp.getVlanTag())) ? 0 - : Long.parseLong(sourceNatIp.getVlanTag()); - - CreateLogicalRouterCommand cmd = new CreateLogicalRouterCommand( - niciraNvpHost.getDetail("l3gatewayserviceuuid"), vlanid, - BroadcastDomainType.getValue(network.getBroadcastUri()), - "router-" + network.getDisplayText(), publicCidr, - sourceNatIp.getGateway(), internalCidr, context - .getDomain().getName() - + "-" - + context.getAccount().getAccountName()); - CreateLogicalRouterAnswer answer = (CreateLogicalRouterAnswer)_agentMgr - .easySend(niciraNvpHost.getId(), cmd); + PublicIp sourceNatIp = _ipAddrMgr.assignSourceNatIpAddressToGuestNetwork(owner, network); + String publicCidr = sourceNatIp.getAddress().addr() + "/" + NetUtils.getCidrSize(sourceNatIp.getVlanNetmask()); + String internalCidr = network.getGateway() + "/" + network.getCidr().split("/")[1]; + // assuming a vlan: + String vtag = sourceNatIp.getVlanTag(); + BroadcastDomainType tiep = null; + try { + tiep = BroadcastDomainType.getTypeOf(vtag); + } catch (URISyntaxException use) { + throw new CloudRuntimeException("vlantag for sourceNatIp is not valid: " + vtag, use); + } + if (tiep == BroadcastDomainType.Vlan) { + vtag = BroadcastDomainType.Vlan.getValueFrom(BroadcastDomainType.fromString(vtag)); + } else if (!(tiep == BroadcastDomainType.UnDecided || tiep == BroadcastDomainType.Native)) { + throw new CloudRuntimeException("only vlans are supported for sourceNatIp, at this moment: " + vtag); + } + long vlanid = (Vlan.UNTAGGED.equals(vtag)) ? 0 : Long.parseLong(vtag); + + CreateLogicalRouterCommand cmd = + new CreateLogicalRouterCommand(niciraNvpHost.getDetail("l3gatewayserviceuuid"), vlanid, BroadcastDomainType.getValue(network.getBroadcastUri()), + "router-" + network.getDisplayText(), publicCidr, sourceNatIp.getGateway(), internalCidr, context.getDomain().getName() + "-" + + context.getAccount().getAccountName()); + CreateLogicalRouterAnswer answer = (CreateLogicalRouterAnswer)_agentMgr.easySend(niciraNvpHost.getId(), cmd); if (answer.getResult() == false) { s_logger.error("Failed to create Logical Router for network " + network.getDisplayText()); diff --git a/plugins/network-elements/ovs/pom.xml b/plugins/network-elements/ovs/pom.xml index 40674f507419..c321b9470ea9 100644 --- a/plugins/network-elements/ovs/pom.xml +++ b/plugins/network-elements/ovs/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java b/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java index 0366143a7e77..6ebc0709e9a7 100644 --- a/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java +++ b/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.network.element; +import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -53,12 +54,14 @@ public boolean destroy(Network network, ReservationContext context) @Override public Map> getCapabilities() { - return null; + Map> capabilities = new HashMap>(); + capabilities.put(Service.Connectivity, null); + return capabilities; } @Override public Provider getProvider() { - return null; + return Network.Provider.Ovs; } @Override diff --git a/plugins/network-elements/palo-alto/pom.xml b/plugins/network-elements/palo-alto/pom.xml index 50b4c134f604..092731133b34 100644 --- a/plugins/network-elements/palo-alto/pom.xml +++ b/plugins/network-elements/palo-alto/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/AddExternalFirewallCmd.java b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/AddExternalFirewallCmd.java deleted file mode 100644 index 84ee869866aa..000000000000 --- a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/AddExternalFirewallCmd.java +++ /dev/null @@ -1,112 +0,0 @@ -// 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.api.commands; - -import javax.inject.Inject; - -import org.apache.cloudstack.api.response.ZoneResponse; -import org.apache.log4j.Logger; - -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.ServerApiException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.host.Host; -import com.cloud.network.element.PaloAltoFirewallElementService; -import org.apache.cloudstack.api.response.ExternalFirewallResponse; -import com.cloud.user.Account; -import com.cloud.utils.exception.CloudRuntimeException; - -@APICommand(name = "addExternalFirewall", description="Adds an external firewall appliance", responseObject = ExternalFirewallResponse.class) -public class AddExternalFirewallCmd extends BaseCmd { - public static final Logger s_logger = Logger.getLogger(AddExternalFirewallCmd.class.getName()); - private static final String s_name = "addexternalfirewallresponse"; - - ///////////////////////////////////////////////////// - //////////////// API parameters ///////////////////// - ///////////////////////////////////////////////////// - - @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class, - required = true, description="Zone in which to add the external firewall appliance.") - private Long zoneId; - - @Parameter(name=ApiConstants.URL, type=CommandType.STRING, required = true, description="URL of the external firewall appliance.") - private String url; - - @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required = true, description="Username of the external firewall appliance.") - private String username; - - @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required = true, description="Password of the external firewall appliance.") - private String password; - - /////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// - - public Long getZoneId() { - return zoneId; - } - - public String getUrl() { - return url; - } - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } - - - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// - - @Inject PaloAltoFirewallElementService _paElementService; - - @Override - public String getCommandName() { - return s_name; - } - - @Override - public long getEntityOwnerId() { - return Account.ACCOUNT_ID_SYSTEM; - } - - @SuppressWarnings("deprecation") - @Override - public void execute(){ - try { - Host externalFirewall = _paElementService.addExternalFirewall(this); - ExternalFirewallResponse response = _paElementService.createExternalFirewallResponse(externalFirewall); - response.setObjectName("externalfirewall"); - response.setResponseName(getCommandName()); - this.setResponseObject(response); - } catch (InvalidParameterValueException ipve) { - throw new ServerApiException(ApiErrorCode.PARAM_ERROR, ipve.getMessage()); - } catch (CloudRuntimeException cre) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, cre.getMessage()); - } - } -} - diff --git a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/DeleteExternalFirewallCmd.java b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/DeleteExternalFirewallCmd.java deleted file mode 100644 index 93f752ac47c8..000000000000 --- a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/DeleteExternalFirewallCmd.java +++ /dev/null @@ -1,88 +0,0 @@ -// 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.api.commands; - -import javax.inject.Inject; - -import org.apache.cloudstack.api.response.HostResponse; -import org.apache.log4j.Logger; - -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.response.SuccessResponse; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.network.element.PaloAltoFirewallElementService; -import com.cloud.user.Account; - -@APICommand(name = "deleteExternalFirewall", description="Deletes an external firewall appliance.", responseObject = SuccessResponse.class) -public class DeleteExternalFirewallCmd extends BaseCmd { - public static final Logger s_logger = Logger.getLogger(DeleteExternalFirewallCmd.class.getName()); - private static final String s_name = "deleteexternalfirewallresponse"; - - ///////////////////////////////////////////////////// - //////////////// API parameters ///////////////////// - ///////////////////////////////////////////////////// - - @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = HostResponse.class, - required = true, description="Id of the external firewall appliance.") - private Long id; - - /////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// - - public Long getId() { - return id; - } - - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// - - @Inject PaloAltoFirewallElementService _paElementService; - - @Override - public String getCommandName() { - return s_name; - } - - @Override - public long getEntityOwnerId() { - return Account.ACCOUNT_ID_SYSTEM; - } - - @SuppressWarnings("deprecation") - @Override - public void execute(){ - try { - boolean result = _paElementService.deleteExternalFirewall(this); - if (result) { - SuccessResponse response = new SuccessResponse(getCommandName()); - response.setResponseName(getCommandName()); - this.setResponseObject(response); - } else { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete external firewall."); - } - } catch (InvalidParameterValueException e) { - throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Failed to delete external firewall."); - } - } -} diff --git a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListExternalFirewallsCmd.java b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListExternalFirewallsCmd.java deleted file mode 100644 index ebced7e20391..000000000000 --- a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListExternalFirewallsCmd.java +++ /dev/null @@ -1,88 +0,0 @@ -// 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.api.commands; - -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; - -import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd; -import org.apache.cloudstack.api.response.ZoneResponse; -import org.apache.log4j.Logger; - -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseListCmd; -import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.response.ListResponse; -import com.cloud.host.Host; -import com.cloud.network.element.PaloAltoFirewallElementService; -import org.apache.cloudstack.api.response.ExternalFirewallResponse; - -@APICommand(name = "listExternalFirewalls", description="List external firewall appliances.", responseObject = ExternalFirewallResponse.class) -public class ListExternalFirewallsCmd extends BaseListCmd { - public static final Logger s_logger = Logger.getLogger(ListServiceOfferingsCmd.class.getName()); - private static final String s_name = "listexternalfirewallsresponse"; - - ///////////////////////////////////////////////////// - //////////////// API parameters ///////////////////// - ///////////////////////////////////////////////////// - - @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class, - required = true, description="zone Id") - private long zoneId; - - ///////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// - - public long getZoneId() { - return zoneId; - } - - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// - - @Inject PaloAltoFirewallElementService _paElementService; - - @Override - public String getCommandName() { - return s_name; - } - - @SuppressWarnings("deprecation") - @Override - public void execute(){ - - List externalFirewalls = _paElementService.listExternalFirewalls(this); - - ListResponse listResponse = new ListResponse(); - List responses = new ArrayList(); - for (Host externalFirewall : externalFirewalls) { - ExternalFirewallResponse response = _paElementService.createExternalFirewallResponse(externalFirewall); - response.setObjectName("externalfirewall"); - response.setResponseName(getCommandName()); - responses.add(response); - } - - listResponse.setResponses(responses); - listResponse.setResponseName(getCommandName()); - this.setResponseObject(listResponse); - } -} diff --git a/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoExternalFirewallElement.java b/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoExternalFirewallElement.java index 3eb802ed8f65..108d5a46ae13 100644 --- a/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoExternalFirewallElement.java +++ b/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoExternalFirewallElement.java @@ -30,12 +30,9 @@ import org.apache.log4j.Logger; import com.cloud.api.ApiDBUtils; -import com.cloud.api.commands.AddExternalFirewallCmd; import com.cloud.api.commands.AddPaloAltoFirewallCmd; import com.cloud.api.commands.ConfigurePaloAltoFirewallCmd; -import com.cloud.api.commands.DeleteExternalFirewallCmd; import com.cloud.api.commands.DeletePaloAltoFirewallCmd; -import com.cloud.api.commands.ListExternalFirewallsCmd; import com.cloud.api.commands.ListPaloAltoFirewallNetworksCmd; import com.cloud.api.commands.ListPaloAltoFirewallsCmd; import com.cloud.api.response.PaloAltoFirewallResponse; @@ -295,82 +292,12 @@ public boolean canEnableIndividualServices() { return true; } - @Override - @Deprecated - // should use more generic addNetworkDevice command to add firewall - public Host addExternalFirewall(AddExternalFirewallCmd cmd) { - Long zoneId = cmd.getZoneId(); - DataCenterVO zone = null; - PhysicalNetworkVO pNetwork = null; - HostVO fwHost = null; - - zone = _dcDao.findById(zoneId); - if (zone == null) { - throw new InvalidParameterValueException("Could not find zone with ID: " + zoneId); - } - - List physicalNetworks = _physicalNetworkDao.listByZone(zoneId); - if ((physicalNetworks == null) || (physicalNetworks.size() > 1)) { - throw new InvalidParameterValueException("There are no physical networks or multiple physical networks configured in zone with ID: " - + zoneId + " to add this device."); - } - pNetwork = physicalNetworks.get(0); - - String deviceType = NetworkDevice.PaloAltoFirewall.getName(); - ExternalFirewallDeviceVO fwDeviceVO = addExternalFirewall(pNetwork.getId(), cmd.getUrl(), cmd.getUsername(), cmd.getPassword(), deviceType, new PaloAltoResource()); - if (fwDeviceVO != null) { - fwHost = _hostDao.findById(fwDeviceVO.getHostId()); - } - - return fwHost; - } - - @Override - public boolean deleteExternalFirewall(DeleteExternalFirewallCmd cmd) { - return deleteExternalFirewall(cmd.getId()); - } - - @Override - @Deprecated - // should use more generic listNetworkDevice command - public List listExternalFirewalls(ListExternalFirewallsCmd cmd) { - List firewallHosts = new ArrayList(); - Long zoneId = cmd.getZoneId(); - DataCenterVO zone = null; - PhysicalNetworkVO pNetwork = null; - - if (zoneId != null) { - zone = _dcDao.findById(zoneId); - if (zone == null) { - throw new InvalidParameterValueException("Could not find zone with ID: " + zoneId); - } - - List physicalNetworks = _physicalNetworkDao.listByZone(zoneId); - if ((physicalNetworks == null) || (physicalNetworks.size() > 1)) { - throw new InvalidParameterValueException("There are no physical networks or multiple physical networks configured in zone with ID: " - + zoneId + " to add this device."); - } - pNetwork = physicalNetworks.get(0); - } - - firewallHosts.addAll(listExternalFirewalls(pNetwork.getId(), NetworkDevice.PaloAltoFirewall.getName())); - return firewallHosts; - } - - @Override - public ExternalFirewallResponse createExternalFirewallResponse(Host externalFirewall) { - return super.createExternalFirewallResponse(externalFirewall); - } - @Override public List> getCommands() { List> cmdList = new ArrayList>(); - cmdList.add(AddExternalFirewallCmd.class); cmdList.add(AddPaloAltoFirewallCmd.class); cmdList.add(ConfigurePaloAltoFirewallCmd.class); - cmdList.add(DeleteExternalFirewallCmd.class); cmdList.add(DeletePaloAltoFirewallCmd.class); - cmdList.add(ListExternalFirewallsCmd.class); cmdList.add(ListPaloAltoFirewallNetworksCmd.class); cmdList.add(ListPaloAltoFirewallsCmd.class); return cmdList; @@ -382,6 +309,7 @@ public ExternalFirewallDeviceVO addPaloAltoFirewall(AddPaloAltoFirewallCmd cmd) if (!deviceName.equalsIgnoreCase(NetworkDevice.PaloAltoFirewall.getName())) { throw new InvalidParameterValueException("Invalid Palo Alto firewall device type"); } + return addExternalFirewall(cmd.getPhysicalNetworkId(), cmd.getUrl(), cmd.getUsername(), cmd.getPassword(), deviceName, new PaloAltoResource()); } diff --git a/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoFirewallElementService.java b/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoFirewallElementService.java index d2842ab101db..dafae8b61ce2 100644 --- a/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoFirewallElementService.java +++ b/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoFirewallElementService.java @@ -18,12 +18,9 @@ import java.util.List; -import com.cloud.api.commands.AddExternalFirewallCmd; import com.cloud.api.commands.AddPaloAltoFirewallCmd; import com.cloud.api.commands.ConfigurePaloAltoFirewallCmd; -import com.cloud.api.commands.DeleteExternalFirewallCmd; import com.cloud.api.commands.DeletePaloAltoFirewallCmd; -import com.cloud.api.commands.ListExternalFirewallsCmd; import com.cloud.api.commands.ListPaloAltoFirewallNetworksCmd; import com.cloud.api.commands.ListPaloAltoFirewallsCmd; import com.cloud.api.response.PaloAltoFirewallResponse; @@ -72,17 +69,5 @@ public interface PaloAltoFirewallElementService extends PluggableService { public List listNetworks(ListPaloAltoFirewallNetworksCmd cmd); public PaloAltoFirewallResponse createPaloAltoFirewallResponse(ExternalFirewallDeviceVO fwDeviceVO); - - - @Deprecated // API helper function supported for backward compatibility - public Host addExternalFirewall(AddExternalFirewallCmd cmd); - - @Deprecated // API helper function supported for backward compatibility - public boolean deleteExternalFirewall(DeleteExternalFirewallCmd cmd); - - @Deprecated // API helper function supported for backward compatibility - public List listExternalFirewalls(ListExternalFirewallsCmd cmd); - @Deprecated // API helper function supported for backward compatibility - public ExternalFirewallResponse createExternalFirewallResponse(Host externalFirewall); } diff --git a/plugins/network-elements/palo-alto/src/com/cloud/network/resource/PaloAltoResource.java b/plugins/network-elements/palo-alto/src/com/cloud/network/resource/PaloAltoResource.java index 2251ce068511..a4bcf5b92c7e 100644 --- a/plugins/network-elements/palo-alto/src/com/cloud/network/resource/PaloAltoResource.java +++ b/plugins/network-elements/palo-alto/src/com/cloud/network/resource/PaloAltoResource.java @@ -31,6 +31,7 @@ import org.xml.sax.InputSource; import javax.naming.ConfigurationException; import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.dom.DOMSource; import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; @@ -466,11 +467,14 @@ private Answer execute(IpAssocCommand cmd, int numRetries) { String guestVlanSubnet = NetUtils.getCidrSubNet(guestVlanGateway, cidrSize); Long publicVlanTag = null; - if (ip.getBroadcastUri() != null && !ip.getBroadcastUri().equals("untagged")) { - try { - publicVlanTag = Long.parseLong(ip.getBroadcastUri()); - } catch (Exception e) { - throw new ExecutionException("Could not parse public VLAN tag: " + ip.getBroadcastUri()); + if (ip.getBroadcastUri() != null) { + String parsedVlanTag = parsePublicVlanTag(ip.getBroadcastUri()); + if (!parsedVlanTag.equals("untagged")) { + try { + publicVlanTag = Long.parseLong(parsedVlanTag); + } catch (Exception e) { + throw new ExecutionException("Could not parse public VLAN tag: " + parsedVlanTag); + } } } @@ -521,6 +525,9 @@ private void implementGuestNetwork(ArrayList cmdList, GuestNet private void shutdownGuestNetwork(ArrayList cmdList, GuestNetworkType type, Long publicVlanTag, String sourceNatIpAddress, long privateVlanTag, String privateGateway, String privateSubnet, long privateCidrSize) throws ExecutionException { privateSubnet = privateSubnet+"/"+privateCidrSize; + // remove any orphaned egress rules if they exist... + removeOrphanedFirewallRules(cmdList, privateVlanTag); + if (type.equals(GuestNetworkType.SOURCE_NAT)) { manageNetworkIsolation(cmdList, PaloAltoPrimative.DELETE, privateVlanTag, privateSubnet, privateGateway); manageSrcNatRule(cmdList, PaloAltoPrimative.DELETE, type, publicVlanTag, sourceNatIpAddress+"/32", privateVlanTag, privateGateway+"/"+privateCidrSize); @@ -941,12 +948,18 @@ public boolean manageDstNatRule(ArrayList cmdList, PaloAltoPri String dstNatName = genDstNatRuleName(publicIp, rule.getId()); String publicInterfaceName; - String publicVlanTag = rule.getSrcVlanTag(); - if (publicVlanTag == null || publicVlanTag.equals("untagged")) { + String publicVlanTag; + if (rule.getSrcVlanTag() == null) { publicInterfaceName = genPublicInterfaceName(new Long("9999")); } else { - publicInterfaceName = genPublicInterfaceName(new Long(publicVlanTag)); + publicVlanTag = parsePublicVlanTag(rule.getSrcVlanTag()); + if (publicVlanTag.equals("untagged")) { + publicInterfaceName = genPublicInterfaceName(new Long("9999")); + } else { + publicInterfaceName = genPublicInterfaceName(new Long(publicVlanTag)); + } } + switch (prim) { @@ -1083,11 +1096,16 @@ public boolean manageStcNatRule(ArrayList cmdList, PaloAltoPri String stcNatName = genStcNatRuleName(publicIp, rule.getId()); String publicInterfaceName; - String publicVlanTag = rule.getSrcVlanTag(); - if (publicVlanTag == null || publicVlanTag.equals("untagged")) { + String publicVlanTag; + if (rule.getSrcVlanTag() == null) { publicInterfaceName = genPublicInterfaceName(new Long("9999")); } else { - publicInterfaceName = genPublicInterfaceName(new Long(publicVlanTag)); + publicVlanTag = parsePublicVlanTag(rule.getSrcVlanTag()); + if (publicVlanTag.equals("untagged")) { + publicInterfaceName = genPublicInterfaceName(new Long("9999")); + } else { + publicInterfaceName = genPublicInterfaceName(new Long(publicVlanTag)); + } } switch (prim) { @@ -1168,13 +1186,21 @@ public boolean manageStcNatRule(ArrayList cmdList, PaloAltoPri /* * Firewall rule implementation */ - - private String genFirewallRuleName(long id) { + private String genFirewallRuleName(long id) { // ingress return "policy_"+Long.toString(id); } + private String genFirewallRuleName(long id, String vlan) { // egress + return "policy_"+Long.toString(id)+"_"+vlan; + } public boolean manageFirewallRule(ArrayList cmdList, PaloAltoPrimative prim, FirewallRuleTO rule) throws ExecutionException { - String ruleName = genFirewallRuleName(rule.getId()); + String ruleName; + if (rule.getTrafficType() == FirewallRule.TrafficType.Egress) { + ruleName = genFirewallRuleName(rule.getId(), rule.getSrcVlanTag()); + } else { + ruleName = genFirewallRuleName(rule.getId()); + } + switch (prim) { @@ -1201,6 +1227,7 @@ public boolean manageFirewallRule(ArrayList cmdList, PaloAltoP String serviceXML; String protocol = rule.getProtocol(); + String action = "allow"; // Only ICMP will use an Application, so others will be any. if (protocol.equals(Protocol.ICMP.toString())) { @@ -1230,11 +1257,23 @@ public boolean manageFirewallRule(ArrayList cmdList, PaloAltoP serviceXML = "any"; } - if (rule.getTrafficType() == FirewallRule.TrafficType.Egress) { // Network egress rule + // handle different types of fire wall rules (egress | ingress) + if (rule.getTrafficType() == FirewallRule.TrafficType.Egress) { // Egress Rule srcZone = _privateZone; dstZone = _publicZone; dstAddressXML = "any"; - } else { + + // defaults to 'allow', the deny rules are as follows + if (rule.getType() == FirewallRule.FirewallRuleType.System) { + if (!rule.isDefaultEgressPolicy()) { // default of deny && system rule, so deny + action = "deny"; + } + } else { + if (rule.isDefaultEgressPolicy()) { // default is allow && user rule, so deny + action = "deny"; + } + } + } else { // Ingress Rule srcZone = _publicZone; dstZone = _privateZone; dstAddressXML = ""+rule.getSrcIp()+""; @@ -1263,6 +1302,7 @@ public boolean manageFirewallRule(ArrayList cmdList, PaloAltoP } } + // build new rule xml String xml = ""; xml += ""+srcZone+""; xml += ""+dstZone+""; @@ -1270,16 +1310,52 @@ public boolean manageFirewallRule(ArrayList cmdList, PaloAltoP xml += ""+dstAddressXML+""; xml += ""+appXML+""; xml += ""+serviceXML+""; - xml += "allow"; + xml += ""+action+""; xml += "no"; xml += "no"; - if (_threatProfile != null) { // add the threat profile if it exists + if (_threatProfile != null && action.equals("allow")) { // add the threat profile if it exists xml += ""+_threatProfile+""; } - if (_logProfile != null) { // add the log profile if it exists + if (_logProfile != null && action.equals("allow")) { // add the log profile if it exists xml += ""+_logProfile+""; } + boolean has_default = false; + String defaultEgressRule = ""; + if (rule.getTrafficType() == FirewallRule.TrafficType.Egress) { + // check if a default egress rule exists because it always has to be after the other rules. + Map e_params = new HashMap(); + e_params.put("type", "config"); + e_params.put("action", "get"); + e_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_0_"+rule.getSrcVlanTag()+"']"); + String e_response = request(PaloAltoMethod.GET, e_params); + has_default = (validResponse(e_response) && responseNotEmpty(e_response)); + + // there is an existing default rule, so we need to remove it and add it back after the new rule is added. + if (has_default) { + s_logger.debug("Moving the default egress rule after the new rule: "+ruleName); + NodeList response_body; + Document doc = getDocument(e_response); + XPath xpath = XPathFactory.newInstance().newXPath(); + try { + XPathExpression expr = xpath.compile("/response[@status='success']/result/entry/node()"); + response_body = (NodeList) expr.evaluate(doc, XPathConstants.NODESET); + } catch (XPathExpressionException e) { + throw new ExecutionException(e.getCause().getMessage()); + } + for (int i=0; i dd_params = new HashMap(); + dd_params.put("type", "config"); + dd_params.put("action", "delete"); + dd_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_0_"+rule.getSrcVlanTag()+"']"); + cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, dd_params)); + } + } + + // add the new rule... Map a_params = new HashMap(); a_params.put("type", "config"); a_params.put("action", "set"); @@ -1287,6 +1363,17 @@ public boolean manageFirewallRule(ArrayList cmdList, PaloAltoP a_params.put("element", xml); cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, a_params)); + // add back the default rule + if (rule.getTrafficType() == FirewallRule.TrafficType.Egress && has_default) { + Map da_params = new HashMap(); + da_params.put("type", "config"); + da_params.put("action", "set"); + da_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_0_"+rule.getSrcVlanTag()+"']"); + da_params.put("element", defaultEgressRule); + cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, da_params)); + s_logger.debug("Completed move of the default egress rule after rule: "+ruleName); + } + return true; case DELETE: @@ -1308,6 +1395,24 @@ public boolean manageFirewallRule(ArrayList cmdList, PaloAltoP } } + // remove orphaned rules if they exist... + public void removeOrphanedFirewallRules(ArrayList cmdList, long vlan) throws ExecutionException { + Map params = new HashMap(); + params.put("type", "config"); + params.put("action", "get"); + params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[contains(@name, 'policy') and contains(@name, '"+Long.toString(vlan)+"')]"); + String response = request(PaloAltoMethod.GET, params); + boolean has_orphans = (validResponse(response) && responseNotEmpty(response)); + + if (has_orphans) { + Map d_params = new HashMap(); + d_params.put("type", "config"); + d_params.put("action", "delete"); + d_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[contains(@name, 'policy') and contains(@name, '"+Long.toString(vlan)+"')]"); + cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, d_params)); + } + } + /* @@ -1436,7 +1541,6 @@ public boolean managePingProfile(ArrayList cmdList, PaloAltoPr } } - private String genServiceName(String protocol, String dstPorts, String srcPorts) { String name; if (srcPorts == null) { @@ -1937,6 +2041,10 @@ private String genIpIdentifier(String ip) { return ip.replace('.', '-').replace('/', '-'); } + private String parsePublicVlanTag(String uri) { + return uri.replace("vlan://", ""); + } + private Protocol getProtocol(String protocolName) throws ExecutionException { protocolName = protocolName.toLowerCase(); @@ -1966,6 +2074,20 @@ private Document getDocument(String xml) throws ExecutionException { } } + // return an xml node as a string + private String nodeToString(Node node) throws ExecutionException { + StringWriter sw = new StringWriter(); + try { + Transformer t = TransformerFactory.newInstance().newTransformer(); + t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + t.transform(new DOMSource(node), new StreamResult(sw)); + } catch (Throwable t) { + throw new ExecutionException("XML convert error when modifying PA config: "+t.getMessage()); + } + return sw.toString(); + } + + // pretty printing of xml strings private String prettyFormat(String input) { int indent = 4; try { @@ -2000,13 +2122,11 @@ private String prettyFormat(String input) { //@Override public void setName(String name) { // TODO Auto-generated method stub - } //@Override public void setConfigParams(Map params) { // TODO Auto-generated method stub - } //@Override @@ -2025,6 +2145,5 @@ public int getRunLevel() { public void setRunLevel(int level) { // TODO Auto-generated method stub - } - + } } diff --git a/plugins/network-elements/palo-alto/test/com/cloud/network/resource/MockablePaloAltoResource.java b/plugins/network-elements/palo-alto/test/com/cloud/network/resource/MockablePaloAltoResource.java index 9a9eb6e0c2e0..5ffb7ce54de8 100755 --- a/plugins/network-elements/palo-alto/test/com/cloud/network/resource/MockablePaloAltoResource.java +++ b/plugins/network-elements/palo-alto/test/com/cloud/network/resource/MockablePaloAltoResource.java @@ -196,10 +196,10 @@ protected String request(PaloAltoMethod method, Map params) thro } } - // get egress firewall rule | has_egress_fw_rule | policy_0 - if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_0']")) { + // get egress firewall rule | has_egress_fw_rule | policy_0_3954 + if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_0_3954']")) { if (context.containsKey("has_egress_fw_rule") && context.get("has_egress_fw_rule").equals("true")) { - response = "trustuntrust10.3.96.1/20anyanycs_tcp_80allownono"; + response = "trustuntrust10.3.96.1/20anyanycs_tcp_80allownono"; } else { response = ""; } @@ -214,6 +214,11 @@ protected String request(PaloAltoMethod method, Map params) thro } } + // get default egress rule | policy_0_3954 + if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[contains(@name, 'policy') and contains(@name, '3954')]")) { + response = ""; + } + // get destination nat rule (port forwarding) | has_dst_nat_rule if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='dst_nat.192-168-80-103_9']")) { if (context.containsKey("has_dst_nat_rule") && context.get("has_dst_nat_rule").equals("true")) { @@ -296,7 +301,7 @@ protected String request(PaloAltoMethod method, Map params) thro } // add egress firewall rule - if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_0']")) { + if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_0_3954']")) { response = "command succeeded"; context.put("has_egress_fw_rule", "true"); } @@ -329,7 +334,7 @@ protected String request(PaloAltoMethod method, Map params) thro // action = 'delete' if (params.get("action").equals("delete")) { // remove egress firewall rule - if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_0']")) { + if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_0_3954']")) { response = "command succeeded"; context.remove("has_egress_fw_rule"); } diff --git a/plugins/network-elements/stratosphere-ssp/pom.xml b/plugins/network-elements/stratosphere-ssp/pom.xml index ded735e3d694..3621c344c7ab 100644 --- a/plugins/network-elements/stratosphere-ssp/pom.xml +++ b/plugins/network-elements/stratosphere-ssp/pom.xml @@ -25,7 +25,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspClient.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspClient.java index ee4d4558bff7..30630a35d69b 100644 --- a/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspClient.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspClient.java @@ -18,22 +18,28 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; - -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpConnectionManager; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.HttpMethod; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; -import org.apache.commons.httpclient.URIException; -import org.apache.commons.httpclient.cookie.CookiePolicy; -import org.apache.commons.httpclient.methods.DeleteMethod; -import org.apache.commons.httpclient.methods.EntityEnclosingMethod; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.PutMethod; -import org.apache.commons.httpclient.methods.RequestEntity; -import org.apache.commons.httpclient.methods.StringRequestEntity; -import org.apache.commons.httpclient.params.HttpClientParams; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; + +import org.apache.http.HttpStatus; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.HttpResponseException; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.params.ClientPNames; +import org.apache.http.client.params.CookiePolicy; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.PoolingClientConnectionManager; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.params.CoreConnectionPNames; import org.apache.log4j.Logger; import com.google.gson.Gson; @@ -44,115 +50,74 @@ */ public class SspClient { private static final Logger s_logger = Logger.getLogger(SspClient.class); - private static final HttpConnectionManager s_httpclient_manager = new MultiThreadedHttpConnectionManager(); - private static final HttpClientParams s_httpclient_params = new HttpClientParams(); + private static final HttpClient s_client = new DefaultHttpClient( + new PoolingClientConnectionManager()); static { - s_httpclient_params.setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); + s_client.getParams() + .setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY) + .setParameter(CoreConnectionPNames.SO_TIMEOUT, 10000); } private final String apiUrl; private final String username; private final String password; - protected HttpClient client; - protected PostMethod postMethod; - protected DeleteMethod deleteMethod; - protected PutMethod putMethod; - public SspClient(String apiUrl, String username, String password) { super(); this.apiUrl = apiUrl; this.username = username; this.password = password; - client = new HttpClient(s_httpclient_params, s_httpclient_manager); - postMethod = new PostMethod(apiUrl); - deleteMethod = new DeleteMethod(apiUrl); - putMethod = new PutMethod(apiUrl); } - public boolean login(){ - PostMethod method = postMethod; - method.setPath("/ws.v1/login"); // NOTE: /ws.v1/login is correct - method.addParameter("username", username); - method.addParameter("password", password); - - try { - client.executeMethod(method); - } catch (HttpException e) { - s_logger.info("Login "+username+" to "+apiUrl+" failed", e); - return false; - } catch (IOException e) { - s_logger.info("Login "+username+" to "+apiUrl+" failed", e); - return false; - } finally { - method.releaseConnection(); - } - String apiCallPath = null; - try { - apiCallPath = method.getName() + " " + method.getURI().toString(); - } catch (URIException e) { - s_logger.error("method getURI failed", e); - } - s_logger.info("ssp api call:" + apiCallPath + " user="+username+" status="+method.getStatusLine()); - if(method.getStatusCode() == HttpStatus.SC_OK){ - return true; - } - return false; + protected HttpClient getHttpClient() { // for mock test + return s_client; } - private String executeMethod(HttpMethod method){ - String apiCallPath = null; + private String executeMethod(HttpRequestBase req, String path) { try { - apiCallPath = method.getName() + " " + method.getURI().toString(); - } catch (URIException e) { - s_logger.error("method getURI failed", e); + URI base = new URI(apiUrl); + req.setURI(new URI(base.getScheme(), base.getUserInfo(), base.getHost(), + base.getPort(), path, null, null)); + } catch (URISyntaxException e) { + s_logger.error("invalid API URL " + apiUrl + " path " + path, e); + return null; } - - String response = null; try { - client.executeMethod(method); - response = method.getResponseBodyAsString(); - } catch (HttpException e) { - s_logger.error("ssp api call failed "+apiCallPath, e); - return null; + String content = null; + try { + content = getHttpClient().execute(req, new BasicResponseHandler()); + s_logger.info("ssp api call: " + req); + } catch (HttpResponseException e) { + s_logger.info("ssp api call failed: " + req, e); + if (e.getStatusCode() == HttpStatus.SC_UNAUTHORIZED && login()) { + req.reset(); + content = getHttpClient().execute(req, new BasicResponseHandler()); + s_logger.info("ssp api retry call: " + req); + } + } + return content; + } catch (ClientProtocolException e) { // includes HttpResponseException + s_logger.error("ssp api call failed: " + req, e); } catch (IOException e) { - s_logger.error("ssp api call failed "+apiCallPath, e); - return null; - } finally { - method.releaseConnection(); + s_logger.error("ssp api call failed: " + req, e); } + return null; + } - if(method.getStatusCode() == HttpStatus.SC_UNAUTHORIZED){ - if(!login()){ - return null; - } - - try { - client.executeMethod(method); - response = method.getResponseBodyAsString(); - } catch (HttpException e) { - s_logger.error("ssp api call failed "+apiCallPath, e); - return null; - } catch (IOException e) { - s_logger.error("ssp api call failed "+apiCallPath, e); - return null; - } finally { - method.releaseConnection(); - } + public boolean login() { + HttpPost method = new HttpPost(); + try { + method.setEntity(new UrlEncodedFormEntity(Arrays.asList( + new BasicNameValuePair("username", username), + new BasicNameValuePair("password", password)))); + } catch (UnsupportedEncodingException e) { + s_logger.error("invalid username or password", e); + return false; } - s_logger.info("ssp api call:" + apiCallPath + " user="+username+" status="+method.getStatusLine()); - if(method instanceof EntityEnclosingMethod){ - EntityEnclosingMethod emethod = (EntityEnclosingMethod)method; - RequestEntity reqEntity = emethod.getRequestEntity(); - if(reqEntity instanceof StringRequestEntity){ - StringRequestEntity strReqEntity = (StringRequestEntity)reqEntity; - s_logger.debug("ssp api request body:"+strReqEntity.getContent()); - }else{ - s_logger.debug("ssp api request body:"+emethod.getRequestEntity()); - } + if (executeMethod(method, "/ws.v1/login") != null) { + return true; } - s_logger.debug("ssp api response body:" + response); - return response; + return false; } public class TenantNetwork { @@ -162,35 +127,21 @@ public class TenantNetwork { public String tenantUuid; } - public TenantNetwork createTenantNetwork(String tenantUuid, String networkName){ + public TenantNetwork createTenantNetwork(String tenantUuid, String networkName) { TenantNetwork req = new TenantNetwork(); req.name = networkName; req.tenantUuid = tenantUuid; - PostMethod method = postMethod; - method.setPath("/ssp.v1/tenant-networks"); - StringRequestEntity entity = null; - try { - entity = new StringRequestEntity(new Gson().toJson(req), "application/json", "UTF-8"); - } catch (UnsupportedEncodingException e) { - s_logger.error("failed creating http request body", e); - return null; - } - method.setRequestEntity(entity); - - String response = executeMethod(method); - if(response != null && method.getStatusCode() == HttpStatus.SC_CREATED){ - return new Gson().fromJson(response, TenantNetwork.class); - } - return null; + HttpPost method = new HttpPost(); + method.setEntity(new StringEntity(new Gson().toJson(req), ContentType.APPLICATION_JSON)); + return new Gson().fromJson( + executeMethod(method, "/ssp.v1/tenant-networks"), + TenantNetwork.class); } - public boolean deleteTenantNetwork(String tenantNetworkUuid){ - DeleteMethod method = deleteMethod; - method.setPath("/ssp.v1/tenant-networks/"+tenantNetworkUuid); - - executeMethod(method); - if(method.getStatusCode() == HttpStatus.SC_NO_CONTENT){ + public boolean deleteTenantNetwork(String tenantNetworkUuid) { + HttpDelete method = new HttpDelete(); + if (executeMethod(method, "/ssp.v1/tenant-networks/" + tenantNetworkUuid) != null) { return true; } return false; @@ -209,64 +160,39 @@ public class TenantPort { public Integer vlanId; } - public TenantPort createTenantPort(String tenantNetworkUuid){ + public TenantPort createTenantPort(String tenantNetworkUuid) { TenantPort req = new TenantPort(); req.networkUuid = tenantNetworkUuid; req.attachmentType = "NoAttachment"; - PostMethod method = postMethod; - method.setPath("/ssp.v1/tenant-ports"); - StringRequestEntity entity = null; - try { - entity = new StringRequestEntity(new Gson().toJson(req), "application/json", "UTF-8"); - } catch (UnsupportedEncodingException e) { - s_logger.error("failed creating http request body", e); - return null; - } - method.setRequestEntity(entity); - - String response = executeMethod(method); - if(response != null && method.getStatusCode() == HttpStatus.SC_CREATED){ - return new Gson().fromJson(response, TenantPort.class); - } - return null; + HttpPost method = new HttpPost(); + method.setEntity(new StringEntity(new Gson().toJson(req), ContentType.APPLICATION_JSON)); + return new Gson().fromJson( + executeMethod(method, "/ssp.v1/tenant-ports"), + TenantPort.class); } - public boolean deleteTenantPort(String tenantPortUuid){ - DeleteMethod method = deleteMethod; - method.setPath("/ssp.v1/tenant-ports/"+tenantPortUuid); - - executeMethod(method); - if(method.getStatusCode() == HttpStatus.SC_NO_CONTENT){ + public boolean deleteTenantPort(String tenantPortUuid) { + HttpDelete method = new HttpDelete(); + if (executeMethod(method, "/ssp.v1/tenant-ports/" + tenantPortUuid) != null) { return true; } return false; } - public TenantPort updateTenantVifBinding(String portUuid, String hypervisorIpAddress){ + public TenantPort updateTenantVifBinding(String portUuid, String hypervisorIpAddress) { TenantPort req = new TenantPort(); - if(hypervisorIpAddress != null){ + if (hypervisorIpAddress != null) { req.attachmentType = "VifAttachment"; req.hypervisorIpAddress = hypervisorIpAddress; - }else{ + } else { req.attachmentType = "NoAttachment"; } - PutMethod method = putMethod; - method.setPath("/ssp.v1/tenant-ports/"+portUuid); - StringRequestEntity entity = null; - try { - entity = new StringRequestEntity(new Gson().toJson(req), "application/json", "UTF-8"); - } catch (UnsupportedEncodingException e) { - s_logger.error("failed creating http request body", e); - return null; - } - method.setRequestEntity(entity); - - String response = executeMethod(method); - if(response != null && method.getStatusCode() == HttpStatus.SC_OK){ - return new Gson().fromJson(response, TenantPort.class); - } - return null; + HttpPut method = new HttpPut(); + method.setEntity(new StringEntity(new Gson().toJson(req), ContentType.APPLICATION_JSON)); + return new Gson().fromJson( + executeMethod(method, "/ssp.v1/tenant-ports/" + portUuid), + TenantPort.class); } } diff --git a/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspElement.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspElement.java index fa0488d870a6..0364e6894a49 100644 --- a/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspElement.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspElement.java @@ -189,14 +189,10 @@ private List fetchSspClients(Long physicalNetworkId, Long dataCenterI public boolean isReady(PhysicalNetworkServiceProvider provider) { PhysicalNetwork physicalNetwork = _physicalNetworkDao.findById(provider.getPhysicalNetworkId()); assert(physicalNetwork!=null); - if(physicalNetwork != null){ - if(fetchSspClients(physicalNetwork.getId(), physicalNetwork.getDataCenterId(), false).size() > 0){ - return true; - } - s_logger.warn("Ssp api endpoint not found. "+physicalNetwork.toString()); - }else{ - s_logger.warn("PhysicalNetwork is NULL."); + if(fetchSspClients(physicalNetwork.getId(), physicalNetwork.getDataCenterId(), false).size() > 0){ + return true; } + s_logger.warn("Ssp api endpoint not found. "+physicalNetwork.toString()); return false; } diff --git a/plugins/network-elements/stratosphere-ssp/sspmock/sspmock.py b/plugins/network-elements/stratosphere-ssp/sspmock/sspmock.py index 5e7e61067c6e..9ac646e244e2 100644 --- a/plugins/network-elements/stratosphere-ssp/sspmock/sspmock.py +++ b/plugins/network-elements/stratosphere-ssp/sspmock/sspmock.py @@ -17,7 +17,8 @@ import json import uuid -from flask import Flask +from flask import Flask,request,make_response +from beaker.middleware import SessionMiddleware app = Flask(__name__) tenant_networks = [] @@ -25,50 +26,59 @@ @app.route("/ws.v1/login", methods=["POST",]) def login(): - response.content_type = "application/json" - return "" + assert "username" in request.form + assert "password" in request.form + request.environ["beaker.session"]["login"] = True + res = make_response("", 200) + res.headers["Content-type"] = "application/json" + return res @app.route("/ssp.v1/tenant-networks", methods=["POST",]) def create_tenant_network(): - response.content_type = "application/json" - response.status = 201 + if "login" not in request.environ["beaker.session"]: + return make_response("", 401) obj = request.json obj["uuid"] = str(uuid.uuid1()) tenant_networks.append(obj) - return json.dumps(obj) + res = make_response(json.dumps(obj), 201) + res.headers["Content-type"] = "application/json" + return res @app.route("/ssp.v1/tenant-networks/", methods=["DELETE",]) def delete_tenant_network(tenant_net_uuid): + if "login" not in request.environ["beaker.session"]: + return make_response("", 401) for net in tenant_networks: if net["uuid"] == tenant_net_uuid: tenant_networks.remove(net) - response.status = 204 - return "" - response.status = 404 - return "" + return make_response("", 204) + return make_response("", 404) @app.route("/ssp.v1/tenant-ports", methods=["POST",]) def create_tenant_port(): - response.content_type = "application/json" - response.status = 201 + if "login" not in request.environ["beaker.session"]: + return make_response("", 401) obj = request.json obj["uuid"] = str(uuid.uuid1()) tenant_ports.append(obj) - return json.dumps(obj) + res = make_response(json.dumps(obj), 201) + res.headers["Content-type"] = "application/json" + return res @app.route("/ssp.v1/tenant-ports/", methods=["DELETE",]) def delete_tenant_port(tenant_port_uuid): + if "login" not in request.environ["beaker.session"]: + return make_response("", 401) for port in tenant_ports: if port["uuid"] == tenant_port_uuid: tenant_ports.remove(port) - response.status = 204 - return "" - response.status = 404 - return "" + return make_response("", 204) + return make_response("", 404) @app.route("/ssp.v1/tenant-ports/", methods=["PUT",]) def update_tenant_port(tenant_port_uuid): - response.content_type = "application/json" + if "login" not in request.environ["beaker.session"]: + return make_response("", 401) for port in tenant_ports: if port["uuid"] == tenant_port_uuid: obj = request.json @@ -76,10 +86,14 @@ def update_tenant_port(tenant_port_uuid): obj["vlan_id"] = 100 tenant_ports.remove(port) tenant_ports.append(obj) - response.status = 200 - return json.dumps(obj) - response.status = 404 - return "" + res = make_response(json.dumps(obj), 200) + res.headers["Content-type"] = "application/json" + return res + return make_response("", 404) if __name__=="__main__": + app.wsgi_app = SessionMiddleware(app.wsgi_app, { + "session.auto":True, + "session.type":"cookie", + "session.validate_key":"hoge"}) app.run(host="0.0.0.0", port=9080, debug=True) diff --git a/plugins/network-elements/stratosphere-ssp/test/org/apache/cloudstack/network/element/SspClientTest.java b/plugins/network-elements/stratosphere-ssp/test/org/apache/cloudstack/network/element/SspClientTest.java index 795d1c169ab0..a6b723ccda1d 100644 --- a/plugins/network-elements/stratosphere-ssp/test/org/apache/cloudstack/network/element/SspClientTest.java +++ b/plugins/network-elements/stratosphere-ssp/test/org/apache/cloudstack/network/element/SspClientTest.java @@ -16,49 +16,35 @@ // under the License. package org.apache.cloudstack.network.element; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.doReturn; import java.util.UUID; -import org.apache.cloudstack.network.element.SspClient; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.URI; -import org.apache.commons.httpclient.methods.DeleteMethod; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.PutMethod; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.BasicResponseHandler; import org.junit.Test; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - public class SspClientTest { - HttpClient _client = mock(HttpClient.class); - PostMethod _postMethod = mock(PostMethod.class); - PutMethod _putMethod = mock(PutMethod.class); - DeleteMethod _deleteMethod = mock(DeleteMethod.class); - String uuid = UUID.randomUUID().toString(); String apiUrl = "http://a.example.jp/"; String username = "foo"; String password = "bar"; - SspClient sspClient = new SspClient(apiUrl, username, password){ - { - client = _client; - postMethod = _postMethod; - putMethod = _putMethod; - deleteMethod = _deleteMethod; - } - }; - - @SuppressWarnings("deprecation") - private URI getUri() throws Exception{ - return new URI(apiUrl); - } @Test public void loginTest() throws Exception { - when(_postMethod.getURI()).thenReturn(getUri()); - when(_postMethod.getStatusCode()).thenReturn(HttpStatus.SC_OK); + SspClient sspClient = spy(new SspClient(apiUrl, username, password)); + + HttpClient client = mock(HttpClient.class); + doReturn(client).when(sspClient).getHttpClient(); + when(client.execute(any(HttpUriRequest.class), any(BasicResponseHandler.class))).thenReturn(""); + assertTrue(sspClient.login()); assertTrue(sspClient.login()); assertTrue(sspClient.login()); @@ -68,13 +54,14 @@ public void loginTest() throws Exception { public void createNetworkTest() throws Exception { String networkName = "example network 1"; String tenant_net_uuid = UUID.randomUUID().toString(); + SspClient sspClient = spy(new SspClient(apiUrl, username, password)); + + HttpClient client = mock(HttpClient.class); + doReturn(client).when(sspClient).getHttpClient(); + String body = "{\"uuid\":\"" + tenant_net_uuid + "\",\"name\":\"" + networkName + + "\",\"tenant_uuid\":\"" + uuid + "\"}"; + when(client.execute(any(HttpUriRequest.class), any(BasicResponseHandler.class))).thenReturn(body); - when(_postMethod.getURI()).thenReturn(getUri()); - when(_postMethod.getStatusCode()).thenReturn(HttpStatus.SC_CREATED); - when(_postMethod.getResponseBodyAsString()).thenReturn( - "{\"uuid\":\""+tenant_net_uuid+ - "\",\"name\":\""+networkName+ - "\",\"tenant_uuid\":\""+uuid+"\"}"); SspClient.TenantNetwork tnet = sspClient.createTenantNetwork(uuid, networkName); assertEquals(tnet.name, networkName); assertEquals(tnet.uuid, tenant_net_uuid); @@ -84,9 +71,11 @@ public void createNetworkTest() throws Exception { @Test public void deleteNetworkTest() throws Exception { String tenant_net_uuid = UUID.randomUUID().toString(); + SspClient sspClient = spy(new SspClient(apiUrl, username, password)); - when(_deleteMethod.getURI()).thenReturn(getUri()); - when(_deleteMethod.getStatusCode()).thenReturn(HttpStatus.SC_NO_CONTENT); + HttpClient client = mock(HttpClient.class); + doReturn(client).when(sspClient).getHttpClient(); + when(client.execute(any(HttpUriRequest.class), any(BasicResponseHandler.class))).thenReturn(""); sspClient.deleteTenantNetwork(tenant_net_uuid); } diff --git a/plugins/network-elements/vxlan/pom.xml b/plugins/network-elements/vxlan/pom.xml index fe3bbd4ac7a9..2e6d2bc5be54 100644 --- a/plugins/network-elements/vxlan/pom.xml +++ b/plugins/network-elements/vxlan/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/pom.xml b/plugins/pom.xml index d0817a2ddc87..4021aecd1629 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloudstack - 4.3.0-SNAPSHOT + 4.3.0 @@ -32,6 +32,7 @@ deployment-planners/user-concentrated-pod deployment-planners/user-dispersing deployment-planners/implicit-dedication + ha-planners/skip-heurestics host-allocators/random dedicated-resources hypervisors/ovm diff --git a/plugins/storage-allocators/random/pom.xml b/plugins/storage-allocators/random/pom.xml index c38d12b9e14f..41cec407d265 100644 --- a/plugins/storage-allocators/random/pom.xml +++ b/plugins/storage-allocators/random/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/storage/image/default/pom.xml b/plugins/storage/image/default/pom.xml index 0fb91d83eb74..a7e2f5bb3f39 100644 --- a/plugins/storage/image/default/pom.xml +++ b/plugins/storage/image/default/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../../pom.xml 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 be7c77db55aa..1af0eba993ff 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; @@ -90,12 +88,21 @@ private String generateCopyUrl(String ipAddress, String uuid){ String scheme = "http"; boolean _sslCopy = false; String sslCfg = _configDao.getValue(Config.SecStorageEncryptCopy.toString()); + String _ssvmUrlDomain = _configDao.getValue("secstorage.ssl.cert.domain"); if ( sslCfg != null ){ _sslCopy = Boolean.parseBoolean(sslCfg); } + if(_sslCopy && (_ssvmUrlDomain == null || _ssvmUrlDomain.isEmpty())){ + s_logger.warn("Empty secondary storage url domain, ignoring SSL"); + _sslCopy = false; + } if (_sslCopy) { - hostname = ipAddress.replace(".", "-"); - hostname = hostname + ".realhostip.com"; + if(_ssvmUrlDomain.startsWith("*")) { + hostname = ipAddress.replace(".", "-"); + hostname = hostname + _ssvmUrlDomain.substring(1); + } else { + hostname = _ssvmUrlDomain; + } scheme = "https"; } return scheme + "://" + hostname + "/userdata/" + uuid; diff --git a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackImageStoreLifeCycleImpl.java b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackImageStoreLifeCycleImpl.java index d6448785a93e..1b69099f9e3f 100644 --- a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackImageStoreLifeCycleImpl.java +++ b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackImageStoreLifeCycleImpl.java @@ -18,6 +18,8 @@ import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -26,6 +28,8 @@ import org.apache.log4j.Logger; +import com.cloud.utils.StringUtils; + import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; @@ -84,13 +88,19 @@ public DataStore initialize(Map dsInfos) { DataStoreRole role = (DataStoreRole) dsInfos.get("role"); Map details = (Map) dsInfos.get("details"); - s_logger.info("Trying to add a new data store at " + url + " to data center " + dcId); + String logString = ""; + if(url.contains("cifs")) { + logString = cleanPassword(url); + } else { + logString = StringUtils.cleanString(url); + } + s_logger.info("Trying to add a new data store at " + logString + " to data center " + dcId); URI uri = null; try { uri = new URI(UriUtils.encodeURIComponent(url)); if (uri.getScheme() == null) { - throw new InvalidParameterValueException("uri.scheme is null " + url + ", add nfs:// (or cifs://) as a prefix"); + throw new InvalidParameterValueException("uri.scheme is null " + StringUtils.cleanString(url) + ", add nfs:// (or cifs://) as a prefix"); } else if (uri.getScheme().equalsIgnoreCase("nfs")) { if (uri.getHost() == null || uri.getHost().equalsIgnoreCase("") || uri.getPath() == null || uri.getPath().equalsIgnoreCase("")) { @@ -170,4 +180,22 @@ public boolean migrateToObjectStore(DataStore store) { return imageStoreHelper.convertToStagingStore(store); } + public static String cleanPassword(String logString) { + String cleanLogString = null; + if (logString != null) { + cleanLogString = logString; + String[] temp = logString.split(","); + int i = 0; + if (temp != null) { + while (i < temp.length) { + temp[i] = StringUtils.cleanString(temp[i]); + i++; + } + List stringList = new ArrayList(); + Collections.addAll(stringList, temp); + cleanLogString = StringUtils.join(stringList, ","); + } + } + return cleanLogString; + } } diff --git a/plugins/storage/image/s3/pom.xml b/plugins/storage/image/s3/pom.xml index 66997badd6fb..34201ff50e21 100644 --- a/plugins/storage/image/s3/pom.xml +++ b/plugins/storage/image/s3/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../../pom.xml diff --git a/plugins/storage/image/sample/pom.xml b/plugins/storage/image/sample/pom.xml index 46e318e52d46..f111a57432ab 100644 --- a/plugins/storage/image/sample/pom.xml +++ b/plugins/storage/image/sample/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../../pom.xml diff --git a/plugins/storage/image/swift/pom.xml b/plugins/storage/image/swift/pom.xml index c55783df0058..e19b88167130 100644 --- a/plugins/storage/image/swift/pom.xml +++ b/plugins/storage/image/swift/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../../pom.xml diff --git a/plugins/storage/volume/default/pom.xml b/plugins/storage/volume/default/pom.xml index 770c4830db73..1283405ada92 100644 --- a/plugins/storage/volume/default/pom.xml +++ b/plugins/storage/volume/default/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../../pom.xml 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 327d87c6722f..b4d24d8d5169 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,20 @@ */ package org.apache.cloudstack.storage.datastore.driver; +import java.util.HashMap; +import java.util.List; +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; @@ -59,6 +53,7 @@ import com.cloud.agent.api.to.StorageFilerTO; import com.cloud.configuration.Config; import com.cloud.exception.StorageUnavailableException; +import com.cloud.host.Host; import com.cloud.host.dao.HostDao; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.SnapshotDao; @@ -82,8 +77,6 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri @Inject StorageManager storageMgr; @Inject - VolumeOrchestrationService volumeMgr; - @Inject VMInstanceDao vmDao; @Inject SnapshotDao snapshotDao; @@ -103,7 +96,12 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri public DataTO getTO(DataObject data) { return null; } - + @Override + public Map getCapabilities() { + Map caps = new HashMap(); + caps.put(DataStoreCapabilities.VOLUME_SNAPSHOT_QUIESCEVM.toString(), "false"); + return caps; + } @Override public DataStoreTO getStoreTO(DataStore store) { return null; @@ -132,6 +130,17 @@ public ChapInfo getChapInfo(VolumeInfo volumeInfo) { return null; } + @Override + public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { return false; } + + @Override + public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {} + + @Override + public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { + return volume.getSize(); + } + @Override public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback callback) { String errMsg = null; @@ -254,10 +263,10 @@ public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback dsInfos) { if (port == -1) { port = 445; } - parameters.setType(StoragePoolType.NetworkFilesystem); + + parameters.setType(StoragePoolType.SMB); parameters.setHost(storageHost); parameters.setPort(port); parameters.setPath(hostPath); - parameters.setUserInfo(uri.getQuery()); - } else if (scheme.equalsIgnoreCase("file")) { if (port == -1) { port = 0; @@ -356,7 +354,8 @@ protected boolean createStoragePool(long hostId, StoragePool pool) { && pool.getPoolType() != StoragePoolType.IscsiLUN && pool.getPoolType() != StoragePoolType.Iscsi && pool.getPoolType() != StoragePoolType.VMFS && pool.getPoolType() != StoragePoolType.SharedMountPoint && pool.getPoolType() != StoragePoolType.PreSetup && pool.getPoolType() != StoragePoolType.OCFS2 - && pool.getPoolType() != StoragePoolType.RBD && pool.getPoolType() != StoragePoolType.CLVM) { + && pool.getPoolType() != StoragePoolType.RBD && pool.getPoolType() != StoragePoolType.CLVM + && pool.getPoolType() != StoragePoolType.SMB) { s_logger.warn(" Doesn't support storage pool type " + pool.getPoolType()); return false; } @@ -473,8 +472,6 @@ public boolean deleteDataStore(DataStore store) { HypervisorType hType = null; if(hostPoolRecords.size() > 0 ){ hType = getHypervisorType(hostPoolRecords.get(0).getHostId()); - } else { - return false; } // Remove the SR associated with the Xenserver @@ -495,7 +492,7 @@ public boolean deleteDataStore(DataStore store) { } } - if (!deleteFlag) { + if (!hostPoolRecords.isEmpty() && !deleteFlag) { throw new CloudRuntimeException("Failed to delete storage pool on host"); } diff --git a/plugins/storage/volume/sample/pom.xml b/plugins/storage/volume/sample/pom.xml index d481a9035fed..3b2ef26a8735 100644 --- a/plugins/storage/volume/sample/pom.xml +++ b/plugins/storage/volume/sample/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../../pom.xml 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 8f4c7bbf2027..82694e76a205 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 @@ -40,9 +40,16 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; +import com.cloud.host.Host; +import com.cloud.storage.StoragePool; +import com.cloud.storage.Volume; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.utils.exception.CloudRuntimeException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver { private static final Logger s_logger = Logger.getLogger(SamplePrimaryDataStoreDriverImpl.class); @Inject @@ -56,6 +63,11 @@ public SamplePrimaryDataStoreDriverImpl() { } + @Override + public Map getCapabilities() { + return null; + } + @Override public DataTO getTO(DataObject data) { return null; @@ -71,6 +83,17 @@ public ChapInfo getChapInfo(VolumeInfo volumeInfo) { return null; } + @Override + public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { return false; } + + @Override + public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {} + + @Override + public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { + return volume.getSize(); + } + private class CreateVolumeContext extends AsyncRpcContext { private final DataObject volume; public CreateVolumeContext(AsyncCompletionCallback callback, DataObject volume) { diff --git a/plugins/storage/volume/solidfire/pom.xml b/plugins/storage/volume/solidfire/pom.xml index 011f5e108b23..e0b1c12c14bf 100644 --- a/plugins/storage/volume/solidfire/pom.xml +++ b/plugins/storage/volume/solidfire/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../../pom.xml 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 1c726cd110b1..e69534b7946a 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,14 @@ package org.apache.cloudstack.storage.datastore.driver; import java.text.NumberFormat; +import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.UUID; 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; @@ -42,8 +38,15 @@ import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; +import com.cloud.dc.ClusterDetailsVO; +import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.dao.DataCenterDao; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StoragePool; +import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.dao.VolumeDetailsDao; @@ -51,6 +54,7 @@ import com.cloud.user.AccountDetailsDao; import com.cloud.user.AccountVO; import com.cloud.user.dao.AccountDao; +import com.cloud.utils.exception.CloudRuntimeException; public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { @Inject private PrimaryDataStoreDao _storagePoolDao; @@ -60,6 +64,13 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { @Inject private DataCenterDao _zoneDao; @Inject private AccountDao _accountDao; @Inject private AccountDetailsDao _accountDetailsDao; + @Inject private ClusterDetailsDao _clusterDetailsDao; + @Inject private HostDao _hostDao; + + @Override + public Map getCapabilities() { + return null; + } @Override public DataTO getTO(DataObject data) { @@ -122,50 +133,47 @@ private SolidFireConnection getSolidFireConnection(long storagePoolId) { return new SolidFireConnection(mVip, mPort, clusterAdminUsername, clusterAdminPassword); } - private SolidFireUtil.SolidFireAccount createSolidFireAccount(String sfAccountName, - SolidFireConnection sfConnection) { + private SolidFireUtil.SolidFireAccount createSolidFireAccount(String sfAccountName, SolidFireConnection sfConnection) { String mVip = sfConnection.getManagementVip(); int mPort = sfConnection.getManagementPort(); String clusterAdminUsername = sfConnection.getClusterAdminUsername(); String clusterAdminPassword = sfConnection.getClusterAdminPassword(); - long accountNumber = SolidFireUtil.createSolidFireAccount(mVip, mPort, - clusterAdminUsername, clusterAdminPassword, sfAccountName); + long accountNumber = SolidFireUtil.createSolidFireAccount(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfAccountName); - return SolidFireUtil.getSolidFireAccountById(mVip, mPort, - clusterAdminUsername, clusterAdminPassword, accountNumber); + return SolidFireUtil.getSolidFireAccountById(mVip, mPort, clusterAdminUsername, clusterAdminPassword, accountNumber); } private void updateCsDbWithAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount) { - AccountDetailVO accountDetails = new AccountDetailVO(csAccountId, + AccountDetailVO accountDetail = new AccountDetailVO(csAccountId, SolidFireUtil.ACCOUNT_ID, String.valueOf(sfAccount.getId())); - _accountDetailsDao.persist(accountDetails); + _accountDetailsDao.persist(accountDetail); - accountDetails = new AccountDetailVO(csAccountId, + accountDetail = new AccountDetailVO(csAccountId, SolidFireUtil.CHAP_INITIATOR_USERNAME, String.valueOf(sfAccount.getName())); - _accountDetailsDao.persist(accountDetails); + _accountDetailsDao.persist(accountDetail); - accountDetails = new AccountDetailVO(csAccountId, + accountDetail = new AccountDetailVO(csAccountId, SolidFireUtil.CHAP_INITIATOR_SECRET, String.valueOf(sfAccount.getInitiatorSecret())); - _accountDetailsDao.persist(accountDetails); + _accountDetailsDao.persist(accountDetail); - accountDetails = new AccountDetailVO(csAccountId, + accountDetail = new AccountDetailVO(csAccountId, SolidFireUtil.CHAP_TARGET_USERNAME, sfAccount.getName()); - _accountDetailsDao.persist(accountDetails); + _accountDetailsDao.persist(accountDetail); - accountDetails = new AccountDetailVO(csAccountId, + accountDetail = new AccountDetailVO(csAccountId, SolidFireUtil.CHAP_TARGET_SECRET, sfAccount.getTargetSecret()); - _accountDetailsDao.persist(accountDetails); + _accountDetailsDao.persist(accountDetail); } private class ChapInfoImpl implements ChapInfo { @@ -174,8 +182,7 @@ private class ChapInfoImpl implements ChapInfo { private final String _targetUsername; private final String _targetSecret; - public ChapInfoImpl(String initiatorUsername, String initiatorSecret, - String targetUsername, String targetSecret) { + public ChapInfoImpl(String initiatorUsername, String initiatorSecret, String targetUsername, String targetSecret) { _initiatorUsername = initiatorUsername; _initiatorSecret = initiatorSecret; _targetUsername = targetUsername; @@ -203,6 +210,12 @@ public String getTargetSecret() { } } + @Override + public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + return null; + } + + /* @Override public ChapInfo getChapInfo(VolumeInfo volumeInfo) { long accountId = volumeInfo.getAccountId(); @@ -215,25 +228,275 @@ public ChapInfo getChapInfo(VolumeInfo volumeInfo) { String chapInitiatorSecret = accountDetail.getValue(); - StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(volumeInfo.getPoolId(), SolidFireUtil.USE_MUTUAL_CHAP_FOR_VMWARE); + accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_USERNAME); + + String chapTargetUsername = accountDetail.getValue(); + + accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_SECRET); + + String chapTargetSecret = accountDetail.getValue(); + + return new ChapInfoImpl(chapInitiatorUsername, chapInitiatorSecret, chapTargetUsername, chapTargetSecret); + } + */ + + // get the VAG associated with volumeInfo's cluster, if any (ListVolumeAccessGroups) + // if the VAG exists + // update the VAG to contain all IQNs of the hosts (ModifyVolumeAccessGroup) + // if the ID of volumeInfo in not in the VAG, add it (ModifyVolumeAccessGroup) + // if the VAG doesn't exist, create it with the IQNs of the hosts and the ID of volumeInfo (CreateVolumeAccessGroup) + @Override + public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) + { + if (volumeInfo == null || host == null || dataStore == null) { + return false; + } + + long sfVolumeId = Long.parseLong(volumeInfo.getFolder()); + long clusterId = host.getClusterId(); + long storagePoolId = dataStore.getId(); + + ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, getVagKey(storagePoolId)); + + String vagId = clusterDetail != null ? clusterDetail.getValue() : null; + + List hosts = _hostDao.findByClusterId(clusterId); + + if (!hostsSupport_iScsi(hosts)) { + return false; + } + + SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId); + + if (vagId != null) { + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), + sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), Long.parseLong(vagId)); + + String[] hostIqns = getNewHostIqns(sfVag.getInitiators(), getIqnsFromHosts(hosts)); + long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); + + SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), + sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(), + hostIqns, volumeIds); + } + else { + long lVagId; + + try { + lVagId = SolidFireUtil.createSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), + sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), "CloudStack-" + UUID.randomUUID().toString(), + getIqnsFromHosts(hosts), new long[] { sfVolumeId }); + } + catch (Exception ex) { + String iqnInVagAlready = "Exceeded maximum number of Volume Access Groups per initiator"; + + if (!ex.getMessage().contains(iqnInVagAlready)) { + throw new CloudRuntimeException(ex.getMessage()); + } + + // getCompatibleVag throws an exception if an existing VAG can't be located + SolidFireUtil.SolidFireVag sfVag = getCompatibleVag(hosts, sfConnection); + + long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); + + SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), + sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(), + sfVag.getInitiators(), volumeIds); + + lVagId = sfVag.getId(); + } + + clusterDetail = new ClusterDetailsVO(clusterId, getVagKey(storagePoolId), String.valueOf(lVagId)); + + _clusterDetailsDao.persist(clusterDetail); + } - boolean useMutualChapForVMware = new Boolean(storagePoolDetail.getValue()); + return true; + } + + // this method takes in a collection of hosts and tries to find an existing VAG that has all three of them in it + // if successful, the VAG is returned; else, a CloudRuntimeException is thrown and this issue should be corrected by an admin + private SolidFireUtil.SolidFireVag getCompatibleVag(List hosts, SolidFireConnection sfConnection) { + List sfVags = SolidFireUtil.getAllSolidFireVags(sfConnection.getManagementVip(), sfConnection.getManagementPort(), + sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword()); + + if (sfVags != null) { + List hostIqns = new ArrayList(); + + // where the method we're in is called, hosts should not be null + for (HostVO host : hosts) { + // where the method we're in is called, host.getStorageUrl() should not be null (it actually should start with "iqn") + hostIqns.add(host.getStorageUrl().toLowerCase()); + } + + for (SolidFireUtil.SolidFireVag sfVag : sfVags) { + List lstInitiators = getStringArrayAsLowerCaseStringList(sfVag.getInitiators()); + + // lstInitiators should not be returned from getStringArrayAsLowerCaseStringList as null + if (lstInitiators.containsAll(hostIqns)) { + return sfVag; + } + } + } - String chapTargetUsername = null; - String chapTargetSecret = null; + throw new CloudRuntimeException("Unable to locate the appropriate SolidFire Volume Access Group"); + } - if (useMutualChapForVMware) { - accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_USERNAME); + private List getStringArrayAsLowerCaseStringList(String[] aString) { + List lstLowerCaseString = new ArrayList(); - chapTargetUsername = accountDetail.getValue(); + if (aString != null) { + for (String str : aString) { + if (str != null) { + lstLowerCaseString.add(str.toLowerCase()); + } + } + } - accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_SECRET); + return lstLowerCaseString; + } - chapTargetSecret = accountDetail.getValue(); + // get the VAG associated with volumeInfo's cluster, if any (ListVolumeAccessGroups) // might not exist if using CHAP + // if the VAG exists + // remove the ID of volumeInfo from the VAG (ModifyVolumeAccessGroup) + @Override + public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) + { + if (volumeInfo == null || host == null || dataStore == null) { + return; } - return new ChapInfoImpl(chapInitiatorUsername, chapInitiatorSecret, - chapTargetUsername, chapTargetSecret); + long sfVolumeId = Long.parseLong(volumeInfo.getFolder()); + long clusterId = host.getClusterId(); + long storagePoolId = dataStore.getId(); + + ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, getVagKey(storagePoolId)); + + String vagId = clusterDetail != null ? clusterDetail.getValue() : null; + + if (vagId != null) { + List hosts = _hostDao.findByClusterId(clusterId); + + SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId); + + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), + sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), Long.parseLong(vagId)); + + String[] hostIqns = getNewHostIqns(sfVag.getInitiators(), getIqnsFromHosts(hosts)); + long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false); + + SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), + sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(), + hostIqns, volumeIds); + } + } + + private boolean hostsSupport_iScsi(List hosts) { + if (hosts == null || hosts.size() == 0) { + return false; + } + + for (Host host : hosts) { + if (host == null || host.getStorageUrl() == null || host.getStorageUrl().trim().length() == 0 || !host.getStorageUrl().startsWith("iqn")) { + return false; + } + } + + return true; + } + + private String[] getNewHostIqns(String[] currentIqns, String[] newIqns) { + List lstIqns = new ArrayList(); + + if (currentIqns != null) { + for (String currentIqn : currentIqns) { + lstIqns.add(currentIqn); + } + } + + if (newIqns != null) { + for (String newIqn : newIqns) { + if (!lstIqns.contains(newIqn)) { + lstIqns.add(newIqn); + } + } + } + + return lstIqns.toArray(new String[0]); + } + + private long[] getNewVolumeIds(long[] volumeIds, long volumeIdToAddOrRemove, boolean add) { + if (add) { + return getNewVolumeIdsAdd(volumeIds, volumeIdToAddOrRemove); + } + + return getNewVolumeIdsRemove(volumeIds, volumeIdToAddOrRemove); + } + + private long[] getNewVolumeIdsAdd(long[] volumeIds, long volumeIdToAdd) { + List lstVolumeIds = new ArrayList(); + + if (volumeIds != null) { + for (long volumeId : volumeIds) { + lstVolumeIds.add(volumeId); + } + } + + if (lstVolumeIds.contains(volumeIdToAdd)) { + return volumeIds; + } + + lstVolumeIds.add(volumeIdToAdd); + + return convertArray(lstVolumeIds); + } + + private long[] getNewVolumeIdsRemove(long[] volumeIds, long volumeIdToRemove) { + List lstVolumeIds = new ArrayList(); + + if (volumeIds != null) { + for (long volumeId : volumeIds) { + lstVolumeIds.add(volumeId); + } + } + + lstVolumeIds.remove(volumeIdToRemove); + + return convertArray(lstVolumeIds); + } + + private long[] convertArray(List items) { + if (items == null) { + return new long[0]; + } + + long[] outArray = new long[items.size()]; + + for (int i = 0; i < items.size(); i++) { + Long value = items.get(i); + + outArray[i] = value; + } + + return outArray; + } + + private String getVagKey(long storagePoolId) { + return "sfVolumeAccessGroup_" + storagePoolId; + } + + private String[] getIqnsFromHosts(List hosts) { + if (hosts == null || hosts.size() == 0) { + throw new CloudRuntimeException("There do not appear to be any hosts in this cluster."); + } + + List lstIqns = new ArrayList(); + + for (Host host : hosts) { + lstIqns.add(host.getStorageUrl()); + } + + return lstIqns.toArray(new String[0]); } private long getDefaultMinIops(long storagePoolId) { @@ -288,8 +551,20 @@ private SolidFireUtil.SolidFireVolume createSolidFireVolume(VolumeInfo volumeInf iops = new Iops(volumeInfo.getMinIops(), volumeInfo.getMaxIops(), getDefaultBurstIops(storagePoolId, volumeInfo.getMaxIops())); } - long volumeSize = volumeInfo.getSize(); - Integer hypervisorSnapshotReserve = volumeInfo.getHypervisorSnapshotReserve(); + long volumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volumeInfo, _storagePoolDao.findById(storagePoolId)); + + long sfVolumeId = SolidFireUtil.createSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, + getSolidFireVolumeName(volumeInfo.getName()), sfAccountId, volumeSize, true, + NumberFormat.getInstance().format(volumeInfo.getSize()), + iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); + + return SolidFireUtil.getSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId); + } + + @Override + public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { + long volumeSize = volume.getSize(); + Integer hypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve(); if (hypervisorSnapshotReserve != null) { if (hypervisorSnapshotReserve < 25) { @@ -299,12 +574,7 @@ private SolidFireUtil.SolidFireVolume createSolidFireVolume(VolumeInfo volumeInf volumeSize += volumeSize * (hypervisorSnapshotReserve / 100f); } - long sfVolumeId = SolidFireUtil.createSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, - getSolidFireVolumeName(volumeInfo.getName()), sfAccountId, volumeSize, true, - NumberFormat.getNumberInstance().format(volumeInfo.getSize().toString()), - iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); - - return SolidFireUtil.getSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId); + return volumeSize; } private String getSolidFireVolumeName(String strCloudStackVolumeName) { @@ -367,12 +637,12 @@ public long getBurstIops() } } - private void deleteSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection) + private SolidFireUtil.SolidFireVolume deleteSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection) { Long storagePoolId = volumeInfo.getPoolId(); if (storagePoolId == null) { - return; // this volume was never assigned to a storage pool, so no SAN volume should exist for it + return null; // this volume was never assigned to a storage pool, so no SAN volume should exist for it } String mVip = sfConnection.getManagementVip(); @@ -382,7 +652,7 @@ private void deleteSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sf long sfVolumeId = Long.parseLong(volumeInfo.getFolder()); - SolidFireUtil.deleteSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId); + return SolidFireUtil.deleteSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId); } private String getSfAccountName(String csAccountUuid, long csAccountId) { @@ -443,7 +713,7 @@ public void createAsync(DataStore dataStore, DataObject dataObject, long capacityBytes = storagePool.getCapacityBytes(); long usedBytes = storagePool.getUsedBytes(); - usedBytes += volumeInfo.getSize(); + usedBytes += sfVolume.getTotalSize(); storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes); @@ -462,6 +732,7 @@ public void createAsync(DataStore dataStore, DataObject dataObject, callback.complete(result); } + /* private void deleteSolidFireAccount(long sfAccountId, SolidFireConnection sfConnection) { String mVip = sfConnection.getManagementVip(); int mPort = sfConnection.getManagementPort(); @@ -502,39 +773,39 @@ private boolean sfAccountHasVolume(long sfAccountId, SolidFireConnection sfConne return false; } + */ @Override - public void deleteAsync(DataStore dataStore, DataObject dataObject, - AsyncCompletionCallback callback) { + public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback callback) { String errMsg = null; if (dataObject.getType() == DataObjectType.VOLUME) { VolumeInfo volumeInfo = (VolumeInfo)dataObject; - AccountVO account = _accountDao.findById(volumeInfo.getAccountId()); - AccountDetailVO accountDetails = _accountDetailsDao.findDetail(account.getAccountId(), SolidFireUtil.ACCOUNT_ID); - long sfAccountId = Long.parseLong(accountDetails.getValue()); + // AccountVO account = _accountDao.findById(volumeInfo.getAccountId()); + // AccountDetailVO accountDetails = _accountDetailsDao.findDetail(account.getAccountId(), SolidFireUtil.ACCOUNT_ID); + // long sfAccountId = Long.parseLong(accountDetails.getValue()); long storagePoolId = dataStore.getId(); SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId); - deleteSolidFireVolume(volumeInfo, sfConnection); + SolidFireUtil.SolidFireVolume sfVolume = deleteSolidFireVolume(volumeInfo, sfConnection); _volumeDao.deleteVolumesByInstance(volumeInfo.getId()); - // if (!sfAccountHasVolume(sfAccountId, sfConnection)) { - // // delete the account from the SolidFire SAN - // deleteSolidFireAccount(sfAccountId, sfConnection); + // if (!sfAccountHasVolume(sfAccountId, sfConnection)) { + // // delete the account from the SolidFire SAN + // deleteSolidFireAccount(sfAccountId, sfConnection); // - // // delete the info in the account_details table - // // that's related to the SolidFire account - // _accountDetailsDao.deleteDetails(account.getAccountId()); - // } + // // delete the info in the account_details table + // // that's related to the SolidFire account + // _accountDetailsDao.deleteDetails(account.getAccountId()); + // } StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); long usedBytes = storagePool.getUsedBytes(); - usedBytes -= volumeInfo.getSize(); + usedBytes -= sfVolume != null ? sfVolume.getTotalSize() : 0; storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes); diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java index be43e1c6af68..4a7140d67f8c 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java @@ -168,17 +168,6 @@ public DataStore initialize(Map dsInfos) { details.put(SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS, String.valueOf(lClusterDefaultMaxIops)); details.put(SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS, String.valueOf(fClusterDefaultBurstIopsPercentOfMaxIops)); - String useMutualChapForVMware = getValue(SolidFireUtil.USE_MUTUAL_CHAP_FOR_VMWARE, url); - - if (useMutualChapForVMware == null || new Boolean(useMutualChapForVMware)) { - useMutualChapForVMware = Boolean.TRUE.toString(); - } - else { - useMutualChapForVMware = Boolean.FALSE.toString(); - } - - details.put(SolidFireUtil.USE_MUTUAL_CHAP_FOR_VMWARE, useMutualChapForVMware); - // this adds a row in the cloud.storage_pool table for this SolidFire cluster return dataStoreHelper.createPrimaryDataStore(parameters); } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java index 43e98301c0fb..350f32f9b88a 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java @@ -76,7 +76,7 @@ public boolean hostConnect(long hostId, long storagePoolId) { if (!answer.getResult()) { String msg = "Unable to attach storage pool " + storagePoolId + " to host " + hostId; - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg); + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg); throw new CloudRuntimeException("Unable to establish a connection from agent to storage pool " + storagePool.getId() + " due to " + answer.getDetails() + " (" + storagePool.getId() + ")"); diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java index 6659f98f15fe..2d528ef683f4 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java @@ -75,8 +75,6 @@ public class SolidFireUtil public static final String CHAP_TARGET_USERNAME = "chapTargetUsername"; public static final String CHAP_TARGET_SECRET = "chapTargetSecret"; - public static final String USE_MUTUAL_CHAP_FOR_VMWARE = "useMutualChapForVMware"; - public static long createSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strSfVolumeName, long lSfAccountId, long lTotalSize, boolean bEnable512e, final String strCloudStackVolumeSize, long lMinIops, long lMaxIops, long lBurstIops) @@ -97,28 +95,6 @@ public static long createSolidFireVolume(String strSfMvip, int iSfPort, String s return volumeCreateResult.result.volumeID; } - public static void deleteSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) - { - final Gson gson = new GsonBuilder().create(); - - VolumeToDelete volumeToDelete = new VolumeToDelete(lVolumeId); - - String strVolumeToDeleteJson = gson.toJson(volumeToDelete); - - executeJsonRpc(strVolumeToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); - } - - public static void purgeSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) - { - final Gson gson = new GsonBuilder().create(); - - VolumeToPurge volumeToPurge = new VolumeToPurge(lVolumeId); - - String strVolumeToPurgeJson = gson.toJson(volumeToPurge); - - executeJsonRpc(strVolumeToPurgeJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); - } - public static SolidFireVolume getSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) { final Gson gson = new GsonBuilder().create(); @@ -137,8 +113,9 @@ public static SolidFireVolume getSolidFireVolume(String strSfMvip, int iSfPort, String strVolumeIqn = getVolumeIqn(volumeGetResult, lVolumeId); long lAccountId = getVolumeAccountId(volumeGetResult, lVolumeId); String strVolumeStatus = getVolumeStatus(volumeGetResult, lVolumeId); + long lTotalSize = getVolumeTotalSize(volumeGetResult, lVolumeId); - return new SolidFireVolume(lVolumeId, strVolumeName, strVolumeIqn, lAccountId, strVolumeStatus); + return new SolidFireVolume(lVolumeId, strVolumeName, strVolumeIqn, lAccountId, strVolumeStatus, lTotalSize); } public static List getSolidFireVolumesForAccountId(String strSfMvip, int iSfPort, @@ -160,13 +137,63 @@ public static List getSolidFireVolumesForAccountId(String strSf List sfVolumes = new ArrayList(); for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) { - sfVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status)); + sfVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status, volume.totalSize)); } return sfVolumes; - } + } + + public static List getDeletedVolumes(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword) + { + final Gson gson = new GsonBuilder().create(); + + ListDeletedVolumes listDeletedVolumes = new ListDeletedVolumes(); + + String strListDeletedVolumesJson = gson.toJson(listDeletedVolumes); + + String strListDeletedVolumesResultJson = executeJsonRpc(strListDeletedVolumesJson, strSfMvip, iSfPort, + strSfAdmin, strSfPassword); + + VolumeGetResult volumeGetResult = gson.fromJson(strListDeletedVolumesResultJson, VolumeGetResult.class); + + verifyResult(volumeGetResult.result, strListDeletedVolumesResultJson, gson); + + List deletedVolumes = new ArrayList (); + + for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) { + deletedVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status, volume.totalSize)); + } + + return deletedVolumes; + } + + public static SolidFireVolume deleteSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) + { + SolidFireVolume sfVolume = getSolidFireVolume(strSfMvip, iSfPort, strSfAdmin, strSfPassword, lVolumeId); + + final Gson gson = new GsonBuilder().create(); + + VolumeToDelete volumeToDelete = new VolumeToDelete(lVolumeId); + + String strVolumeToDeleteJson = gson.toJson(volumeToDelete); - private static final String ACTIVE = "active"; + executeJsonRpc(strVolumeToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + + return sfVolume; + } + + public static void purgeSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) + { + final Gson gson = new GsonBuilder().create(); + + VolumeToPurge volumeToPurge = new VolumeToPurge(lVolumeId); + + String strVolumeToPurgeJson = gson.toJson(volumeToPurge); + + executeJsonRpc(strVolumeToPurgeJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + } + + private static final String ACTIVE = "active"; public static class SolidFireVolume { @@ -175,15 +202,17 @@ public static class SolidFireVolume private final String _iqn; private final long _accountId; private final String _status; + private final long _totalSize; public SolidFireVolume(long id, String name, String iqn, - long accountId, String status) + long accountId, String status, long totalSize) { _id = id; _name = name; _iqn = "/" + iqn + "/0"; _accountId = accountId; _status = status; + _totalSize = totalSize; } public long getId() @@ -211,6 +240,10 @@ public boolean isActive() return ACTIVE.equalsIgnoreCase(_status); } + public long getTotalSize() { + return _totalSize; + } + @Override public int hashCode() { return _iqn.hashCode(); @@ -235,16 +268,15 @@ public boolean equals(Object obj) { if (_id == sfv._id && _name.equals(sfv._name) && _iqn.equals(sfv._iqn) && _accountId == sfv._accountId && - isActive() == sfv.isActive()) { + isActive() == sfv.isActive() && getTotalSize() == sfv.getTotalSize()) { return true; } return false; } - } + } - public static long createSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, - String strAccountName) + public static long createSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strAccountName) { final Gson gson = new GsonBuilder().create(); @@ -261,20 +293,7 @@ public static long createSolidFireAccount(String strSfMvip, int iSfPort, String return accountAddResult.result.accountID; } - public static void deleteSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, - long lAccountId) - { - final Gson gson = new GsonBuilder().create(); - - AccountToRemove accountToRemove = new AccountToRemove(lAccountId); - - String strAccountToRemoveJson = gson.toJson(accountToRemove); - - executeJsonRpc(strAccountToRemoveJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); - } - - public static SolidFireAccount getSolidFireAccountById(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, - long lSfAccountId) + public static SolidFireAccount getSolidFireAccountById(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lSfAccountId) { final Gson gson = new GsonBuilder().create(); @@ -295,8 +314,7 @@ public static SolidFireAccount getSolidFireAccountById(String strSfMvip, int iSf return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret); } - public static SolidFireAccount getSolidFireAccountByName(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, - String strSfAccountName) + public static SolidFireAccount getSolidFireAccountByName(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strSfAccountName) { final Gson gson = new GsonBuilder().create(); @@ -317,6 +335,17 @@ public static SolidFireAccount getSolidFireAccountByName(String strSfMvip, int i return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret); } + public static void deleteSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lAccountId) + { + final Gson gson = new GsonBuilder().create(); + + AccountToRemove accountToRemove = new AccountToRemove(lAccountId); + + String strAccountToRemoveJson = gson.toJson(accountToRemove); + + executeJsonRpc(strAccountToRemoveJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + } + public static class SolidFireAccount { private final long _id; @@ -373,56 +402,92 @@ public boolean equals(Object obj) { } SolidFireAccount sfa = (SolidFireAccount)obj; - + if (_id == sfa._id && _name.equals(sfa._name) && _initiatorSecret.equals(sfa._initiatorSecret) && _targetSecret.equals(sfa._targetSecret)) { return true; } - + return false; } } - public static List getDeletedVolumes(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword) + public static long createSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strVagName, + String[] iqns, long[] volumeIds) { final Gson gson = new GsonBuilder().create(); - ListDeletedVolumes listDeletedVolumes = new ListDeletedVolumes(); + VagToCreate vagToCreate = new VagToCreate(strVagName, iqns, volumeIds); - String strListDeletedVolumesJson = gson.toJson(listDeletedVolumes); + String strVagCreateJson = gson.toJson(vagToCreate); - String strListDeletedVolumesResultJson = executeJsonRpc(strListDeletedVolumesJson, strSfMvip, iSfPort, - strSfAdmin, strSfPassword); + String strVagCreateResultJson = executeJsonRpc(strVagCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); - VolumeGetResult volumeGetResult = gson.fromJson(strListDeletedVolumesResultJson, VolumeGetResult.class); + VagCreateResult vagCreateResult = gson.fromJson(strVagCreateResultJson, VagCreateResult.class); - verifyResult(volumeGetResult.result, strListDeletedVolumesResultJson, gson); + verifyResult(vagCreateResult.result, strVagCreateResultJson, gson); - List deletedVolumes = new ArrayList (); + return vagCreateResult.result.volumeAccessGroupID; + } - for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) { - deletedVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status)); - } + public static void modifySolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId, + String[] iqns, long[] volumeIds) + { + final Gson gson = new GsonBuilder().create(); - return deletedVolumes; + VagToModify vagToModify = new VagToModify(lVagId, iqns, volumeIds); + + String strVagModifyJson = gson.toJson(vagToModify); + + executeJsonRpc(strVagModifyJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); } - public static long createSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strVagName) + public static SolidFireVag getSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId) { final Gson gson = new GsonBuilder().create(); - VagToCreate vagToCreate = new VagToCreate(strVagName); + VagToGet vagToGet = new VagToGet(lVagId); - String strVagCreateJson = gson.toJson(vagToCreate); + String strVagToGetJson = gson.toJson(vagToGet); - String strVagCreateResultJson = executeJsonRpc(strVagCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + String strVagGetResultJson = executeJsonRpc(strVagToGetJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); - VagCreateResult vagCreateResult = gson.fromJson(strVagCreateResultJson, VagCreateResult.class); + VagGetResult vagGetResult = gson.fromJson(strVagGetResultJson, VagGetResult.class); - verifyResult(vagCreateResult.result, strVagCreateResultJson, gson); + verifyResult(vagGetResult.result, strVagGetResultJson, gson); - return vagCreateResult.result.volumeAccessGroupID; + String[] vagIqns = getVagIqns(vagGetResult, lVagId); + long[] vagVolumeIds = getVagVolumeIds(vagGetResult, lVagId); + + return new SolidFireVag(lVagId, vagIqns, vagVolumeIds); + } + + public static List getAllSolidFireVags(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword) + { + final Gson gson = new GsonBuilder().create(); + + AllVags allVags = new AllVags(); + + String strAllVagsJson = gson.toJson(allVags); + + String strAllVagsGetResultJson = executeJsonRpc(strAllVagsJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + + VagGetResult allVagsGetResult = gson.fromJson(strAllVagsGetResultJson, VagGetResult.class); + + verifyResult(allVagsGetResult.result, strAllVagsGetResultJson, gson); + + List lstSolidFireVags = new ArrayList(); + + if (allVagsGetResult.result.volumeAccessGroups != null ) { + for (VagGetResult.Result.Vag vag : allVagsGetResult.result.volumeAccessGroups) { + SolidFireVag sfVag = new SolidFireVag(vag.volumeAccessGroupID, vag.initiators, vag.volumes); + + lstSolidFireVags.add(sfVag); + } + } + + return lstSolidFireVags; } public static void deleteSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId) @@ -436,6 +501,64 @@ public static void deleteSolidFireVag(String strSfMvip, int iSfPort, String strS executeJsonRpc(strVagToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); } + public static class SolidFireVag + { + private final long _id; + private final String[] _initiators; + private final long[] _volumeIds; + + public SolidFireVag(long id, String[] initiators, long[] volumeIds) + { + _id = id; + _initiators = initiators; + _volumeIds = volumeIds; + } + + public long getId() + { + return _id; + } + + public String[] getInitiators() + { + return _initiators; + } + + public long[] getVolumeIds() + { + return _volumeIds; + } + + @Override + public int hashCode() { + return String.valueOf(_id).hashCode(); + } + + @Override + public String toString() { + return String.valueOf(_id); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + if (!obj.getClass().equals(SolidFireVag.class)) { + return false; + } + + SolidFireVag sfvag = (SolidFireVag)obj; + + if (_id == sfvag._id) { + return true; + } + + return false; + } + } + @SuppressWarnings("unused") private static final class VolumeToCreate { @@ -496,6 +619,57 @@ private VolumeToCreateParamsQoS(final long lMinIOPS, final long lMaxIOPS, final } } + @SuppressWarnings("unused") + private static final class VolumeToGet + { + private final String method = "ListActiveVolumes"; + private final VolumeToGetParams params; + + private VolumeToGet(final long lVolumeId) + { + params = new VolumeToGetParams(lVolumeId); + } + + private static final class VolumeToGetParams + { + private final long startVolumeID; + private final long limit = 1; + + private VolumeToGetParams(final long lVolumeId) + { + startVolumeID = lVolumeId; + } + } + } + + @SuppressWarnings("unused") + private static final class VolumesToGetForAccount + { + private final String method = "ListVolumesForAccount"; + private final VolumesToGetForAccountParams params; + + private VolumesToGetForAccount(final long lAccountId) + { + params = new VolumesToGetForAccountParams(lAccountId); + } + + private static final class VolumesToGetForAccountParams + { + private final long accountID; + + private VolumesToGetForAccountParams(final long lAccountId) + { + accountID = lAccountId; + } + } + } + + @SuppressWarnings("unused") + private static final class ListDeletedVolumes + { + private final String method = "ListDeletedVolumes"; + } + @SuppressWarnings("unused") private static final class VolumeToDelete { @@ -518,12 +692,6 @@ private VolumeToDeleteParams(final long lVolumeId) } } - @SuppressWarnings("unused") - private static final class ListDeletedVolumes - { - private final String method = "ListDeletedVolumes"; - } - @SuppressWarnings("unused") private static final class VolumeToPurge { @@ -547,44 +715,43 @@ private VolumeToPurgeParams(final long lVolumeId) } @SuppressWarnings("unused") - private static final class VolumeToGet + private static final class AccountToAdd { - private final String method = "ListActiveVolumes"; - private final VolumeToGetParams params; + private final String method = "AddAccount"; + private final AccountToAddParams params; - private VolumeToGet(final long lVolumeId) + private AccountToAdd(final String strAccountName) { - params = new VolumeToGetParams(lVolumeId); + params = new AccountToAddParams(strAccountName); } - private static final class VolumeToGetParams + private static final class AccountToAddParams { - private final long startVolumeID; - private final long limit = 1; + private final String username; - private VolumeToGetParams(final long lVolumeId) + private AccountToAddParams(final String strAccountName) { - startVolumeID = lVolumeId; + username = strAccountName; } } } @SuppressWarnings("unused") - private static final class VolumesToGetForAccount + private static final class AccountToGetById { - private final String method = "ListVolumesForAccount"; - private final VolumesToGetForAccountParams params; + private final String method = "GetAccountByID"; + private final AccountToGetByIdParams params; - private VolumesToGetForAccount(final long lAccountId) + private AccountToGetById(final long lAccountId) { - params = new VolumesToGetForAccountParams(lAccountId); + params = new AccountToGetByIdParams(lAccountId); } - private static final class VolumesToGetForAccountParams + private static final class AccountToGetByIdParams { private final long accountID; - private VolumesToGetForAccountParams(final long lAccountId) + private AccountToGetByIdParams(final long lAccountId) { accountID = lAccountId; } @@ -592,23 +759,23 @@ private VolumesToGetForAccountParams(final long lAccountId) } @SuppressWarnings("unused") - private static final class AccountToAdd + private static final class AccountToGetByName { - private final String method = "AddAccount"; - private final AccountToAddParams params; + private final String method = "GetAccountByName"; + private final AccountToGetByNameParams params; - private AccountToAdd(final String strAccountName) + private AccountToGetByName(final String strUsername) { - params = new AccountToAddParams(strAccountName); + params = new AccountToGetByNameParams(strUsername); } - private static final class AccountToAddParams + private static final class AccountToGetByNameParams { private final String username; - private AccountToAddParams(final String strAccountName) + private AccountToGetByNameParams(final String strUsername) { - username = strAccountName; + username = strUsername; } } } @@ -636,71 +803,95 @@ private AccountToRemoveParams(final long lAccountId) } @SuppressWarnings("unused") - private static final class AccountToGetById + private static final class VagToCreate { - private final String method = "GetAccountByID"; - private final AccountToGetByIdParams params; + private final String method = "CreateVolumeAccessGroup"; + private final VagToCreateParams params; - private AccountToGetById(final long lAccountId) + private VagToCreate(final String strVagName, final String[] iqns, final long[] volumeIds) { - params = new AccountToGetByIdParams(lAccountId); + params = new VagToCreateParams(strVagName, iqns, volumeIds); } - private static final class AccountToGetByIdParams + private static final class VagToCreateParams { - private final long accountID; + private final String name; + private final String[] initiators; + private final long[] volumes; - private AccountToGetByIdParams(final long lAccountId) + private VagToCreateParams(final String strVagName, final String[] iqns, final long[] volumeIds) { - accountID = lAccountId; + name = strVagName; + initiators = iqns; + volumes = volumeIds; } } } @SuppressWarnings("unused") - private static final class AccountToGetByName + private static final class VagToModify { - private final String method = "GetAccountByName"; - private final AccountToGetByNameParams params; + private final String method = "ModifyVolumeAccessGroup"; + private final VagToModifyParams params; - private AccountToGetByName(final String strUsername) + private VagToModify(final long lVagName, final String[] iqns, final long[] volumeIds) { - params = new AccountToGetByNameParams(strUsername); + params = new VagToModifyParams(lVagName, iqns, volumeIds); } - private static final class AccountToGetByNameParams + private static final class VagToModifyParams { - private final String username; + private final long volumeAccessGroupID; + private final String[] initiators; + private final long[] volumes; - private AccountToGetByNameParams(final String strUsername) + private VagToModifyParams(final long lVagName, final String[] iqns, final long[] volumeIds) { - username = strUsername; + volumeAccessGroupID = lVagName; + initiators = iqns; + volumes = volumeIds; } } } @SuppressWarnings("unused") - private static final class VagToCreate + private static final class VagToGet { - private final String method = "CreateVolumeAccessGroup"; - private final VagToCreateParams params; + private final String method = "ListVolumeAccessGroups"; + private final VagToGetParams params; - private VagToCreate(final String strVagName) + private VagToGet(final long lVagId) { - params = new VagToCreateParams(strVagName); + params = new VagToGetParams(lVagId); } - private static final class VagToCreateParams + private static final class VagToGetParams { - private final String name; + private final long startVolumeAccessGroupID; + private final long limit = 1; - private VagToCreateParams(final String strVagName) + private VagToGetParams(final long lVagId) { - name = strVagName; + startVolumeAccessGroupID = lVagId; } } } + @SuppressWarnings("unused") + private static final class AllVags + { + private final String method = "ListVolumeAccessGroups"; + private final VagToGetParams params; + + private AllVags() + { + params = new VagToGetParams(); + } + + private static final class VagToGetParams + {} + } + @SuppressWarnings("unused") private static final class VagToDelete { @@ -748,6 +939,7 @@ private static final class Volume private String iqn; private long accountID; private String status; + private long totalSize; } } } @@ -790,6 +982,23 @@ private static final class Result } } + private static final class VagGetResult + { + private Result result; + + private static final class Result + { + private Vag[] volumeAccessGroups; + + private static final class Vag + { + private long volumeAccessGroupID; + private String[] initiators; + private long[] volumes; + } + } + } + private static final class JsonError { private Error error; @@ -849,7 +1058,7 @@ private static String executeJsonRpc(String strJsonToExecute, String strMvip, in httpClient = getHttpClient(iPort); - URI uri = new URI("https://" + strMvip + ":" + iPort + "/json-rpc/1.0"); + URI uri = new URI("https://" + strMvip + ":" + iPort + "/json-rpc/5.0"); AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_SCHEME); UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(strAdmin, strPassword); @@ -927,8 +1136,7 @@ private static String getVolumeName(VolumeGetResult volumeGetResult, long lVolum return volumeGetResult.result.volumes[0].name; } - throw new CloudRuntimeException("Could not determine the name of the volume, " + - "but the volume was created with an ID of " + lVolumeId + "."); + throw new CloudRuntimeException("Could not determine the name of the volume for volume ID of " + lVolumeId + "."); } private static String getVolumeIqn(VolumeGetResult volumeGetResult, long lVolumeId) @@ -939,8 +1147,7 @@ private static String getVolumeIqn(VolumeGetResult volumeGetResult, long lVolume return volumeGetResult.result.volumes[0].iqn; } - throw new CloudRuntimeException("Could not determine the IQN of the volume, " + - "but the volume was created with an ID of " + lVolumeId + "."); + throw new CloudRuntimeException("Could not determine the IQN of the volume for volume ID of " + lVolumeId + "."); } private static long getVolumeAccountId(VolumeGetResult volumeGetResult, long lVolumeId) @@ -951,8 +1158,7 @@ private static long getVolumeAccountId(VolumeGetResult volumeGetResult, long lVo return volumeGetResult.result.volumes[0].accountID; } - throw new CloudRuntimeException("Could not determine the volume's account ID, " + - "but the volume was created with an ID of " + lVolumeId + "."); + throw new CloudRuntimeException("Could not determine the account ID of the volume for volume ID of " + lVolumeId + "."); } private static String getVolumeStatus(VolumeGetResult volumeGetResult, long lVolumeId) @@ -963,7 +1169,39 @@ private static String getVolumeStatus(VolumeGetResult volumeGetResult, long lVol return volumeGetResult.result.volumes[0].status; } - throw new CloudRuntimeException("Could not determine the status of the volume, " + - "but the volume was created with an ID of " + lVolumeId + "."); + throw new CloudRuntimeException("Could not determine the status of the volume for volume ID of " + lVolumeId + "."); + } + + private static long getVolumeTotalSize(VolumeGetResult volumeGetResult, long lVolumeId) + { + if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && + volumeGetResult.result.volumes[0].volumeID == lVolumeId) + { + return volumeGetResult.result.volumes[0].totalSize; + } + + throw new CloudRuntimeException("Could not determine the total size of the volume for volume ID of " + lVolumeId + "."); + } + + private static String[] getVagIqns(VagGetResult vagGetResult, long lVagId) + { + if (vagGetResult.result.volumeAccessGroups != null && vagGetResult.result.volumeAccessGroups.length == 1 && + vagGetResult.result.volumeAccessGroups[0].volumeAccessGroupID == lVagId) + { + return vagGetResult.result.volumeAccessGroups[0].initiators; + } + + throw new CloudRuntimeException("Could not determine the IQNs of the volume access group for volume access group ID of " + lVagId + "."); + } + + private static long[] getVagVolumeIds(VagGetResult vagGetResult, long lVagId) + { + if (vagGetResult.result.volumeAccessGroups != null && vagGetResult.result.volumeAccessGroups.length == 1 && + vagGetResult.result.volumeAccessGroups[0].volumeAccessGroupID == lVagId) + { + return vagGetResult.result.volumeAccessGroups[0].volumes; + } + + throw new CloudRuntimeException("Could not determine the volume IDs of the volume access group for volume access group ID of " + lVagId + "."); } } diff --git a/plugins/user-authenticators/ldap/pom.xml b/plugins/user-authenticators/ldap/pom.xml index 34121e4db312..ecb208d04d68 100644 --- a/plugins/user-authenticators/ldap/pom.xml +++ b/plugins/user-authenticators/ldap/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPConfigCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPConfigCmd.java new file mode 100644 index 000000000000..3faf8b768b27 --- /dev/null +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPConfigCmd.java @@ -0,0 +1,261 @@ +// 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.api.command; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.LDAPConfigResponse; +import org.apache.cloudstack.api.response.LdapConfigurationResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.framework.config.impl.ConfigurationVO; +import org.apache.cloudstack.ldap.LdapConfiguration; +import org.apache.cloudstack.ldap.LdapConfigurationVO; +import org.apache.cloudstack.ldap.LdapManager; +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.log4j.Logger; + +import com.cloud.exception.*; +import com.cloud.user.Account; +import com.cloud.utils.Pair; + +/** + * @deprecated as of 4.3 use the new api {@link LdapAddConfigurationCmd} + */ +@Deprecated +@APICommand(name = "ldapConfig", description = "Configure the LDAP context for this site.", responseObject = LDAPConfigResponse.class, since = "3.0.0") +public class LDAPConfigCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(LDAPConfigCmd.class.getName()); + + private static final String s_name = "ldapconfigresponse"; + + @Inject + private ConfigurationDao _configDao; + + @Inject + private LdapManager _ldapManager; + + @Inject + private LdapConfiguration _ldapConfiguration; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @Parameter(name = ApiConstants.LIST_ALL, type = CommandType.BOOLEAN, description = "If true return current LDAP configuration") + private Boolean listAll; + + @Parameter(name = ApiConstants.HOST_NAME, type = CommandType.STRING, description = "Hostname or ip address of the ldap server eg: my.ldap.com") + private String hostname; + + @Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, description = "Specify the LDAP port if required, default is 389.") + private Integer port = 0; + + @Parameter(name = ApiConstants.USE_SSL, type = CommandType.BOOLEAN, description = "Check Use SSL if the external LDAP server is configured for LDAP over SSL.") + private Boolean useSSL; + + @Parameter(name = ApiConstants.SEARCH_BASE, type = CommandType.STRING, description = "The search base defines the starting point for the search in the directory tree Example: dc=cloud,dc=com.") + private String searchBase; + + @Parameter(name = ApiConstants.QUERY_FILTER, type = CommandType.STRING, description = "You specify a query filter here, which narrows down the users, who can be part of this domain.") + private String queryFilter; + + @Parameter(name = ApiConstants.BIND_DN, type = CommandType.STRING, description = "Specify the distinguished name of a user with the search permission on the directory.") + private String bindDN; + + @Parameter(name = ApiConstants.BIND_PASSWORD, type = CommandType.STRING, description = "Enter the password.") + private String bindPassword; + + @Parameter(name = ApiConstants.TRUST_STORE, type = CommandType.STRING, description = "Enter the path to trust certificates store.") + private String trustStore; + + @Parameter(name = ApiConstants.TRUST_STORE_PASSWORD, type = CommandType.STRING, description = "Enter the password for trust store.") + private String trustStorePassword; + + public Boolean getListAll() { + return listAll == null ? Boolean.FALSE : listAll; + } + + public String getBindPassword() { + return bindPassword; + } + + public String getBindDN() { + return bindDN; + } + + public void setBindDN(String bdn) { + this.bindDN = bdn; + } + + public String getQueryFilter() { + return queryFilter; + } + + public void setQueryFilter(String queryFilter) { + this.queryFilter = StringEscapeUtils.unescapeHtml(queryFilter); + } + + public String getSearchBase() { + return searchBase; + } + + public void setSearchBase(String searchBase) { + this.searchBase = searchBase; + } + + public Boolean getUseSSL() { + return useSSL == null ? Boolean.FALSE : useSSL; + } + + public void setUseSSL(Boolean useSSL) { + this.useSSL = useSSL; + } + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public Integer getPort() { + return port <= 0 ? 389 : port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public String getTrustStore() { + return trustStore; + } + + public void setTrustStore(String trustStore) { + this.trustStore = trustStore; + } + + public String getTrustStorePassword() { + return trustStorePassword; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + if (getListAll()) { + // return the existing conf + + LdapListConfigurationCmd listConfigurationCmd = new LdapListConfigurationCmd(_ldapManager); + Pair, Integer> result = _ldapManager.listConfigurations(listConfigurationCmd); + ListResponse response = new ListResponse(); + List responses = new ArrayList(); + + if (result.second() > 0) { + boolean useSSlConfig = _ldapConfiguration.getSSLStatus(); + String searchBaseConfig = _ldapConfiguration.getBaseDn(); + String bindDnConfig = _ldapConfiguration.getBindPrincipal(); + for (LdapConfigurationVO ldapConfigurationVO : result.first()) { + responses.add(this.createLDAPConfigResponse(ldapConfigurationVO.getHostname(), ldapConfigurationVO.getPort(), useSSlConfig, null, searchBaseConfig, + bindDnConfig)); + } + } + response.setResponses(responses); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else if (getHostname() == null || getPort() == null) { + throw new InvalidParameterValueException("You need to provide hostname, port to configure your LDAP server"); + } else { + boolean result = this.updateLDAP(); + if (result) { + LDAPConfigResponse lr = this.createLDAPConfigResponse(getHostname(), getPort(), getUseSSL(), getQueryFilter(), getSearchBase(), getBindDN()); + lr.setResponseName(getCommandName()); + this.setResponseObject(lr); + } + } + + } + + private LDAPConfigResponse createLDAPConfigResponse(String hostname, Integer port, Boolean useSSL, String queryFilter, String searchBase, String bindDN) { + LDAPConfigResponse lr = new LDAPConfigResponse(); + lr.setHostname(hostname); + lr.setPort(port.toString()); + lr.setUseSSL(useSSL.toString()); + lr.setQueryFilter(queryFilter); + lr.setBindDN(bindDN); + lr.setSearchBase(searchBase); + lr.setObjectName("ldapconfig"); + return lr; + } + + private boolean updateLDAP() { + LdapConfigurationResponse response = _ldapManager.addConfiguration(hostname, port); + + /** + * There is no query filter now. It is derived from ldap.user.object and ldap.search.group.principle + */ +// ConfigurationVO cvo = _configDao.findByName(LDAPParams.queryfilter.toString()); +// _configDao.update(cvo.getName(),cvo.getCategory(),getQueryFilter()); + + ConfigurationVO cvo = _configDao.findByName("ldap.basedn"); + _configDao.update(cvo.getName(), cvo.getCategory(), getSearchBase()); + + /** + * There is no ssl now. it is derived from the presence of trust store and password + */ +// cvo = _configDao.findByName(LDAPParams.usessl.toString()); +// _configDao.update(cvo.getName(),cvo.getCategory(),getUseSSL().toString()); + + cvo = _configDao.findByName("ldap.bind.principal"); + _configDao.update(cvo.getName(), cvo.getCategory(), getBindDN()); + + cvo = _configDao.findByName("ldap.bind.password"); + _configDao.update(cvo.getName(), cvo.getCategory(), getBindPassword()); + + cvo = _configDao.findByName("ldap.truststore"); + _configDao.update(cvo.getName(), cvo.getCategory(), getTrustStore()); + + cvo = _configDao.findByName("ldap.truststore.password"); + _configDao.update(cvo.getName(), cvo.getCategory(), getTrustStorePassword()); + + return true; + } + + private List listLDAPConfig() { + + LdapListConfigurationCmd listConfigurationCmd = new LdapListConfigurationCmd(_ldapManager); + Pair, Integer> result = _ldapManager.listConfigurations(listConfigurationCmd); + return result.first(); + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + +} diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPRemoveCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPRemoveCmd.java new file mode 100644 index 000000000000..535a545ade79 --- /dev/null +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPRemoveCmd.java @@ -0,0 +1,77 @@ +// 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.api.command; + +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.response.LDAPConfigResponse; +import org.apache.cloudstack.api.response.LDAPRemoveResponse; +import org.apache.cloudstack.ldap.LdapConfigurationVO; +import org.apache.cloudstack.ldap.LdapManager; +import org.apache.log4j.Logger; + +import com.cloud.user.Account; +import com.cloud.utils.Pair; + +/** + * @deprecated as of 4.3 use the new api {@link LdapDeleteConfigurationCmd} + */ +@Deprecated +@APICommand(name = "ldapRemove", description = "Remove the LDAP context for this site.", responseObject = LDAPConfigResponse.class, since = "3.0.1") +public class LDAPRemoveCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(LDAPRemoveCmd.class.getName()); + + @Inject + private LdapManager _ldapManager; + + private static final String s_name = "ldapremoveresponse"; + + @Override + public void execute() { + boolean result = this.removeLDAP(); + if (result) { + LDAPRemoveResponse lr = new LDAPRemoveResponse(); + lr.setObjectName("ldapremove"); + lr.setResponseName(getCommandName()); + this.setResponseObject(lr); + } + } + + private boolean removeLDAP() { + LdapListConfigurationCmd listConfigurationCmd = new LdapListConfigurationCmd(_ldapManager); + Pair, Integer> result = _ldapManager.listConfigurations(listConfigurationCmd); + for (LdapConfigurationVO config : result.first()) { + _ldapManager.deleteConfiguration(config.getHostname()); + } + return true; + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + +} diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java index 981e72e64e15..08784102b2f2 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java @@ -125,7 +125,7 @@ private String generatePassword() throws ServerApiException { final SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG"); final byte bytes[] = new byte[20]; randomGen.nextBytes(bytes); - return Base64.encode(bytes).toString(); + return new String(Base64.encode(bytes)); } catch (final NoSuchAlgorithmException e) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate random password"); diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java index 063db0e5ae16..5e724e8fa5c2 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java @@ -16,11 +16,17 @@ // under the License. package org.apache.cloudstack.api.command; -import com.cloud.domain.Domain; -import com.cloud.exception.*; -import com.cloud.user.AccountService; -import com.cloud.user.DomainService; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.inject.Inject; + import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.LdapUserResponse; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.ldap.LdapManager; @@ -30,13 +36,10 @@ import org.apache.log4j.Logger; import org.bouncycastle.util.encoders.Base64; -import javax.inject.Inject; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import com.cloud.domain.Domain; +import com.cloud.exception.*; +import com.cloud.user.AccountService; +import com.cloud.user.DomainService; @APICommand(name = "importLdapUsers", description = "Import LDAP users", responseObject = LdapUserResponse.class, since = "4.3.0") public class LdapImportUsersCmd extends BaseListCmd { @@ -45,117 +48,136 @@ public class LdapImportUsersCmd extends BaseListCmd { private static final String s_name = "ldapuserresponse"; - @Parameter(name = ApiConstants.TIMEZONE, type = CommandType.STRING, - description = "Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.") + @Parameter(name = ApiConstants.TIMEZONE, type = CommandType.STRING, description = "Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.") private String timezone; - @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, required = true, - description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") + @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, required = true, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") private Short accountType; @Parameter(name = ApiConstants.ACCOUNT_DETAILS, type = CommandType.MAP, description = "details for account used to store specific parameters") private Map details; - @Parameter(name = ApiConstants.DOMAIN, type = CommandType.STRING, - description = "Specifies the domain to which the ldap users are to be imported. If no domain is specified, a domain will created using group parameter. If the " + - "group is also not specified, a domain name based on the OU information will be created. If no OU hierarchy exists, will be defaulted to ROOT domain") - private String domainName; + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Specifies the domain to which the ldap users are to be " + + "imported. If no domain is specified, a domain will created using group parameter. If the group is also not specified, a domain name based on the OU information will be " + + "created. If no OU hierarchy exists, will be defaulted to ROOT domain") + private Long domainId; - @Parameter(name = ApiConstants.GROUP, type = CommandType.STRING, - description = "Specifies the group name from which the ldap users are to be imported. If no group is specified, all the users will be imported.") + @Parameter(name = ApiConstants.GROUP, type = CommandType.STRING, description = "Specifies the group name from which the ldap users are to be imported. " + + "If no group is specified, all the users will be imported.") private String groupName; + private Domain _domain; + @Inject private LdapManager _ldapManager; public LdapImportUsersCmd() { - super(); + super(); } public LdapImportUsersCmd(final LdapManager ldapManager, final DomainService domainService, final AccountService accountService) { - super(); - _ldapManager = ldapManager; - _domainService = domainService; - _accountService = accountService; + super(); + _ldapManager = ldapManager; + _domainService = domainService; + _accountService = accountService; } @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, - NetworkRuleConflictException { - List ldapResponses = null; - final ListResponse response = new ListResponse(); - try { - List users; - if(StringUtils.isNotBlank(groupName)) { - users = _ldapManager.getUsersInGroup(groupName); - } else { - users = _ldapManager.getUsers(); - } - for (LdapUser user : users) { - Domain domain = getDomain(user); - _accountService.createUserAccount(user.getUsername(), generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, user.getUsername(), - accountType, domain.getId(), domain.getNetworkDomain(), details, UUID.randomUUID().toString(), UUID.randomUUID().toString()); - } - ldapResponses = createLdapUserResponse(users); - } catch (final NoLdapUserMatchingQueryException ex) { - ldapResponses = new ArrayList(); - } finally { - response.setResponses(ldapResponses); - response.setResponseName(getCommandName()); - setResponseObject(response); - } + NetworkRuleConflictException { + + List users; + try { + if (StringUtils.isNotBlank(groupName)) { + users = _ldapManager.getUsersInGroup(groupName); + } else { + users = _ldapManager.getUsers(); + } + } catch (NoLdapUserMatchingQueryException ex) { + users = new ArrayList(); + s_logger.info("No Ldap user matching query. "+" ::: "+ex.getMessage()); + } + + List addedUsers = new ArrayList(); + for (LdapUser user : users) { + Domain domain = getDomain(user); + try { + _accountService.createUserAccount(user.getUsername(), generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, user.getUsername(), + accountType, domain.getId(), domain.getNetworkDomain(), details, UUID.randomUUID().toString(), UUID.randomUUID().toString()); + addedUsers.add(user); + } catch (InvalidParameterValueException ex) { + s_logger.error("Failed to create user with username: " + user.getUsername() +" ::: "+ex.getMessage()); + } + } + ListResponse response = new ListResponse(); + response.setResponses(createLdapUserResponse(addedUsers)); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + private Domain getDomainForName(String name) { + Domain domain = null; + if (StringUtils.isNotBlank(name)) { + //removing all the special characters and trimming its length to 190 to make the domain valid. + String domainName = StringUtils.substring(name.replaceAll("\\W", ""), 0, 190); + if (StringUtils.isNotBlank(domainName)) { + domain = _domainService.getDomainByName(domainName, Domain.ROOT_DOMAIN); + if (domain == null) { + domain = _domainService.createDomain(domainName, Domain.ROOT_DOMAIN, domainName, UUID.randomUUID().toString()); + } + } + } + return domain; } private Domain getDomain(LdapUser user) { - String csDomainName = null; - if (StringUtils.isNotBlank(domainName)) { - csDomainName = domainName; - } else { - if (StringUtils.isNotBlank(groupName)) { - csDomainName = groupName; - } else if (StringUtils.isNotBlank(user.getDomain())) { - csDomainName = user.getDomain(); - } - //removing all the special characters and trimming it length 190 to make the domain valid. - csDomainName = StringUtils.substring(csDomainName.replaceAll("\\W",""),0,190); - } - Domain domain; - if (StringUtils.isNotBlank(csDomainName)) { - domain = _domainService.getDomainByName(csDomainName, Domain.ROOT_DOMAIN); - - if (domain == null) { - domain = _domainService.createDomain(csDomainName, Domain.ROOT_DOMAIN, csDomainName, UUID.randomUUID().toString()); - } - } else { - domain = _domainService.getDomain(Domain.ROOT_DOMAIN); - } - - return domain; + Domain domain; + if (_domain != null) { + //this means either domain id or groupname is passed and this will be same for all the users in this call. hence returning it. + domain = _domain; + } else { + if (domainId != null) { + // a domain Id is passed. use it for this user and all the users in the same api call (by setting _domain) + domain = _domain = _domainService.getDomain(domainId); + } else { + // a group name is passed. use it for this user and all the users in the same api call(by setting _domain) + domain = _domain = getDomainForName(groupName); + if (domain == null) { + //use the domain from the LDAP for this user + domain = getDomainForName(user.getDomain()); + } + } + if (domain == null) { + // could not get a domain using domainId / LDAP group / OU of LDAP user. using ROOT domain for this user + domain = _domainService.getDomain(Domain.ROOT_DOMAIN); + } + } + return domain; } private List createLdapUserResponse(List users) { - final List ldapResponses = new ArrayList(); - for (final LdapUser user : users) { - final LdapUserResponse ldapResponse = _ldapManager.createLdapUserResponse(user); - ldapResponse.setObjectName("LdapUser"); - ldapResponses.add(ldapResponse); - } - return ldapResponses; + final List ldapResponses = new ArrayList(); + for (final LdapUser user : users) { + final LdapUserResponse ldapResponse = _ldapManager.createLdapUserResponse(user); + ldapResponse.setObjectName("LdapUser"); + ldapResponses.add(ldapResponse); + } + return ldapResponses; } @Override public String getCommandName() { - return s_name; + return s_name; } private String generatePassword() throws ServerApiException { - try { - final SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG"); - final byte bytes[] = new byte[20]; - randomGen.nextBytes(bytes); - return Base64.encode(bytes).toString(); - } catch (final NoSuchAlgorithmException e) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate random password"); - } + try { + final SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG"); + final byte bytes[] = new byte[20]; + randomGen.nextBytes(bytes); + return new String(Base64.encode(bytes)); + } catch (final NoSuchAlgorithmException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate random password"); + } } } diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LDAPConfigResponse.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LDAPConfigResponse.java new file mode 100644 index 000000000000..8570bacab061 --- /dev/null +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LDAPConfigResponse.java @@ -0,0 +1,115 @@ +// 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.api.response; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +/** + * @deprecated as of 4.3 along with the api {@link org.apache.cloudstack.api.command.LDAPConfigCmd} + */ +@Deprecated +public class LDAPConfigResponse extends BaseResponse { + + @SerializedName(ApiConstants.HOST_NAME) + @Param(description = "Hostname or ip address of the ldap server eg: my.ldap.com") + private String hostname; + + @SerializedName(ApiConstants.PORT) + @Param(description = "Specify the LDAP port if required, default is 389") + private String port; + + @SerializedName(ApiConstants.USE_SSL) + @Param(description = "Check Use SSL if the external LDAP server is configured for LDAP over SSL") + private String useSSL; + + @SerializedName(ApiConstants.SEARCH_BASE) + @Param(description = "The search base defines the starting point for the search in the directory tree Example: dc=cloud,dc=com") + private String searchBase; + + @SerializedName(ApiConstants.QUERY_FILTER) + @Param(description = "You specify a query filter here, which narrows down the users, who can be part of this domain") + private String queryFilter; + + @SerializedName(ApiConstants.BIND_DN) + @Param(description = "Specify the distinguished name of a user with the search permission on the directory") + private String bindDN; + + @SerializedName(ApiConstants.BIND_PASSWORD) + @Param(description = "DN password") + private String bindPassword; + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + + public String getUseSSL() { + return useSSL; + } + + public void setUseSSL(String useSSL) { + this.useSSL = useSSL; + } + + public String getSearchBase() { + return searchBase; + } + + public void setSearchBase(String searchBase) { + this.searchBase = searchBase; + } + + public String getQueryFilter() { + return queryFilter; + } + + public void setQueryFilter(String queryFilter) { + this.queryFilter = queryFilter; + } + + public String getBindDN() { + return bindDN; + } + + public void setBindDN(String bindDN) { + this.bindDN = bindDN; + } + + public String getBindPassword() { + return bindPassword; + } + + public void setBindPassword(String bindPassword) { + this.bindPassword = bindPassword; + } + +} diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LDAPRemoveResponse.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LDAPRemoveResponse.java new file mode 100644 index 000000000000..9b473d2f385c --- /dev/null +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LDAPRemoveResponse.java @@ -0,0 +1,30 @@ +// 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.api.response; + +import org.apache.cloudstack.api.BaseResponse; + +/** + * @deprecated as of 4.3 along with the api {@link org.apache.cloudstack.api.command.LDAPRemoveCmd} + */ +@Deprecated +public class LDAPRemoveResponse extends BaseResponse { + + public LDAPRemoveResponse() { + super(); + } +} diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java index 559a9794b2de..dac917bba6db 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java @@ -25,6 +25,7 @@ import com.cloud.server.auth.DefaultUserAuthenticator; import com.cloud.user.UserAccount; import com.cloud.user.dao.UserAccountDao; +import com.cloud.utils.Pair; public class LdapAuthenticator extends DefaultUserAuthenticator { private static final Logger s_logger = Logger @@ -46,23 +47,27 @@ public LdapAuthenticator(final LdapManager ldapManager, _userAccountDao = userAccountDao; } - @Override - public boolean authenticate(final String username, final String password, - final Long domainId, final Map requestParameters) { + @Override + public Pair authenticate(final String username, final String password, final Long domainId, final Map requestParameters) { final UserAccount user = _userAccountDao.getUserAccount(username, domainId); - if (user == null) { - s_logger.debug("Unable to find user with " + username - + " in domain " + domainId); - return false; - } else if (_ldapManager.isLdapEnabled()) { - return _ldapManager.canAuthenticate(username, password); - } else { - return false; - } - } + if (user == null) { + s_logger.debug("Unable to find user with " + username + " in domain " + domainId); + return new Pair(false, null); + } else if (_ldapManager.isLdapEnabled()) { + boolean result = _ldapManager.canAuthenticate(username, password); + ActionOnFailedAuthentication action = null; + if (result == false) { + action = ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT; + } + return new Pair(result, action); + + } else { + return new Pair(false, ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT); + } + } @Override public String encode(final String password) { diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManagerImpl.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManagerImpl.java index 891d62538ab1..578ebce7f772 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManagerImpl.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManagerImpl.java @@ -38,205 +38,185 @@ @Component @Local(value = LdapManager.class) public class LdapManagerImpl implements LdapManager, LdapValidator { - private static final Logger s_logger = Logger - .getLogger(LdapManagerImpl.class.getName()); - - @Inject - private LdapConfigurationDao _ldapConfigurationDao; - - @Inject - private LdapContextFactory _ldapContextFactory; - - @Inject - private LdapUserManager _ldapUserManager; - - public LdapManagerImpl() { - super(); - } - - public LdapManagerImpl(final LdapConfigurationDao ldapConfigurationDao, - final LdapContextFactory ldapContextFactory, - final LdapUserManager ldapUserManager) { - super(); - _ldapConfigurationDao = ldapConfigurationDao; - _ldapContextFactory = ldapContextFactory; - _ldapUserManager = ldapUserManager; - } - - @Override - public LdapConfigurationResponse addConfiguration(final String hostname, - final int port) throws InvalidParameterValueException { - LdapConfigurationVO configuration = _ldapConfigurationDao - .findByHostname(hostname); - if (configuration == null) { - try { - final String providerUrl = "ldap://" + hostname + ":" + port; - _ldapContextFactory.createBindContext(providerUrl); - configuration = new LdapConfigurationVO(hostname, port); - _ldapConfigurationDao.persist(configuration); - s_logger.info("Added new ldap server with hostname: " - + hostname); - return new LdapConfigurationResponse(hostname, port); - } catch (final NamingException e) { - throw new InvalidParameterValueException( - "Unable to bind to the given LDAP server"); - } - } else { - throw new InvalidParameterValueException("Duplicate configuration"); - } - } - - @Override - public boolean canAuthenticate(final String username, final String password) { - final String escapedUsername = LdapUtils - .escapeLDAPSearchFilter(username); - try { - final LdapUser user = getUser(escapedUsername); - final String principal = user.getPrincipal(); - final DirContext context = _ldapContextFactory.createUserContext( - principal, password); - closeContext(context); - return true; - } catch (final NamingException e) { - s_logger.info("Failed to authenticate user: " + username - + ". incorrect password."); - return false; - } - } - - private void closeContext(final DirContext context) { - try { - if (context != null) { - context.close(); - } - } catch (final NamingException e) { - s_logger.warn(e.getMessage()); - } - } - - @Override - public LdapConfigurationResponse createLdapConfigurationResponse( - final LdapConfigurationVO configuration) { - final LdapConfigurationResponse response = new LdapConfigurationResponse(); - response.setHostname(configuration.getHostname()); - response.setPort(configuration.getPort()); - return response; - } - - @Override - public LdapUserResponse createLdapUserResponse(final LdapUser user) { - final LdapUserResponse response = new LdapUserResponse(); - response.setUsername(user.getUsername()); - response.setFirstname(user.getFirstname()); - response.setLastname(user.getLastname()); - response.setEmail(user.getEmail()); - response.setPrincipal(user.getPrincipal()); - response.setDomain(user.getDomain()); - return response; - } - - @Override - public LdapConfigurationResponse deleteConfiguration(final String hostname) - throws InvalidParameterValueException { - final LdapConfigurationVO configuration = _ldapConfigurationDao - .findByHostname(hostname); - if (configuration == null) { - throw new InvalidParameterValueException( - "Cannot find configuration with hostname " + hostname); - } else { - _ldapConfigurationDao.remove(configuration.getId()); - s_logger.info("Removed ldap server with hostname: " + hostname); - return new LdapConfigurationResponse(configuration.getHostname(), - configuration.getPort()); - } - } - - @Override - public List> getCommands() { - final List> cmdList = new ArrayList>(); - cmdList.add(LdapUserSearchCmd.class); - cmdList.add(LdapListUsersCmd.class); - cmdList.add(LdapAddConfigurationCmd.class); - cmdList.add(LdapDeleteConfigurationCmd.class); - cmdList.add(LdapListConfigurationCmd.class); - cmdList.add(LdapCreateAccountCmd.class); - cmdList.add(LdapImportUsersCmd.class); - return cmdList; - } - - @Override - public LdapUser getUser(final String username) throws NamingException { - DirContext context = null; - try { - context = _ldapContextFactory.createBindContext(); - - final String escapedUsername = LdapUtils - .escapeLDAPSearchFilter(username); - return _ldapUserManager.getUser(escapedUsername, context); - - } catch (final NamingException e) { - throw e; - } finally { - closeContext(context); - } - } - - @Override - public List getUsers() throws NoLdapUserMatchingQueryException { - DirContext context = null; - try { - context = _ldapContextFactory.createBindContext(); - return _ldapUserManager.getUsers(context); - } catch (final NamingException e) { - throw new NoLdapUserMatchingQueryException("*"); - } finally { - closeContext(context); - } - } + private static final Logger s_logger = Logger.getLogger(LdapManagerImpl.class.getName()); + + @Inject + private LdapConfigurationDao _ldapConfigurationDao; + + @Inject + private LdapContextFactory _ldapContextFactory; + + @Inject + private LdapUserManager _ldapUserManager; + + public LdapManagerImpl() { + super(); + } + + public LdapManagerImpl(final LdapConfigurationDao ldapConfigurationDao, final LdapContextFactory ldapContextFactory, final LdapUserManager ldapUserManager) { + super(); + _ldapConfigurationDao = ldapConfigurationDao; + _ldapContextFactory = ldapContextFactory; + _ldapUserManager = ldapUserManager; + } + + @Override + public LdapConfigurationResponse addConfiguration(final String hostname, final int port) throws InvalidParameterValueException { + LdapConfigurationVO configuration = _ldapConfigurationDao.findByHostname(hostname); + if (configuration == null) { + try { + final String providerUrl = "ldap://" + hostname + ":" + port; + _ldapContextFactory.createBindContext(providerUrl); + configuration = new LdapConfigurationVO(hostname, port); + _ldapConfigurationDao.persist(configuration); + s_logger.info("Added new ldap server with hostname: " + hostname); + return new LdapConfigurationResponse(hostname, port); + } catch (final NamingException e) { + throw new InvalidParameterValueException("Unable to bind to the given LDAP server"); + } + } else { + throw new InvalidParameterValueException("Duplicate configuration"); + } + } + + @Override + public boolean canAuthenticate(final String username, final String password) { + final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username); + try { + final LdapUser user = getUser(escapedUsername); + final String principal = user.getPrincipal(); + final DirContext context = _ldapContextFactory.createUserContext(principal, password); + closeContext(context); + return true; + } catch (final NamingException e) { + s_logger.info("Failed to authenticate user: " + username + ". incorrect password."); + return false; + } + } + + private void closeContext(final DirContext context) { + try { + if (context != null) { + context.close(); + } + } catch (final NamingException e) { + s_logger.warn(e.getMessage()); + } + } + + @Override + public LdapConfigurationResponse createLdapConfigurationResponse(final LdapConfigurationVO configuration) { + final LdapConfigurationResponse response = new LdapConfigurationResponse(); + response.setHostname(configuration.getHostname()); + response.setPort(configuration.getPort()); + return response; + } + + @Override + public LdapUserResponse createLdapUserResponse(final LdapUser user) { + final LdapUserResponse response = new LdapUserResponse(); + response.setUsername(user.getUsername()); + response.setFirstname(user.getFirstname()); + response.setLastname(user.getLastname()); + response.setEmail(user.getEmail()); + response.setPrincipal(user.getPrincipal()); + response.setDomain(user.getDomain()); + return response; + } + + @Override + public LdapConfigurationResponse deleteConfiguration(final String hostname) throws InvalidParameterValueException { + final LdapConfigurationVO configuration = _ldapConfigurationDao.findByHostname(hostname); + if (configuration == null) { + throw new InvalidParameterValueException("Cannot find configuration with hostname " + hostname); + } else { + _ldapConfigurationDao.remove(configuration.getId()); + s_logger.info("Removed ldap server with hostname: " + hostname); + return new LdapConfigurationResponse(configuration.getHostname(), configuration.getPort()); + } + } + + @Override + public List> getCommands() { + final List> cmdList = new ArrayList>(); + cmdList.add(LdapUserSearchCmd.class); + cmdList.add(LdapListUsersCmd.class); + cmdList.add(LdapAddConfigurationCmd.class); + cmdList.add(LdapDeleteConfigurationCmd.class); + cmdList.add(LdapListConfigurationCmd.class); + cmdList.add(LdapCreateAccountCmd.class); + cmdList.add(LdapImportUsersCmd.class); + cmdList.add(LDAPConfigCmd.class); + cmdList.add(LDAPRemoveCmd.class); + return cmdList; + } + + @Override + public LdapUser getUser(final String username) throws NamingException { + DirContext context = null; + try { + context = _ldapContextFactory.createBindContext(); + + final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username); + return _ldapUserManager.getUser(escapedUsername, context); + + } catch (final NamingException e) { + throw e; + } finally { + closeContext(context); + } + } + + @Override + public List getUsers() throws NoLdapUserMatchingQueryException { + DirContext context = null; + try { + context = _ldapContextFactory.createBindContext(); + return _ldapUserManager.getUsers(context); + } catch (final NamingException e) { + throw new NoLdapUserMatchingQueryException("*"); + } finally { + closeContext(context); + } + } @Override public List getUsersInGroup(String groupName) throws NoLdapUserMatchingQueryException { - DirContext context = null; - try { - context = _ldapContextFactory.createBindContext(); - return _ldapUserManager.getUsersInGroup(groupName, context); - } catch (final NamingException e) { - throw new NoLdapUserMatchingQueryException("groupName=" + groupName); - } finally { - closeContext(context); - } + DirContext context = null; + try { + context = _ldapContextFactory.createBindContext(); + return _ldapUserManager.getUsersInGroup(groupName, context); + } catch (final NamingException e) { + throw new NoLdapUserMatchingQueryException("groupName=" + groupName); + } finally { + closeContext(context); + } + } + + @Override + public boolean isLdapEnabled() { + return listConfigurations(new LdapListConfigurationCmd(this)).second() > 0; } @Override - public boolean isLdapEnabled() { - return listConfigurations(new LdapListConfigurationCmd(this)).second() > 0; - } - - @Override - public Pair, Integer> listConfigurations( - final LdapListConfigurationCmd cmd) { - final String hostname = cmd.getHostname(); - final int port = cmd.getPort(); - final Pair, Integer> result = _ldapConfigurationDao - .searchConfigurations(hostname, port); - return new Pair, Integer>( - result.first(), result.second()); - } - - @Override - public List searchUsers(final String username) - throws NoLdapUserMatchingQueryException { - DirContext context = null; - try { - context = _ldapContextFactory.createBindContext(); - final String escapedUsername = LdapUtils - .escapeLDAPSearchFilter(username); - return _ldapUserManager.getUsers("*" + escapedUsername + "*", - context); - } catch (final NamingException e) { - throw new NoLdapUserMatchingQueryException(username); - } finally { - closeContext(context); - } - } -} \ No newline at end of file + public Pair, Integer> listConfigurations(final LdapListConfigurationCmd cmd) { + final String hostname = cmd.getHostname(); + final int port = cmd.getPort(); + final Pair, Integer> result = _ldapConfigurationDao.searchConfigurations(hostname, port); + return new Pair, Integer>(result.first(), result.second()); + } + + @Override + public List searchUsers(final String username) throws NoLdapUserMatchingQueryException { + DirContext context = null; + try { + context = _ldapContextFactory.createBindContext(); + final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username); + return _ldapUserManager.getUsers("*" + escapedUsername + "*", context); + } catch (final NamingException e) { + throw new NoLdapUserMatchingQueryException(username); + } finally { + closeContext(context); + } + } +} diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy index 04556401d714..a66da1f3cffc 100644 --- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy +++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy @@ -20,8 +20,6 @@ import com.cloud.domain.Domain import com.cloud.domain.DomainVO import com.cloud.user.AccountService import com.cloud.user.DomainService -import com.cloud.user.UserAccount -import com.cloud.user.UserAccountVO import org.apache.cloudstack.api.command.LdapImportUsersCmd import org.apache.cloudstack.api.response.LdapUserResponse import org.apache.cloudstack.ldap.LdapManager @@ -31,160 +29,167 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification { def "Test successful return of getCommandName"() { - given: "We have an LdapManager, DomainService and a LdapImportUsersCmd" - def ldapManager = Mock(LdapManager) - def domainService = Mock(DomainService) - def accountService = Mock(AccountService) - def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) - when: "Get command name is called" - String commandName = ldapImportUsersCmd.getCommandName() - then: "ldapuserresponse is returned" - commandName == "ldapuserresponse" + given: "We have an LdapManager, DomainService and a LdapImportUsersCmd" + def ldapManager = Mock(LdapManager) + def domainService = Mock(DomainService) + def accountService = Mock(AccountService) + def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) + when: "Get command name is called" + String commandName = ldapImportUsersCmd.getCommandName() + then: "ldapuserresponse is returned" + commandName == "ldapuserresponse" } def "Test successful response from execute"() { - given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd" - def ldapManager = Mock(LdapManager) - def domainService = Mock(DomainService) - def accountService = Mock(AccountService) - - List users = new ArrayList() - users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) - users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")) - ldapManager.getUsers() >> users - LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") - LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering") - ldapManager.createLdapUserResponse(_) >>>[response1, response2] - - - Domain domain = new DomainVO("engineering", 1L, 1L, "engineering", UUID.randomUUID().toString()) - domainService.getDomainByName("engineering", 1L) >>> [null, domain] - 1 * domainService.createDomain("engineering", 1L, "engineering", _) >> domain - - def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) - ldapImportUsersCmd.accountType = 2; - - when: "LdapListUsersCmd is executed" - ldapImportUsersCmd.execute() - then: "a list of size 2 is returned" - ldapImportUsersCmd.responseObject.getResponses().size() == 2 + given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd" + def ldapManager = Mock(LdapManager) + def domainService = Mock(DomainService) + def accountService = Mock(AccountService) + + List users = new ArrayList() + users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) + users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")) + ldapManager.getUsers() >> users + LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") + LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering") + ldapManager.createLdapUserResponse(_) >>> [response1, response2] + + + Domain domain = new DomainVO("engineering", 1L, 1L, "engineering", UUID.randomUUID().toString()) + 2 * domainService.getDomainByName("engineering", 1L) >>> [null, domain] + 1 * domainService.createDomain("engineering", 1L, "engineering", _) >> domain + + def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) + ldapImportUsersCmd.accountType = 2; + + when: "LdapListUsersCmd is executed" + ldapImportUsersCmd.execute() + then: "a list of size 2 is returned" + ldapImportUsersCmd.responseObject.getResponses().size() == 2 } def "Test successful response from execute with group specified"() { - given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd" - def ldapManager = Mock(LdapManager) - def domainService = Mock(DomainService) - def accountService = Mock(AccountService) - - List users = new ArrayList() - users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) - users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")) - ldapManager.getUsersInGroup("TestGroup") >> users - LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") - LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering") - ldapManager.createLdapUserResponse(_) >>>[response1, response2] - - - Domain domain = new DomainVO("TestGroup", 1L, 1L, "TestGroup", UUID.randomUUID().toString()) - domainService.getDomainByName("TestGroup", 1L) >>> [null, domain] - 1 * domainService.createDomain("TestGroup", 1L, "TestGroup", _) >> domain - - def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) - ldapImportUsersCmd.accountType = 2; - ldapImportUsersCmd.groupName = "TestGroup"; - - when: "LdapListUsersCmd is executed" - ldapImportUsersCmd.execute() - then: "a list of size 2 is returned" - ldapImportUsersCmd.responseObject.getResponses().size() == 2 + given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd" + def ldapManager = Mock(LdapManager) + def domainService = Mock(DomainService) + def accountService = Mock(AccountService) + + List users = new ArrayList() + users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) + users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")) + ldapManager.getUsersInGroup("TestGroup") >> users + LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") + LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering") + ldapManager.createLdapUserResponse(_) >>> [response1, response2] + + + Domain domain = new DomainVO("TestGroup", 1L, 1L, "TestGroup", UUID.randomUUID().toString()) + 1 * domainService.getDomainByName("TestGroup", 1L) >>> null + 1 * domainService.createDomain("TestGroup", 1L, "TestGroup", _) >> domain + + def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) + ldapImportUsersCmd.accountType = 2; + ldapImportUsersCmd.groupName = "TestGroup"; + + when: "LdapListUsersCmd is executed" + ldapImportUsersCmd.execute() + then: "a list of size 2 is returned" + ldapImportUsersCmd.responseObject.getResponses().size() == 2 } def "Test successful response from execute with group and domain specified"() { - given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd" - def ldapManager = Mock(LdapManager) - def domainService = Mock(DomainService) - def accountService = Mock(AccountService) - - List users = new ArrayList() - users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) - users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")) - ldapManager.getUsersInGroup("TestGroup") >> users - LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") - LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering") - ldapManager.createLdapUserResponse(_) >>>[response1, response2] - - - Domain domain = new DomainVO("TestDomain", 1L, 1L, "TestDomain", UUID.randomUUID().toString()) - domainService.getDomainByName("TestDomain", 1L) >>> [null, domain] - 1 * domainService.createDomain("TestDomain", 1L, "TestDomain", _) >> domain - - def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) - ldapImportUsersCmd.accountType = 2; - ldapImportUsersCmd.groupName = "TestGroup"; - ldapImportUsersCmd.domainName = "TestDomain"; - - when: "LdapListUsersCmd is executed" - ldapImportUsersCmd.execute() - then: "a list of size 2 is returned" - ldapImportUsersCmd.responseObject.getResponses().size() == 2 + given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd" + def ldapManager = Mock(LdapManager) + def domainService = Mock(DomainService) + def accountService = Mock(AccountService) + + List users = new ArrayList() + users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) + users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")) + ldapManager.getUsersInGroup("TestGroup") >> users + LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") + LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering") + ldapManager.createLdapUserResponse(_) >>> [response1, response2] + + + Domain domain = new DomainVO("TestDomain", 1L, 1L, "TestDomain", UUID.randomUUID().toString()) + 1 * domainService.getDomain(1L) >> domain; + + def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) + ldapImportUsersCmd.accountType = 2; + ldapImportUsersCmd.groupName = "TestGroup"; + ldapImportUsersCmd.domainId = 1L; + + when: "LdapListUsersCmd is executed" + ldapImportUsersCmd.execute() + then: "a list of size 2 is returned" + ldapImportUsersCmd.responseObject.getResponses().size() == 2 } def "Test successful response from execute with domain specified"() { - given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd" - def ldapManager = Mock(LdapManager) - def domainService = Mock(DomainService) - def accountService = Mock(AccountService) - - List users = new ArrayList() - users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) - users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")) - ldapManager.getUsers() >> users - LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") - LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering") - ldapManager.createLdapUserResponse(_) >>>[response1, response2] - - - Domain domain = new DomainVO("TestDomain", 1L, 1L, "TestDomain", UUID.randomUUID().toString()) - domainService.getDomainByName("TestDomain", 1L) >>> [null, domain] - 1 * domainService.createDomain("TestDomain", 1L, "TestDomain", _) >> domain - - def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) - ldapImportUsersCmd.accountType = 2; - ldapImportUsersCmd.domainName = "TestDomain"; - - when: "LdapListUsersCmd is executed" - ldapImportUsersCmd.execute() - then: "a list of size 2 is returned" - ldapImportUsersCmd.responseObject.getResponses().size() == 2 + given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd" + def ldapManager = Mock(LdapManager) + def domainService = Mock(DomainService) + def accountService = Mock(AccountService) + + List users = new ArrayList() + users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) + users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")) + ldapManager.getUsers() >> users + LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") + LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering") + ldapManager.createLdapUserResponse(_) >>> [response1, response2] + + + Domain domain = new DomainVO("TestDomain", 1L, 1L, "TestDomain", UUID.randomUUID().toString()) + 1 * domainService.getDomain(1L) >> domain; + + def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) + ldapImportUsersCmd.accountType = 2; + ldapImportUsersCmd.domainId = 1L; + + when: "LdapListUsersCmd is executed" + ldapImportUsersCmd.execute() + then: "a list of size 2 is returned" + ldapImportUsersCmd.responseObject.getResponses().size() == 2 } - def "Test getDomain with no domain or group name specified specified"() { - given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd" - def ldapManager = Mock(LdapManager) - def domainService = Mock(DomainService) - def accountService = Mock(AccountService) - def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) - ldapImportUsersCmd.domainName = varDomainName - ldapImportUsersCmd.groupName = varGroupName - - def ldapUser1 = new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") - def ldapUser2 = new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering"); - - Domain domain = new DomainVO(expectedDomainName, 1L, 1L, expectedDomainName, UUID.randomUUID().toString()) - 2 * domainService.getDomainByName(expectedDomainName, 1L) >>> [null, domain] - 1 * domainService.createDomain(expectedDomainName, 1L, expectedDomainName, _) >> domain - - def result1 = ldapImportUsersCmd.getDomain(ldapUser1) - def result2 = ldapImportUsersCmd.getDomain(ldapUser2) - expect: "engineering domain is returned" - result1 == domain - result2 == domain - where: "The domain and group are set to the following values" - varDomainName | varGroupName | expectedDomainName - null | null | "engineering" - "TestDomain" | null | "TestDomain" - "TestDomain" | "TestGroup" | "TestDomain" - null | "TestGroup" | "TestGroup" + def "Test getDomain"() { + given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd" + def ldapManager = Mock(LdapManager) + def domainService = Mock(DomainService) + def accountService = Mock(AccountService) + def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) + ldapImportUsersCmd.domainId = varDomainId + ldapImportUsersCmd.groupName = varGroupName + + def ldapUser1 = new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") + def ldapUser2 = new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering"); + + Domain domain = new DomainVO(expectedDomainName, 1L, 1L, expectedDomainName, UUID.randomUUID().toString()); + if (varDomainId != null) { + 1 * domainService.getDomain(varDomainId) >> domain; + } else { + if(varGroupName != null) { + 1 * domainService.getDomainByName(expectedDomainName, 1L) >> null + } else { + domainService.getDomainByName(expectedDomainName, 1L) >>> [null, domain] + } + 1 * domainService.createDomain(expectedDomainName, 1L, expectedDomainName, _) >> domain + } + + def result1 = ldapImportUsersCmd.getDomain(ldapUser1) + def result2 = ldapImportUsersCmd.getDomain(ldapUser2) + expect: "engineering domain is returned" + result1 == domain + result2 == domain + where: "The domain and group are set to the following values" + varDomainId | varGroupName | expectedDomainName + null | null | "engineering" + 1L | null | "TestDomain" + 1L | "TestGroup" | "TestDomain" + null | "TestGroup" | "TestGroup" + null | "Test Group" | "TestGroup" } diff --git a/plugins/user-authenticators/md5/pom.xml b/plugins/user-authenticators/md5/pom.xml index 0d4231688307..0276c31817fe 100644 --- a/plugins/user-authenticators/md5/pom.xml +++ b/plugins/user-authenticators/md5/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java b/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java index 63583af4ad65..f8f75ed675a3 100644 --- a/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java +++ b/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java @@ -27,6 +27,7 @@ import com.cloud.user.UserAccount; import com.cloud.user.dao.UserAccountDao; +import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; /** @@ -34,47 +35,48 @@ * comparing it against the local database. * */ -@Local(value={UserAuthenticator.class}) +@Local(value = {UserAuthenticator.class}) public class MD5UserAuthenticator extends DefaultUserAuthenticator { - public static final Logger s_logger = Logger.getLogger(MD5UserAuthenticator.class); - - @Inject private UserAccountDao _userAccountDao; - - @Override - public boolean authenticate(String username, String password, Long domainId, Map requestParameters ) { - if (s_logger.isDebugEnabled()) { + public static final Logger s_logger = Logger.getLogger(MD5UserAuthenticator.class); + + @Inject + private UserAccountDao _userAccountDao; + + @Override + public Pair authenticate(String username, String password, Long domainId, Map requestParameters) { + if (s_logger.isDebugEnabled()) { s_logger.debug("Retrieving user: " + username); } UserAccount user = _userAccountDao.getUserAccount(username, domainId); if (user == null) { s_logger.debug("Unable to find user with " + username + " in domain " + domainId); - return false; + return new Pair(false, null); } - + if (!user.getPassword().equals(encode(password))) { s_logger.debug("Password does not match"); - return false; + return new Pair(false, ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT); } - return true; - } + return new Pair(true, null); + } - public String encode(String password) { - MessageDigest md5 = null; - try { - md5 = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - throw new CloudRuntimeException("Unable to hash password", e); - } + public String encode(String password) { + MessageDigest md5 = null; + try { + md5 = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + throw new CloudRuntimeException("Unable to hash password", e); + } - md5.reset(); - BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes())); - String pwStr = pwInt.toString(16); - int padding = 32 - pwStr.length(); - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < padding; i++) { - sb.append('0'); // make sure the MD5 password is 32 digits long - } - sb.append(pwStr); - return sb.toString(); - } + md5.reset(); + BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes())); + String pwStr = pwInt.toString(16); + int padding = 32 - pwStr.length(); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < padding; i++) { + sb.append('0'); // make sure the MD5 password is 32 digits long + } + sb.append(pwStr); + return sb.toString(); + } } diff --git a/plugins/user-authenticators/plain-text/pom.xml b/plugins/user-authenticators/plain-text/pom.xml index 14f021e07ef9..149eeac0bb19 100644 --- a/plugins/user-authenticators/plain-text/pom.xml +++ b/plugins/user-authenticators/plain-text/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java b/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java index 849e82e093d2..6a5f415bf736 100644 --- a/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java +++ b/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java @@ -24,36 +24,38 @@ import com.cloud.user.UserAccount; import com.cloud.user.dao.UserAccountDao; +import com.cloud.utils.Pair; - -@Local(value={UserAuthenticator.class}) +@Local(value = {UserAuthenticator.class}) public class PlainTextUserAuthenticator extends DefaultUserAuthenticator { - public static final Logger s_logger = Logger.getLogger(PlainTextUserAuthenticator.class); - - @Inject private UserAccountDao _userAccountDao; - - @Override - public boolean authenticate(String username, String password, Long domainId, Map requestParameters ) { - if (s_logger.isDebugEnabled()) { + public static final Logger s_logger = Logger.getLogger(PlainTextUserAuthenticator.class); + + @Inject + private UserAccountDao _userAccountDao; + + @Override + public Pair authenticate(String username, String password, Long domainId, Map requestParameters) { + if (s_logger.isDebugEnabled()) { s_logger.debug("Retrieving user: " + username); } UserAccount user = _userAccountDao.getUserAccount(username, domainId); if (user == null) { s_logger.debug("Unable to find user with " + username + " in domain " + domainId); - return false; + return new Pair(false, null); } - + if (!user.getPassword().equals(password)) { s_logger.debug("Password does not match"); - return false; + return new Pair(false, ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT); } - return true; - } - - @Override - public String encode(String password) { - // Plaintext so no encoding at all - return password; - } + + return new Pair(true, null); + } + + @Override + public String encode(String password) { + // Plaintext so no encoding at all + return password; + } } diff --git a/plugins/user-authenticators/sha256salted/pom.xml b/plugins/user-authenticators/sha256salted/pom.xml index 3ff190565db7..06e1c0be4b4d 100644 --- a/plugins/user-authenticators/sha256salted/pom.xml +++ b/plugins/user-authenticators/sha256salted/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.3.0-SNAPSHOT + 4.3.0 ../../pom.xml diff --git a/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java b/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java index 3592ddc8169e..36305f18c991 100644 --- a/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java +++ b/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java @@ -30,9 +30,10 @@ import com.cloud.user.UserAccount; import com.cloud.user.dao.UserAccountDao; +import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; -@Local(value={UserAuthenticator.class}) +@Local(value = {UserAuthenticator.class}) public class SHA256SaltedUserAuthenticator extends DefaultUserAuthenticator { public static final Logger s_logger = Logger.getLogger(SHA256SaltedUserAuthenticator.class); private static final String s_defaultPassword = "000000000000000000000000000="; @@ -45,8 +46,7 @@ public class SHA256SaltedUserAuthenticator extends DefaultUserAuthenticator { * @see com.cloud.server.auth.UserAuthenticator#authenticate(java.lang.String, java.lang.String, java.lang.Long, java.util.Map) */ @Override - public boolean authenticate(String username, String password, - Long domainId, Map requestParameters) { + public Pair authenticate(String username, String password, Long domainId, Map requestParameters) { if (s_logger.isDebugEnabled()) { s_logger.debug("Retrieving user: " + username); } @@ -72,7 +72,12 @@ public boolean authenticate(String username, String password, try { String hashedPassword = encode(password, salt); /* constantTimeEquals comes first in boolean since we need to thwart timing attacks */ - return constantTimeEquals(realPassword, hashedPassword) && realUser; + boolean result = constantTimeEquals(realPassword, hashedPassword) && realUser; + ActionOnFailedAuthentication action = null; + if (!result && realUser) { + action = ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT; + } + return new Pair(result, action); } catch (NoSuchAlgorithmException e) { throw new CloudRuntimeException("Unable to hash password", e); } catch (UnsupportedEncodingException e) { diff --git a/plugins/user-authenticators/sha256salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java b/plugins/user-authenticators/sha256salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java index 4c4c152326dc..39751c7b61d2 100644 --- a/plugins/user-authenticators/sha256salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java +++ b/plugins/user-authenticators/sha256salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java @@ -92,11 +92,11 @@ public void testEncode() throws UnsupportedEncodingException, NoSuchAlgorithmExc @Test public void testAuthentication() throws UnsupportedEncodingException, NoSuchAlgorithmException { Map dummyMap = new HashMap(); - assertEquals("32 byte salt authenticated", true, authenticator.authenticate("admin", "password", 0L, dummyMap)); - assertEquals("20 byte salt authenticated", true, authenticator.authenticate("admin20Byte", "password", 0L, dummyMap)); - assertEquals("fake user not authenticated", false, authenticator.authenticate("fake", "fake", 0L, dummyMap)); - assertEquals("bad password not authenticated", false, authenticator.authenticate("admin", "fake", 0L, dummyMap)); - assertEquals("20 byte user bad password not authenticated", false, authenticator.authenticate("admin20Byte", "fake", 0L, dummyMap)); + assertEquals("32 byte salt authenticated", true, authenticator.authenticate("admin", "password", 0L, dummyMap).first()); + assertEquals("20 byte salt authenticated", true, authenticator.authenticate("admin20Byte", "password", 0L, dummyMap).first()); + assertEquals("fake user not authenticated", false, authenticator.authenticate("fake", "fake", 0L, dummyMap).first()); + assertEquals("bad password not authenticated", false, authenticator.authenticate("admin", "fake", 0L, dummyMap).first()); + assertEquals("20 byte user bad password not authenticated", false, authenticator.authenticate("admin20Byte", "fake", 0L, dummyMap).first()); } // @Test diff --git a/pom.xml b/pom.xml index 2cee0840696f..d9ba1874f86a 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ org.apache.cloudstack cloudstack - 4.3.0-SNAPSHOT + 4.3.0 pom Apache CloudStack Apache CloudStack is an IaaS (“Infrastracture as a Service”) cloud orchestration platform. @@ -55,7 +55,7 @@ 1.9.0 build213-svnkit-1.3-patch 2.6.6 - 1.7.1 + 1.7.2 14.0-rc1 5.6.100-1-SNAPSHOT 3.1 @@ -82,11 +82,12 @@ 0.10 build/replace.properties 0.5.1 - 0.1.3 + 0.1.4 target 1.0.10 4.0.0 2.10 + 2.5.3 @@ -444,6 +445,21 @@ ${basedir}/${cs.target.dir}/classes ${basedir}/${cs.target.dir}/test-classes + + + org.codehaus.mojo + findbugs-maven-plugin + + + cloudstack-findbugs + none + + check + + + + + @@ -712,6 +728,25 @@ + + org.codehaus.mojo + findbugs-maven-plugin + ${cs.findbugs.version} + + Max + High + true + false + + + + cloudstack-findbugs + + check + + + + @@ -771,5 +806,23 @@ vmware-base + + enablefindbugs + + + + org.codehaus.mojo + findbugs-maven-plugin + + + cloudstack-findbugs + process-classes + true + + + + + + diff --git a/python/lib/cloudutils/serviceConfig.py b/python/lib/cloudutils/serviceConfig.py index d7c7e78c3abb..3c2333429261 100755 --- a/python/lib/cloudutils/serviceConfig.py +++ b/python/lib/cloudutils/serviceConfig.py @@ -763,9 +763,6 @@ def config(self): for port in self.ports: self.allowPort(port) - #FIXME: urgly make /root writable - bash("sudo chmod 0777 /root") - return True except: raise diff --git a/quickcloud/pom.xml b/quickcloud/pom.xml index 1b9975e8e429..4b6f9e2210cf 100644 --- a/quickcloud/pom.xml +++ b/quickcloud/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-maven-standard - 4.3.0-SNAPSHOT + 4.3.0 ../maven-standard/pom.xml diff --git a/scripts/storage/secondary/cloud-install-sys-tmplt b/scripts/storage/secondary/cloud-install-sys-tmplt index 2e822f3504c5..96b11de41d43 100755 --- a/scripts/storage/secondary/cloud-install-sys-tmplt +++ b/scripts/storage/secondary/cloud-install-sys-tmplt @@ -20,9 +20,9 @@ usage() { - printf "Usage: %s: -m -f [-h ] [ -s ][-u ] [-F ] [-e