diff --git a/agent/src/com/cloud/agent/VmmAgentShell.java b/agent/src/com/cloud/agent/VmmAgentShell.java deleted file mode 100644 index 190d1168284..00000000000 --- a/agent/src/com/cloud/agent/VmmAgentShell.java +++ /dev/null @@ -1,504 +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.agent; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.Agent.ExitStatus; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.StartupVMMAgentCommand; -import com.cloud.agent.dao.StorageComponent; -import com.cloud.agent.dao.impl.PropertiesStorage; -import com.cloud.agent.transport.Request; -import com.cloud.resource.ServerResource; -import com.cloud.utils.NumbersUtil; -import com.cloud.utils.PropertiesUtil; -import com.cloud.utils.backoff.BackoffAlgorithm; -import com.cloud.utils.backoff.impl.ConstantTimeBackoff; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.net.MacAddress; -import com.cloud.utils.nio.HandlerFactory; -import com.cloud.utils.nio.Link; -import com.cloud.utils.nio.NioServer; -import com.cloud.utils.nio.Task; - -/** - * Implementation of agent shell to run the agents on System Center Virtual Machine manager - **/ - -public class VmmAgentShell implements IAgentShell, HandlerFactory { - - private static final Logger s_logger = Logger.getLogger(VmmAgentShell.class.getName()); - private final Properties _properties = new Properties(); - private final Map _cmdLineProperties = new HashMap(); - private StorageComponent _storage; - private BackoffAlgorithm _backoff; - private String _version; - private String _zone; - private String _pod; - private String _cluster; - private String _host; - private String _privateIp; - private int _port; - private int _proxyPort; - private int _workers; - private String _guid; - static private NioServer _connection; - static private int _listenerPort=9000; - private int _nextAgentId = 1; - private volatile boolean _exit = false; - private int _pingRetries; - private final Thread _consoleProxyMain = null; - private final List _agents = new ArrayList(); - - public VmmAgentShell() { - } - - @Override - public Properties getProperties() { - return _properties; - } - - @Override - public BackoffAlgorithm getBackoffAlgorithm() { - return _backoff; - } - - @Override - public int getPingRetries() { - return _pingRetries; - } - - @Override - public String getZone() { - return _zone; - } - - @Override - public String getPod() { - return _pod; - } - - @Override - public String getHost() { - return _host; - } - - @Override - public String getPrivateIp() { - return _privateIp; - } - - @Override - public int getPort() { - return _port; - } - - @Override - public int getProxyPort() { - return _proxyPort; - } - - @Override - public int getWorkers() { - return _workers; - } - - @Override - public String getGuid() { - return _guid; - } - - @Override - public void upgradeAgent(String url) { - // TODO Auto-generated method stub - - } - - @Override - public String getVersion() { - return _version; - } - - @Override - public Map getCmdLineProperties() { - // TODO Auto-generated method stub - return _cmdLineProperties; - } - - public String getProperty(String prefix, String name) { - if(prefix != null) - return _properties.getProperty(prefix + "." + name); - - return _properties.getProperty(name); - } - - @Override - public String getPersistentProperty(String prefix, String name) { - if(prefix != null) - return _storage.get(prefix + "." + name); - return _storage.get(name); - } - - @Override - public void setPersistentProperty(String prefix, String name, String value) { - if(prefix != null) - _storage.persist(prefix + "." + name, value); - else - _storage.persist(name, value); - } - - private void loadProperties() throws ConfigurationException { - final File file = PropertiesUtil.findConfigFile("agent.properties"); - if (file == null) { - throw new ConfigurationException("Unable to find agent.properties."); - } - - s_logger.info("agent.properties found at " + file.getAbsolutePath()); - - try { - _properties.load(new FileInputStream(file)); - } catch (final FileNotFoundException ex) { - throw new CloudRuntimeException("Cannot find the file: " + file.getAbsolutePath(), ex); - } catch (final IOException ex) { - throw new CloudRuntimeException("IOException in reading " + file.getAbsolutePath(), ex); - } - } - - protected boolean parseCommand(final String[] args) throws ConfigurationException { - String host = null; - String workers = null; - String port = null; - String zone = null; - String pod = null; - String guid = null; - for (int i = 0; i < args.length; i++) { - final String[] tokens = args[i].split("="); - if (tokens.length != 2) { - System.out.println("Invalid Parameter: " + args[i]); - continue; - } - - // save command line properties - _cmdLineProperties.put(tokens[0], tokens[1]); - - if (tokens[0].equalsIgnoreCase("port")) { - port = tokens[1]; - } else if (tokens[0].equalsIgnoreCase("threads")) { - workers = tokens[1]; - } else if (tokens[0].equalsIgnoreCase("host")) { - host = tokens[1]; - } else if(tokens[0].equalsIgnoreCase("zone")) { - zone = tokens[1]; - } else if(tokens[0].equalsIgnoreCase("pod")) { - pod = tokens[1]; - } else if(tokens[0].equalsIgnoreCase("guid")) { - guid = tokens[1]; - } else if(tokens[0].equalsIgnoreCase("eth1ip")) { - _privateIp = tokens[1]; - } - } - - if (port == null) { - port = getProperty(null, "port"); - } - - _port = NumbersUtil.parseInt(port, 8250); - - _proxyPort = NumbersUtil.parseInt(getProperty(null, "consoleproxy.httpListenPort"), 443); - - if (workers == null) { - workers = getProperty(null, "workers"); - } - - _workers = NumbersUtil.parseInt(workers, 5); - - if (host == null) { - host = getProperty(null, "host"); - } - - if (host == null) { - host = "localhost"; - } - _host = host; - - if(zone != null) - _zone = zone; - else - _zone = getProperty(null, "zone"); - if (_zone == null || (_zone.startsWith("@") && _zone.endsWith("@"))) { - _zone = "default"; - } - - if(pod != null) - _pod = pod; - else - _pod = getProperty(null, "pod"); - if (_pod == null || (_pod.startsWith("@") && _pod.endsWith("@"))) { - _pod = "default"; - } - - if (_host == null || (_host.startsWith("@") && _host.endsWith("@"))) { - throw new ConfigurationException("Host is not configured correctly: " + _host); - } - - final String retries = getProperty(null, "ping.retries"); - _pingRetries = NumbersUtil.parseInt(retries, 5); - - String value = getProperty(null, "developer"); - boolean developer = Boolean.parseBoolean(value); - - if(guid != null) - _guid = guid; - else - _guid = getProperty(null, "guid"); - if (_guid == null) { - if (!developer) { - throw new ConfigurationException("Unable to find the guid"); - } - _guid = MacAddress.getMacAddress().toString(":"); - } - - return true; - } - - private void launchAgentFromTypeInfo() throws ConfigurationException { - String typeInfo = getProperty(null, "type"); - if (typeInfo == null) { - s_logger.error("Unable to retrieve the type"); - throw new ConfigurationException("Unable to retrieve the type of this agent."); - } - s_logger.trace("Launching agent based on type=" + typeInfo); - } - - private void launchAgent() throws ConfigurationException { - String resourceClassNames = getProperty(null, "resource"); - s_logger.trace("resource=" + resourceClassNames); - if(resourceClassNames != null) { - launchAgentFromClassInfo(resourceClassNames); - return; - } - - launchAgentFromTypeInfo(); - } - - private void init(String[] args) throws ConfigurationException{ - - final Class c = this.getClass(); - _version = c.getPackage().getImplementationVersion(); - if (_version == null) { - throw new CloudRuntimeException("Unable to find the implementation version of this agent"); - } - s_logger.info("Implementation Version is " + _version); - - parseCommand(args); - - s_logger.info("Defaulting to using properties file for storage"); - _storage = new PropertiesStorage(); - _storage.configure("Storage", new HashMap()); - - // merge with properties from command line to let resource access command line parameters - for(Map.Entry cmdLineProp : getCmdLineProperties().entrySet()) { - _properties.put(cmdLineProp.getKey(), cmdLineProp.getValue()); - } - - s_logger.info("Defaulting to the constant time backoff algorithm"); - _backoff = new ConstantTimeBackoff(); - _backoff.configure("ConstantTimeBackoff", new HashMap()); - } - - private void launchAgentFromClassInfo(String resourceClassNames) throws ConfigurationException { - String[] names = resourceClassNames.split("\\|"); - for(String name: names) { - Class impl; - try { - impl = Class.forName(name); - final Constructor constructor = impl.getDeclaredConstructor(); - constructor.setAccessible(true); - ServerResource resource = (ServerResource)constructor.newInstance(); - launchAgent(getNextAgentId(), resource); - } catch (final ClassNotFoundException e) { - throw new ConfigurationException("Resource class not found: " + name); - } catch (final SecurityException e) { - throw new ConfigurationException("Security excetion when loading resource: " + name); - } catch (final NoSuchMethodException e) { - throw new ConfigurationException("Method not found excetion when loading resource: " + name); - } catch (final IllegalArgumentException e) { - throw new ConfigurationException("Illegal argument excetion when loading resource: " + name); - } catch (final InstantiationException e) { - throw new ConfigurationException("Instantiation excetion when loading resource: " + name); - } catch (final IllegalAccessException e) { - throw new ConfigurationException("Illegal access exception when loading resource: " + name); - } catch (final InvocationTargetException e) { - throw new ConfigurationException("Invocation target exception when loading resource: " + name); - } - } - } - - private void launchAgent(int localAgentId, ServerResource resource) throws ConfigurationException { - // we don't track agent after it is launched for now - Agent agent = new Agent(this, localAgentId, resource); - _agents.add(agent); - agent.start(); - } - - public synchronized int getNextAgentId() { - return _nextAgentId++; - } - - private void run(String[] args) { - - try { - System.setProperty("java.net.preferIPv4Stack","true"); - loadProperties(); - init(args); - - String instance = getProperty(null, "instance"); - if (instance == null) { - instance = ""; - } else { - instance += "."; - } - - // TODO need to do this check. For Agentshell running on windows needs different approach - //final String run = "agent." + instance + "pid"; - //s_logger.debug("Checking to see if " + run + "exists."); - //ProcessUtil.pidCheck(run); - - - // TODO: For Hyper-V agent.properties need to be revamped to support multiple agents - // corresponding to multiple clusters but running on a SCVMM host - - // read the persistent storage and launch the agents - //launchAgent(); - - // FIXME get rid of this approach of agent listening for boot strap commands from the management server - - // now listen for bootstrap request from the management server and launch agents - _connection = new NioServer("VmmAgentShell", _listenerPort, 1, this); - _connection.start(); - s_logger.info("SCVMM agent is listening on port " +_listenerPort + " for bootstrap command from management server"); - while(_connection.isRunning()); - } catch(final ConfigurationException e) { - s_logger.error("Unable to start agent: " + e.getMessage()); - System.out.println("Unable to start agent: " + e.getMessage()); - System.exit(ExitStatus.Configuration.value()); - } catch (final Exception e) { - s_logger.error("Unable to start agent: ", e); - System.out.println("Unable to start agent: " + e.getMessage()); - System.exit(ExitStatus.Error.value()); - } - } - - @Override - public Task create(com.cloud.utils.nio.Task.Type type, Link link, - byte[] data) { - return new AgentBootStrapHandler(type, link, data); - } - - public void stop() { - _exit = true; - if(_consoleProxyMain != null) { - _consoleProxyMain.interrupt(); - } - } - - public static void main(String[] args) { - - VmmAgentShell shell = new VmmAgentShell(); - Runtime.getRuntime().addShutdownHook(new ShutdownThread(shell)); - shell.run(args); - } - - // class to handle the bootstrap command from the management server - private class AgentBootStrapHandler extends Task { - - public AgentBootStrapHandler(Task.Type type, Link link, byte[] data) { - super(type, link, data); - } - - @Override - protected void doTask(Task task) throws Exception { - final Type type = task.getType(); - s_logger.info("recieved task of type "+ type.toString() +" to handle in BootStrapTakHandler"); - if (type == Task.Type.DATA) - { - final byte[] data = task.getData(); - final Request request = Request.parse(data); - final Command cmd = request.getCommand(); - - if (cmd instanceof StartupVMMAgentCommand) { - - StartupVMMAgentCommand vmmCmd = (StartupVMMAgentCommand) cmd; - - _zone = Long.toString(vmmCmd.getDataCenter()); - _cmdLineProperties.put("zone", _zone); - - _pod = Long.toString(vmmCmd.getPod()); - _cmdLineProperties.put("pod", _pod); - - _cluster = vmmCmd.getClusterName(); - _cmdLineProperties.put("cluster", _cluster); - - _guid = vmmCmd.getGuid(); - _cmdLineProperties.put("guid", _guid); - - _host = vmmCmd.getManagementServerIP(); - _port = NumbersUtil.parseInt(vmmCmd.getport(), 8250); - - s_logger.info("Recieved boot strap command from management server with parameters " + - " Zone:"+ _zone + " "+ - " Cluster:"+ _cluster + " "+ - " pod:"+_pod + " "+ - " host:"+ _host +" "+ - " port:"+_port); - - launchAgentFromClassInfo("com.cloud.hypervisor.hyperv.resource.HypervResource"); - - // TODO: persist the info in agent.properties for agent restarts - } - } - } - } - - private static class ShutdownThread extends Thread { - VmmAgentShell _shell; - public ShutdownThread(VmmAgentShell shell) { - this._shell = shell; - } - - @Override - public void run() { - _shell.stop(); - } - } - -} \ No newline at end of file diff --git a/api/src/com/cloud/agent/api/to/DiskTO.java b/api/src/com/cloud/agent/api/to/DiskTO.java index 7b32f006606..556ccd4db46 100644 --- a/api/src/com/cloud/agent/api/to/DiskTO.java +++ b/api/src/com/cloud/agent/api/to/DiskTO.java @@ -23,14 +23,16 @@ import com.cloud.storage.Volume; public class DiskTO { private DataTO data; private Long diskSeq; + private String vdiUuid; private Volume.Type type; public DiskTO() { } - public DiskTO(DataTO data, Long diskSeq, Volume.Type type) { + public DiskTO(DataTO data, Long diskSeq, String vdiUuid, Volume.Type type) { this.data = data; this.diskSeq = diskSeq; + this.vdiUuid = vdiUuid; this.type = type; } @@ -50,6 +52,14 @@ public class DiskTO { this.diskSeq = diskSeq; } + public String getVdiUuid() { + return vdiUuid; + } + + public void setVdiUuid(String vdiUuid) { + this.vdiUuid = vdiUuid; + } + public Volume.Type getType() { return type; } diff --git a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java index c6ee9f24a11..544071d12b2 100644 --- a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java +++ b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java @@ -108,6 +108,12 @@ public class FirewallRuleTO implements InternalIdentity { this.trafficType = trafficType; } + public FirewallRuleTO(FirewallRule rule, String srcVlanTag, String srcIp, FirewallRule.Purpose purpose, FirewallRule.TrafficType trafficType, boolean defaultEgressPolicy) { + this(rule.getId(),srcVlanTag, srcIp, rule.getProtocol(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getState()==State.Revoke, rule.getState()==State.Active, purpose,rule.getSourceCidrList(),rule.getIcmpType(),rule.getIcmpCode()); + this.trafficType = trafficType; + this.defaultEgressPolicy = defaultEgressPolicy; + } + public FirewallRuleTO(FirewallRule rule, String srcVlanTag, String srcIp, FirewallRule.Purpose purpose, boolean revokeState, boolean alreadyAdded) { this(rule.getId(),srcVlanTag, srcIp, rule.getProtocol(), rule.getSourcePortStart(), rule.getSourcePortEnd(), revokeState, alreadyAdded, purpose,rule.getSourceCidrList(),rule.getIcmpType(),rule.getIcmpCode()); } diff --git a/api/src/com/cloud/network/NetworkModel.java b/api/src/com/cloud/network/NetworkModel.java index ea39d835eb7..01c0e2195d4 100644 --- a/api/src/com/cloud/network/NetworkModel.java +++ b/api/src/com/cloud/network/NetworkModel.java @@ -276,4 +276,6 @@ public interface NetworkModel { Nic getNicInNetworkIncludingRemoved(long vmId, long networkId); boolean getExecuteInSeqNtwkElmtCmd(); + + boolean isNetworkReadyForGc(long networkId); } \ No newline at end of file diff --git a/api/src/com/cloud/offering/DiskOffering.java b/api/src/com/cloud/offering/DiskOffering.java index ae4528cc81a..9c196e08b69 100644 --- a/api/src/com/cloud/offering/DiskOffering.java +++ b/api/src/com/cloud/offering/DiskOffering.java @@ -47,12 +47,24 @@ public interface DiskOffering extends InfrastructureEntity, Identity, InternalId Date getCreated(); - long getDiskSize(); - boolean isCustomized(); void setDiskSize(long diskSize); + long getDiskSize(); + + void setCustomizedIops(Boolean customizedIops); + + Boolean isCustomizedIops(); + + void setMinIops(Long minIops); + + Long getMinIops(); + + void setMaxIops(Long maxIops); + + Long getMaxIops(); + void setBytesReadRate(Long bytesReadRate); Long getBytesReadRate(); diff --git a/api/src/com/cloud/storage/Storage.java b/api/src/com/cloud/storage/Storage.java index 9a50ffa786c..07b6667e246 100755 --- a/api/src/com/cloud/storage/Storage.java +++ b/api/src/com/cloud/storage/Storage.java @@ -26,6 +26,7 @@ public class Storage { VHD(true, true, true, "vhd"), ISO(false, false, false, "iso"), OVA(true, true, true, "ova"), + VHDX(true, true, true, "vhdx"), BAREMETAL(false, false, false, "BAREMETAL"), TAR(false, false, false, "tar"); diff --git a/api/src/com/cloud/storage/StoragePool.java b/api/src/com/cloud/storage/StoragePool.java index 8f8b8644ddc..6e9af12d24e 100644 --- a/api/src/com/cloud/storage/StoragePool.java +++ b/api/src/com/cloud/storage/StoragePool.java @@ -60,6 +60,8 @@ public interface StoragePool extends Identity, InternalIdentity { */ long getUsedBytes(); + Long getCapacityIops(); + Long getClusterId(); /** diff --git a/api/src/com/cloud/storage/Volume.java b/api/src/com/cloud/storage/Volume.java index f5ed4e267b6..342dfd3ab2e 100755 --- a/api/src/com/cloud/storage/Volume.java +++ b/api/src/com/cloud/storage/Volume.java @@ -122,6 +122,12 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba */ Long getSize(); + Long getMinIops(); + + Long getMaxIops(); + + String get_iScsiName(); + /** * @return the vm instance id */ diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 809e0236968..dd876f75ed3 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -51,6 +51,9 @@ public class ApiConstants { public static final String CPU_OVERCOMMIT_RATIO="cpuovercommitratio"; public static final String CREATED = "created"; public static final String CUSTOMIZED = "customized"; + public static final String CUSTOMIZED_IOPS = "customizediops"; + public static final String MIN_IOPS = "miniops"; + public static final String MAX_IOPS = "maxiops"; public static final String DESCRIPTION = "description"; public static final String DESTINATION_ZONE_ID = "destzoneid"; public static final String DETAILS = "details"; @@ -326,6 +329,9 @@ public class ApiConstants { public static final String SERVICE_CAPABILITY_LIST = "servicecapabilitylist"; public static final String CAN_CHOOSE_SERVICE_CAPABILITY = "canchooseservicecapability"; public static final String PROVIDER = "provider"; + public static final String MANAGED = "managed"; + public static final String CAPACITY_BYTES = "capacitybytes"; + 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_METHODS = "isolationmethods"; diff --git a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java index 9c86dcc9cfe..2d380a9e6f9 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java @@ -53,7 +53,7 @@ public class CreateDiskOfferingCmd extends BaseCmd { @Parameter(name=ApiConstants.TAGS, type=CommandType.STRING, description="tags for the disk offering", length=4096) private String tags; - @Parameter(name=ApiConstants.CUSTOMIZED, type=CommandType.BOOLEAN, description="whether disk offering is custom or not") + @Parameter(name=ApiConstants.CUSTOMIZED, type=CommandType.BOOLEAN, description="whether disk offering size is custom or not") private Boolean customized; @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.UUID, entityType=DomainResponse.class, @@ -63,6 +63,9 @@ public class CreateDiskOfferingCmd extends BaseCmd { @Parameter(name=ApiConstants.STORAGE_TYPE, type=CommandType.STRING, description="the storage type of the disk offering. Values are local and shared.") private String storageType = ServiceOffering.StorageType.shared.toString(); + @Parameter(name=ApiConstants.DISPLAY_OFFERING, type=CommandType.BOOLEAN, description="an optional field, whether to display the offering to the end user or not.") + private Boolean displayOffering; + @Parameter(name=ApiConstants.BYTES_READ_RATE, type=CommandType.LONG, required=false, description="bytes read rate of the disk offering") private Long bytesReadRate; @@ -75,8 +78,14 @@ public class CreateDiskOfferingCmd extends BaseCmd { @Parameter(name=ApiConstants.IOPS_WRITE_RATE, type=CommandType.LONG, required=false, description="io requests write rate of the disk offering") private Long iopsWriteRate; - @Parameter(name=ApiConstants.DISPLAY_OFFERING, type=CommandType.BOOLEAN, description="an optional field, whether to display the offering to the end user or not.") - private Boolean displayOffering; + @Parameter(name=ApiConstants.CUSTOMIZED_IOPS, type=CommandType.BOOLEAN, required=false, description="whether disk offering iops is custom or not") + private Boolean customizedIops; + + @Parameter(name=ApiConstants.MIN_IOPS, type=CommandType.LONG, required=false, description="min iops of the disk offering") + private Long minIops; + + @Parameter(name=ApiConstants.MAX_IOPS, type=CommandType.LONG, required=false, description="max iops of the disk offering") + private Long maxIops; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -102,6 +111,18 @@ public class CreateDiskOfferingCmd extends BaseCmd { return customized; } + public Boolean isCustomizedIops() { + return customizedIops; + } + + public Long getMinIops() { + return minIops; + } + + public Long getMaxIops() { + return maxIops; + } + public Long getDomainId(){ return domainId; } diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java index 2b1832955ce..2ee5a30cf8b 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java @@ -81,6 +81,18 @@ public class CreateStoragePoolCmd extends BaseCmd { required=false, description="the scope of the storage: cluster or zone") private String scope; + @Parameter(name=ApiConstants.MANAGED, type=CommandType.BOOLEAN, + required=false, description="whether the storage should be managed by CloudStack") + private Boolean managed; + + @Parameter(name=ApiConstants.CAPACITY_IOPS, type=CommandType.LONG, + required=false, description="IOPS CloudStack can provision from this storage pool") + private Long capacityIops; + + @Parameter(name=ApiConstants.CAPACITY_BYTES, type=CommandType.LONG, + required=false, description="bytes CloudStack can provision from this storage pool") + private Long capacityBytes; + @Parameter(name=ApiConstants.HYPERVISOR, type=CommandType.STRING, required=false, description="hypervisor type of the hosts in zone that will be attached to this storage pool. KVM, VMware supported as of now.") private String hypervisor; @@ -125,6 +137,18 @@ public class CreateStoragePoolCmd extends BaseCmd { return this.scope; } + public Boolean isManaged() { + return managed; + } + + public Long getCapacityIops() { + return capacityIops; + } + + public Long getCapacityBytes() { + return capacityBytes; + } + public String getHypervisor() { return hypervisor; } diff --git a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java index 8f9e817383c..78633c69574 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java @@ -213,7 +213,7 @@ public class RegisterTemplateCmd extends BaseCmd { } public Boolean isRoutingType() { - return isRoutingType == null ? false : isRoutingType; + return isRoutingType; } ///////////////////////////////////////////////////// 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 eff874cca4e..2c153b7fab1 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 @@ -69,6 +69,12 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd { @Parameter(name=ApiConstants.SIZE, type=CommandType.LONG, description="Arbitrary volume size") private Long size; + @Parameter(name=ApiConstants.MIN_IOPS, type=CommandType.LONG, description="min iops") + private Long minIops; + + @Parameter(name=ApiConstants.MAX_IOPS, type=CommandType.LONG, description="max iops") + private Long maxIops; + @Parameter(name=ApiConstants.SNAPSHOT_ID, type=CommandType.UUID, entityType=SnapshotResponse.class, description="the snapshot ID for the disk volume. Either diskOfferingId or snapshotId must be passed in.") private Long snapshotId; @@ -105,6 +111,14 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd { return size; } + public Long getMinIops() { + return minIops; + } + + public Long getMaxIops() { + return maxIops; + } + public Long getSnapshotId() { return snapshotId; } diff --git a/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java b/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java index af2124f3e2e..fdd24c59f85 100644 --- a/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java +++ b/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java @@ -53,6 +53,15 @@ public class DiskOfferingResponse extends BaseResponse { @SerializedName("iscustomized") @Param(description="true if disk offering uses custom size, false otherwise") private Boolean customized; + @SerializedName("iscustomizediops") @Param(description="true if disk offering uses custom iops, false otherwise") + private Boolean customizedIops; + + @SerializedName(ApiConstants.MIN_IOPS) @Param(description="the min iops of the disk offering") + private Long minIops; + + @SerializedName(ApiConstants.MAX_IOPS) @Param(description="the max iops of the disk offering") + private Long maxIops; + @SerializedName(ApiConstants.TAGS) @Param(description="the tags for the disk offering") private String tags; @@ -155,6 +164,30 @@ public class DiskOfferingResponse extends BaseResponse { this.customized = customized; } + public Boolean isCustomizedIops() { + return customizedIops; + } + + public void setCustomizedIops(Boolean customizedIops) { + this.customizedIops = customizedIops; + } + + public Long getMinIops() { + return minIops; + } + + public void setMinIops(Long minIops) { + this.minIops = minIops; + } + + public Long getMaxIops() { + return maxIops; + } + + public void setMaxIops(Long maxIops) { + this.maxIops = maxIops; + } + public String getStorageType() { return storageType; } diff --git a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java index d7b391d43c1..1a0222ebc92 100644 --- a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java +++ b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java @@ -76,6 +76,9 @@ public class StoragePoolResponse extends BaseResponse { @SerializedName("disksizeused") @Param(description="the host's currently used disk size") private Long diskSizeUsed; + @SerializedName("capacityiops") @Param(description="IOPS CloudStack can provision from this storage pool") + private Long capacityIops; + @SerializedName("tags") @Param(description="the tags for the storage pool") private String tags; @@ -239,6 +242,14 @@ public class StoragePoolResponse extends BaseResponse { this.diskSizeUsed = diskSizeUsed; } + public Long getCapacityIops() { + return capacityIops; + } + + public void setCapacityIops(Long capacityIops) { + this.capacityIops = capacityIops; + } + public String getTags() { return tags; } diff --git a/api/src/org/apache/cloudstack/api/response/TemplateZoneResponse.java b/api/src/org/apache/cloudstack/api/response/TemplateZoneResponse.java index 9d26ad9fc10..3af9a2f19b6 100644 --- a/api/src/org/apache/cloudstack/api/response/TemplateZoneResponse.java +++ b/api/src/org/apache/cloudstack/api/response/TemplateZoneResponse.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.response; +import java.util.Date; + import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; @@ -29,6 +31,15 @@ public class TemplateZoneResponse extends BaseResponse { @SerializedName(ApiConstants.ZONE_NAME) @Param(description="the name of the zone for the template") private String zoneName; + @SerializedName(ApiConstants.STATUS) @Param(description="the status of the template") + private String status; + + @SerializedName(ApiConstants.IS_READY) // propName="ready" (FIXME: this used to be part of Param annotation, do we need it?) + @Param(description="true if the template is ready to be deployed from, false otherwise.") + private boolean isReady; + + @SerializedName(ApiConstants.CREATED) @Param(description="the date this template was created") + private Date created; public TemplateZoneResponse(){ super(); @@ -58,6 +69,31 @@ public class TemplateZoneResponse extends BaseResponse { this.zoneName = zoneName; } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public boolean isReady() { + return isReady; + } + + public void setReady(boolean isReady) { + this.isReady = isReady; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + @Override public int hashCode() { final int prime = 31; @@ -69,21 +105,26 @@ public class TemplateZoneResponse extends BaseResponse { @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; - if (obj == null) + } + if (obj == null) { return false; - if (getClass() != obj.getClass()) + } + if (getClass() != obj.getClass()) { return false; + } TemplateZoneResponse other = (TemplateZoneResponse) obj; String oid = this.getZoneId(); if (oid == null) { - if (other.getZoneId() != null) + if (other.getZoneId() != null) { return false; - } else if (!oid.equals(other.getZoneId())) + } + } else if (!oid.equals(other.getZoneId())) { return false; - else if ( this.getZoneName().equals(other.getZoneName())) + } else if ( this.getZoneName().equals(other.getZoneName())) { return false; + } return true; } diff --git a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java index a006e57e0f7..7f7922fc9d1 100644 --- a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java +++ b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java @@ -76,6 +76,14 @@ public class VolumeResponse extends BaseResponse implements ControlledViewEntity @Param(description = "size of the disk volume") private Long size; + @SerializedName(ApiConstants.MIN_IOPS) + @Param(description = "min iops of the disk volume") + private Long minIops; + + @SerializedName(ApiConstants.MAX_IOPS) + @Param(description = "max iops of the disk volume") + private Long maxIops; + @SerializedName(ApiConstants.CREATED) @Param(description = "the date the disk volume was created") private Date created; @@ -241,6 +249,14 @@ public class VolumeResponse extends BaseResponse implements ControlledViewEntity this.size = size; } + public void setMinIops(Long minIops) { + this.minIops = minIops; + } + + public void setMaxIops(Long maxIops) { + this.maxIops = maxIops; + } + public void setCreated(Date created) { this.created = created; } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java index f24bfedf42c..15ed9083f84 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java @@ -849,9 +849,9 @@ public class EC2Engine extends ManagerBase { CloudStackAccount caller = getCurrentAccount(); CloudStackZone zone = findZone(); - CloudStackNetwork net = findNetwork(zone); + //CloudStackNetwork net = findNetwork(zone); // CloudStackIpAddress resp = getApi().associateIpAddress(null, null, null, "0036952d-48df-4422-9fd0-94b0885e18cb"); - CloudStackIpAddress resp = getApi().associateIpAddress(zone.getId(), caller.getName(), caller.getDomainId(), net != null ? net.getId():null); + CloudStackIpAddress resp = getApi().associateIpAddress(zone.getId(), caller.getName(), caller.getDomainId(), null); ec2Address.setAssociatedInstanceId(resp.getId()); if (resp.getIpAddress() == null) { @@ -1399,14 +1399,14 @@ public class EC2Engine extends ManagerBase { CloudStackZone zone = zones.get(0); // network - CloudStackNetwork network = findNetwork(zone); + //CloudStackNetwork network = findNetwork(zone); // now actually deploy the vms for( int i=0; i < createInstances; i++ ) { try{ CloudStackUserVm resp = getApi().deployVirtualMachine(svcOffering.getId(), - request.getTemplateId(), zoneId, null, null, null, null, - null, null, null, request.getKeyName(), null, (network != null ? network.getId() : null), + request.getTemplateId(), zoneId, null, null, null, null, + null, null, null, request.getKeyName(), null, null, null, constructList(request.getGroupSet()), request.getSize().longValue(), request.getUserData()); EC2Instance vm = new EC2Instance(); vm.setId(resp.getId().toString()); @@ -1744,16 +1744,8 @@ public class EC2Engine extends ManagerBase { private CloudStackServiceOfferingVO getCSServiceOfferingId(String instanceType) throws Exception { try { - // list of valid values for AWS EC2 instanceType - String[] validInstanceTypes = {"t1.micro", "m1.small", "m1.medium", "m1.large", "m1.xlarge", - "c1.medium", "c1.xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge", - "m3.xlarge", "m3.2xlarge", "hi1.4xlarge", "cc1.4xlarge", "cg1.4xlarge", "cc2.8xlarge"}; - if (instanceType == null) instanceType = "m1.small"; // default value - else if ( !Arrays.asList(validInstanceTypes).contains(instanceType)) { - throw new Exception("Specified instance type is invalid"); - } return scvoDao.getSvcOfferingByName(instanceType); } catch(Exception e) { logger.error( "Error while retrieving ServiceOffering information by name - ", e); diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index ad8d29d8eac..b1a09b103f9 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -14,6 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +label.custom.disk.iops=Custom IOPS +label.disk.iops.min=Min IOPS +label.disk.iops.max=Max IOPS +label.disk.iops.total=IOPS Total label.view.secondary.ips=View secondary IPs message.acquire.ip.nic=Please confirm that you would like to acquire a new secondary IP for this NIC.
NOTE: You need to manually configure the newly-acquired secondary IP inside the virtual machine. message.select.affinity.groups=Please select any affinity groups you want this VM to belong to: @@ -395,7 +399,7 @@ label.code=Code label.community=Community label.compute.and.storage=Compute and Storage label.compute.offering=Compute offering -label.compute.offerings=Compute offerings +label.compute.offerings=Compute Offerings label.compute=Compute label.configuration=Configuration label.configure.network.ACLs=Configure Network ACLs @@ -1046,6 +1050,7 @@ label.stopped.vms=Stopped VMs label.storage.tags=Storage Tags label.storage.traffic=Storage Traffic label.storage.type=Storage Type +label.qos.type=QoS Type label.storage=Storage label.subdomain.access=Subdomain Access label.submit=Submit diff --git a/client/pom.xml b/client/pom.xml index b8182c26bb4..222c5208534 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -20,6 +20,11 @@ 4.2.0-SNAPSHOT + + org.apache.cloudstack + cloud-plugin-storage-volume-solidfire + ${project.version} + org.apache.cloudstack cloud-server @@ -268,7 +273,12 @@ org.apache.cloudstack cloud-plugin-storage-image-swift ${project.version} - + + + org.apache.cloudstack + cloud-plugin-storage-image-simulator + ${project.version} + org.apache.cloudstack cloud-plugin-syslog-alerts diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 627c65560fe..8031911bbef 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -19,14 +19,12 @@ @@ -533,10 +531,6 @@ - - - - @@ -614,6 +608,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -682,10 +765,10 @@ - + - + @@ -721,17 +804,14 @@ + + - - - - - @@ -744,44 +824,22 @@ - - - - - - + + - - - - - - - - - - - - + + - - - - - + - - - - @@ -791,19 +849,18 @@ + + + + + + + - - - - - - - - @@ -876,6 +933,8 @@ + + diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 648b69d5be3..6a38795b8e2 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -606,6 +606,12 @@ addBaremetalPxeKickStartServer=1 addBaremetalPxePingServer=1 addBaremetalDhcp=1 +#### UCS commands +addUcsManager=1 +listUcsProfile=1 +listUcsBlade=1 +associatesUcsProfileToBlade=1 + #### New Load Balancer commands createLoadBalancer=15 listLoadBalancers=15 diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 9ffecbbcfed..2e018748cb9 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -31,6 +31,8 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + + - + + + + + + + + + + + + + + + + + + + diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index d4cc06d7a24..fcd5b5544fb 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -80,7 +80,6 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/tomcatconf/simulatorComponentContext.xml.in b/client/tomcatconf/simulatorComponentContext.xml.in index d71cf162569..92278a4da8e 100644 --- a/client/tomcatconf/simulatorComponentContext.xml.in +++ b/client/tomcatconf/simulatorComponentContext.xml.in @@ -18,17 +18,8 @@ --> + http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> - - - @@ -47,6 +34,23 @@ + + + + + + + + + + + + + + + @@ -85,7 +89,6 @@ - @@ -124,10 +127,6 @@ - - @@ -175,9 +174,6 @@ - @@ -206,15 +202,16 @@ - + + + + @@ -239,5 +236,4 @@ - diff --git a/core/src/com/cloud/agent/api/AttachVolumeAnswer.java b/core/src/com/cloud/agent/api/AttachVolumeAnswer.java index b377b7c1386..6b965b05043 100644 --- a/core/src/com/cloud/agent/api/AttachVolumeAnswer.java +++ b/core/src/com/cloud/agent/api/AttachVolumeAnswer.java @@ -19,35 +19,33 @@ package com.cloud.agent.api; public class AttachVolumeAnswer extends Answer { private Long deviceId; + private String vdiUuid; private String chainInfo; - protected AttachVolumeAnswer() { - - } - public AttachVolumeAnswer(AttachVolumeCommand cmd, String result) { super(cmd, false, result); this.deviceId = null; } - public AttachVolumeAnswer(AttachVolumeCommand cmd, Long deviceId) { + public AttachVolumeAnswer(AttachVolumeCommand cmd, Long deviceId, String vdiUuid) { super(cmd); this.deviceId = deviceId; + this.vdiUuid = vdiUuid; } - public AttachVolumeAnswer(AttachVolumeCommand cmd) { super(cmd); this.deviceId = null; } - /** - * @return the deviceId - */ public Long getDeviceId() { return deviceId; } + public String getVdiUuid() { + return vdiUuid; + } + public void setChainInfo(String chainInfo) { this.chainInfo = chainInfo; } diff --git a/core/src/com/cloud/agent/api/AttachVolumeCommand.java b/core/src/com/cloud/agent/api/AttachVolumeCommand.java index 2658262a6cd..2eb503ab099 100644 --- a/core/src/com/cloud/agent/api/AttachVolumeCommand.java +++ b/core/src/com/cloud/agent/api/AttachVolumeCommand.java @@ -19,29 +19,37 @@ package com.cloud.agent.api; import com.cloud.storage.Storage.StoragePoolType; public class AttachVolumeCommand extends Command { - - boolean attach; - String vmName; - StoragePoolType pooltype; - String poolUuid; - String volumeFolder; - String volumePath; - String volumeName; - Long deviceId; - String chainInfo; - Long bytesReadRate; - Long bytesWriteRate; - Long iopsReadRate; - Long iopsWriteRate; + private boolean attach; + private boolean _managed; + private String vmName; + private StoragePoolType pooltype; + private String volumePath; + private String volumeName; + private Long deviceId; + private String chainInfo; + private String poolUuid; + private String _storageHost; + private int _storagePort; + private String _iScsiName; + private String _chapInitiatorUsername; + private String _chapInitiatorPassword; + private String _chapTargetUsername; + private String _chapTargetPassword; + private Long bytesReadRate; + private Long bytesWriteRate; + private Long iopsReadRate; + private Long iopsWriteRate; protected AttachVolumeCommand() { } - public AttachVolumeCommand(boolean attach, String vmName, StoragePoolType pooltype, String volumeFolder, String volumePath, String volumeName, Long deviceId, String chainInfo) { + public AttachVolumeCommand(boolean attach, boolean managed, String vmName, + StoragePoolType pooltype, String volumePath, String volumeName, + Long deviceId, String chainInfo) { this.attach = attach; + this._managed = managed; this.vmName = vmName; this.pooltype = pooltype; - this.volumeFolder = volumeFolder; this.volumePath = volumePath; this.volumeName = volumeName; this.deviceId = deviceId; @@ -54,7 +62,7 @@ public class AttachVolumeCommand extends Command { } public boolean getAttach() { - return attach; + return attach; } public String getVmName() { @@ -69,16 +77,12 @@ public class AttachVolumeCommand extends Command { this.pooltype = pooltype; } - public String getVolumeFolder() { - return volumeFolder; - } - public String getVolumePath() { return volumePath; } public String getVolumeName() { - return volumeName; + return volumeName; } public Long getDeviceId() { @@ -90,17 +94,77 @@ public class AttachVolumeCommand extends Command { } public String getPoolUuid() { - return poolUuid; + return poolUuid; } public void setPoolUuid(String poolUuid) { - this.poolUuid = poolUuid; + this.poolUuid = poolUuid; } public String getChainInfo() { - return chainInfo; + return chainInfo; } + public void setStorageHost(String storageHost) { + _storageHost = storageHost; + } + + public String getStorageHost() { + return _storageHost; + } + + public void setStoragePort(int storagePort) { + _storagePort = storagePort; + } + + public int getStoragePort() { + return _storagePort; + } + + public boolean isManaged() { + return _managed; + } + + public void set_iScsiName(String iScsiName) { + this._iScsiName = iScsiName; + } + + public String get_iScsiName() { + return _iScsiName; + } + + public void setChapInitiatorUsername(String chapInitiatorUsername) { + _chapInitiatorUsername = chapInitiatorUsername; + } + + public String getChapInitiatorUsername() { + return _chapInitiatorUsername; + } + + public void setChapInitiatorPassword(String chapInitiatorPassword) { + _chapInitiatorPassword = chapInitiatorPassword; + } + + public String getChapInitiatorPassword() { + return _chapInitiatorPassword; + } + + public void setChapTargetUsername(String chapTargetUsername) { + _chapTargetUsername = chapTargetUsername; + } + + public String getChapTargetUsername() { + return _chapTargetUsername; + } + + public void setChapTargetPassword(String chapTargetPassword) { + _chapTargetPassword = chapTargetPassword; + } + + public String getChapTargetPassword() { + return _chapTargetPassword; + } + public void setBytesReadRate(Long bytesReadRate) { this.bytesReadRate = bytesReadRate; } diff --git a/core/src/com/cloud/hypervisor/hyperv/resource/HypervResource.java b/core/src/com/cloud/hypervisor/hyperv/resource/HypervResource.java deleted file mode 100755 index ca26bffc571..00000000000 --- a/core/src/com/cloud/hypervisor/hyperv/resource/HypervResource.java +++ /dev/null @@ -1,979 +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.hypervisor.hyperv.resource; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStreamReader; -import java.rmi.RemoteException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import javax.ejb.Local; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.IAgentControl; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.AttachIsoCommand; -import com.cloud.agent.api.AttachVolumeCommand; -import com.cloud.agent.api.BackupSnapshotCommand; -import com.cloud.agent.api.CheckHealthCommand; -import com.cloud.agent.api.CheckNetworkCommand; -import com.cloud.agent.api.CheckOnHostCommand; -import com.cloud.agent.api.CheckVirtualMachineCommand; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand; -import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand; -import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; -import com.cloud.agent.api.DeleteStoragePoolCommand; -import com.cloud.agent.api.GetHostStatsAnswer; -import com.cloud.agent.api.GetHostStatsCommand; -import com.cloud.agent.api.GetStorageStatsAnswer; -import com.cloud.agent.api.GetStorageStatsCommand; -import com.cloud.agent.api.GetVmStatsCommand; -import com.cloud.agent.api.GetVncPortCommand; -import com.cloud.agent.api.HostStatsEntry; -import com.cloud.agent.api.MaintainCommand; -import com.cloud.agent.api.ManageSnapshotCommand; -import com.cloud.agent.api.MigrateCommand; -import com.cloud.agent.api.ModifySshKeysCommand; -import com.cloud.agent.api.ModifyStoragePoolAnswer; -import com.cloud.agent.api.ModifyStoragePoolCommand; -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.PoolEjectCommand; -import com.cloud.agent.api.PrepareForMigrationCommand; -import com.cloud.agent.api.ReadyAnswer; -import com.cloud.agent.api.ReadyCommand; -import com.cloud.agent.api.RebootCommand; -import com.cloud.agent.api.RebootRouterCommand; -import com.cloud.agent.api.SetupCommand; -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.StopCommand; -import com.cloud.agent.api.ValidateSnapshotCommand; -import com.cloud.agent.api.check.CheckSshAnswer; -import com.cloud.agent.api.check.CheckSshCommand; -import com.cloud.agent.api.routing.DhcpEntryCommand; -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.SetPortForwardingRulesCommand; -import com.cloud.agent.api.routing.SetStaticNatRulesCommand; -import com.cloud.agent.api.routing.VmDataCommand; -import com.cloud.agent.api.routing.VpnUsersCfgCommand; -import com.cloud.agent.api.storage.CopyVolumeCommand; -import com.cloud.agent.api.storage.CreateAnswer; -import com.cloud.agent.api.storage.CreateCommand; -import com.cloud.agent.api.storage.DestroyCommand; -import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; -import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; -import com.cloud.agent.api.to.StorageFilerTO; -import com.cloud.agent.api.to.VirtualMachineTO; -import com.cloud.agent.api.to.VolumeTO; -import com.cloud.host.Host.Type; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.utils.ssh.SshHelper; -import com.cloud.resource.ServerResource; -import com.cloud.resource.ServerResourceBase; -import com.cloud.serializer.GsonHelper; -import com.cloud.storage.Volume; -import com.cloud.storage.template.TemplateProp; -import com.cloud.utils.Pair; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.vm.DiskProfile; -import com.cloud.vm.VirtualMachine.PowerState; -import com.cloud.vm.VirtualMachine.State; -import com.google.gson.Gson; - -/** - * Implementation of resource base class for Hyper-V hypervisor - **/ - -@Local(value={ServerResource.class}) -public class HypervResource extends ServerResourceBase implements ServerResource{ - private String _dcId; - private String _podId; - private String _clusterId; - private String _guid; - private String _name; - private static final Logger s_logger = Logger.getLogger(HypervResource.class); - private IAgentControl agentControl; - private volatile Boolean _wakeUp = false; - protected Gson _gson; - protected HashMap _vms = new HashMap(512); - protected final int DEFAULT_DOMR_SSHPORT = 3922; - - public HypervResource() - { - _gson = GsonHelper.getGsonLogger(); - } - - @Override - public Answer executeRequest(Command cmd) { - - if (cmd instanceof CreateCommand) { - return execute((CreateCommand) cmd); - } else if (cmd instanceof SetPortForwardingRulesCommand) { - s_logger.info("SCVMM agent recived command SetPortForwardingRulesCommand"); - //return execute((SetPortForwardingRulesCommand) cmd); - } else if (cmd instanceof SetStaticNatRulesCommand) { - s_logger.info("SCVMM agent recived command SetStaticNatRulesCommand"); - //return execute((SetStaticNatRulesCommand) cmd); - }else if (cmd instanceof LoadBalancerConfigCommand) { - s_logger.info("SCVMM agent recived command SetStaticNatRulesCommand"); - //return execute((LoadBalancerConfigCommand) cmd); - } else if (cmd instanceof IpAssocCommand) { - s_logger.info("SCVMM agent recived command IPAssocCommand"); - //return execute((IPAssocCommand) cmd); - } else if (cmd instanceof SavePasswordCommand) { - s_logger.info("SCVMM agent recived command SavePasswordCommand"); - //return execute((SavePasswordCommand) cmd); - } else if (cmd instanceof DhcpEntryCommand) { - return execute((DhcpEntryCommand) cmd); - } else if (cmd instanceof VmDataCommand) { - //return execute((VmDataCommand) cmd); - } else if (cmd instanceof ReadyCommand) { - s_logger.info("SCVMM agent recived ReadyCommand: " + _gson.toJson(cmd)); - return new ReadyAnswer((ReadyCommand) cmd); - } else if (cmd instanceof GetHostStatsCommand) { - return execute((GetHostStatsCommand) cmd); - } else if (cmd instanceof GetVmStatsCommand) { - s_logger.info("SCVMM agent recived command GetVmStatsCommand"); - //return execute((GetVmStatsCommand) cmd); - } else if (cmd instanceof CheckHealthCommand) { - //return execute((CheckHealthCommand) cmd); - } else if (cmd instanceof StopCommand) { - //return execute((StopCommand) cmd); - } else if (cmd instanceof RebootRouterCommand) { - //return execute((RebootRouterCommand) cmd); - } else if (cmd instanceof RebootCommand) { - //return execute((RebootCommand) cmd); - } else if (cmd instanceof CheckVirtualMachineCommand) { - s_logger.info("SCVMM agent recived command CheckVirtualMachineCommand"); - //return execute((CheckVirtualMachineCommand) cmd); - } else if (cmd instanceof PrepareForMigrationCommand) { - //return execute((PrepareForMigrationCommand) cmd); - } else if (cmd instanceof MigrateCommand) { - //return execute((MigrateCommand) cmd); - } else if (cmd instanceof DestroyCommand) { - //return execute((DestroyCommand) cmd); - } else if (cmd instanceof ModifyStoragePoolCommand) { - return execute((ModifyStoragePoolCommand) cmd); - } else if (cmd instanceof DeleteStoragePoolCommand) { - s_logger.info("SCVMM agent recived command DeleteStoragePoolCommand"); - Answer answer = new Answer(cmd, true, "success"); - return answer; - //return execute((DeleteStoragePoolCommand) cmd); - } else if (cmd instanceof CopyVolumeCommand) { - s_logger.info("SCVMM agent recived command CopyVolumeCommand"); - //return execute((CopyVolumeCommand) cmd); - } else if (cmd instanceof AttachVolumeCommand) { - s_logger.info("SCVMM agent recived command AttachVolumeCommand"); - //return execute((AttachVolumeCommand) cmd); - } else if (cmd instanceof AttachIsoCommand) { - //return execute((AttachIsoCommand) cmd); - } else if (cmd instanceof ValidateSnapshotCommand) { - //return execute((ValidateSnapshotCommand) cmd); - } else if (cmd instanceof ManageSnapshotCommand) { - //return execute((ManageSnapshotCommand) cmd); - } else if (cmd instanceof BackupSnapshotCommand) { - //return execute((BackupSnapshotCommand) cmd); - } else if (cmd instanceof CreateVolumeFromSnapshotCommand) { - //return execute((CreateVolumeFromSnapshotCommand) cmd); - } else if (cmd instanceof CreatePrivateTemplateFromVolumeCommand) { - //return execute((CreatePrivateTemplateFromVolumeCommand) cmd); - } else if (cmd instanceof CreatePrivateTemplateFromSnapshotCommand) { - //return execute((CreatePrivateTemplateFromSnapshotCommand) cmd); - } else if (cmd instanceof GetStorageStatsCommand) { - return execute((GetStorageStatsCommand) cmd); - } else if (cmd instanceof PrimaryStorageDownloadCommand) { - s_logger.info("SCVMM agent recived command PrimaryStorageDownloadCommand"); - return execute((PrimaryStorageDownloadCommand) cmd); - } else if (cmd instanceof GetVncPortCommand) { - //return execute((GetVncPortCommand) cmd); - } else if (cmd instanceof SetupCommand) { - //return execute((SetupCommand) cmd); - } else if (cmd instanceof MaintainCommand) { - //return execute((MaintainCommand) cmd); - } else if (cmd instanceof PingTestCommand) { - s_logger.info("SCVMM agent recived command PingTestCommand"); - //return execute((PingTestCommand) cmd); - } else if (cmd instanceof CheckOnHostCommand) { - s_logger.info("SCVMM agent recived command CheckOnHostCommand"); - //return execute((CheckOnHostCommand) cmd); - } else if (cmd instanceof ModifySshKeysCommand) { - //return execute((ModifySshKeysCommand) cmd); - } else if (cmd instanceof PoolEjectCommand) { - //return execute((PoolEjectCommand) cmd); - } else if (cmd instanceof NetworkUsageCommand) { - //return execute((NetworkUsageCommand) cmd); - } else if (cmd instanceof StartCommand) { - return execute((StartCommand) cmd); - } else if (cmd instanceof RemoteAccessVpnCfgCommand) { - //return execute((RemoteAccessVpnCfgCommand) cmd); - } else if (cmd instanceof VpnUsersCfgCommand) { - //return execute((VpnUsersCfgCommand) cmd); - } else if (cmd instanceof CheckSshCommand) { - return execute((CheckSshCommand)cmd); - } else if (cmd instanceof CheckNetworkCommand) { - //return execute((CheckNetworkCommand) cmd); - } else { - s_logger.info("SCVMM agent recived unimplemented command: " + _gson.toJson(cmd)); - return Answer.createUnsupportedCommandAnswer(cmd); - } - - return Answer.createUnsupportedCommandAnswer(cmd); - } - - public PrimaryStorageDownloadAnswer execute(PrimaryStorageDownloadCommand cmd) { - - if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource PrimaryStorageDownloadCommand: " + _gson.toJson(cmd)); - } - - try { - String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); - String primaryStroageUrl = cmd.getPrimaryStorageUrl(); - String templateUuidName =null; - assert ((primaryStroageUrl != null) && (secondaryStorageUrl != null)); - // FIXME: paths and system vm name are hard coded - String templateUrl = cmd.getUrl(); - String templatePath = templateUrl.replace('/', '\\'); - templatePath = templatePath.substring(4); - if (!templatePath.endsWith(".vhd")) { - String templateName = cmd.getName(); - templateUuidName = UUID.nameUUIDFromBytes((templateName + "@" + cmd.getPoolUuid()).getBytes()).toString(); - if (!templatePath.endsWith("\\")) { - templatePath = templatePath + "\\"; - } - //templatePath = templatePath + templateUuidName + ".vhd"; - templatePath = templatePath + "systemvm.vhd"; - } - - s_logger.info("template URL: "+ templateUrl + "template name: "+ cmd.getName() + " sec storage " + secondaryStorageUrl+ " pri storage" + primaryStroageUrl); - - StringBuilder cmdStr = new StringBuilder("cmd /c powershell.exe "); - cmdStr.append("copy-item '"); - cmdStr.append(templatePath.toCharArray()); - cmdStr.append("' 'C:\\programdata\\Virtual Machine Manager Library Files\\VHDs\\';"); - - s_logger.info("Running command: " + cmdStr); - Process p = Runtime.getRuntime().exec(cmdStr.toString()); - p.getOutputStream().close(); - - InputStreamReader temperrReader = new InputStreamReader(new BufferedInputStream(p.getErrorStream())); - BufferedReader errreader = new BufferedReader(temperrReader); - if (errreader.ready()) { - String errorOutput = new String(""); - s_logger.info("errors found while running cmdlet: " + cmdStr.toString()); - while (true){ - String errline = errreader.readLine(); - if (errline == null) { - break; - } - errorOutput = errorOutput + errline; - } - s_logger.info(errorOutput); - } - - p.getErrorStream().close(); - InputStreamReader tempReader = new InputStreamReader(new BufferedInputStream(p.getInputStream())); - BufferedReader reader = new BufferedReader(tempReader); - - String output = new String(""); - - while (true){ - String line = reader.readLine(); - if (line == null) { - break; - } - output = output + line; - } - p.getInputStream().close(); - - s_logger.info("Command output: "+ output); - - if (output.contains("FullyQualifiedErrorId") || output.contains("Error") || output.contains("Exception")) { - return new PrimaryStorageDownloadAnswer("Failed to copy template to SCVMM library share from secondary storage."); - } - - return new PrimaryStorageDownloadAnswer(templateUuidName, 0); - - } catch (Exception e) - { - s_logger.info("Exception caught: "+e.getMessage()); - return new PrimaryStorageDownloadAnswer("Failed to copy template to SCVMM library share from secondary storage."); - } - } - - protected Answer execute(CreateCommand cmd) { - if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource CreateCommand: " + _gson.toJson(cmd)); - } - - try { - long volId = cmd.getVolumeId(); - String templateUrl = cmd.getTemplateUrl();; - StorageFilerTO pool = cmd.getPool(); - DiskProfile diskchar = cmd.getDiskCharacteristics(); - - if (diskchar.getType() == Volume.Type.ROOT) { - if (cmd.getTemplateUrl() == null) { - //create root volume - VolumeTO vol = new VolumeTO(cmd.getVolumeId(), - diskchar.getType(), - pool.getType(), pool.getUuid(), cmd.getDiskCharacteristics().getName(), - pool.getPath(), cmd.getDiskCharacteristics().getName(), cmd.getDiskCharacteristics().getSize(), - null); - return new CreateAnswer(cmd, vol); - } else { - VolumeTO vol = new VolumeTO(cmd.getVolumeId(), - diskchar.getType(), - pool.getType(), pool.getUuid(), cmd.getDiskCharacteristics().getName(), - pool.getPath(), cmd.getDiskCharacteristics().getName(), cmd.getDiskCharacteristics().getSize(), null); - return new CreateAnswer(cmd, vol); - } - - } else { - //create data volume - String volumeUuid = "cloud.worker." + UUID.randomUUID().toString(); - VolumeTO vol = new VolumeTO(cmd.getVolumeId(), - diskchar.getType(), - pool.getType(), pool.getUuid(), cmd.getDiskCharacteristics().getName(), - pool.getPath(), volumeUuid, cmd.getDiskCharacteristics().getSize(), null); - return new CreateAnswer(cmd, vol); - } - } catch (Exception ex) { - return null; - } - } - - protected StartAnswer execute(StartCommand cmd) { - - if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource StartCommand: " + _gson.toJson(cmd)); - } - - VirtualMachineTO vmSpec = cmd.getVirtualMachine(); - String vmName = vmSpec.getName(); - State state = State.Stopped; - String scriptFileName = vmName+ ".ps1"; - String newLine = System.getProperty("line.separator"); - String bootArgsDiskName = vmName+"-bootparams.vhd"; - String bootArgsDiskPath = "C:\\ProgramData\\Virtual Machine Manager Library Files\\VHDs\\"+bootArgsDiskName; - - try { - // mark VM as starting state so that sync() can know not to report stopped too early - synchronized (_vms) { - _vms.put(vmName, State.Starting); - { - // create and attach boot parameter disk - String diskpartScriptName = vmName+"-Diskpart.txt"; - - StringBuilder cmdDiskpart = new StringBuilder("create vdisk file=\"");cmdDiskpart.append(bootArgsDiskPath.toCharArray());cmdDiskpart.append("\" maximum=10 type=expandable" + newLine); - cmdDiskpart.append("select vdisk file=\"");cmdDiskpart.append(bootArgsDiskPath.toCharArray());cmdDiskpart.append("\"" + newLine); - cmdDiskpart.append("attach vdisk" + newLine); - cmdDiskpart.append("create partition primary" + newLine); - cmdDiskpart.append("format fs=ntfs label=\"test vhd\" quick" + newLine); - cmdDiskpart.append("assign letter="+vmName.toCharArray()[0]+ newLine); - cmdDiskpart.append("attach vdisk" + newLine); - - File f=new File(diskpartScriptName); - FileOutputStream fop=new FileOutputStream(f); - fop.write(cmdDiskpart.toString().getBytes()); - fop.flush(); - fop.close(); - - s_logger.info("Running diskpart attach command"); - Process p = Runtime.getRuntime().exec("cmd.exe /c diskpart.exe /s "+diskpartScriptName); - p.getOutputStream().close(); - - InputStreamReader temperrReader = new InputStreamReader(new BufferedInputStream(p.getErrorStream())); - BufferedReader errreader = new BufferedReader(temperrReader); - - if (errreader.ready()) { - String errorOutput = new String(""); - while (true){ - String errline = errreader.readLine(); - if (errline == null) { - break; - } - errorOutput = errorOutput + errline; - } - s_logger.info("errors found while running diskpart command: " + errorOutput); - } - - p.getErrorStream().close(); - InputStreamReader tempReader = new InputStreamReader(new BufferedInputStream(p.getInputStream())); - BufferedReader reader = new BufferedReader(tempReader); - - String output = new String(""); - - while (true){ - String line = reader.readLine(); - if (line == null) { - break; - } - output = output + line; - } - p.getInputStream().close(); - s_logger.info("diskpart detahc command output: "+ output); - } - // wait for a while so that disk formatting is done - Thread.sleep(60000); - - //create boot args on the disk - String bootArgs = vmSpec.getBootArgs(); - String Drive = vmName.substring(0,1); - File fBootargs =new File(Drive+":\\cmdline"); - FileOutputStream fopBoot=new FileOutputStream(fBootargs); - fopBoot.write(bootArgs.toString().getBytes()); - fopBoot.flush(); - fopBoot.close(); - - //detach the boot parameter disk - { - String diskpartDetachScriptName = vmName+"-Detach-Diskpart.txt"; - - StringBuilder cmdDetachDiskpart = new StringBuilder("select vdisk file=\""); - cmdDetachDiskpart.append(bootArgsDiskPath.toCharArray());cmdDetachDiskpart.append("\"" + newLine); - cmdDetachDiskpart.append("detach vdisk" + newLine); - - File fd=new File(diskpartDetachScriptName); - FileOutputStream fdop=new FileOutputStream(fd); - fdop.write(cmdDetachDiskpart.toString().getBytes()); - fdop.flush(); - fdop.close(); - - s_logger.info("Running diskpart detach command"); - Process pd = Runtime.getRuntime().exec("cmd.exe /c diskpart.exe /s "+diskpartDetachScriptName); - pd.getOutputStream().close(); - InputStreamReader temperrReader1 = new InputStreamReader(new BufferedInputStream(pd.getErrorStream())); - BufferedReader errreader1 = new BufferedReader(temperrReader1); - - if (errreader1.ready()) { - String errorOutput = new String(""); - while (true){ - String errline = errreader1.readLine(); - if (errline == null) { - break; - } - errorOutput = errorOutput + errline; - } - s_logger.info("errors found while running diskpart detach command: " + errorOutput); - } - - pd.getErrorStream().close(); - InputStreamReader tempReader1 = new InputStreamReader(new BufferedInputStream(pd.getInputStream())); - BufferedReader reader1 = new BufferedReader(tempReader1); - - String output1 = new String(""); - - while (true){ - String line = reader1.readLine(); - if (line == null) { - break; - } - output1 = output1 + line; - } - - pd.getInputStream().close(); - s_logger.info("diskpart detach command output: "+ output1); - } - } - - UUID id = UUID.randomUUID(); - String hwProfileId = id.toString(); - - StringBuilder cmdStr = new StringBuilder("Add-PSSnapin Microsoft.SystemCenter.VirtualMachineManager;" + newLine); - cmdStr.append("Get-VMMServer -ComputerName localhost;" + newLine); - cmdStr.append("$JobGroupId = [Guid]::NewGuid().ToString();" + newLine); - cmdStr.append("$hwProfileId = [Guid]::NewGuid().ToString(); " + newLine); - cmdStr.append("$CPUType = Get-CPUType -VMMServer localhost | where {$_.Name -eq " + "'1.20 GHz Athlon MP'}; " + newLine); - cmdStr.append("$ISO = Get-ISO -VMMServer localhost | where { $_.Name -match \"systemvm\" }; " + newLine); - cmdStr.append("$VMHost = Get-VMHost -VMMServer localhost | where {$_.Name -eq \"HYPERVHOST.hypervdc.intranet.lab.vmops.com\"}; " + newLine); - cmdStr.append("$VNetwork = Get-VirtualNetwork -VMHost $VMHost -Name \"public\"; " + newLine); - cmdStr.append("New-VirtualNetworkAdapter -VMMServer localhost -JobGroup $JobGroupID -PhysicalAddressType Dynamic -VirtualNetwork $vnetwork; " + newLine); - cmdStr.append("New-VirtualNetworkAdapter -VMMServer localhost -JobGroup $JobGroupID -PhysicalAddressType Dynamic -VirtualNetwork $vnetwork; " + newLine); - cmdStr.append("New-VirtualNetworkAdapter -VMMServer localhost -JobGroup $JobGroupID -PhysicalAddressType Dynamic -VirtualNetwork $vnetwork; " + newLine); - cmdStr.append("New-VirtualDVDDrive -VMMServer localhost -JobGroup $JobGroupID -Bus 1 -LUN 0 -ISO $ISO ; " + newLine); - cmdStr.append("New-HardwareProfile -VMMServer localhost -JobGroup $JobGroupID -Owner \"HYPERVDC\\Administrator\" -CPUType $CPUType -Name $hwProfileId"); - cmdStr.append(" -Description \"Profile used to create a VM/Template\"" + - " -CPUCount 1 -MemoryMB 512 -RelativeWeight 100 -HighlyAvailable $true -NumLock $false -BootOrder \"CD\", " + - "\"IdeHardDrive\", \"PxeBoot\", \"Floppy\" -LimitCPUFunctionality $false -LimitCPUForMigration $false; " + newLine); - - cmdStr.append("$JobGroupId = [Guid]::NewGuid().ToString(); " + newLine); - - //refresh library share - cmdStr.append("$share = Get-LibraryShare;"+newLine); - cmdStr.append("Refresh-LibraryShare -LibraryShare $share;"+newLine); - - // create root disk - cmdStr.append("$VirtualHardDisk1 = Get-VirtualHardDisk -VMMServer localhost | where {$_.Location -eq \"\\\\scvmm.hypervdc.intranet.lab.vmops.com\\MSSCVMMLibrary\\VHDs\\systemvm.vhd\"} | where {$_.HostName -eq \"scvmm.hypervdc.intranet.lab.vmops.com\"}" + newLine); - cmdStr.append("New-VirtualDiskDrive -VMMServer localhost -JobGroup $JobGroupID -IDE -Bus 0 -LUN 0 -VirtualHardDisk $VirtualHardDisk1 -Filename \""); - cmdStr.append(vmName.toCharArray()); - cmdStr.append("-systemvm.vhd\"; " + newLine); - - // create boot param data disk - cmdStr.append("$VirtualHardDisk2 = Get-VirtualHardDisk -VMMServer localhost " + - " | where {$_.Location -eq \"\\\\scvmm.hypervdc.intranet.lab.vmops.com\\MSSCVMMLibrary\\VHDs\\"); - cmdStr.append(bootArgsDiskName.toCharArray()); - cmdStr.append("\" } | where {$_.HostName -eq \"scvmm.hypervdc.intranet.lab.vmops.com\"}" + newLine); - cmdStr.append("New-VirtualDiskDrive -VMMServer localhost -JobGroup $JobGroupID -IDE -Bus 0 -LUN 1 -VirtualHardDisk $VirtualHardDisk2 -Filename \""); - cmdStr.append(bootArgsDiskName.toCharArray()); - cmdStr.append("\";"+newLine); - - cmdStr.append("$HardwareProfile = Get-HardwareProfile -VMMServer localhost | where {$_.Name -eq $hwProfileId};" + newLine); - cmdStr.append("$OperatingSystem = Get-OperatingSystem -VMMServer localhost | where {$_.Name -eq 'Other Linux (32 bit)'};" + newLine); - - cmdStr.append("New-VM -VMMServer localhost -Name \""); - cmdStr.append(vmName.toCharArray()); - - cmdStr.append("\" -Description \"\" -Owner \"HYPERVDC\\Administrator\" -VMHost $VMHost -Path \"C:\\ClusterStorage\\Volume1\" -HardwareProfile $HardwareProfile " + - " -JobGroup $JobGroupID" + - " -OperatingSystem $OperatingSystem -RunAsSystem -StartVM -StartAction NeverAutoTurnOnVM -StopAction SaveVM;" + newLine); - - File f=new File(scriptFileName); - FileOutputStream fop=new FileOutputStream(f); - fop.write(cmdStr.toString().getBytes()); - fop.flush(); - fop.close(); - s_logger.info("Running command: " + cmdStr); - Process p = Runtime.getRuntime().exec("cmd.exe /c Powershell -Command \" & '.\\" + scriptFileName +"'\""); - p.getOutputStream().close(); - - InputStreamReader temperrReader = new InputStreamReader(new BufferedInputStream(p.getErrorStream())); - BufferedReader errreader = new BufferedReader(temperrReader); - - if (errreader.ready()) { - String errorOutput = new String(""); - while (true){ - String errline = errreader.readLine(); - if (errline == null) { - break; - } - errorOutput = errorOutput + errline; - } - s_logger.info("errors found while running cmdlet to create VM: " + errorOutput); - } - - p.getErrorStream().close(); - InputStreamReader tempReader = new InputStreamReader(new BufferedInputStream(p.getInputStream())); - BufferedReader reader = new BufferedReader(tempReader); - - String output = new String(""); - - while (true){ - String line = reader.readLine(); - if (line == null) { - break; - } - output = output + line; - } - p.getInputStream().close(); - - s_logger.info("vm create cmmdlet output: "+ output); - - if (output.contains("FullyQualifiedErrorId") || output.contains("Error") || output.contains("Exception")) { - s_logger.info("No errors found in running cmdlet "+ cmdStr.toString()); - return new StartAnswer(cmd, "Failed to start VM"); - } - - state = State.Running; - return new StartAnswer(cmd); - } catch (Exception e){ - return new StartAnswer(cmd, "Failed to start VM"); - } finally { - //delete the PS script file - //File f=new File(".\\"+scriptFileName); - //f.delete(); - synchronized (_vms) { - if (state != State.Stopped) { - _vms.put(vmName, state); - } else { - _vms.remove(vmName); - } - } - } - } - - protected Answer execute(DhcpEntryCommand cmd) { - if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource DhcpEntryCommand: " + _gson.toJson(cmd)); - } - - String args = " " + cmd.getVmMac(); - args += " " + cmd.getVmIpAddress(); - args += " " + cmd.getVmName(); - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Run command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + ", /root/edithosts.sh " + args); - } - - try { - Pair result = SshHelper.sshExecute(cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP), DEFAULT_DOMR_SSHPORT, "root", - new File("id_rsa.cloud"), null, "/root/edithosts.sh " + args); - - if (!result.first()) { - s_logger.error("dhcp_entry command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) - + " failed, message: " + result.second()); - - return new Answer(cmd, false, "DhcpEntry failed due to " + result.second()); - } - - if (s_logger.isInfoEnabled()) { - s_logger.info("dhcp_entry command on domain router " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + " completed"); - } - - } catch (Throwable e) { - s_logger.error("Unexpected exception ", e); - return new Answer(cmd, false, "DhcpEntry failed due to exception"); - } - - return new Answer(cmd); - } - - protected CheckSshAnswer execute(CheckSshCommand cmd) { - String vmName = cmd.getName(); - String privateIp = cmd.getIp(); - int cmdPort = cmd.getPort(); - - if (s_logger.isInfoEnabled()) { - s_logger.info("Ping VM:" + cmd.getName() + " IP:" + privateIp + " port:" + cmdPort); - } - return new CheckSshAnswer(cmd); - } - - @Override - public void setAgentControl(IAgentControl agentControl) { - this.agentControl = agentControl; - } - - @Override - public Type getType() { - // TODO Auto-generated method stub - return null; - } - - @Override - public StartupCommand[] initialize() { - - s_logger.info("recieved initialize request for cluster:" + _clusterId); - List vmHostList = getHostsInCluster(_clusterId); - - if (vmHostList.size() == 0) { - s_logger.info("cluster is not recognized or zero instances in the cluster"); - } - - StartupCommand[] answerCmds = new StartupCommand[vmHostList.size()]; - - int index =0; - for (String hostName: vmHostList) { - s_logger.info("Node :" + hostName); - StartupRoutingCommand cmd = new StartupRoutingCommand(); - answerCmds[index] = cmd; - fillHostInfo(cmd,hostName); - index++; - } - - s_logger.info("response sent to initialize request for cluster:" + _clusterId); - return answerCmds; - } - - protected void fillHostInfo(StartupRoutingCommand cmd, String hostName) { - - Map details = cmd.getHostDetails(); - if (details == null) { - details = new HashMap(); - } - - try { - fillHostHardwareInfo(cmd); - fillHostNetworkInfo(cmd); - fillHostDetailsInfo(details); - } catch (Exception e) { - s_logger.error("Exception while retrieving host info ", e); - throw new CloudRuntimeException("Exception while retrieving host info"); - } - - cmd.setName(hostName); - cmd.setHostDetails(details); - cmd.setGuid(_guid); - cmd.setDataCenter(_dcId); - cmd.setPod(_podId); - cmd.setCluster(_clusterId); - cmd.setHypervisorType(HypervisorType.Hyperv); - } - - private void fillHostDetailsInfo(Map details) throws Exception { - - } - - private Answer execute(GetHostStatsCommand cmd) { - - if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource GetHostStatsCommand: " + _gson.toJson(cmd)); - } - - try { - // FIXME: get the actual host stats by running powershell cmdlet. This is just for prototype. - HostStatsEntry hostStats = new HostStatsEntry(cmd.getHostId(), 0, 10000, 10000, - "host", 2*1024*1024, 1*1024*1024, 1*1024*1024, 0); - s_logger.info("returning stats :" + 2*1024*1024 + " " + 1*1024*1024 + " " + 1*1024*1024); - return new GetHostStatsAnswer(cmd, hostStats); - } catch (Exception e) { - HostStatsEntry hostStats = new HostStatsEntry(cmd.getHostId(), 0, 0, 0, - "host", 0, 0, 0, 0); - String msg = "Unable to execute GetHostStatsCommand due to exception " + e.getMessage(); - s_logger.error(msg, e); - return new GetHostStatsAnswer(cmd, hostStats); - } - } - - protected Answer execute(ModifyStoragePoolCommand cmd) { - if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource ModifyStoragePoolCommand: " + _gson.toJson(cmd)); - } - - try { - StorageFilerTO pool = cmd.getPool(); - s_logger.info("Primary storage pool details: " + pool.getHost() + " " + pool.getPath()); - Map tInfo = new HashMap(); - // FIXME: get the actual storage capacity and storage stats of CSV volume - // by running powershell cmdlet. This hardcoding just for prototype. - ModifyStoragePoolAnswer answer = new ModifyStoragePoolAnswer(cmd, - 1024*1024*1024*1024L, 512*1024*1024*1024L, tInfo); - - return answer; - } catch (Throwable e) { - return new Answer(cmd, false, "Unable to execute ModifyStoragePoolCommand due to exception " + e.getMessage()); - } - } - - protected Answer execute(GetStorageStatsCommand cmd) { - if (s_logger.isInfoEnabled()) { - s_logger.info("Executing GetStorageStatsCommand command: " + _gson.toJson(cmd)); - } - // FIXME: get the actual storage capacity and storage stats of CSV volume - return new GetStorageStatsAnswer(cmd, 1024*1024*1024*1024L, 512*1024*1024*1024L); - } - - private void fillHostHardwareInfo(StartupRoutingCommand cmd) throws RemoteException { - try { - // FIXME: get the actual host capacity by running cmdlet.This hardcoding just for prototype - cmd.setCaps("hvm"); - cmd.setDom0MinMemory(0); - cmd.setSpeed(100000); - cmd.setCpus(6); - long ram = new Long("211642163904"); - cmd.setMemory(ram); - } catch (Throwable e) { - s_logger.error("Unable to query host network info due to exception ", e); - throw new CloudRuntimeException("Unable to query host network info due to exception"); - } - } - - private void fillHostNetworkInfo(StartupRoutingCommand cmd) throws RemoteException { - try { - // FIXME: get the actual host and storage IP by running cmdlet.This hardcoding just for prototype - cmd.setPrivateIpAddress("192.168.154.236"); - cmd.setPrivateNetmask("255.255.255.0"); - cmd.setPrivateMacAddress("00:16:3e:77:e2:a0"); - - cmd.setStorageIpAddress("192.168.154.36"); - cmd.setStorageNetmask("255.255.255.0"); - cmd.setStorageMacAddress("00:16:3e:77:e2:a0"); - } catch (Throwable e) { - s_logger.error("Unable to query host network info due to exception ", e); - throw new CloudRuntimeException("Unable to query host network info due to exception"); - } - } - - private List getHostsInCluster(String clusterName) - { - List hypervHosts = new ArrayList(); - - try { - //StringBuilder cmd = new StringBuilder("cmd /c powershell.exe -OutputFormat XML "); - StringBuilder cmd = new StringBuilder("cmd /c powershell.exe "); - cmd.append("-Command Add-PSSnapin Microsoft.SystemCenter.VirtualMachineManager; "); - cmd.append("Get-VMMServer -ComputerName localhost; "); - cmd.append("Get-VMHostCluster "); - cmd.append(clusterName.toCharArray()); - - Process p = Runtime.getRuntime().exec(cmd.toString()); - p.getOutputStream().close(); - - InputStreamReader temperrReader = new InputStreamReader(new BufferedInputStream(p.getErrorStream())); - BufferedReader errreader = new BufferedReader(temperrReader); - if (errreader.ready()) { - String errorOutput = new String(""); - s_logger.info("errors found while running cmdlet Get-VMHostCluster"); - while (true){ - String errline = errreader.readLine(); - if (errline == null) { - break; - } - errorOutput = errorOutput + errline; - } - s_logger.info(errorOutput); - } else { - s_logger.info("No errors found in running cmdlet:" + cmd); - } - - p.getErrorStream().close(); - /* - InputStream in = (InputStream) p.getInputStream(); - XMLInputFactory factory = XMLInputFactory.newInstance(); - XMLStreamReader parser = factory.createXMLStreamReader(in); - - while(parser.hasNext()) { - - int eventType = parser.next(); - switch (eventType) { - - case START_ELEMENT: - // Do something - break; - case END_ELEMENT: - // Do something - break; - // And so on ... - } - } - parser.close(); - */ - - InputStreamReader tempReader = new InputStreamReader(new BufferedInputStream(p.getInputStream())); - BufferedReader reader = new BufferedReader(tempReader); - - String output = new String(""); - - while (true){ - String line = reader.readLine(); - if (line == null) { - break; - } - output = output + line; - } - - String nodesListStr = output.substring(output.indexOf("Nodes")); - nodesListStr = nodesListStr.substring(nodesListStr.indexOf('{', 0)+1, nodesListStr.indexOf('}', 0)); - String[] nodesList = nodesListStr.split(","); - - for (String node : nodesList) { - hypervHosts.add(node); - } - - p.getInputStream().close(); - } catch (Exception e) - { - s_logger.info("Exception caught: "+e.getMessage()); - } - return hypervHosts; - } - - protected HashMap sync() { - HashMap changes = new HashMap(); - - try { - synchronized (_vms) { - } - - } catch (Throwable e) { - s_logger.error("Unable to perform sync information collection process at this point due to exception ", e); - return null; - } - return changes; - } - - @Override - public PingCommand getCurrentStatus(long id) { - HashMap newStates = sync(); - if (newStates == null) { - newStates = new HashMap(); - } - PingRoutingCommand cmd = new PingRoutingCommand(com.cloud.host.Host.Type.Routing, id, newStates); - return cmd; - } - - @Override - public boolean configure(String name, Map params) - throws ConfigurationException { - - _dcId = params.get("zone").toString(); - _podId= params.get("pod").toString(); - _clusterId = params.get("cluster").toString(); - _guid = params.get("guid").toString(); - - boolean success = super.configure(name, params); - if (! success) { - return false; - } - return true; - } - - @Override - protected String getDefaultScriptsDir() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void setName(String name) { - // TODO Auto-generated method stub - - } - - @Override - public void setConfigParams(Map params) { - // TODO Auto-generated method stub - - } - - @Override - public Map getConfigParams() { - // TODO Auto-generated method stub - return null; - } - - @Override - public int getRunLevel() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public void setRunLevel(int level) { - // TODO Auto-generated method stub - - } -} diff --git a/core/src/com/cloud/storage/resource/StorageProcessor.java b/core/src/com/cloud/storage/resource/StorageProcessor.java index ca441edcb79..f503fa3889c 100644 --- a/core/src/com/cloud/storage/resource/StorageProcessor.java +++ b/core/src/com/cloud/storage/resource/StorageProcessor.java @@ -32,7 +32,7 @@ public interface StorageProcessor { public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd); public Answer copyVolumeFromPrimaryToSecondary(CopyCommand cmd); public Answer createTemplateFromVolume(CopyCommand cmd); - public Answer backupSnasphot(CopyCommand cmd); + public Answer backupSnapshot(CopyCommand cmd); public Answer attachIso(AttachCommand cmd); public Answer attachVolume(AttachCommand cmd); public Answer dettachIso(DettachCommand cmd); diff --git a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java index 23ccd318253..c0bbfbea4d9 100644 --- a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java +++ b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java @@ -81,7 +81,7 @@ public class StorageSubsystemCommandHandlerBase implements StorageSubsystemComma return processor.createTemplateFromVolume(cmd); } } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && srcData.getDataStore().getRole() == DataStoreRole.Primary) { - return processor.backupSnasphot(cmd); + return processor.backupSnapshot(cmd); } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.VOLUME) { return processor.createVolumeFromSnapshot(cmd); } diff --git a/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java index 251a6cb917e..9e43d9f1793 100644 --- a/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java +++ b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java @@ -26,14 +26,14 @@ import com.cloud.agent.api.AttachVolumeCommand; import com.cloud.storage.Storage.StoragePoolType; public class AttachVolumeAnswerTest { - AttachVolumeCommand avc = new AttachVolumeCommand(true, "vmname", - StoragePoolType.Filesystem, "vFolder", "vPath", "vName", + AttachVolumeCommand avc = new AttachVolumeCommand(true, false, "vmname", + StoragePoolType.Filesystem, "vPath", "vName", 123456789L, "chainInfo"); AttachVolumeAnswer ava1 = new AttachVolumeAnswer(avc); String results = ""; AttachVolumeAnswer ava2 = new AttachVolumeAnswer(avc, results); Long deviceId = 10L; - AttachVolumeAnswer ava3 = new AttachVolumeAnswer(avc, deviceId); + AttachVolumeAnswer ava3 = new AttachVolumeAnswer(avc, deviceId, ""); @Test public void testGetDeviceId() { diff --git a/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java index 1ec416a4d02..6f413c0268d 100644 --- a/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java +++ b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java @@ -25,8 +25,8 @@ import com.cloud.agent.api.AttachVolumeCommand; import com.cloud.storage.Storage.StoragePoolType; public class AttachVolumeCommandTest { - AttachVolumeCommand avc = new AttachVolumeCommand(true, "vmname", - StoragePoolType.Filesystem, "vFolder", "vPath", "vName", + AttachVolumeCommand avc = new AttachVolumeCommand(true, false, "vmname", + StoragePoolType.Filesystem, "vPath", "vName", 123456789L, "chainInfo"); @Test @@ -65,12 +65,6 @@ public class AttachVolumeCommandTest { assertTrue(pt.equals(StoragePoolType.Iscsi)); } - @Test - public void testGetVolumeFolder() { - String vFolder = avc.getVolumeFolder(); - assertTrue(vFolder.equals("vFolder")); - } - @Test public void testGetVolumePath() { String vPath = avc.getVolumePath(); 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 989059322a9..0fee8c64d87 100644 --- a/core/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java +++ b/core/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java @@ -87,6 +87,11 @@ public class BackupSnapshotCommandTest { return 0L; }; + @Override + public Long getCapacityIops() { + return 0L; + } + @Override public Long getClusterId() { return 0L; 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 4db65570f1b..b834a26b6cc 100644 --- a/core/test/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java +++ b/core/test/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java @@ -125,6 +125,11 @@ public class CheckNetworkAnswerTest { return 0L; }; + @Override + public Long getCapacityIops() { + return 0L; + }; + @Override public Long getClusterId() { return 0L; 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 3076d453434..35bdfc8c883 100644 --- a/core/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java +++ b/core/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java @@ -78,6 +78,10 @@ public class SnapshotCommandTest { return 0L; }; + public Long getCapacityIops() { + return 0L; + }; + public Long getClusterId() { return 0L; }; diff --git a/developer/pom.xml b/developer/pom.xml index a680b8aa98e..e9284f44109 100644 --- a/developer/pom.xml +++ b/developer/pom.xml @@ -58,6 +58,12 @@ ${project.version} compile + + org.apache.cloudstack + cloud-plugin-storage-image-simulator + ${project.version} + compile + install diff --git a/docs/en-US/attaching-volume.xml b/docs/en-US/attaching-volume.xml index 360555eac06..7511ec32a4d 100644 --- a/docs/en-US/attaching-volume.xml +++ b/docs/en-US/attaching-volume.xml @@ -21,24 +21,41 @@ specific language governing permissions and limitations under the License. --> -
- Attaching a Volume - You can attach a volume to a guest VM to provide extra disk storage. Attach a volume when you first create a new volume, when you are moving an existing volume from one VM to another, or after you have migrated a volume from one storage pool to another. - - Log in to the &PRODUCT; UI as a user or admin. - In the left navigation, click Storage. - In Select View, choose Volumes. - 4. Click the volume name in the Volumes list, then click the Attach Disk button - - - - AttachDiskButton.png: button to attach a volume - - - In the Instance popup, choose the VM to which you want to attach the volume. You will only see instances to which you are allowed to attach volumes; for example, a user will see only instances created by that user, but the administrator will have more choices. - - - When the volume has been attached, you should be able to see it by clicking Instances, the instance name, and View Volumes. - -
+ Attaching a Volume + You can attach a volume to a guest VM to provide extra disk storage. Attach a volume when + you first create a new volume, when you are moving an existing volume from one VM to another, or + after you have migrated a volume from one storage pool to another. + + + Log in to the &PRODUCT; UI as a user or admin. + + + In the left navigation, click Storage. + + + In Select View, choose Volumes. + + + 4. Click the volume name in the Volumes list, then click the Attach Disk button + + + + + AttachDiskButton.png: button to attach a volume + + + + + + In the Instance popup, choose the VM to which you want to attach the volume. You will + only see instances to which you are allowed to attach volumes; for example, a user will see + only instances created by that user, but the administrator will have more choices. + + + + When the volume has been attached, you should be able to see it by clicking Instances, + the instance name, and View Volumes. + + + diff --git a/docs/en-US/creating-a-plugin.xml b/docs/en-US/creating-a-plugin.xml new file mode 100644 index 00000000000..448d4e6ea69 --- /dev/null +++ b/docs/en-US/creating-a-plugin.xml @@ -0,0 +1,29 @@ + + +%BOOK_ENTITIES; +]> + + + + + Plugin Development + This chapter will detail different elements related to the development of plugins within Cloudstack + + diff --git a/docs/en-US/creating-my-first-plugin.xml b/docs/en-US/creating-my-first-plugin.xml new file mode 100644 index 00000000000..3809fd30335 --- /dev/null +++ b/docs/en-US/creating-my-first-plugin.xml @@ -0,0 +1,216 @@ + + +
+ Creating my first plugin + This is a brief walk through of creating a simple plugin that adds an additional command to the API to return the message "Hello World". +
+ Letting Cloudstack know about the plugin + Before we can being we need to tell Cloudstack about the existance of our plugin. In order to do this we are required to edit some files related to the cloud-client-ui module + + + Navigate to the folder called client + + + Open pom.xml and add a dependency, this will look something like the following: + + client/pom.xml + <dependency> + <groupId>org.apache.cloudstack</groupId> + <artifactId>cloud-plugin-api-helloworld</artifactId> + <version>${project.version}</version> +</dependency> + + + + Continuing with client as your working directory open up tomcatconf/applicationContext.xml.in + + + Within this file we must insert a bean to load our class: + + client/tomcatconf/applicationContext.xml.in + <bean id="helloWorldImpl" class="org.apache.cloudstack.helloworld.HelloWorldImpl" /> + + + + Finally we need to register the additional API commands we add. Again with client as your working directory this is done by modifying tomcatconf/commands.properties.in + + + Within the file we simply add the names of the API commands we want to create followed by a permission number. 1 = admin, 2 = resource domain admin, 4 = domain admin, 8 = user. + + tomcatconf/commands.properties.in + helloWorld=8 + + + +
+
+ Creating the plugin + Within the Cloudstack filing structure all plugins live under the plugins folder. Since the sample plugin for this document is going to be API related it will live in plugins/api/helloworld. Along with this we will need a standard maven package layout, so lets create all the required folders: + $ mkdir -p plugins/api/helloworld/{src,target,test} +$ mkdir -p plugins/api/helloworld/src/org/apache/cloudstack/{api,helloworld} +$ mkdir -p plugins/api/helloworld/src/org/apache/cloudstack/api/{command,response} +$ mkdir -p plugins/api/helloworld/src/org/apache/cloudstack/api/command/user/helloworld + With helloworld as our working directory we should have a tree layout like the following: + $ cd plugins/api/helloworld +$ tree +. +|-- src +| `-- org +| `-- apache +| `-- cloudstack +| |-- api +| | |-- command +| | | `-- user +| | | `-- helloworld +| | |-- response +| `-- helloworld +|-- target +`-- test + +12 directories, 0 files + First we will create a pom.xml for our plugin: + + plugins/api/helloworld/pom.xml + <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <artifactId>cloud-plugin-api-helloworld</artifactId> + <name>Apache CloudStack Plugin - Hello World Plugin</name> + <parent> + <groupId>org.apache.cloudstack</groupId> + <artifactId>cloudstack-plugins</artifactId> + <version>4.2.0-SNAPSHOT</version> + <relativePath>../../pom.xml</relativePath> + </parent> + <dependencies> + <dependency> + <groupId>org.apache.cloudstack</groupId> + <artifactId>cloud-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.cloudstack</groupId> + <artifactId>cloud-utils</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + <build> + <defaultGoal>install</defaultGoal> + <sourceDirectory>src</sourceDirectory> + <testSourceDirectory>test</testSourceDirectory> + </build> +</project> + + Next we need to make the root plugin pom aware of our plugin to do this simply edit plugins/pom.xml inserting a line like the following: + ...... +<module>api/helloworld</module> +...... + Finally we will being to create code for your plugin. Create an interface called HelloWorld that will extend PluggableService within src/org/apache/cloudstack/hellowold + package org.apache.cloudstack.helloworld; + +import com.cloud.utils.component.PluggableService; + +public interface HelloWorld extends PluggableService { } + Create an implementation of HelloWorld called HelloWorldImpl: + package org.apache.cloudstack.helloworld; + +import org.apache.cloudstack.api.command.user.helloworld.HelloWorldCmd; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import java.util.*; + +@Component +@Local(value = HelloWorld.class) +public class HelloWorldImpl implements HelloWorld { + private static final Logger s_logger = Logger.getLogger(HelloWorldImpl.class); + + public HelloWorldImpl() { + super(); + } + /** + * This informs cloudstack of the API commands you are creating. + */ + @Override + public List<Class<?>> getCommands() { + List<Class<?>> cmdList = new ArrayList<Class<?>>(); + cmdList.add(HelloWorldCmd.class); + return cmdList; + } +} + Next we will create our API command navigate to src/org/apache/cloudstack/api/command/user/helloworld and open up HelloWorldCmd.java, create it as follows + package org.apache.cloudstack.api.command.user.helloworld; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.response.HelloWorldResponse; +import org.apache.log4j.Logger; + +// Note this name matches the name you inserted into client/tomcatconf/commands.properties.in +@APICommand(name = "helloWorld", responseObject = HelloWorldResponse.class, description = "Returns a hello world message", since = "4.2.0") +public class HelloWorldCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(HelloWorldCmd.class.getName()); + private static final String s_name = "helloworldresponse"; + + @Override + public void execute() + { + HelloWorldResponse response = new HelloWorldResponse(); + response.setObjectName("helloworld"); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return 0; + } +} + Finally we need to create our HelloWorldResponse class, this will exist within src/org/apache/cloudstack/api/response/ + package org.apache.cloudstack.api.response; + +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.BaseResponse; +import com.cloud.serializer.Param; + +@SuppressWarnings("unused") +public class HelloWorldResponse extends BaseResponse { + @SerializedName("HelloWorld") @Param(description="HelloWorld Response") + private String HelloWorld; + + public HelloWorldResponse(){ + this.HelloWorld = "Hello World"; + } +} +
+
+ Compiling your plugin: + Within the directory of your plugin i.e. plugins/api/helloworld run mvn clean install. + After this we need to recompile the client-cloud-ui to do this come back to the cloudstack base directory and execute mvn -pl client clean install +
+
+ Starting Cloudstack and Testing: + Start up cloudstack with the normal mvn pl :client-cloud-ui jetty:run, wait a few moments for it to start up then head over to: localhost:8096/client/api?command=helloWorld and you should see your HelloWorld message. +
+
diff --git a/docs/en-US/creating-new-volumes.xml b/docs/en-US/creating-new-volumes.xml index 5a12d7f5783..5440dc5a016 100644 --- a/docs/en-US/creating-new-volumes.xml +++ b/docs/en-US/creating-new-volumes.xml @@ -20,44 +20,65 @@ KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---> +-->
- Creating a New Volume - You can add more data disk volumes to a guest VM at any time, up to the limits of your storage capacity. Both &PRODUCT; administrators and users can add volumes to VM instances. When you create a new volume, it is stored as an entity in &PRODUCT;, but the actual storage resources are not allocated on the physical storage device until you attach the volume. This optimization allows the &PRODUCT; to provision the volume nearest to the guest that will use it when the first attachment is made. -
- Using Local Storage for Data Volumes - You can create data volumes on local storage (supported with XenServer, KVM, and VMware). - The data volume is placed on the same - host as the VM instance that is attached to the data volume. These - local data volumes can be attached to virtual machines, detached, re-attached, - and deleted just as with the other types of data volume. - Local storage is ideal for scenarios where persistence of data volumes and HA - is not required. Some of the benefits include reduced disk I/O latency and cost - reduction from using inexpensive local disks. - In order for local volumes to be used, the feature must be enabled for the - zone. - You can create a data disk offering for local storage. When a user creates a - new VM, they can select this disk offering in order to cause the data disk - volume to be placed in local storage. - You can not migrate a VM that has a volume in local storage to a different - host, nor migrate the volume itself away to a different host. If you want to put - a host into maintenance mode, you must first stop any VMs with local data - volumes on that host. -
-
- To Create a New Volume - - Log in to the &PRODUCT; UI as a user or admin. - In the left navigation bar, click Storage. - In Select View, choose Volumes. - To create a new volume, click Add Volume, provide the following details, and click OK. - - Name. Give the volume a unique name so you can find it later. - Availability Zone. Where do you want the storage to reside? This should be close to the VM that will use the volume. - Disk Offering. Choose the characteristics of the storage. - - The new volume appears in the list of volumes with the state “Allocated.” The volume data is stored in &PRODUCT;, but the volume is not yet ready for use - To start using the volume, continue to Attaching a Volume - -
+ Creating a New Volume + You can add more data disk volumes to a guest VM at any time, up to the limits of your + storage capacity. Both &PRODUCT; administrators and users can add volumes to VM instances. When + you create a new volume, it is stored as an entity in &PRODUCT;, but the actual storage + resources are not allocated on the physical storage device until you attach the volume. This + optimization allows the &PRODUCT; to provision the volume nearest to the guest that will use it + when the first attachment is made. +
+ Using Local Storage for Data Volumes + You can create data volumes on local storage (supported with XenServer, KVM, and VMware). + The data volume is placed on the same host as the VM instance that is attached to the data + volume. These local data volumes can be attached to virtual machines, detached, re-attached, + and deleted just as with the other types of data volume. + Local storage is ideal for scenarios where persistence of data volumes and HA is not + required. Some of the benefits include reduced disk I/O latency and cost reduction from using + inexpensive local disks. + In order for local volumes to be used, the feature must be enabled for the zone. + You can create a data disk offering for local storage. When a user creates a new VM, they + can select this disk offering in order to cause the data disk volume to be placed in local + storage. + You can not migrate a VM that has a volume in local storage to a different host, nor + migrate the volume itself away to a different host. If you want to put a host into maintenance + mode, you must first stop any VMs with local data volumes on that host. +
+
+ To Create a New Volume + + + Log in to the &PRODUCT; UI as a user or admin. + + + In the left navigation bar, click Storage. + + + In Select View, choose Volumes. + + + To create a new volume, click Add Volume, provide the following details, and click + OK. + + + Name. Give the volume a unique name so you can find it later. + + + Availability Zone. Where do you want the storage to reside? This should be close + to the VM that will use the volume. + + + Disk Offering. Choose the characteristics of the storage. + + + The new volume appears in the list of volumes with the state “Allocated.” The volume + data is stored in &PRODUCT;, but the volume is not yet ready for use + + + To start using the volume, continue to Attaching a Volume + + +
diff --git a/docs/en-US/detach-move-volumes.xml b/docs/en-US/detach-move-volumes.xml index fda6e66cede..7103c305c4f 100644 --- a/docs/en-US/detach-move-volumes.xml +++ b/docs/en-US/detach-move-volumes.xml @@ -22,25 +22,39 @@ under the License. -->
- Detaching and Moving Volumes - This procedure is different from moving disk volumes from one storage pool to another. See VM Storage Migration - A volume can be detached from a guest VM and attached to another guest. Both &PRODUCT; administrators and users can detach volumes from VMs and move them to other VMs. - If the two VMs are in different clusters, and the volume is large, it may take several minutes for the volume to be moved to the new VM. - - - Log in to the &PRODUCT; UI as a user or admin. - In the left navigation bar, click Storage, and choose Volumes in Select View. Alternatively, if you know which VM the volume is attached to, you can click Instances, click the VM name, and click View Volumes. - Click the name of the volume you want to detach, then click the Detach Disk button. - - - - - DetachDiskButton.png: button to detach a volume - - - - To move the volume to another VM, follow the steps in . - -
- + Detaching and Moving Volumes + + This procedure is different from moving disk volumes from one storage pool to another. See + VM Storage Migration + + A volume can be detached from a guest VM and attached to another guest. Both &PRODUCT; + administrators and users can detach volumes from VMs and move them to other VMs. + If the two VMs are in different clusters, and the volume is large, it may take several + minutes for the volume to be moved to the new VM. + + + + Log in to the &PRODUCT; UI as a user or admin. + + + In the left navigation bar, click Storage, and choose Volumes in Select View. + Alternatively, if you know which VM the volume is attached to, you can click Instances, + click the VM name, and click View Volumes. + + + Click the name of the volume you want to detach, then click the Detach Disk button. + + + + + DetachDiskButton.png: button to detach a volume + + + + + + To move the volume to another VM, follow the steps in . + + + diff --git a/docs/en-US/networks.xml b/docs/en-US/networks.xml index d1fc541659a..e00beac3ec7 100644 --- a/docs/en-US/networks.xml +++ b/docs/en-US/networks.xml @@ -48,6 +48,7 @@ + diff --git a/docs/en-US/plugin-development.xml b/docs/en-US/plugin-development.xml new file mode 100644 index 00000000000..0492877eba4 --- /dev/null +++ b/docs/en-US/plugin-development.xml @@ -0,0 +1,28 @@ + + +%BOOK_ENTITIES; +]> + + + + + Plugin Development + + diff --git a/docs/en-US/portable-ip.xml b/docs/en-US/portable-ip.xml index 81590df47a0..83d5b43b206 100644 --- a/docs/en-US/portable-ip.xml +++ b/docs/en-US/portable-ip.xml @@ -22,13 +22,35 @@ Portable IPs
About Portable IP - Portable IPs in &PRODUCT; are nothing but elastic IPs that can be transferred across - geographically separated zones. As an administrator, you can provision a pool of portable IPs - at region level and are available for user consumption. The users can acquire portable IPs if - admin has provisioned portable public IPs at the region level they are part of. These IPs can - be use for any service within an advanced zone. You can also use portable IPs for EIP service - in basic zones. Additionally, a portable IP can be transferred from one network to another - network. + Portable IPs in &PRODUCT; are region-level pool of IPs, which are elastic in nature, that + can be transferred across geographically separated zones. As an administrator, you can + provision a pool of portable IPs at region level and are available for user consumption. The + users can acquire portable IPs if admin has provisioned portable public IPs at the region + level they are part of. These IPs can be use for any service within an advanced zone. You can + also use portable IPs for EIP services in basic zones. + The salient features of Portable IP are as follows: + + IP is statically allocated + + + IP need not be associated with a network + + + Network association is transferable across networks + + + IP is transferable across both Basic and Advanced zones + + + IP is transferable across VPC, non-VPC Isolated and Shared networks + + + + + + + +
Configuring Portable IPs @@ -73,7 +95,9 @@ - Click OK. + + Click OK. +
diff --git a/docs/en-US/storage.xml b/docs/en-US/storage.xml index 580fe59e1e1..3ef73246d1d 100644 --- a/docs/en-US/storage.xml +++ b/docs/en-US/storage.xml @@ -1,5 +1,5 @@ - %BOOK_ENTITIES; ]> @@ -21,12 +21,11 @@ specific language governing permissions and limitations under the License. --> - - Working With Storage - - - - - + Working With Storage + + + + + diff --git a/docs/en-US/upload-existing-volume-to-vm.xml b/docs/en-US/upload-existing-volume-to-vm.xml index d2b657164c8..46813747273 100644 --- a/docs/en-US/upload-existing-volume-to-vm.xml +++ b/docs/en-US/upload-existing-volume-to-vm.xml @@ -21,56 +21,91 @@ specific language governing permissions and limitations under the License. --> -
- Uploading an Existing Volume to a Virtual Machine - Existing data can be made accessible to a virtual machine. This is called uploading a volume to the VM. For example, this is useful to upload data from a local file system and attach it to a VM. Root administrators, domain administrators, and end users can all upload existing volumes to VMs. - The upload is performed using HTTP. The uploaded volume is placed in the zone's secondary storage - You cannot upload a volume if the preconfigured volume limit has already been reached. The default limit for the cloud is set in the global configuration parameter max.account.volumes, but administrators can also set per-domain limits that are different from the global default. See Setting Usage Limits - To upload a volume: - - (Optional) Create an MD5 hash (checksum) of the disk image file that you are going to upload. After uploading the data disk, &PRODUCT; will use this value to verify that no data corruption has occurred. - Log in to the &PRODUCT; UI as an administrator or user - In the left navigation bar, click Storage. - Click Upload Volume. - Provide the following: - - Name and Description. Any desired name and a brief description that can be shown in the UI. - Availability Zone. Choose the zone where you want to store the volume. VMs running on hosts in this zone can attach the volume. - Format. Choose one of the following to indicate the disk image format of the volume. - - - - - Hypervisor - Disk Image Format - - - - - XenServer - VHD - - - VMware - OVA - - - KVM - QCOW2 - - - - - - URL. The secure HTTP or HTTPS URL that &PRODUCT; can use to access your disk. The type of file at the URL must match the value chosen in Format. For example, if Format is VHD, the URL might look like the following: - http://yourFileServerIP/userdata/myDataDisk.vhd - MD5 checksum. (Optional) Use the hash that you created in step . - + + + - Wait until the status of the volume shows that the upload is complete. Click Instances - Volumes, find the name you specified in step , and make sure the status is Uploaded. - + + URL. The secure HTTP or HTTPS URL that &PRODUCT; can use to access your disk. The + type of file at the URL must match the value chosen in Format. For example, if Format is + VHD, the URL might look like the following: + http://yourFileServerIP/userdata/myDataDisk.vhd + + + MD5 checksum. (Optional) Use the hash that you created in step 1. + + + + + Wait until the status of the volume shows that the upload is complete. Click Instances - + Volumes, find the name you specified in step 5, and make sure the status is Uploaded. + +
diff --git a/docs/en-US/vm-storage-migration.xml b/docs/en-US/vm-storage-migration.xml index 7c3824b4817..e0dad57faa0 100644 --- a/docs/en-US/vm-storage-migration.xml +++ b/docs/en-US/vm-storage-migration.xml @@ -22,14 +22,19 @@ under the License. -->
- VM Storage Migration - Supported in XenServer, KVM, and VMware. - This procedure is different from moving disk volumes from one VM to another. See Detaching and Moving Volumes . - - - You can migrate a virtual machine’s root disk volume or any additional data disk volume from one storage pool to another in the same zone. - You can use the storage migration feature to achieve some commonly desired administration goals, such as balancing the load on storage pools and increasing the reliability of virtual machines by moving them away from any storage pool that is experiencing issues. - - -
- + VM Storage Migration + Supported in XenServer, KVM, and VMware. + + This procedure is different from moving disk volumes from one VM to another. See Detaching + and Moving Volumes . + + You can migrate a virtual machine’s root disk volume or any additional data disk volume from + one storage pool to another in the same zone. + You can use the storage migration feature to achieve some commonly desired administration + goals, such as balancing the load on storage pools and increasing the reliability of virtual + machines by moving them away from any storage pool that is experiencing issues. + + +
diff --git a/docs/en-US/volume-deletion-garbage-collection.xml b/docs/en-US/volume-deletion-garbage-collection.xml index d162d848cc3..418643890f3 100644 --- a/docs/en-US/volume-deletion-garbage-collection.xml +++ b/docs/en-US/volume-deletion-garbage-collection.xml @@ -21,15 +21,24 @@ specific language governing permissions and limitations under the License. --> -
- Volume Deletion and Garbage Collection - The deletion of a volume does not delete the snapshots that have been created from the volume - When a VM is destroyed, data disk volumes that are attached to the VM are not deleted. - Volumes are permanently destroyed using a garbage collection process. The global configuration variables expunge.delay and expunge.interval determine when the physical deletion of volumes will occur. - - expunge.delay: determines how old the volume must be before it is destroyed, in seconds - expunge.interval: determines how often to run the garbage collection check - - Administrators should adjust these values depending on site policies around data retention. + Volume Deletion and Garbage Collection + The deletion of a volume does not delete the snapshots that have been created from the + volume + When a VM is destroyed, data disk volumes that are attached to the VM are not + deleted. + Volumes are permanently destroyed using a garbage collection process. The global + configuration variables expunge.delay and expunge.interval determine when the physical deletion + of volumes will occur. + + + expunge.delay: determines how old the volume must be before it is destroyed, in + seconds + + + expunge.interval: determines how often to run the garbage collection check + + + Administrators should adjust these values depending on site policies around data + retention.
diff --git a/docs/en-US/working-with-volumes.xml b/docs/en-US/working-with-volumes.xml index ab567d2d0ca..6832cffe339 100644 --- a/docs/en-US/working-with-volumes.xml +++ b/docs/en-US/working-with-volumes.xml @@ -21,29 +21,32 @@ specific language governing permissions and limitations under the License. --> -
- Using Swift for Secondary Storage - A volume provides storage to a guest VM. The volume can provide for - a root disk or an additional data disk. &PRODUCT; supports additional - volumes for guest VMs. - - Volumes are created for a specific hypervisor type. A volume that has - been attached to guest using one hypervisor type (e.g, XenServer) may not - be attached to a guest that is using another hypervisor type (e.g. - vSphere, KVM). This is because the different hypervisors use - different disk image formats. - - &PRODUCT; defines a volume as a unit of storage available to a guest - VM. Volumes are either root disks or data disks. The root disk has "/" - in the file system and is usually the boot device. Data disks provide - for additional storage (e.g. As "/opt" or "D:"). Every guest VM has a root - disk, and VMs can also optionally have a data disk. End users can mount - multiple data disks to guest VMs. Users choose data disks from the disk - offerings created by administrators. The user can create a template from - a volume as well; this is the standard procedure for private template - creation. Volumes are hypervisor-specific: a volume from one hypervisor - type may not be used on a guest of another hypervisor type. - + Working With Volumes + A volume provides storage to a guest VM. The volume can provide for a root disk or an + additional data disk. &PRODUCT; supports additional volumes for guest VMs. + Volumes are created for a specific hypervisor type. A volume that has been attached to guest + using one hypervisor type (e.g, XenServer) may not be attached to a guest that is using another + hypervisor type, for example:vSphere, KVM. This is because the different hypervisors use different + disk image formats. + &PRODUCT; defines a volume as a unit of storage available to a guest VM. Volumes are either + root disks or data disks. The root disk has "/" in the file system and is usually the boot + device. Data disks provide for additional storage, for example: "/opt" or "D:". Every guest VM + has a root disk, and VMs can also optionally have a data disk. End users can mount multiple data + disks to guest VMs. Users choose data disks from the disk offerings created by administrators. + The user can create a template from a volume as well; this is the standard procedure for private + template creation. Volumes are hypervisor-specific: a volume from one hypervisor type may not be + used on a guest of another hypervisor type. + + &PRODUCT; supports attaching up to 13 data disks to a VM on XenServer hypervisor versions + 6.0 and above. For the VMs on other hypervisor types, the data disk limit is 6. + + + + + + + +
- diff --git a/docs/qig/en-US/Author_Group.xml b/docs/qig/en-US/Author_Group.xml new file mode 100644 index 00000000000..432ef6fd3ac --- /dev/null +++ b/docs/qig/en-US/Author_Group.xml @@ -0,0 +1,32 @@ + + +%BOOK_ENTITIES; +]> + + + + + + + Apache + CloudStack + + + diff --git a/docs/qig/en-US/Book_Info.xml b/docs/qig/en-US/Book_Info.xml new file mode 100644 index 00000000000..e356de4415a --- /dev/null +++ b/docs/qig/en-US/Book_Info.xml @@ -0,0 +1,52 @@ + + +%BOOK_ENTITIES; +]> + + + + + + Quick Install Guide + Prescriptive instructions for deploying Apache CloudStack + Apache CloudStack + 4.0.2 + 0 + 0 + + + This guide is designed to provide a strict environment to guarantee + a higher degree of success in initial deployments of Apache CloudStack. + All of the elements of the environment will be provided to you. + Apache CloudStack is capable of much more complex configurations, + but they are beyond the scope of this document. + + + + + + + + + + + + + diff --git a/docs/qig/en-US/Chapter.xml b/docs/qig/en-US/Chapter.xml new file mode 100644 index 00000000000..4adf63c207a --- /dev/null +++ b/docs/qig/en-US/Chapter.xml @@ -0,0 +1,53 @@ + + +%BOOK_ENTITIES; +]> + + + + + + Test Chapter + + This is a test paragraph + +
+ Test Section 1 + + This is a test paragraph in a section + +
+ +
+ Test Section 2 + + This is a test paragraph in Section 2 + + + + listitem text + + + + +
+ +
+ diff --git a/docs/qig/en-US/Environment.xml b/docs/qig/en-US/Environment.xml new file mode 100644 index 00000000000..e48b4051bc3 --- /dev/null +++ b/docs/qig/en-US/Environment.xml @@ -0,0 +1,258 @@ + + +%BOOK_ENTITIES; +]> + + + + + + Environment + + Before you begin, you need to prepare the environment before you install CloudStack. + We will go over the steps to prepare now. + +
+ Operating System + + Using the CentOS 6.4 x86_64 minimal install ISO, you'll need to install CentOS + on your hardware. The defaults will generally be acceptable for this installation. + + + Once this installation is complete, you'll want to connect to your freshly + installed machine via SSH as the root user. Note that you should not allow root + logins in a production environment, so be sure to turn off remote logins once you + have finished the installation and configuration. + +
+ Configuring the network + + By default the network will not come up on your hardware and you + will need to configure it to work in your environment. Since we + specified that there will be no DHCP server in this environment + we will be manually configuring your network interface. We will + assume, for the purposes of this exercise, that eth0 is the only network + interface that will be connected and used. + + + Connecting via the console you should login as root. Check the + file /etc/sysconfig/network-scripts/ifcfg-eth0, + it will look like this by default: + +DEVICE="eth0" +HWADDR="52:54:00:B9:A6:C0" +NM_CONTROLLED="yes" +ONBOOT="no" + + + + Unfortunately, this configuration will not permit you to connect to the network, + and is also unsuitable for our purposes with CloudStack. We want to + configure that file so that it specifies the IP address, netmask, etc., as shown + in the following example: + + + Hardware Addresses + You should not use the hardware address (aka MAC address) from our example + for your configuration. It is network interface specific, so you should keep the + address already provided in the HWADDR directive. + + + +DEVICE=eth0 +HWADDR=52:54:00:B9:A6:C0 +NM_CONTROLLED=no +ONBOOT=yes +BOOTPROTO=none +IPADDR=172.16.10.2 +NETMASK=255.255.255.0 +GATEWAY=172.16.10.1 +DNS1=8.8.8.8 +DNS2=8.8.4.4 + + + IP Addressing + Throughout this document we are assuming that you will + have a /24 network for your CloudStack implementation. This can be any + RFC 1918 network. However, we are assuming that you will match the + machine address that we are using. Thus we may use + 172.16.10.2 and because + you might be using the 192.168.55.0/24 network you would use + 192.168.55.2 + + + Now that we have the configuration files properly set up, we need to run a + few commands to start up the network + # chkconfig network on + # service network start +
+
+ Hostname + + Cloudstack requires that the hostname be properly set. If you used the default + options in the installation, then your hostname is currently set to + localhost.localdomain. To test this we will run: + # hostname --fqdn + At this point it will likely return: + localhost + To rectify this situation - we'll set the hostname by editing the + /etc/hosts file so that it follows a similar format to this example: +127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 +::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 +172.16.10.2 srvr1.cloud.priv + + + After you've modified that file, go ahead and restart the network using: +# service network restart + Now recheck with the hostname --fqdn command and ensure that it returns + a FQDN response +
+
+ SELinux + At the moment, for CloudStack to work properly SELinux must be + set to permissive. We want to both configure this for future boots and modify it + in the current running system. + + To configure SELinux to be permissive in the running system we need to run + the following command: + # setenforce 0 + + To ensure that it remains in that state we need to configure the file + /etc/selinux/config to reflect the permissive state, + as shown in this example: + + +# This file controls the state of SELinux on the system. +# SELINUX= can take one of these three values: +# enforcing - SELinux security policy is enforced. +# permissive - SELinux prints warnings instead of enforcing. +# disabled - No SELinux policy is loaded. +SELINUX=permissive +# SELINUXTYPE= can take one of these two values: +# targeted - Targeted processes are protected, +# mls - Multi Level Security protection. +SELINUXTYPE=targeted + + +
+
+ NTP + NTP configuration is a necessity for keeping all of the clocks in your cloud + servers in sync. However, NTP is not installed by default. So we'll install and + and configure NTP at this stage. Installation is accomplished as follows: + + # yum -y install ntp + The actual default configuration is fine for our purposes, so we merely need to + enable it and set it to start on boot as follows: + # chkconfig ntpd on + # service ntpd start +
+
+ Configuring the CloudStack Package Repository + + We need to configure the machine to use a CloudStack package repository. + + The below repository is not an official Apache CloudStack project repository + + The Apache CloudStack official releases are source code. As such there are no + 'official' binaries available. The full installation guide describes how to take + the source release and generate RPMs and and yum repository. This guide attempts + to keep things as simple as possible, and thus we are using one of the + community-provided yum repositories. + + + + To add the CloudStack repository, create /etc/yum.repos.d/cloudstack.repo and insert the following information. + +[cloudstack] +name=cloudstack +baseurl=http://cloudstack.apt-get.eu/rhel/4.1/ +enabled=1 +gpgcheck=0 + +
+
+
+ NFS + + Our configuration is going to use NFS for both primary and secondary + storage. We are going to go ahead and setup two NFS shares for those + purposes. We'll start out by installing + nfs-utils. + + # yum install nfs-utils + + We now need to configure NFS to serve up two different shares. This is handled comparatively easily + in the /etc/exports file. You should ensure that it has the following content: + + +/secondary *(rw,async,no_root_squash) +/primary *(rw,async,no_root_squash) + + + You will note that we specified two directories that don't exist (yet) on the system. + We'll go ahead and create those directories and set permissions appropriately on them with the following commands: + + +# mkdir /primary +# mkdir /secondary + + CentOS 6.x releases use NFSv4 by default. NFSv4 requires that domain setting matches on all clients. + In our case, the domain is cloud.priv, so ensure that the domain setting in /etc/idmapd.conf + is uncommented and set as follows: + Domain = cloud.priv + Now you'll need uncomment the configuration values in the file /etc/sysconfig/nfs + +LOCKD_TCPPORT=32803 +LOCKD_UDPPORT=32769 +MOUNTD_PORT=892 +RQUOTAD_PORT=875 +STATD_PORT=662 +STATD_OUTGOING_PORT=2020 + + Now we need to configure the firewall to permit incoming NFS connections. + Edit the file /etc/sysconfig/iptables + + +-A INPUT -s 172.16.10.0/24 -m state --state NEW -p udp --dport 111 -j ACCEPT +-A INPUT -s 172.16.10.0/24 -m state --state NEW -p tcp --dport 111 -j ACCEPT +-A INPUT -s 172.16.10.0/24 -m state --state NEW -p tcp --dport 2049 -j ACCEPT +-A INPUT -s 172.16.10.0/24 -m state --state NEW -p tcp --dport 32803 -j ACCEPT +-A INPUT -s 172.16.10.0/24 -m state --state NEW -p udp --dport 32769 -j ACCEPT +-A INPUT -s 172.16.10.0/24 -m state --state NEW -p tcp --dport 892 -j ACCEPT +-A INPUT -s 172.16.10.0/24 -m state --state NEW -p udp --dport 892 -j ACCEPT +-A INPUT -s 172.16.10.0/24 -m state --state NEW -p tcp --dport 875 -j ACCEPT +-A INPUT -s 172.16.10.0/24 -m state --state NEW -p udp --dport 875 -j ACCEPT +-A INPUT -s 172.16.10.0/24 -m state --state NEW -p tcp --dport 662 -j ACCEPT +-A INPUT -s 172.16.10.0/24 -m state --state NEW -p udp --dport 662 -j ACCEPT + + Now you can restart the iptables service with the following command: + + # service iptables restart + We now need to configure nfs service to start on boot and actually start it on the host by + executing the following commands: + +# service rpcbind start +# service nfs start +# chkconfig rpcbind on +# chkconfig nfs on + +
+
diff --git a/docs/qig/en-US/Management.xml b/docs/qig/en-US/Management.xml new file mode 100644 index 00000000000..8c6040ffa2b --- /dev/null +++ b/docs/qig/en-US/Management.xml @@ -0,0 +1,99 @@ + + +%BOOK_ENTITIES; +]> + + + + + + Installation of the management server + + Now it is time to start installing CloudStack's management server + and some of the related components. + +
+ Database Installation and Configuration + + We'll start out by installing MySQL and configuring + some options to ensure CloudStack runs well. + + + To install MySQL run the following command: + # yum -y install mysql-server + + With MySQL installed we need to make + a few configuration changes to /etc/my.cnf. + Specifically we need to add the following options to the [mysqld] section: + +innodb_rollback_on_timeout=1 +innodb_lock_wait_timeout=600 +max_connections=350 +log-bin=mysql-bin +binlog-format = 'ROW' + + + + Now that MySQL is properly configured we can + start it and configure it to start on boot as follows: + +# service mysqld start +# chkconfig mysqld on + + + +
+ +
+ Installation + We are now going to install the management server. We do that by executing the following command: + # yum -y install cloud-client + + With the application itself installed we can now setup the database, we'll do that with the following command + and options: + + # cloudstack-setup-databases cloud:password@localhost --deploy-as=root + When this process is finished, you should see a message like "CloudStack has successfully initialized the database." + + Now that the database has been created, we can take the final step in setting up the management server by issuing the following command: + # cloudstack-setup-management +
+
+ System Template Setup + CloudStack uses a number of system VMs to provide functionality for + accessing the console of virtual machines, providing various networking + services, and managing various aspects of storage. This step will + acquire those system images ready for deployment when we bootstrap + your cloud. + + + Now we need to download the system VM template and deploy that to the + share we just mounted. The management server includes a script to properly + manipulate the system VMs images. + + # /usr/share/cloudstack-common/scripts/storage/secondary/cloud-install-sys-tmplt -m /secondary -u http://download.cloud.com/templates/acton/acton-systemvm-02062012.qcow2.bz2 -h kvm -F + + + That concludes our setup of the management server. We still need to + configure CloudStack, but we will do that after we get our hypervisor + set up. + +
+
diff --git a/docs/qig/en-US/Overview.xml b/docs/qig/en-US/Overview.xml new file mode 100644 index 00000000000..31915f54475 --- /dev/null +++ b/docs/qig/en-US/Overview.xml @@ -0,0 +1,93 @@ + + +%BOOK_ENTITIES; +]> + + + + + + Overview + + Infrastructure-as-a-Service (IaaS) clouds can be a complex thing to build, + and by definition they have a plethora of options, which often lead to confusion + for even experienced admins who are newcomers to building cloud platforms. + The goal for this runbook is to provide a straightforward set of instructions + to get you up and running with CloudStack with a minimum amount of trouble. + +
+ What exactly are we building? + + This runbook will focus on building a CloudStack cloud using KVM with + CentOS 6.4 with NFS storage on a flat layer-2 network utilizing + layer-3 network isolation (aka Security Groups), and doing it all + on a single piece of hardware. + + + KVM, or Kernel-based Virtual Machine is a virtualization technology + for the Linux kernel. KVM supports native virtualization atop + processors with hardware virtualization extensions. + + + Security Groups act as distributed firewalls that control access + to a group of virtual machines. + +
+
+ High level overview of the process + + Before we actually get to installing CloudStack, we'll start with + installing our base operating system, and then configuring that to act + as an NFS server for several types of storage. We'll install the + management server, download the systemVMs, and finally install the agent + software. Finally we'll spend a good deal of time configuring the entire + cloud in the CloudStack web interface. + +
+
+ Prerequisites + + To complete this runbook you'll need the following items: + + + + At least one computer which supports hardware virtualization. + + + + + The + + CentOS 6.4 x86_64 minimal install CD + + + + + + A /24 network with the gateway being at xxx.xxx.xxx.1, no DHCP should be on this network and + none of the computers running CloudStack will have a dynamic address. Again this is done for + the sake of simplicity. + + + + +
+ +
diff --git a/docs/qig/en-US/Preface.xml b/docs/qig/en-US/Preface.xml new file mode 100644 index 00000000000..d6ba80edb6d --- /dev/null +++ b/docs/qig/en-US/Preface.xml @@ -0,0 +1,33 @@ + + +%BOOK_ENTITIES; +]> + + + + + + Preface + + + + + + diff --git a/docs/qig/en-US/Revision_History.xml b/docs/qig/en-US/Revision_History.xml new file mode 100644 index 00000000000..1ff4d772adc --- /dev/null +++ b/docs/qig/en-US/Revision_History.xml @@ -0,0 +1,42 @@ + + +%BOOK_ENTITIES; +]> + + + + + + Revision History + + + + 0-0 + Fri Jun 28 2013 + + + Initial creation of book by publican + + + + + + + diff --git a/docs/qig/en-US/config.xml b/docs/qig/en-US/config.xml new file mode 100644 index 00000000000..7ff7a72f613 --- /dev/null +++ b/docs/qig/en-US/config.xml @@ -0,0 +1,177 @@ + + +%BOOK_ENTITIES; +]> + + + + + + Configuration + + As we noted before we will be using security groups to provide isolation + and by default that implies that we'll be using a flat layer-2 network. + It also means that the simplicity of our setup means that we can use the + quick installer. + +
+ UI Access + + To get access to CloudStack's web interface, merely point your + browser to http://172.16.10.2:8080/client + The default username is 'admin', and the default password is 'password'. + You should see a splash screen that allows you to choose several options + for setting up CloudStack. You should choose the + option. + + + You should now see a prompt requiring you to change the password for + the admin user. Please do so. + +
+
+ Setting up a Zone + + A zone is the largest organization entity in CloudStack - and we'll be creating one, this + should be the screen that you see in front of you now. And for us there are 5 pieces of + information that we need. + + + Name - we will set this to the ever-descriptive 'Zone1' for our cloud. + + + Public DNS 1 - we will set this to '8.8.8.8' for our cloud. + + + Public DNS 2 - we will set this to '8.8.4.4' for our cloud. + + + Internal DNS1 - we will also set this to '8.8.8.8' for our cloud. + + + Internal DNS2 - we will also set this to '8.8.8.4' for our cloud. + + + + + Notes about DNS settings + + CloudStack distinguishes between internal and public DNS. Internal + DNS is assumed to be capable of resolving internal-only + hostnames, such as your NFS server’s DNS name. Public DNS is + provided to the guest VMs to resolve public IP addresses. You can + enter the same DNS server for both types, but if you do so, you + must make sure that both internal and public IP addresses can + route to the DNS server. In our specific case we will not use any + names for resources internally, and we have indeed them set to look + to the same external resource so as to not add a namerserver setup + to our list of requirements. + + +
+
+ Pod Configuration + Now that we've added a Zone, the next step that comes up is a prompt + for information regading a pod. Which is looking for 4 items. + + + Name - We'll use Pod1 for our cloud. + + + Gateway - We'll use 172.16.10.1 as our gateway + + + Netmask - We'll use 255.255.255.0 + + + Start/end reserved system IPs - we will use 172.16.10.10-172.16.10.20 + + + Guest gateway - We'll use 172.16.10.1 + + + Guest netmask - We'll use 255.255.255.0 + + + Guest start/end IP - We'll use 172.16.10.30-172.16.10.200 + + + +
+
+ Cluster + Now that we've added a Zone, we need only add a few more items for configuring the cluster. + + + Name - We'll use Cluster1 + + + Hypervisor - Choose KVM + + + + You should be prompted to add the first host to your cluster at this point. Only a few bits of information are needed. + + + Hostname - we'll use the IP address 172.16.10.2 since we didn't set up a DNS server. + + + Username - we'll use 'root' + + + Password - enter the operating system password for the root user + + + +
+ Primary Storage + With your cluster now setup - you should be prompted for primary storage information. Choose NFS as the storage type and then enter the following values in the fields: + + + Name - We'll use 'Primary1' + + + Server - We'll be using the IP address 172.16.10.2 + + + Path - Well define /primary as the path we are using + + + +
+
+ Secondary Storage + If this is a new zone, you'll be prompted for secondary storage information - populate it as follows: + + + NFS server - We'll use the IP address 172.16.10.2 + + + Path - We'll use /secondary + + + + Now, click Launch and your cloud should begin setup - it may take several minutes depending on your internet connection speed for setup to finalize. +
+
+ + +
+ diff --git a/docs/qig/en-US/kvm.xml b/docs/qig/en-US/kvm.xml new file mode 100644 index 00000000000..91ed9d5cee9 --- /dev/null +++ b/docs/qig/en-US/kvm.xml @@ -0,0 +1,142 @@ + + +%BOOK_ENTITIES; +]> + + + + + + KVM Setup and installation + + KVM is the hypervisor we'll be using - we will recover the initial setup + which has already been done on the hypervisor host and cover installation + of the agent software, you can use the same steps to add additional KVM + nodes to your CloudStack environment. + +
+ Prerequisites + + We explicitly are using the management server as a compute node as well, + which means that we have already performed many of the prerequisite steps + when setting up the management server, but we will list them here for + clarity. Those steps are: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + You shouldn't need to do that for the management server, of course, but + any additional hosts will need for you to complete the above steps. + +
+ +
+ Installation + Installation of the KVM agent is trivial with just a single command, but afterwards we'll need to configure a few things. + # yum -y install cloud-agent +
+ KVM Configuration + We have two different parts of KVM to configure, libvirt, and QEMU. +
+ QEMU Configuration + + KVM configuration is relatively simple at only a single item. We need to + edit the QEMU VNC configuration. This is done by editing + /etc/libvirt/qemu.conf and ensuring the following + line is present and uncommented. + vnc_listen=0.0.0.0 + +
+
+ Libvirt Configuration + + CloudStack uses libvirt for managing virtual machines. Therefore it + is vital that libvirt is configured correctly. Libvirt is a dependency + of cloud-agent and should already be installed. + + + + In order to have live migration working libvirt has to listen + for unsecured TCP connections. We also need to turn off libvirts + attempt to use Multicast DNS advertising. Both of these settings + are in /etc/libvirt/libvirtd.conf + + Set the following paramaters: + listen_tls = 0 + listen_tcp = 1 + tcp_port = "16059" + auth_tcp = "none" + mdns_adv = 0 + + + Turning on "listen_tcp" in libvirtd.conf is not enough, we have to change the parameters as well: + On RHEL or CentOS modify /etc/sysconfig/libvirtd: + Uncomment the following line: + #LIBVIRTD_ARGS="--listen" + On Ubuntu: modify /etc/init/libvirt-bin.conf + Change the following line (at the end of the file): + exec /usr/sbin/libvirtd -d + to (just add -l) + exec /usr/sbin/libvirtd -d -l + + + Restart libvirt + In RHEL or CentOS: + $ service libvirtd restart + In Ubuntu: + $ service libvirt-bin restart + + +
+
+ KVM configuration complete + + That concludes our installation and configuration of KVM, and we'll now move to using the CloudStack UI + for the actual configuration of our cloud. + +
+
+
+
diff --git a/docs/qig/en-US/qig.ent b/docs/qig/en-US/qig.ent new file mode 100644 index 00000000000..3b1649a2ba9 --- /dev/null +++ b/docs/qig/en-US/qig.ent @@ -0,0 +1,22 @@ + + + + + + diff --git a/docs/qig/en-US/qig.xml b/docs/qig/en-US/qig.xml new file mode 100644 index 00000000000..00dd2e4a1f0 --- /dev/null +++ b/docs/qig/en-US/qig.xml @@ -0,0 +1,36 @@ + + +%BOOK_ENTITIES; +]> + + + + + + + + + + + + + + + diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ChapInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ChapInfo.java new file mode 100644 index 00000000000..97c9ecbaab0 --- /dev/null +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ChapInfo.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.engine.subsystem.api.storage; + +public interface ChapInfo { + String getInitiatorUsername(); + String getInitiatorSecret(); + String getTargetUsername(); + String getTargetSecret(); +} 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 1cb6e158489..127b8589987 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 @@ -24,17 +24,11 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.command.CommandResult; public interface DataStoreDriver { - void createAsync(DataObject data, AsyncCompletionCallback callback); - - void deleteAsync(DataObject data, AsyncCompletionCallback callback); - - void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback callback); - - boolean canCopy(DataObject srcData, DataObject destData); - - void resize(DataObject data, AsyncCompletionCallback callback); - DataTO getTO(DataObject data); - DataStoreTO getStoreTO(DataStore store); + void createAsync(DataStore store, DataObject data, AsyncCompletionCallback callback); + void deleteAsync(DataStore store, DataObject data, AsyncCompletionCallback callback); + void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback callback); + boolean canCopy(DataObject srcData, DataObject destData); + void resize(DataObject data, AsyncCompletionCallback callback); } 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 2528a536d64..b124d835dda 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 @@ -22,7 +22,7 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.command.CommandResult; public interface PrimaryDataStoreDriver extends DataStoreDriver { - void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback); - - void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback); + public ChapInfo getChapInfo(VolumeInfo volumeInfo); + 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/PrimaryDataStoreParameters.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreParameters.java index 3b5362a2d06..c05419f6641 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreParameters.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreParameters.java @@ -20,6 +20,7 @@ package org.apache.cloudstack.engine.subsystem.api.storage; import java.util.Map; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Storage.StoragePoolType; public class PrimaryDataStoreParameters { @@ -30,12 +31,17 @@ public class PrimaryDataStoreParameters { private Map details; private String tags; private StoragePoolType type; + private HypervisorType hypervisorType; private String host; private String path; private int port; private String uuid; private String name; private String userInfo; + private long capacityBytes; + private long usedBytes; + private boolean managed; + private Long capacityIops; /** * @return the userInfo @@ -187,6 +193,30 @@ public class PrimaryDataStoreParameters { this.providerName = providerName; } + public void setManaged(boolean managed) { + this.managed = managed; + } + + public boolean isManaged() { + return managed; + } + + public void setCapacityIops(Long capacityIops) { + this.capacityIops = capacityIops; + } + + public Long getCapacityIops() { + return capacityIops; + } + + public void setHypervisorType(HypervisorType hypervisorType) { + this.hypervisorType = hypervisorType; + } + + public HypervisorType getHypervisorType() { + return hypervisorType; + } + /** * @return the clusterId */ @@ -231,4 +261,24 @@ public class PrimaryDataStoreParameters { public void setZoneId(Long zoneId) { this.zoneId = zoneId; } + + public long getCapacityBytes() + { + return capacityBytes; + } + + public void setCapacityBytes(long capacityBytes) + { + this.capacityBytes = capacityBytes; + } + + public long getUsedBytes() + { + return usedBytes; + } + + public void setUsedBytes(long usedBytes) + { + this.usedBytes = usedBytes; + } } 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 f96ea4032d1..7515088f331 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 @@ -42,6 +42,8 @@ public interface VolumeService { } } + ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore); + /** * Creates the volume based on the given criteria * diff --git a/engine/api/src/org/apache/cloudstack/storage/command/AttachCommand.java b/engine/api/src/org/apache/cloudstack/storage/command/AttachCommand.java index 6b4e9f7ed00..44bce910d02 100644 --- a/engine/api/src/org/apache/cloudstack/storage/command/AttachCommand.java +++ b/engine/api/src/org/apache/cloudstack/storage/command/AttachCommand.java @@ -24,6 +24,14 @@ import com.cloud.agent.api.to.DiskTO; public final class AttachCommand extends Command implements StorageSubSystemCommand { private DiskTO disk; private String vmName; + private String _storageHost; + private int _storagePort; + private boolean _managed; + private String _iScsiName; + private String _chapInitiatorUsername; + private String _chapInitiatorPassword; + private String _chapTargetUsername; + private String _chapTargetPassword; public AttachCommand(DiskTO disk, String vmName) { super(); @@ -52,4 +60,67 @@ public final class AttachCommand extends Command implements StorageSubSystemComm this.vmName = vmName; } + public void setStorageHost(String storageHost) { + _storageHost = storageHost; + } + + public String getStorageHost() { + return _storageHost; + } + + public void setStoragePort(int storagePort) { + _storagePort = storagePort; + } + + public int getStoragePort() { + return _storagePort; + } + + public void setManaged(boolean managed) { + _managed = managed; + } + + public boolean isManaged() { + return _managed; + } + + public void set_iScsiName(String iScsiName) { + this._iScsiName = iScsiName; + } + + public String get_iScsiName() { + return _iScsiName; + } + + public void setChapInitiatorUsername(String chapInitiatorUsername) { + _chapInitiatorUsername = chapInitiatorUsername; + } + + public String getChapInitiatorUsername() { + return _chapInitiatorUsername; + } + + public void setChapInitiatorPassword(String chapInitiatorPassword) { + _chapInitiatorPassword = chapInitiatorPassword; + } + + public String getChapInitiatorPassword() { + return _chapInitiatorPassword; + } + + public void setChapTargetUsername(String chapTargetUsername) { + _chapTargetUsername = chapTargetUsername; + } + + public String getChapTargetUsername() { + return _chapTargetUsername; + } + + public void setChapTargetPassword(String chapTargetPassword) { + _chapTargetPassword = chapTargetPassword; + } + + public String getChapTargetPassword() { + return _chapTargetPassword; + } } diff --git a/engine/api/src/org/apache/cloudstack/storage/command/DettachCommand.java b/engine/api/src/org/apache/cloudstack/storage/command/DettachCommand.java index a0ab4b2e6f4..bb7325c3e81 100644 --- a/engine/api/src/org/apache/cloudstack/storage/command/DettachCommand.java +++ b/engine/api/src/org/apache/cloudstack/storage/command/DettachCommand.java @@ -24,6 +24,8 @@ import com.cloud.agent.api.to.DiskTO; public class DettachCommand extends Command implements StorageSubSystemCommand { private DiskTO disk; private String vmName; + private boolean _managed; + private String _iScsiName; public DettachCommand(DiskTO disk, String vmName) { super(); @@ -52,4 +54,19 @@ public class DettachCommand extends Command implements StorageSubSystemCommand { this.vmName = vmName; } + public void setManaged(boolean managed) { + _managed = managed; + } + + public boolean isManaged() { + return _managed; + } + + public void set_iScsiName(String iScsiName) { + _iScsiName = iScsiName; + } + + public String get_iScsiName() { + return _iScsiName; + } } diff --git a/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java index 9b8de679b08..a8c1e7feb49 100644 --- a/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java +++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java @@ -103,6 +103,12 @@ public class StoragePoolVO implements StoragePool { @Enumerated(value = EnumType.STRING) private ScopeType scope; + @Column(name = "managed") + private boolean managed; + + @Column(name = "capacity_iops", updatable = true, nullable = true) + private Long capacityIops; + @Column(name = "hypervisor") @Enumerated(value = EnumType.STRING) private HypervisorType hypervisor; @@ -201,8 +207,24 @@ public class StoragePoolVO implements StoragePool { usedBytes = available; } - public void setCapacityBytes(long capacity) { - capacityBytes = capacity; + public void setCapacityBytes(long capacityBytes) { + this.capacityBytes = capacityBytes; + } + + public void setManaged(boolean managed) { + this.managed = managed; + } + + public boolean isManaged() { + return managed; + } + + public void setCapacityIops(Long capacityIops) { + this.capacityIops = capacityIops; + } + + public Long getCapacityIops() { + return capacityIops; } public Long getClusterId() { diff --git a/engine/components-api/src/com/cloud/storage/VolumeManager.java b/engine/components-api/src/com/cloud/storage/VolumeManager.java index 15f24f78b9a..71741d5bf64 100644 --- a/engine/components-api/src/com/cloud/storage/VolumeManager.java +++ b/engine/components-api/src/com/cloud/storage/VolumeManager.java @@ -44,7 +44,6 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; public interface VolumeManager extends VolumeApiService { - VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType) throws ConcurrentOperationException; diff --git a/engine/schema/src/com/cloud/dc/VlanVO.java b/engine/schema/src/com/cloud/dc/VlanVO.java index a2f7a9cfb59..d262409e6a9 100644 --- a/engine/schema/src/com/cloud/dc/VlanVO.java +++ b/engine/schema/src/com/cloud/dc/VlanVO.java @@ -197,4 +197,8 @@ public class VlanVO implements Vlan { public void setIp6Range(String ip6Range) { this.ip6Range = ip6Range; } + + public void setIpRange(String ipRange) { + this.ip6Range = ipRange; + } } diff --git a/engine/schema/src/com/cloud/network/dao/IPAddressDao.java b/engine/schema/src/com/cloud/network/dao/IPAddressDao.java index fecd44a32b1..3eba6d802d9 100755 --- a/engine/schema/src/com/cloud/network/dao/IPAddressDao.java +++ b/engine/schema/src/com/cloud/network/dao/IPAddressDao.java @@ -17,9 +17,11 @@ package com.cloud.network.dao; import com.cloud.dc.Vlan.VlanType; +import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDao; import com.cloud.utils.net.Ip; +import java.sql.SQLException; import java.util.List; public interface IPAddressDao extends GenericDao { @@ -72,4 +74,8 @@ public interface IPAddressDao extends GenericDao { IPAddressVO findByIpAndVlanId(String ipAddress, long vlanid); long countFreeIpsInVlan(long vlanDbId); + + boolean deletePublicIPRangeExceptAliasIP(long vlanDbId, String aliasIp) throws SQLException; + + boolean deletePublicIPRange(long vlanDbId) throws SQLException; } diff --git a/engine/schema/src/com/cloud/network/dao/IPAddressDaoImpl.java b/engine/schema/src/com/cloud/network/dao/IPAddressDaoImpl.java index 886011ecc31..1051b694d3d 100755 --- a/engine/schema/src/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/engine/schema/src/com/cloud/network/dao/IPAddressDaoImpl.java @@ -40,6 +40,7 @@ import javax.ejb.Local; import javax.inject.Inject; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.SQLException; import java.util.Date; import java.util.List; @@ -364,6 +365,28 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen return customSearch(sc, null).get(0); } + @Override + public boolean deletePublicIPRangeExceptAliasIP(long vlanDbId, String aliasIp) throws SQLException { + Transaction txn = Transaction.currentTxn(); + String deleteSql = "DELETE FROM `cloud`.`user_ip_address` WHERE vlan_db_id = ? and public_ip_address!=?"; + + txn.start(); + PreparedStatement stmt = txn.prepareAutoCloseStatement(deleteSql); + stmt.setLong(1, vlanDbId); + stmt.setString(2, aliasIp); + stmt.executeUpdate(); + txn.commit(); + return true; + } + + @Override + public boolean deletePublicIPRange(long vlanDbId) throws SQLException{ + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("vlan", vlanDbId); + remove(sc); + return true; + } + @Override @DB public boolean remove(Long id) { diff --git a/engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java b/engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java index c55cf28273a..0f83815a986 100644 --- a/engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java +++ b/engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java @@ -208,6 +208,9 @@ public class NetworkDaoImpl extends GenericDaoBase implements N VpcNetworksCount = createSearchBuilder(Long.class); VpcNetworksCount.and("vpcId", VpcNetworksCount.entity().getVpcId(), Op.EQ); VpcNetworksCount.select(null, Func.COUNT, VpcNetworksCount.entity().getId()); + SearchBuilder join9 = _ntwkOffDao.createSearchBuilder(); + join9.and("isSystem", join9.entity().isSystemOnly(), Op.EQ); + VpcNetworksCount.join("offerings", join9, VpcNetworksCount.entity().getNetworkOfferingId(), join9.entity().getId(), JoinBuilder.JoinType.INNER); VpcNetworksCount.done(); OfferingAccountNetworkSearch = createSearchBuilder(); @@ -587,6 +590,8 @@ public class NetworkDaoImpl extends GenericDaoBase implements N public long countVpcNetworks(long vpcId) { SearchCriteria sc = VpcNetworksCount.create(); sc.setParameters("vpcId", vpcId); + //offering shouldn't be system (the one used by the private gateway) + sc.setJoinParameters("offerings", "isSystem", false); return customSearch(sc, null).get(0); } diff --git a/engine/schema/src/com/cloud/storage/DiskOfferingVO.java b/engine/schema/src/com/cloud/storage/DiskOfferingVO.java index b7363e7208a..d9656b4c138 100755 --- a/engine/schema/src/com/cloud/storage/DiskOfferingVO.java +++ b/engine/schema/src/com/cloud/storage/DiskOfferingVO.java @@ -94,6 +94,15 @@ public class DiskOfferingVO implements DiskOffering { @Column(name = "uuid") private String uuid; + @Column(name="customized_iops") + private Boolean customizedIops; + + @Column(name="min_iops") + Long minIops; + + @Column(name="max_iops") + Long maxIops; + @Column(name = "sort_key") int sortKey; @@ -116,8 +125,8 @@ public class DiskOfferingVO implements DiskOffering { this.uuid = UUID.randomUUID().toString(); } - public DiskOfferingVO(Long domainId, String name, String displayText, long diskSize, String tags, - boolean isCustomized) { + public DiskOfferingVO(Long domainId, String name, String displayText, long diskSize, String tags, boolean isCustomized, + Boolean isCustomizedIops, Long minIops, Long maxIops) { this.domainId = domainId; this.name = name; this.displayText = displayText; @@ -128,6 +137,9 @@ public class DiskOfferingVO implements DiskOffering { this.useLocalStorage = false; this.customized = isCustomized; this.uuid = UUID.randomUUID().toString(); + this.customizedIops = isCustomizedIops; + this.minIops = minIops; + this.maxIops = maxIops; } public DiskOfferingVO(String name, String displayText, boolean mirrored, String tags, boolean recreatable, @@ -175,6 +187,36 @@ public class DiskOfferingVO implements DiskOffering { } @Override + public Boolean isCustomizedIops() { + return customizedIops; + } + + @Override + public void setCustomizedIops(Boolean customizedIops) { + this.customizedIops = customizedIops; + } + + @Override + public Long getMinIops() { + return minIops; + } + + @Override + public void setMinIops(Long minIops) { + this.minIops = minIops; + } + + @Override + public Long getMaxIops() { + return maxIops; + } + + @Override + public void setMaxIops(Long maxIops) { + this.maxIops = maxIops; + } + + @Override public String getUniqueName() { return uniqueName; } diff --git a/engine/schema/src/com/cloud/storage/VolumeVO.java b/engine/schema/src/com/cloud/storage/VolumeVO.java index 02c09a2f271..7b54f3df538 100755 --- a/engine/schema/src/com/cloud/storage/VolumeVO.java +++ b/engine/schema/src/com/cloud/storage/VolumeVO.java @@ -70,6 +70,12 @@ public class VolumeVO implements Volume { @Column(name = "size") Long size; + @Column(name = "min_iops") + Long minIops; + + @Column(name = "max_iops") + Long maxIops; + @Column(name = "folder") String folder; @@ -141,25 +147,32 @@ public class VolumeVO implements Volume { @Column(name = "display_volume", updatable = true, nullable = false) protected boolean displayVolume; + @Column(name = "iscsi_name") + private String _iScsiName; + @Transient // @Column(name="reservation") String reservationId; // Real Constructor - public VolumeVO(Type type, String name, long dcId, long domainId, long accountId, long diskOfferingId, long size) { + public VolumeVO(Type type, String name, long dcId, long domainId, long accountId, long diskOfferingId, long size, + Long minIops, Long maxIops, String iScsiName) { this.volumeType = type; this.name = name; this.dataCenterId = dcId; this.accountId = accountId; this.domainId = domainId; this.size = size; + this.minIops = minIops; + this.maxIops = maxIops; + this._iScsiName = iScsiName; this.diskOfferingId = diskOfferingId; this.state = State.Allocated; this.uuid = UUID.randomUUID().toString(); } - public VolumeVO(String name, Long dcId, Long podId, long accountId, long domainId, Long instanceId, String folder, - String path, long size, Volume.Type vType) { + public VolumeVO(String name, long dcId, long podId, long accountId, long domainId, Long instanceId, String folder, String path, + long size, Long minIops, Long maxIops, String iScsiName, Volume.Type vType) { this.name = name; this.accountId = accountId; this.domainId = domainId; @@ -167,6 +180,9 @@ public class VolumeVO implements Volume { this.folder = folder; this.path = path; this.size = size; + this.minIops = minIops; + this.maxIops = maxIops; + this._iScsiName = iScsiName; this.podId = podId; this.dataCenterId = dcId; this.volumeType = vType; @@ -177,11 +193,15 @@ public class VolumeVO implements Volume { // Copy Constructor public VolumeVO(Volume that) { - this(that.getName(), that.getDataCenterId(), that.getPodId(), that.getAccountId(), that.getDomainId(), that - .getInstanceId(), that.getFolder(), that.getPath(), that.getSize(), that.getVolumeType()); + this(that.getName(), that.getDataCenterId(), that.getPodId(), that.getAccountId(), that.getDomainId(), that.getInstanceId(), + that.getFolder(), that.getPath(), that.getSize(), that.getMinIops(), that.getMaxIops(), + that.get_iScsiName(), that.getVolumeType()); this.recreatable = that.isRecreatable(); this.state = that.getState(); this.size = that.getSize(); + this.minIops = that.getMinIops(); + this.maxIops = that.getMaxIops(); + this._iScsiName = that.get_iScsiName(); this.diskOfferingId = that.getDiskOfferingId(); this.poolId = that.getPoolId(); this.attached = that.getAttached(); @@ -274,6 +294,24 @@ public class VolumeVO implements Volume { this.size = size; } + @Override + public Long getMinIops() { + return minIops; + } + + public void setMinIops(Long minIops) { + this.minIops = minIops; + } + + @Override + public Long getMaxIops() { + return maxIops; + } + + public void setMaxIops(Long maxIops) { + this.maxIops = maxIops; + } + @Override public Long getInstanceId() { return instanceId; @@ -464,6 +502,15 @@ public class VolumeVO implements Volume { this.uuid = uuid; } + @Override + public String get_iScsiName() { + return this._iScsiName; + } + + public void set_iScsiName(String iScsiName) { + this._iScsiName = iScsiName; + } + public boolean isDisplayVolume() { return displayVolume; } diff --git a/engine/schema/src/com/cloud/storage/dao/VMTemplateDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateDaoImpl.java index ad33e7abd99..9e7599052a7 100755 --- a/engine/schema/src/com/cloud/storage/dao/VMTemplateDaoImpl.java +++ b/engine/schema/src/com/cloud/storage/dao/VMTemplateDaoImpl.java @@ -28,8 +28,6 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; -import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -56,9 +54,7 @@ import com.cloud.utils.db.JoinBuilder; 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.Transaction; -import com.cloud.utils.db.UpdateBuilder; import com.cloud.utils.exception.CloudRuntimeException; @Component @@ -102,7 +98,7 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem private SearchBuilder PublicIsoSearch; private SearchBuilder UserIsoSearch; private GenericSearchBuilder CountTemplatesByAccount; - // private SearchBuilder updateStateSearch; + // private SearchBuilder updateStateSearch; @Inject ResourceTagDao _tagsDao; @@ -344,6 +340,7 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem AccountIdSearch = createSearchBuilder(); AccountIdSearch.and("accountId", AccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ); AccountIdSearch.and("publicTemplate", AccountIdSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ); + AccountIdSearch.and("removed", AccountIdSearch.entity().getRemoved(), SearchCriteria.Op.NULL); // only list not removed templates for this account AccountIdSearch.done(); SearchBuilder tmpltZoneSearch = _templateZoneDao.createSearchBuilder(); @@ -369,11 +366,11 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem CountTemplatesByAccount.and("removed", CountTemplatesByAccount.entity().getRemoved(), SearchCriteria.Op.NULL); CountTemplatesByAccount.done(); -// updateStateSearch = this.createSearchBuilder(); -// updateStateSearch.and("id", updateStateSearch.entity().getId(), Op.EQ); -// updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ); -// updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ); -// updateStateSearch.done(); + // updateStateSearch = this.createSearchBuilder(); + // updateStateSearch.and("id", updateStateSearch.entity().getId(), Op.EQ); + // updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ); + // updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ); + // updateStateSearch.done(); return result; } diff --git a/engine/schema/src/com/cloud/storage/dao/VolumeDao.java b/engine/schema/src/com/cloud/storage/dao/VolumeDao.java index 79c0dc37786..fb7dc706f10 100755 --- a/engine/schema/src/com/cloud/storage/dao/VolumeDao.java +++ b/engine/schema/src/com/cloud/storage/dao/VolumeDao.java @@ -58,6 +58,8 @@ public interface VolumeDao extends GenericDao, StateDao findByPoolId(long poolId); + List findByPoolId(long poolId, Volume.Type volumeType); + List findByInstanceAndDeviceId(long instanceId, long deviceId); List findUsableVolumesForInstance(long instanceId); diff --git a/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java index f82b51157c4..ba85466a930 100755 --- a/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java +++ b/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java @@ -109,6 +109,19 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol sc.setParameters("poolId", poolId); sc.setParameters("notDestroyed", Volume.State.Destroy); sc.setParameters("vType", Volume.Type.ROOT.toString()); + return listBy(sc); + } + + @Override + public List findByPoolId(long poolId, Volume.Type volumeType) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("poolId", poolId); + sc.setParameters("notDestroyed", Volume.State.Destroy); + + if (volumeType != null) { + sc.setParameters("vType", volumeType.toString()); + } + return listBy(sc); } diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade2214to30.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade2214to30.java index 2d77429367a..e1b56df8da8 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade2214to30.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade2214to30.java @@ -462,7 +462,7 @@ public class Upgrade2214to30 extends Upgrade30xBase implements DbUpgrade { ResultSet rs = null; try { int numRows = 0; - pstmt = conn.prepareStatement("select count(id) from `cloud`.`vm_instance` where removed is null"); + pstmt = conn.prepareStatement("select count(id) from `cloud`.`vm_instance`"); rs = pstmt.executeQuery(); if(rs.next()){ numRows = rs.getInt(1); @@ -471,7 +471,7 @@ public class Upgrade2214to30 extends Upgrade30xBase implements DbUpgrade { pstmt.close(); int offset = 0; while(offset < numRows){ - pstmt = conn.prepareStatement("select id, vnc_password from `cloud`.`vm_instance` where removed is null limit "+offset+", 500"); + pstmt = conn.prepareStatement("select id, vnc_password from `cloud`.`vm_instance` limit "+offset+", 500"); rs = pstmt.executeQuery(); while (rs.next()) { long id = rs.getLong(1); 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 4b4e52106ff..a8107727692 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 @@ -147,7 +147,7 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager { object = cacheReplacementAlgorithm.chooseOneToBeReplaced(store); findAStore = store; if (object != null) { - break; + break; } } @@ -230,6 +230,12 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager { @Override public DataObject createCacheObject(DataObject data, Scope scope) { DataStore cacheStore = this.getCacheStorage(scope); + + if (cacheStore == null) + { + String errMsg = "No cache DataStore in scope id " + scope.getScopeId() + " type " + scope.getScopeType().toString(); + throw new CloudRuntimeException(errMsg); + } return this.createCacheObject(data, cacheStore); } 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 631de6a47a3..04d04363a37 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 @@ -35,6 +35,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreState 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.StorageCacheManager; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; @@ -57,6 +58,7 @@ import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.host.Host; import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.DataStoreRole; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; @@ -135,6 +137,22 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { if (destStoreTO instanceof NfsTO || destStoreTO.getRole() == DataStoreRole.ImageCache) { return false; } + + if (srcData.getType() == DataObjectType.TEMPLATE) { + TemplateInfo template = (TemplateInfo)srcData; + if (template.getHypervisorType() == HypervisorType.Hyperv) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("needCacheStorage false due to src TemplateInfo, which is DataObjectType.TEMPLATE of HypervisorType.Hyperv"); + } + return false; + } + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("needCacheStorage true, dest at " + + destTO.getPath() + " dest role " + destStoreTO.getRole().toString() + + srcTO.getPath() + " src role " + srcStoreTO.getRole().toString() ); + } return true; } @@ -157,26 +175,24 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { int _primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); Answer answer = null; + boolean usingCache = false; DataObject cacheData = null; + DataObject srcForCopy = srcData; try { if (needCacheStorage(srcData, destData)) { - // need to copy it to image cache store Scope destScope = getZoneScope(destData.getDataStore().getScope()); - cacheData = cacheMgr.createCacheObject(srcData, destScope); - CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _primaryStorageDownloadWait); - EndPoint ep = selector.select(cacheData, destData); - answer = ep.sendMessage(cmd); - } else { - // handle copy it to/from cache store - CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _primaryStorageDownloadWait); - EndPoint ep = selector.select(srcData, destData); - answer = ep.sendMessage(cmd); + srcForCopy = cacheData = cacheMgr.createCacheObject(srcData, destScope); } + + CopyCommand cmd = new CopyCommand(srcForCopy.getTO(), destData.getTO(), _primaryStorageDownloadWait); + EndPoint ep = selector.select(srcForCopy, destData); + answer = ep.sendMessage(cmd); + if (cacheData != null) { if (answer == null || !answer.getResult()) { - cacheMgr.deleteCacheObject(cacheData); + cacheMgr.deleteCacheObject(srcForCopy); } else { - cacheMgr.releaseCacheObject(cacheData); + cacheMgr.releaseCacheObject(srcForCopy); } } return answer; @@ -187,7 +203,6 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { } throw new CloudRuntimeException(e.toString()); } - } protected DataObject cacheSnapshotChain(SnapshotInfo snapshot) { @@ -204,10 +219,10 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { } protected void deleteSnapshotCacheChain(SnapshotInfo snapshot) { - while (snapshot != null) { - cacheMgr.deleteCacheObject(snapshot); - snapshot = snapshot.getParent(); - } + while (snapshot != null) { + cacheMgr.deleteCacheObject(snapshot); + snapshot = snapshot.getParent(); + } } protected Answer copyVolumeFromSnapshot(DataObject snapObj, DataObject volObj) { @@ -317,6 +332,8 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { Answer answer = null; String errMsg = null; try { + s_logger.debug("copyAsync inspecting src type " + srcData.getType().toString() + + " copyAsync inspecting dest type " + destData.getType().toString()); if (srcData.getType() == DataObjectType.SNAPSHOT && destData.getType() == DataObjectType.VOLUME) { answer = copyVolumeFromSnapshot(srcData, destData); @@ -404,7 +421,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { @Override public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, - AsyncCompletionCallback callback) { + AsyncCompletionCallback callback) { CopyCommandResult result = new CopyCommandResult(null, null); result.setResult("Unsupported operation requested for copying data."); callback.complete(result); diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java index 22de0b25279..c1cbdc772cc 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java @@ -18,11 +18,9 @@ */ package org.apache.cloudstack.storage.motion; -import java.util.List; -import java.util.Map; - -import javax.inject.Inject; - +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.host.Host; +import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionService; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; @@ -32,9 +30,9 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.springframework.stereotype.Component; -import com.cloud.agent.api.to.VirtualMachineTO; -import com.cloud.host.Host; -import com.cloud.utils.exception.CloudRuntimeException; +import javax.inject.Inject; +import java.util.List; +import java.util.Map; @Component public class DataMotionServiceImpl implements DataMotionService { @@ -72,4 +70,8 @@ public class DataMotionServiceImpl implements DataMotionService { } throw new CloudRuntimeException("can't find strategy to move data"); } + + public void setStrategies(List strategies) { + this.strategies = strategies; + } } 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 96c35f36f34..22eb01063e9 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 @@ -40,16 +40,14 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreState import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; 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.TemplateEvent; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService; -import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.framework.async.AsyncRpcConext; +import org.apache.cloudstack.framework.async.AsyncRpcContext; import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.datastore.DataObjectManager; @@ -84,7 +82,6 @@ import com.cloud.template.TemplateManager; import com.cloud.user.AccountManager; import com.cloud.user.ResourceLimitService; import com.cloud.utils.UriUtils; -import com.cloud.utils.fsm.NoTransitionException; @Component public class TemplateServiceImpl implements TemplateService { @@ -122,7 +119,7 @@ public class TemplateServiceImpl implements TemplateService { @Inject TemplateManager _tmpltMgr; - class TemplateOpContext extends AsyncRpcConext { + class TemplateOpContext extends AsyncRpcContext { final TemplateObject template; final AsyncCallFuture future; @@ -166,7 +163,7 @@ public class TemplateServiceImpl implements TemplateService { AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().createTemplateCallback(null, null)).setContext(context); - store.getDriver().createAsync(templateOnStore, caller); + store.getDriver().createAsync(store, templateOnStore, caller); } @Override @@ -511,7 +508,7 @@ public class TemplateServiceImpl implements TemplateService { TemplateOpContext context = new TemplateOpContext(null, to, future); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().deleteTemplateCallback(null, null)).setContext(context); - to.getDataStore().getDriver().deleteAsync(to, caller); + to.getDataStore().getDriver().deleteAsync(to.getDataStore(), to, caller); return future; } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java index 6d8e8e59c6f..438ab69c399 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java @@ -145,7 +145,7 @@ public class ImageStoreImpl implements ImageStoreEntity { @Override public boolean delete(DataObject obj) { AsyncCallFuture future = new AsyncCallFuture(); - this.driver.deleteAsync(obj, future); + this.driver.deleteAsync(obj.getDataStore(), obj, future); try { future.get(); } catch (InterruptedException e) { diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java index 40d9d418938..90696cae806 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java @@ -148,7 +148,8 @@ public class StorageAllocatorTest { diskOffering = diskOfferingDao.persist(diskOffering); diskOfferingId = diskOffering.getId(); - volume = new VolumeVO(Volume.Type.ROOT, "volume", dcId, 1, 1, diskOffering.getId(), diskOffering.getDiskSize()); + volume = new VolumeVO(Volume.Type.ROOT, "volume", dcId, 1, 1, diskOffering.getId(), diskOffering.getDiskSize(), + diskOffering.getMinIops(), diskOffering.getMaxIops(), ""); volume = volumeDao.persist(volume); volumeId = volume.getId(); } 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 2579a38157d..f1eed3a4b62 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 @@ -347,7 +347,7 @@ public class SnapshotTest extends CloudStackTestNGBase { private VolumeVO createVolume(Long templateId, long dataStoreId) { - VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000); + VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000, 0L, 0L, ""); volume.setDataCenterId(this.dcId); volume.setPoolId(dataStoreId); volume = volumeDao.persist(volume); 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 70fdb1b5829..cbfafc93333 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 @@ -317,7 +317,7 @@ public class VolumeTest extends CloudStackTestNGBase { } private VolumeVO createVolume(Long templateId, long dataStoreId) { - VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000); + VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000, 0L, 0L, ""); ; volume.setPoolId(dataStoreId); volume = volumeDao.persist(volume); 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 4acc8dc7de8..be9dd19c6b0 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 @@ -317,7 +317,7 @@ public class VolumeTestVmware extends CloudStackTestNGBase { } private VolumeVO createVolume(Long templateId, long dataStoreId) { - VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000); + VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000, 0L, 0L, ""); ; volume.setPoolId(dataStoreId); volume = volumeDao.persist(volume); 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 42b0463c71b..08de7f3a941 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 @@ -363,7 +363,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { } private VolumeVO createVolume(Long templateId, long dataStoreId) { - VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000); + VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000, 0L, 0L, ""); volume.setPoolId(dataStoreId); volume = volumeDao.persist(volume); return volume; diff --git a/engine/storage/integration-test/test/resource/component.xml b/engine/storage/integration-test/test/resource/component.xml index 5ba87e8ebe9..d7fe9030e80 100644 --- a/engine/storage/integration-test/test/resource/component.xml +++ b/engine/storage/integration-test/test/resource/component.xml @@ -125,11 +125,6 @@ - - - - - @@ -188,10 +183,6 @@ - - - - diff --git a/engine/storage/integration-test/test/resource/storageContext.xml b/engine/storage/integration-test/test/resource/storageContext.xml index 9f4f102edec..f9c891a036f 100644 --- a/engine/storage/integration-test/test/resource/storageContext.xml +++ b/engine/storage/integration-test/test/resource/storageContext.xml @@ -81,7 +81,8 @@ - + + 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 631d220f69d..3d7d4f26aa6 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 @@ -33,7 +33,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreState import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.framework.async.AsyncRpcConext; +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.storage.datastore.ObjectInDataStoreManager; @@ -79,7 +79,7 @@ public class SnapshotServiceImpl implements SnapshotService { @Inject VMSnapshotDao _vmSnapshotDao; - static private class CreateSnapshotContext extends AsyncRpcConext { + static private class CreateSnapshotContext extends AsyncRpcContext { final SnapshotInfo snapshot; final AsyncCallFuture future; @@ -91,7 +91,7 @@ public class SnapshotServiceImpl implements SnapshotService { } } - static private class DeleteSnapshotContext extends AsyncRpcConext { + static private class DeleteSnapshotContext extends AsyncRpcContext { final SnapshotInfo snapshot; final AsyncCallFuture future; @@ -104,7 +104,7 @@ public class SnapshotServiceImpl implements SnapshotService { } - static private class CopySnapshotContext extends AsyncRpcConext { + static private class CopySnapshotContext extends AsyncRpcContext { final SnapshotInfo srcSnapshot; final SnapshotInfo destSnapshot; final AsyncCallFuture future; @@ -355,7 +355,7 @@ public class SnapshotServiceImpl implements SnapshotService { AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().deleteSnapshotCallback(null, null)).setContext(context); DataStore store = snapInfo.getDataStore(); - store.getDriver().deleteAsync(snapInfo, caller); + store.getDriver().deleteAsync(store, snapInfo, caller); SnapshotResult result = null; try { 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 e916a5c7971..30830b66ad1 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java @@ -49,7 +49,9 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator { Volume volume = _volumeDao.findById(dskCh.getVolumeId()); List requestVolumes = new ArrayList(); requestVolumes.add(volume); - return storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool); + + return storageMgr.storagePoolHasEnoughIops(requestVolumes, pool) && + storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool); } @Override @@ -57,18 +59,27 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator { DeploymentPlan plan, ExcludeList avoid, int returnUpTo) { s_logger.debug("ZoneWideStoragePoolAllocator to find storage pool"); List suitablePools = new ArrayList(); - HypervisorType hypervisor = dskCh.getHypervisorType(); - if (hypervisor != null) { - if (hypervisor != HypervisorType.KVM && hypervisor != HypervisorType.VMware) { - s_logger.debug("Only kvm, VMware hypervisors are enabled to support zone wide storage"); - return suitablePools; + + List storagePools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags()); + + if (storagePools == null) { + storagePools = new ArrayList(); + } + + List anyHypervisorStoragePools = new ArrayList(); + + for (StoragePoolVO storagePool : storagePools) { + if (HypervisorType.Any.equals(storagePool.getHypervisor())) { + anyHypervisorStoragePools.add(storagePool); } } - List storagePools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags()); List storagePoolsByHypervisor = _storagePoolDao.findZoneWideStoragePoolsByHypervisor(plan.getDataCenterId(), dskCh.getHypervisorType()); + storagePools.retainAll(storagePoolsByHypervisor); + storagePools.addAll(anyHypervisorStoragePools); + // add remaining pools in zone, that did not match tags, to avoid set List allPools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), null); allPools.removeAll(storagePools); diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java index fa9f9935bcf..db69c649622 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java @@ -30,7 +30,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreState import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.framework.async.AsyncRpcConext; +import org.apache.cloudstack.framework.async.AsyncRpcContext; import org.apache.cloudstack.storage.command.CommandResult; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -78,7 +78,7 @@ public class DataObjectManagerImpl implements DataObjectManager { return objectInDataStoreMgr.get(dataObj, dataStore); } - class CreateContext extends AsyncRpcConext { + class CreateContext extends AsyncRpcContext { final DataObject objInStrore; public CreateContext(AsyncCompletionCallback callback, DataObject objInStore) { @@ -162,7 +162,7 @@ public class DataObjectManagerImpl implements DataObjectManager { AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().createAsynCallback(null, null)).setContext(context); - store.getDriver().createAsync(objInStore, caller); + store.getDriver().createAsync(store, objInStore, caller); return; } @@ -205,7 +205,7 @@ public class DataObjectManagerImpl implements DataObjectManager { return null; } - class CopyContext extends AsyncRpcConext { + class CopyContext extends AsyncRpcContext { DataObject destObj; DataObject srcObj; @@ -293,7 +293,7 @@ public class DataObjectManagerImpl implements DataObjectManager { return null; } - class DeleteContext extends AsyncRpcConext { + class DeleteContext extends AsyncRpcContext { private final DataObject obj; public DeleteContext(AsyncCompletionCallback callback, DataObject obj) { @@ -321,7 +321,7 @@ public class DataObjectManagerImpl implements DataObjectManager { AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().deleteAsynCallback(null, null)).setContext(context); - data.getDataStore().getDriver().deleteAsync(data, caller); + data.getDataStore().getDriver().deleteAsync(data.getDataStore(), data, caller); return; } 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 b92f92f655e..71df262dc85 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java @@ -18,11 +18,9 @@ */ package org.apache.cloudstack.storage.datastore; -import java.util.List; -import java.util.Map; - -import javax.inject.Inject; - +import com.cloud.storage.DataStoreRole; +import com.cloud.utils.exception.CloudRuntimeException; +import edu.emory.mathcs.backport.java.util.Collections; 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.Scope; @@ -30,22 +28,20 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.storage.image.datastore.ImageStoreProviderManager; import org.springframework.stereotype.Component; -import com.cloud.storage.DataStoreRole; -import com.cloud.utils.exception.CloudRuntimeException; - -import edu.emory.mathcs.backport.java.util.Collections; +import javax.inject.Inject; +import java.util.List; @Component public class DataStoreManagerImpl implements DataStoreManager { @Inject - PrimaryDataStoreProviderManager primaryStorMgr; + PrimaryDataStoreProviderManager primaryStoreMgr; @Inject ImageStoreProviderManager imageDataStoreMgr; @Override public DataStore getDataStore(long storeId, DataStoreRole role) { if (role == DataStoreRole.Primary) { - return primaryStorMgr.getPrimaryDataStore(storeId); + return primaryStoreMgr.getPrimaryDataStore(storeId); } else if (role == DataStoreRole.Image) { return imageDataStoreMgr.getImageStore(storeId); } else if (role == DataStoreRole.ImageCache) { @@ -57,7 +53,7 @@ public class DataStoreManagerImpl implements DataStoreManager { @Override public DataStore getDataStore(String uuid, DataStoreRole role) { if (role == DataStoreRole.Primary) { - return primaryStorMgr.getPrimaryDataStore(uuid); + return primaryStoreMgr.getPrimaryDataStore(uuid); } else if (role == DataStoreRole.Image) { return imageDataStoreMgr.getImageStore(uuid); } @@ -81,7 +77,7 @@ public class DataStoreManagerImpl implements DataStoreManager { @Override public DataStore getPrimaryDataStore(long storeId) { - return primaryStorMgr.getPrimaryDataStore(storeId); + return primaryStoreMgr.getPrimaryDataStore(storeId); } @Override @@ -94,4 +90,11 @@ public class DataStoreManagerImpl implements DataStoreManager { return imageDataStoreMgr.listImageStores(); } + public void setPrimaryStoreMgr(PrimaryDataStoreProviderManager primaryStoreMgr) { + this.primaryStoreMgr = primaryStoreMgr; + } + + public void setImageDataStoreMgr(ImageStoreProviderManager imageDataStoreMgr) { + this.imageDataStoreMgr = imageDataStoreMgr; + } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java index e861910116a..0aebee22c11 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java @@ -175,6 +175,12 @@ public class PrimaryDataStoreEntityImpl implements StorageEntity { return 0; } + @Override + public Long getCapacityIops() { + // TODO Auto-generated method stub + return 0L; + } + @Override public Long getClusterId() { // TODO Auto-generated method stub diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java index 50238a89a70..92b4e7a5479 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java @@ -18,15 +18,8 @@ */ package org.apache.cloudstack.storage.datastore.provider; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.inject.Inject; -import javax.naming.ConfigurationException; - +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.component.ManagerBase; import org.apache.cloudstack.api.response.StorageProviderResponse; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider.DataStoreProviderType; @@ -38,8 +31,13 @@ import org.apache.cloudstack.storage.image.datastore.ImageStoreProviderManager; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.utils.component.ManagerBase; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; @Component public class DataStoreProviderManagerImpl extends ManagerBase implements DataStoreProviderManager { @@ -50,7 +48,7 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto @Inject PrimaryDataStoreProviderManager primaryDataStoreProviderMgr; @Inject - ImageStoreProviderManager imageDataStoreProviderMgr; + ImageStoreProviderManager imageStoreProviderMgr; @Override public DataStoreProvider getDataStoreProvider(String name) { @@ -125,7 +123,7 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto (PrimaryDataStoreDriver) provider.getDataStoreDriver()); primaryDataStoreProviderMgr.registerHostListener(provider.getName(), provider.getHostListener()); } else if (types.contains(DataStoreProviderType.IMAGE)) { - imageDataStoreProviderMgr.registerDriver(provider.getName(), + imageStoreProviderMgr.registerDriver(provider.getName(), (ImageStoreDriver) provider.getDataStoreDriver()); } } catch (Exception e) { @@ -168,4 +166,16 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto throw new InvalidParameterValueException("Invalid parameter: " + type); } } + + public void setProviders(List providers) { + this.providers = providers; + } + + public void setPrimaryDataStoreProviderMgr(PrimaryDataStoreProviderManager primaryDataStoreProviderMgr) { + this.primaryDataStoreProviderMgr = primaryDataStoreProviderMgr; + } + + public void setImageStoreProviderMgr(ImageStoreProviderManager imageDataStoreProviderMgr) { + this.imageStoreProviderMgr = imageDataStoreProviderMgr; + } } 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 93b0c2b373d..86462472743 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java @@ -18,28 +18,6 @@ */ package org.apache.cloudstack.storage.image; -import java.util.Date; -import java.util.Set; -import javax.inject.Inject; - -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.AsyncRpcConext; -import org.apache.cloudstack.storage.command.CommandResult; -import org.apache.cloudstack.storage.command.DeleteCommand; -import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; -import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO; -import org.apache.cloudstack.storage.image.ImageStoreDriver; -import org.apache.log4j.Logger; - import com.cloud.agent.api.Answer; import com.cloud.agent.api.storage.DownloadAnswer; import com.cloud.agent.api.to.DataObjectType; @@ -50,11 +28,30 @@ import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.download.DownloadMonitor; +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; +import org.apache.cloudstack.storage.command.CommandResult; +import org.apache.cloudstack.storage.command.DeleteCommand; +import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; +import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO; +import org.apache.log4j.Logger; + +import javax.inject.Inject; +import java.util.Date; public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { private static final Logger s_logger = Logger.getLogger(BaseImageStoreDriverImpl.class); @Inject - VMTemplateDao templateDao; + VMTemplateDao _templateDao; @Inject DownloadMonitor _downloadMonitor; @Inject @@ -71,7 +68,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { return null; } - class CreateContext extends AsyncRpcConext { + protected class CreateContext extends AsyncRpcContext { final DataObject data; public CreateContext(AsyncCompletionCallback callback, DataObject data) { @@ -81,7 +78,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { } @Override - public void createAsync(DataObject data, AsyncCompletionCallback callback) { + public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback callback) { CreateContext context = new CreateContext(callback, data); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher .create(this); @@ -95,7 +92,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { } } - protected Void createTemplateAsyncCallback(AsyncCallbackDispatcher callback, + protected Void createTemplateAsyncCallback(AsyncCallbackDispatcher callback, CreateContext context) { DownloadAnswer answer = callback.getResult(); DataObject obj = context.data; @@ -115,9 +112,9 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { updateBuilder.setPhysicalSize(answer.getTemplatePhySicalSize()); _templateStoreDao.update(tmpltStoreVO.getId(), updateBuilder); // update size in vm_template table - VMTemplateVO tmlptUpdater = templateDao.createForUpdate(); + VMTemplateVO tmlptUpdater = _templateDao.createForUpdate(); tmlptUpdater.setSize(answer.getTemplateSize()); - templateDao.update(obj.getId(), tmlptUpdater); + _templateDao.update(obj.getId(), tmlptUpdater); } AsyncCompletionCallback caller = context.getParentCallback(); @@ -131,9 +128,9 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { caller.complete(result); } else if (answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { if (answer.getCheckSum() != null) { - VMTemplateVO templateDaoBuilder = templateDao.createForUpdate(); + VMTemplateVO templateDaoBuilder = _templateDao.createForUpdate(); templateDaoBuilder.setChecksum(answer.getCheckSum()); - templateDao.update(obj.getId(), templateDaoBuilder); + _templateDao.update(obj.getId(), templateDaoBuilder); } CreateCmdResult result = new CreateCmdResult(null, null); @@ -142,7 +139,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { return null; } - protected Void createVolumeAsyncCallback(AsyncCallbackDispatcher callback, + protected Void createVolumeAsyncCallback(AsyncCallbackDispatcher callback, CreateContext context) { DownloadAnswer answer = callback.getResult(); DataObject obj = context.data; @@ -184,7 +181,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { } @Override - public void deleteAsync(DataObject data, AsyncCompletionCallback callback) { + public void deleteAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback callback) { DeleteCommand cmd = new DeleteCommand(data.getTO()); CommandResult result = new CommandResult(); 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 6815dec4d99..53ead0b99f5 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 @@ -79,6 +79,11 @@ public class PrimaryDataStoreHelper { dataStoreVO.setClusterId(params.getClusterId()); dataStoreVO.setStatus(StoragePoolStatus.Initialized); dataStoreVO.setUserInfo(params.getUserInfo()); + dataStoreVO.setManaged(params.isManaged()); + dataStoreVO.setCapacityIops(params.getCapacityIops()); + dataStoreVO.setCapacityBytes(params.getCapacityBytes()); + dataStoreVO.setUsedBytes(params.getUsedBytes()); + dataStoreVO.setHypervisor(params.getHypervisorType()); Map details = params.getDetails(); String tags = params.getTags(); 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 cfdb5c0821d..420fd2922f4 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 @@ -287,6 +287,11 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore { return this.pdsv.getUsedBytes(); } + @Override + public Long getCapacityIops() { + return this.pdsv.getCapacityIops(); + } + @Override public Long getClusterId() { return this.pdsv.getClusterId(); 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 071c110da48..55fc3a64c53 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 @@ -107,6 +107,11 @@ public class VolumeObject implements VolumeInfo { volumeVO.setUuid(uuid); } + @Override + public String get_iScsiName() { + return volumeVO.get_iScsiName(); + } + public void setSize(Long size) { volumeVO.setSize(size); } @@ -126,6 +131,16 @@ public class VolumeObject implements VolumeInfo { return volumeVO.getSize(); } + @Override + public Long getMinIops() { + return volumeVO.getMinIops(); + } + + @Override + public Long getMaxIops() { + return volumeVO.getMaxIops(); + } + public long getVolumeId() { return volumeVO.getId(); } 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 3f6c4be75ce..58e0134ca28 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 @@ -36,16 +36,20 @@ 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.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; +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.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.framework.async.AsyncRpcConext; +import org.apache.cloudstack.framework.async.AsyncRpcContext; import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.datastore.DataObjectManager; @@ -69,10 +73,12 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.host.Host; import com.cloud.storage.DataStoreRole; import com.cloud.storage.StoragePool; +import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VMTemplatePoolDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.storage.template.TemplateProp; @@ -80,6 +86,7 @@ import com.cloud.user.AccountManager; import com.cloud.user.ResourceLimitService; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.DB; +import com.cloud.utils.exception.CloudRuntimeException; @Component public class VolumeServiceImpl implements VolumeService { @@ -109,6 +116,8 @@ public class VolumeServiceImpl implements VolumeService { @Inject VolumeDataStoreDao _volumeStoreDao; @Inject + VMTemplatePoolDao _tmpltPoolDao; + @Inject VolumeDao _volumeDao; @Inject EndPointSelector _epSelector; @@ -116,7 +125,7 @@ public class VolumeServiceImpl implements VolumeService { public VolumeServiceImpl() { } - private class CreateVolumeContext extends AsyncRpcConext { + private class CreateVolumeContext extends AsyncRpcContext { private final DataObject volume; private final AsyncCallFuture future; @@ -139,6 +148,16 @@ public class VolumeServiceImpl implements VolumeService { } + public ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore) { + DataStoreDriver dataStoreDriver = dataStore.getDriver(); + + if (dataStoreDriver instanceof PrimaryDataStoreDriver) { + return ((PrimaryDataStoreDriver)dataStoreDriver).getChapInfo(volumeInfo); + } + + return null; + } + @Override public AsyncCallFuture createVolumeAsync(VolumeInfo volume, DataStore dataStore) { AsyncCallFuture future = new AsyncCallFuture(); @@ -150,7 +169,7 @@ public class VolumeServiceImpl implements VolumeService { AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().createVolumeCallback(null, null)).setContext(context); - dataStore.getDriver().createAsync(volumeOnStore, caller); + dataStore.getDriver().createAsync(dataStore, volumeOnStore, caller); return future; } @@ -173,7 +192,7 @@ public class VolumeServiceImpl implements VolumeService { return null; } - private class DeleteVolumeContext extends AsyncRpcConext { + private class DeleteVolumeContext extends AsyncRpcContext { private final VolumeObject volume; private final AsyncCallFuture future; /** @@ -235,7 +254,7 @@ public class VolumeServiceImpl implements VolumeService { AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().deleteVolumeCallback(null, null)).setContext(context); - volume.getDataStore().getDriver().deleteAsync(volume, caller); + volume.getDataStore().getDriver().deleteAsync(volume.getDataStore(), volume, caller); return future; } @@ -266,22 +285,24 @@ public class VolumeServiceImpl implements VolumeService { return null; } - class CreateBaseImageContext extends AsyncRpcConext { + class CreateBaseImageContext extends AsyncRpcContext { private final VolumeInfo volume; private final PrimaryDataStore dataStore; private final TemplateInfo srcTemplate; private final AsyncCallFuture future; final DataObject destObj; + long templatePoolId; public CreateBaseImageContext(AsyncCompletionCallback callback, VolumeInfo volume, PrimaryDataStore datastore, TemplateInfo srcTemplate, AsyncCallFuture future, - DataObject destObj) { + DataObject destObj, long templatePoolId) { super(callback); this.volume = volume; this.dataStore = datastore; this.future = future; this.srcTemplate = srcTemplate; this.destObj = destObj; + this.templatePoolId = templatePoolId; } public VolumeInfo getVolume() { @@ -300,6 +321,11 @@ public class VolumeServiceImpl implements VolumeService { return this.future; } + public long getTemplatePoolId() { + return templatePoolId; + } + + } private TemplateInfo waitForTemplateDownloaded(PrimaryDataStore store, TemplateInfo template) { @@ -327,44 +353,51 @@ public class VolumeServiceImpl implements VolumeService { AsyncCallFuture future) { DataObject templateOnPrimaryStoreObj = dataStore.create(template); + + VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(dataStore.getId(), template.getId()); + if (templatePoolRef == null) { + throw new CloudRuntimeException("Failed to find template " + template.getUniqueName() + + " in VMTemplateStoragePool"); + } + long templatePoolRefId = templatePoolRef.getId(); CreateBaseImageContext context = new CreateBaseImageContext(null, volume, - dataStore, template, future, templateOnPrimaryStoreObj); + dataStore, template, future, templateOnPrimaryStoreObj, templatePoolRefId); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().copyBaseImageCallback(null, null)).setContext(context); - try { - templateOnPrimaryStoreObj.processEvent(Event.CreateOnlyRequested); - } catch (Exception e) { - s_logger.info("Multiple threads are trying to copy template to primary storage, current thread should just wait"); - try { - templateOnPrimaryStoreObj = waitForTemplateDownloaded(dataStore, template); - } catch (Exception e1) { - s_logger.debug("wait for template:" + template.getId() + " downloading finished, but failed"); - VolumeApiResult result = new VolumeApiResult(volume); - result.setResult(e1.toString()); - future.complete(result); - return; - } - if (templateOnPrimaryStoreObj == null) { - VolumeApiResult result = new VolumeApiResult(volume); - result.setResult("wait for template:" + template.getId() + " downloading finished, but failed"); - future.complete(result); - return; - } else { - s_logger.debug("waiting for template:" + template.getId() + " downloading finished, success"); + int storagePoolMaxWaitSeconds = NumbersUtil.parseInt( + configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600); + templatePoolRef = _tmpltPoolDao.acquireInLockTable(templatePoolRefId, storagePoolMaxWaitSeconds); + if (templatePoolRef == null) { + templatePoolRef = _tmpltPoolDao.findByPoolTemplate(dataStore.getId(), template.getId()); + if (templatePoolRef.getState() == ObjectInDataStoreStateMachine.State.Ready ) { + s_logger.info("Unable to acquire lock on VMTemplateStoragePool " + templatePoolRefId + ", But Template " + template.getUniqueName() + " is already copied to primary storage, skip copying"); createVolumeFromBaseImageAsync(volume, templateOnPrimaryStoreObj, dataStore, future); return; } + throw new CloudRuntimeException("Unable to acquire lock on VMTemplateStoragePool: " + templatePoolRefId); } try { + // lock acquired + if (templatePoolRef.getState() == ObjectInDataStoreStateMachine.State.Ready ) { + s_logger.info("Template " + template.getUniqueName() + " is already copied to primary storage, skip copying"); + createVolumeFromBaseImageAsync(volume, templateOnPrimaryStoreObj, dataStore, future); + return; + } + // remove the leftover hanging entry + dataStore.delete(templateOnPrimaryStoreObj); + // create a new entry to restart copying process + templateOnPrimaryStoreObj = dataStore.create(template); + templateOnPrimaryStoreObj.processEvent(Event.CreateOnlyRequested); motionSrv.copyAsync(template, templateOnPrimaryStoreObj, caller); - } catch (Exception e) { + } catch (Throwable e) { s_logger.debug("failed to create template on storage", e); templateOnPrimaryStoreObj.processEvent(Event.OperationFailed); VolumeApiResult result = new VolumeApiResult(volume); result.setResult(e.toString()); future.complete(result); + _tmpltPoolDao.releaseFromLockTable(templatePoolRefId); } return; } @@ -379,17 +412,19 @@ public class VolumeServiceImpl implements VolumeService { DataObject templateOnPrimaryStoreObj = context.destObj; if (!result.isSuccess()) { templateOnPrimaryStoreObj.processEvent(Event.OperationFailed); + _tmpltPoolDao.releaseFromLockTable(context.getTemplatePoolId()); res.setResult(result.getResult()); future.complete(res); return null; } templateOnPrimaryStoreObj.processEvent(Event.OperationSuccessed, result.getAnswer()); + _tmpltPoolDao.releaseFromLockTable(context.getTemplatePoolId()); createVolumeFromBaseImageAsync(context.volume, templateOnPrimaryStoreObj, context.dataStore, future); return null; } - private class CreateVolumeFromBaseImageContext extends AsyncRpcConext { + private class CreateVolumeFromBaseImageContext extends AsyncRpcContext { private final DataObject vo; private final AsyncCallFuture future; private final DataObject templateOnStore; @@ -544,7 +579,7 @@ public class VolumeServiceImpl implements VolumeService { return volDao.persist(newVol); } - private class CopyVolumeContext extends AsyncRpcConext { + private class CopyVolumeContext extends AsyncRpcContext { final VolumeInfo srcVolume; final VolumeInfo destVolume; final AsyncCallFuture future; @@ -748,7 +783,7 @@ public class VolumeServiceImpl implements VolumeService { return null; } - private class MigrateVolumeContext extends AsyncRpcConext { + private class MigrateVolumeContext extends AsyncRpcContext { final VolumeInfo srcVolume; final VolumeInfo destVolume; final AsyncCallFuture future; @@ -816,7 +851,7 @@ public class VolumeServiceImpl implements VolumeService { return null; } - private class MigrateVmWithVolumesContext extends AsyncRpcConext { + private class MigrateVmWithVolumesContext extends AsyncRpcContext { final Map volumeToPool; final AsyncCallFuture future; @@ -916,7 +951,7 @@ public class VolumeServiceImpl implements VolumeService { caller.setCallback(caller.getTarget().registerVolumeCallback(null, null)); caller.setContext(context); - store.getDriver().createAsync(volumeOnStore, caller); + store.getDriver().createAsync(store, volumeOnStore, caller); return future; } diff --git a/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncRpcConext.java b/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncRpcContext.java similarity index 91% rename from framework/ipc/src/org/apache/cloudstack/framework/async/AsyncRpcConext.java rename to framework/ipc/src/org/apache/cloudstack/framework/async/AsyncRpcContext.java index 102364c932c..cdb20546d40 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncRpcConext.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncRpcContext.java @@ -18,12 +18,12 @@ */ package org.apache.cloudstack.framework.async; -public class AsyncRpcConext { +public class AsyncRpcContext { protected final AsyncCompletionCallback parentCallBack; - public AsyncRpcConext(AsyncCompletionCallback callback) { + public AsyncRpcContext(AsyncCompletionCallback callback) { this.parentCallBack = callback; } - + public AsyncCompletionCallback getParentCallback() { return this.parentCallBack; } diff --git a/framework/ipc/test/org/apache/cloudstack/framework/codestyle/AsyncSampleEventDrivenStyleCaller.java b/framework/ipc/test/org/apache/cloudstack/framework/codestyle/AsyncSampleEventDrivenStyleCaller.java index db39588038a..d98ba654daf 100644 --- a/framework/ipc/test/org/apache/cloudstack/framework/codestyle/AsyncSampleEventDrivenStyleCaller.java +++ b/framework/ipc/test/org/apache/cloudstack/framework/codestyle/AsyncSampleEventDrivenStyleCaller.java @@ -24,7 +24,7 @@ import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCallbackDriver; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.framework.async.AsyncRpcConext; +import org.apache.cloudstack.framework.async.AsyncRpcContext; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -59,7 +59,7 @@ public class AsyncSampleEventDrivenStyleCaller { } } - private class TestContext extends AsyncRpcConext { + private class TestContext extends AsyncRpcContext { private boolean finished; private String result; /** diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index 1f112ddd686..f7eb629e265 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -299,6 +299,7 @@ cp -r awsapi/target/cloud-awsapi-%{_maventag}/* ${RPM_BUILD_ROOT}%{_datadir}/%{n install -D awsapi-setup/setup/cloud-setup-bridge ${RPM_BUILD_ROOT}%{_bindir}/cloudstack-setup-bridge install -D awsapi-setup/setup/cloudstack-aws-api-register ${RPM_BUILD_ROOT}%{_bindir}/cloudstack-aws-api-register cp -r awsapi-setup/db/mysql/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-bridge/setup +cp awsapi/resource/Axis2/axis2.xml ${RPM_BUILD_ROOT}%{_datadir}/%{name}-bridge/webapps/awsapi/WEB-INF/conf for name in applicationContext.xml cloud-bridge.properties commons-logging.properties crypto.properties xes.keystore ec2-service.properties ; do mv ${RPM_BUILD_ROOT}%{_datadir}/%{name}-bridge/webapps/awsapi/WEB-INF/classes/$name \ 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 d5cbe97d1d7..35c862ca4fb 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 @@ -57,6 +57,7 @@ import javax.ejb.Local; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; +import org.apache.commons.io.FileUtils; import org.libvirt.Connect; import org.libvirt.Domain; import org.libvirt.DomainBlockStats; @@ -230,7 +231,6 @@ import com.cloud.storage.template.Processor.FormatInfo; import com.cloud.storage.template.QCOW2Processor; import com.cloud.storage.template.TemplateLocation; import com.cloud.storage.template.TemplateProp; -import com.cloud.utils.FileUtil; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.PropertiesUtil; @@ -2575,7 +2575,7 @@ ServerResource { return new AttachVolumeAnswer(cmd, e.toString()); } - return new AttachVolumeAnswer(cmd, cmd.getDeviceId()); + return new AttachVolumeAnswer(cmd, cmd.getDeviceId(), cmd.getVolumePath()); } private Answer execute(ReadyCommand cmd) { @@ -4861,24 +4861,18 @@ ServerResource { } } - private Pair getNicStats(String nicName) { - double rx = 0.0; - String rxFile = "/sys/class/net/" + nicName + "/statistics/rx_bytes"; - String rxContent = FileUtil.readFileAsString(rxFile); - if (rxContent == null) { - s_logger.warn("Failed to read the rx_bytes for " + nicName + " from " + rxFile); + static Pair getNicStats(String nicName) { + return new Pair(readDouble(nicName, "rx_bytes"), readDouble(nicName, "tx_bytes")); } - rx = Double.parseDouble(rxContent); - double tx = 0.0; - String txFile = "/sys/class/net/" + nicName + "/statistics/tx_bytes"; - String txContent = FileUtil.readFileAsString(txFile); - if (txContent == null) { - s_logger.warn("Failed to read the tx_bytes for " + nicName + " from " + txFile); + static double readDouble(String nicName, String fileName) { + final String path = "/sys/class/net/" + nicName + "/statistics/" + fileName; + try { + return Double.parseDouble(FileUtils.readFileToString(new File(path))); + } catch (IOException ioe) { + s_logger.warn("Failed to read the " + fileName + " for " + nicName + " from " + path, ioe); + return 0.0; } - tx = Double.parseDouble(txContent); - - return new Pair(rx, tx); } private Answer execute(NetworkRulesSystemVmCommand cmd) { 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 8dce094f358..25c94f76c95 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 @@ -404,7 +404,7 @@ public class KVMStorageProcessor implements StorageProcessor { } @Override - public Answer backupSnasphot(CopyCommand cmd) { + public Answer backupSnapshot(CopyCommand cmd) { DataTO srcData = cmd.getSrcTO(); DataTO destData = cmd.getDestTO(); SnapshotObjectTO snapshot = (SnapshotObjectTO) srcData; 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 c82c31fc510..56d6536efd5 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 @@ -21,12 +21,17 @@ package com.cloud.hypervisor.kvm.resource; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.template.VirtualMachineTemplate.BootloaderType; +import com.cloud.utils.Pair; import com.cloud.vm.VirtualMachine; + +import org.apache.commons.lang.SystemUtils; +import org.junit.Assume; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; public class LibvirtComputingResourceTest { @@ -183,4 +188,13 @@ public class LibvirtComputingResourceTest { assertEquals(vmStr, vm.toString()); } + + @Test + public void testGetNicStats() { + //this test is only working on linux because of the loopback interface name + //also the tested code seems to work only on linux + Assume.assumeTrue(SystemUtils.IS_OS_LINUX); + Pair stats = LibvirtComputingResource.getNicStats("lo"); + assertNotNull(stats); + } } 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 8542de3bd9f..69efc83dbe1 100755 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java @@ -16,24 +16,6 @@ // under the License. package com.cloud.agent.manager; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.regex.PatternSyntaxException; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.CheckHealthCommand; @@ -45,7 +27,6 @@ import com.cloud.agent.api.HostStatsEntry; import com.cloud.agent.api.MaintainAnswer; import com.cloud.agent.api.PingTestCommand; import com.cloud.dc.dao.HostPodDao; -import com.cloud.host.Host; import com.cloud.resource.AgentResourceBase; import com.cloud.resource.AgentRoutingResource; import com.cloud.resource.AgentStorageResource; @@ -62,8 +43,24 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.regex.PatternSyntaxException; + @Component @Local(value = { MockAgentManager.class }) public class MockAgentManagerImpl extends ManagerBase implements MockAgentManager { @@ -195,9 +192,6 @@ public class MockAgentManagerImpl extends ManagerBase implements MockAgentManage random = SecureRandom.getInstance("SHA1PRNG"); _executor = new ThreadPoolExecutor(1, 5, 1, TimeUnit.DAYS, new LinkedBlockingQueue(), new NamedThreadFactory("Simulator-Agent-Mgr")); - // ComponentLocator locator = ComponentLocator.getCurrentLocator(); - // _simulatorMgr = (SimulatorManager) - // locator.getComponent(SimulatorManager.Name); } catch (NoSuchAlgorithmException e) { s_logger.debug("Failed to initialize random:" + e.toString()); return false; @@ -330,10 +324,6 @@ public class MockAgentManagerImpl extends ManagerBase implements MockAgentManage details.put("guid", this.guid); storageResource.configure("secondaryStorage", params); storageResource.start(); - // on the simulator the ssvm is as good as a direct - // agent - _resourceMgr.addHost(mockHost.getDataCenterId(), storageResource, Host.Type.SecondaryStorageVM, - details); _resources.put(this.guid, storageResource); } catch (ConfigurationException e) { s_logger.debug("Failed to load secondary storage resource: " + e.toString()); diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java index 21b81e1d7bb..c81f0797014 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java @@ -258,7 +258,7 @@ public class MockStorageManagerImpl extends ManagerBase implements MockStorageMa } txn.commit(); - return new AttachVolumeAnswer(cmd, cmd.getDeviceId()); + return new AttachVolumeAnswer(cmd, cmd.getDeviceId(), cmd.getVolumePath()); } catch (Exception ex) { txn.rollback(); throw new CloudRuntimeException("Error when attaching volume " + cmd.getVolumeName() + " to VM " @@ -476,7 +476,7 @@ public class MockStorageManagerImpl extends ManagerBase implements MockStorageMa } Transaction txn = Transaction.open(Transaction.SIMULATOR_DB); MockSecStorageVO storage = null; - String nfsUrl = ((NfsTO)cmd.getDataStore()).getUrl(); + String nfsUrl = ((NfsTO) store).getUrl(); try { txn.start(); storage = _mockSecStorageDao.findByUrl(nfsUrl); @@ -868,19 +868,16 @@ public class MockStorageManagerImpl extends ManagerBase implements MockStorageMa @Override public boolean configure(String name, Map params) throws ConfigurationException { - // TODO Auto-generated method stub return true; } @Override public boolean start() { - // TODO Auto-generated method stub return true; } @Override public boolean stop() { - // TODO Auto-generated method stub return true; } @@ -891,18 +888,13 @@ public class MockStorageManagerImpl extends ManagerBase implements MockStorageMa @Override public void preinstallTemplates(String url, long zoneId) { - Transaction txn = Transaction.open(Transaction.SIMULATOR_DB); MockSecStorageVO storage = null; try { - txn.start(); storage = _mockSecStorageDao.findByUrl(url); - txn.commit(); } catch (Exception ex) { - txn.rollback(); throw new CloudRuntimeException("Unable to find sec storage at " + url, ex); } finally { - txn.close(); - txn = Transaction.open(Transaction.CLOUD_DB); + Transaction txn = Transaction.open(Transaction.CLOUD_DB); txn.close(); } if (storage == null) { @@ -923,7 +915,7 @@ public class MockStorageManagerImpl extends ManagerBase implements MockStorageMa storage.setCapacity(DEFAULT_HOST_STORAGE_SIZE); storage.setMountPoint(dir); - txn = Transaction.open(Transaction.SIMULATOR_DB); + Transaction txn = Transaction.open(Transaction.SIMULATOR_DB); try { txn.start(); storage = _mockSecStorageDao.persist(storage); @@ -981,7 +973,6 @@ public class MockStorageManagerImpl extends ManagerBase implements MockStorageMa txn.close(); } } - } @Override diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java index 16ba367f844..d2be9cfbd5b 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java @@ -94,7 +94,7 @@ public class SimulatorStorageProcessor implements StorageProcessor { } @Override - public Answer backupSnasphot(CopyCommand cmd) { + public Answer backupSnapshot(CopyCommand cmd) { DataTO srcData = cmd.getSrcTO(); DataTO destData = cmd.getDestTO(); SnapshotObjectTO snapshot = (SnapshotObjectTO) srcData; 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 7250318f4c6..35a44596cb5 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManager.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManager.java @@ -17,7 +17,15 @@ // 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 com.cloud.utils.component.Manager; import com.cloud.utils.component.PluggableService; 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 e0aefcfa230..150e3dc19fd 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java @@ -32,12 +32,20 @@ import javax.naming.ConfigurationException; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; +import org.apache.cloudstack.api.AddUcsManagerCmd; import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.AssociateUcsProfileToBladeCmd; import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.ListUcsBladeCmd; +import org.apache.cloudstack.api.ListUcsManagerCmd; +import org.apache.cloudstack.api.ListUcsProfileCmd; import org.apache.cloudstack.api.ResponseGenerator; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.ClusterResponse; 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.cxf.helpers.FileUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AddUcsManagerCmd.java b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/AddUcsManagerCmd.java similarity index 96% rename from plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AddUcsManagerCmd.java rename to plugins/hypervisors/ucs/src/org/apache/cloudstack/api/AddUcsManagerCmd.java index 274cfbd9fad..e5ae0bd623c 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AddUcsManagerCmd.java +++ b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/AddUcsManagerCmd.java @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. // -package com.cloud.ucs.manager; +package org.apache.cloudstack.api; import javax.inject.Inject; @@ -26,6 +26,7 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.BaseCmd.CommandType; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.UcsManagerResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.log4j.Logger; @@ -35,6 +36,7 @@ import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.server.ManagementService; +import com.cloud.ucs.manager.UcsManager; import com.cloud.user.Account; @APICommand(name="addUcsManager", description="Adds a Ucs manager", responseObject=UcsManagerResponse.class) diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AssociateUcsProfileToBladeCmd.java b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/AssociateUcsProfileToBladeCmd.java similarity index 93% rename from plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AssociateUcsProfileToBladeCmd.java rename to plugins/hypervisors/ucs/src/org/apache/cloudstack/api/AssociateUcsProfileToBladeCmd.java index 0f95bb9bd25..c3178cddce7 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AssociateUcsProfileToBladeCmd.java +++ b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/AssociateUcsProfileToBladeCmd.java @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. // -package com.cloud.ucs.manager; +package org.apache.cloudstack.api; import javax.inject.Inject; @@ -25,6 +25,8 @@ 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.UcsBladeResponse; +import org.apache.cloudstack.api.response.UcsManagerResponse; import org.apache.log4j.Logger; import com.cloud.exception.ConcurrentOperationException; @@ -32,8 +34,9 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.ucs.manager.UcsManager; import com.cloud.user.Account; -@APICommand(name="associatesUscProfileToBlade", description="associate a profile to a blade", responseObject=UcsBladeResponse.class) +@APICommand(name="associatesUcsProfileToBlade", description="associate a profile to a blade", responseObject=UcsBladeResponse.class) public class AssociateUcsProfileToBladeCmd extends BaseCmd { public static final Logger s_logger = Logger.getLogger(AssociateUcsProfileToBladeCmd.class); diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsBladeCmd.java b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/ListUcsBladeCmd.java similarity index 94% rename from plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsBladeCmd.java rename to plugins/hypervisors/ucs/src/org/apache/cloudstack/api/ListUcsBladeCmd.java index 3c6587ed2b3..e42cf65a94b 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsBladeCmd.java +++ b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/ListUcsBladeCmd.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.ucs.manager; +package org.apache.cloudstack.api; import javax.inject.Inject; @@ -26,6 +26,8 @@ import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; 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 com.cloud.exception.ConcurrentOperationException; @@ -33,6 +35,7 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.ucs.manager.UcsManager; import com.cloud.user.Account; @APICommand(name="listUcsBlade", description="List ucs blades", responseObject=UcsBladeResponse.class) diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsManagerCmd.java b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/ListUcsManagerCmd.java similarity index 96% rename from plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsManagerCmd.java rename to plugins/hypervisors/ucs/src/org/apache/cloudstack/api/ListUcsManagerCmd.java index e705b177d64..e9b66449910 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsManagerCmd.java +++ b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/ListUcsManagerCmd.java @@ -23,7 +23,7 @@ // // Unless required by applicable law or agreed to in writing, // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -package com.cloud.ucs.manager; +package org.apache.cloudstack.api; import javax.inject.Inject; @@ -35,6 +35,7 @@ import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.UcsManagerResponse; import org.apache.log4j.Logger; import com.cloud.exception.ConcurrentOperationException; @@ -43,6 +44,7 @@ import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.server.ManagementService; +import com.cloud.ucs.manager.UcsManager; import com.cloud.user.Account; @APICommand(description="List ucs manager", responseObject=UcsManagerResponse.class) public class ListUcsManagerCmd extends BaseListCmd { diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsProfileCmd.java b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/ListUcsProfileCmd.java similarity index 94% rename from plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsProfileCmd.java rename to plugins/hypervisors/ucs/src/org/apache/cloudstack/api/ListUcsProfileCmd.java index 7bc4dec4094..56f3f5d3f88 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsProfileCmd.java +++ b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/ListUcsProfileCmd.java @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. // -package com.cloud.ucs.manager; +package org.apache.cloudstack.api; import javax.inject.Inject; @@ -28,6 +28,8 @@ import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.UcsManagerResponse; +import org.apache.cloudstack.api.response.UcsProfileResponse; import org.apache.log4j.Logger; import com.cloud.exception.ConcurrentOperationException; @@ -36,6 +38,7 @@ import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.server.ManagementService; +import com.cloud.ucs.manager.UcsManager; import com.cloud.user.Account; @APICommand(name="listUcsProfile", description="List profile in ucs manager", responseObject=UcsProfileResponse.class) public class ListUcsProfileCmd extends BaseListCmd { diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsBladeResponse.java b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/response/UcsBladeResponse.java similarity index 98% rename from plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsBladeResponse.java rename to plugins/hypervisors/ucs/src/org/apache/cloudstack/api/response/UcsBladeResponse.java index b06d62ac377..7416978ccd8 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsBladeResponse.java +++ b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/response/UcsBladeResponse.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.ucs.manager; +package org.apache.cloudstack.api.response; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerResponse.java b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/response/UcsManagerResponse.java similarity index 97% rename from plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerResponse.java rename to plugins/hypervisors/ucs/src/org/apache/cloudstack/api/response/UcsManagerResponse.java index e389a830139..87994a0b416 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerResponse.java +++ b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/response/UcsManagerResponse.java @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. // -package com.cloud.ucs.manager; +package org.apache.cloudstack.api.response; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.EntityReference; diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsProfileResponse.java b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/response/UcsProfileResponse.java similarity index 96% rename from plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsProfileResponse.java rename to plugins/hypervisors/ucs/src/org/apache/cloudstack/api/response/UcsProfileResponse.java index 14a22152633..f49e104214e 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsProfileResponse.java +++ b/plugins/hypervisors/ucs/src/org/apache/cloudstack/api/response/UcsProfileResponse.java @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. // -package com.cloud.ucs.manager; +package org.apache.cloudstack.api.response; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; 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 0606f388a80..25f69fdacf9 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 @@ -83,6 +83,7 @@ import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; import com.cloud.utils.Ternary; import com.cloud.utils.script.Script; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachine; import com.cloud.vm.snapshot.VMSnapshot; @@ -685,7 +686,10 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { String result; Script command; String templateVMDKName = ""; - String snapshotFullVMDKName = snapshotRoot + "/"; + //String snapshotFullVMDKName = snapshotRoot + "/"; + // the backedUpSnapshotUuid field currently has the format: uuid/uuid. so we need to extract the uuid out + String backupSSUuid = backedUpSnapshotUuid.substring(0, backedUpSnapshotUuid.indexOf('/')); + String snapshotFullVMDKName = snapshotRoot + "/" + backupSSUuid + "/"; synchronized(installPath.intern()) { command = new Script(false, "mkdir", _timeout, s_logger); @@ -740,12 +744,15 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { throw new Exception(msg); } - File snapshotdir = new File(snapshotRoot); + s_logger.info("vmdkfile parent dir: " + snapshotFullVMDKName); + File snapshotdir = new File(snapshotFullVMDKName); + // File snapshotdir = new File(snapshotRoot); File[] ssfiles = snapshotdir.listFiles(); // List filenames = new ArrayList(); for (int i = 0; i < ssfiles.length; i++) { String vmdkfile = ssfiles[i].getName(); - if(vmdkfile.toLowerCase().startsWith(backedUpSnapshotUuid) && vmdkfile.toLowerCase().endsWith(".vmdk")) { + s_logger.info("vmdk file name: " + vmdkfile); + if(vmdkfile.toLowerCase().startsWith(backupSSUuid) && vmdkfile.toLowerCase().endsWith(".vmdk")) { snapshotFullVMDKName += vmdkfile; templateVMDKName += vmdkfile; break; @@ -1082,6 +1089,9 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { private String getVolumePathInDatastore(DatastoreMO dsMo, String volumeFileName) throws Exception { String datastoreVolumePath = dsMo.searchFileInSubFolders(volumeFileName, true); assert (datastoreVolumePath != null) : "Virtual disk file missing from datastore."; + if (datastoreVolumePath == null) { + throw new CloudRuntimeException("Unable to find file " + volumeFileName + " in datastore " + dsMo.getName()); + } return datastoreVolumePath; } 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 0e5997e31d8..7c7e0b4a803 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 @@ -53,9 +53,20 @@ import com.vmware.vim25.ComputeResourceSummary; import com.vmware.vim25.DatastoreSummary; import com.vmware.vim25.DynamicProperty; import com.vmware.vim25.GuestInfo; +import com.vmware.vim25.GuestOsDescriptor; 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; +import com.vmware.vim25.HostInternetScsiHbaStaticTarget; +import com.vmware.vim25.HostInternetScsiTargetTransport; +import com.vmware.vim25.HostScsiDisk; +import com.vmware.vim25.HostScsiTopology; +import com.vmware.vim25.HostScsiTopologyInterface; +import com.vmware.vim25.HostScsiTopologyLun; +import com.vmware.vim25.HostScsiTopologyTarget; import com.vmware.vim25.ManagedObjectReference; import com.vmware.vim25.ObjectContent; import com.vmware.vim25.OptionValue; @@ -255,8 +266,10 @@ import com.cloud.hypervisor.vmware.mo.CustomFieldsManagerMO; import com.cloud.hypervisor.vmware.mo.DatacenterMO; import com.cloud.hypervisor.vmware.mo.DatastoreMO; import com.cloud.hypervisor.vmware.mo.DiskControllerType; +import com.cloud.hypervisor.vmware.mo.HostDatastoreSystemMO; import com.cloud.hypervisor.vmware.mo.HostFirewallSystemMO; import com.cloud.hypervisor.vmware.mo.HostMO; +import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO; import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper; import com.cloud.hypervisor.vmware.mo.NetworkDetails; import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType; @@ -592,7 +605,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa try { VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); - ManagedObjectReference morDc = hyperHost.getHyperHostDatacenter(); // find VM through datacenter (VM is not at the target host yet) VirtualMachineMO vmMo = hyperHost.findVmOnPeerHyperHost(vmName); if (vmMo == null) { @@ -2537,9 +2549,17 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(), vmSpec.getMinSpeed(),(int) (vmSpec.getMaxRam()/(1024*1024)), ramMb, translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs()).value(), vmSpec.getLimitCpuUse()); + String guestOsId = translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs()).value(); + boolean guestSupportsCpuHotAdd = false; + boolean guestSupportsMemoryHotAdd = false; + GuestOsDescriptor vmGuestOsDescriptor = vmMo.getGuestOsDescriptor(guestOsId); + if (vmGuestOsDescriptor != null) { + guestSupportsCpuHotAdd = vmGuestOsDescriptor.isSupportsCpuHotAdd(); + guestSupportsMemoryHotAdd = vmGuestOsDescriptor.isSupportsMemoryHotAdd(); + } - vmConfigSpec.setMemoryHotAddEnabled(true); - vmConfigSpec.setCpuHotAddEnabled(true); + vmConfigSpec.setMemoryHotAddEnabled(guestSupportsMemoryHotAdd); + vmConfigSpec.setCpuHotAddEnabled(guestSupportsCpuHotAdd); if ("true".equals(vmSpec.getDetails().get(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG))) { s_logger.debug("Nested Virtualization enabled in configuration, checking hypervisor capability"); @@ -3243,7 +3263,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa HashMap newStates = getVmStates(); List requestedVmNames = cmd.getVmNames(); - List vmNames = new ArrayList(); + List vmNames = new ArrayList(); if (requestedVmNames != null) { for (String vmName : requestedVmNames) { @@ -3749,8 +3769,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa s_logger.info("Executing resource MigrateVolumeCommand: " + _gson.toJson(cmd)); } - VmwareContext context = getServiceContext(); - VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); final String vmName = volMgr.getVmNameFromVolumeId(cmd.getVolumeId()); VirtualMachineMO vmMo = null; @@ -3902,6 +3920,45 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } + protected ManagedObjectReference handleDatastoreAndVmdk(AttachVolumeCommand cmd) throws Exception { + ManagedObjectReference morDs = null; + + VmwareContext context = getServiceContext(); + VmwareHypervisorHost hyperHost = getHyperHost(context); + + String iqn = cmd.get_iScsiName(); + + if (cmd.getAttach()) { + morDs = createVmfsDatastore(hyperHost, iqn, + cmd.getStorageHost(), cmd.getStoragePort(), iqn, + cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(), + cmd.getChapTargetUsername(), cmd.getChapTargetPassword()); + + DatastoreMO dsMo = new DatastoreMO(context, morDs); + + String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName()); + + if (!dsMo.fileExists(volumeDatastorePath)) { + String dummyVmName = getWorkerName(context, cmd, 0); + + VirtualMachineMO vmMo = prepareVolumeHostDummyVm(hyperHost, dsMo, dummyVmName); + + if (vmMo == null) { + throw new Exception("Unable to create a dummy VM for volume creation"); + } + + vmMo.createDisk(volumeDatastorePath, (int)(dsMo.getSummary().getFreeSpace() / (1024L * 1024L)), + morDs, vmMo.getScsiDeviceControllerKey()); + vmMo.detachDisk(volumeDatastorePath, false); + } + } + else { + deleteVmfsDatastore(hyperHost, iqn, cmd.getStorageHost(), cmd.getStoragePort(), iqn); + } + + return morDs; + } + protected Answer execute(AttachVolumeCommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource AttachVolumeCommand: " + _gson.toJson(cmd)); @@ -3921,7 +3978,15 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa throw new Exception(msg); } - ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid()); + ManagedObjectReference morDs = null; + + if (cmd.getAttach() && cmd.isManaged()) { + morDs = handleDatastoreAndVmdk(cmd); + } + else { + morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid()); + } + if (morDs == null) { String msg = "Unable to find the mounted datastore to execute AttachVolumeCommand, vmName: " + cmd.getVmName(); s_logger.error(msg); @@ -3931,13 +3996,19 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDs); String datastoreVolumePath = dsMo.searchFileInSubFolders(cmd.getVolumePath() + ".vmdk", true); assert (datastoreVolumePath != null) : "Virtual disk file must exist in specified datastore for attach/detach operations."; - - AttachVolumeAnswer answer = new AttachVolumeAnswer(cmd, cmd.getDeviceId()); + if (datastoreVolumePath == null) { + throw new CloudRuntimeException("Unable to find file " + cmd.getVolumePath() + ".vmdk in datastore " + dsMo.getName()); + } + AttachVolumeAnswer answer = new AttachVolumeAnswer(cmd, cmd.getDeviceId(), datastoreVolumePath); if (cmd.getAttach()) { vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs); } else { vmMo.removeAllSnapshots(); vmMo.detachDisk(datastoreVolumePath, false); + + if (cmd.isManaged()) { + handleDatastoreAndVmdk(cmd); + } } return answer; @@ -3953,6 +4024,200 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } + private ManagedObjectReference createVmfsDatastore(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(); + ClusterMO cluster = new ClusterMO(context, morCluster); + List> lstHosts = cluster.getClusterHosts(); + + HostInternetScsiHbaStaticTarget target = new HostInternetScsiHbaStaticTarget(); + + target.setAddress(storageIpAddress); + target.setPort(storagePortNumber); + target.setIScsiName(iqn); + + HostInternetScsiHbaAuthenticationProperties auth = new HostInternetScsiHbaAuthenticationProperties(); + + String strAuthType = "chapRequired"; + + auth.setChapAuthEnabled(true); + auth.setChapInherited(false); + auth.setChapAuthenticationType(strAuthType); + auth.setChapName(chapName); + auth.setChapSecret(chapSecret); + auth.setMutualChapInherited(false); + auth.setMutualChapAuthenticationType(strAuthType); + auth.setMutualChapName(mutualChapName); + auth.setMutualChapSecret(mutualChapSecret); + + target.setAuthenticationProperties(auth); + + final List lstTargets = new ArrayList(); + + lstTargets.add(target); + + HostDatastoreSystemMO hostDatastoreSystem = null; + HostStorageSystemMO hostStorageSystem = null; + + final List threads = new ArrayList(); + final List exceptions = new ArrayList(); + + for (Pair hostPair : lstHosts) { + HostMO host = new HostMO(context, hostPair.first()); + hostDatastoreSystem = host.getHostDatastoreSystemMO(); + hostStorageSystem = host.getHostStorageSystemMO(); + + boolean iScsiHbaConfigured = false; + + for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) { + if (hba instanceof HostInternetScsiHba) { + // just finding an instance of HostInternetScsiHba means that we have found at least one configured iSCSI HBA + // at least one iSCSI HBA must be configured before a CloudStack user can use this host for iSCSI storage + iScsiHbaConfigured = true; + + final String iScsiHbaDevice = hba.getDevice(); + + final HostStorageSystemMO hss = hostStorageSystem; + + threads.add(new Thread() { + @Override + public void run() { + try { + hss.addInternetScsiStaticTargets(iScsiHbaDevice, lstTargets); + + hss.rescanHba(iScsiHbaDevice); + } + catch (Exception ex) { + synchronized (exceptions) { + exceptions.add(ex); + } + } + } + }); + } + } + + if (!iScsiHbaConfigured) { + throw new Exception("An iSCSI HBA must be configured before a host can use iSCSI storage."); + } + } + + for (Thread thread : threads) { + thread.start(); + } + + for (Thread thread : threads) { + thread.join(); + } + + if (exceptions.size() > 0) { + throw new Exception(exceptions.get(0).getMessage()); + } + + ManagedObjectReference morDs = hostDatastoreSystem.findDatastore(iqn); + + if (morDs != null) { + return morDs; + } + + List lstHostScsiDisks = hostDatastoreSystem.queryAvailableDisksForVmfs(); + + HostScsiDisk hostScsiDisk = getHostScsiDisk(hostStorageSystem.getStorageDeviceInfo().getScsiTopology(), lstHostScsiDisks, iqn); + + if (hostScsiDisk == null) { + throw new Exception("A relevant SCSI disk could not be located to use to create a datastore."); + } + + return hostDatastoreSystem.createVmfsDatastore(datastoreName, hostScsiDisk); + } + + // the purpose of this method is to find the HostScsiDisk in the passed-in array that exists (if any) because + // we added the static iqn to an iSCSI HBA + private static HostScsiDisk getHostScsiDisk(HostScsiTopology hst, List lstHostScsiDisks, String iqn) { + for (HostScsiTopologyInterface adapter : hst.getAdapter()) { + if (adapter.getTarget() != null) { + for (HostScsiTopologyTarget target : adapter.getTarget()) { + if (target.getTransport() instanceof HostInternetScsiTargetTransport) { + String iScsiName = ((HostInternetScsiTargetTransport)target.getTransport()).getIScsiName(); + + if (iqn.equals(iScsiName)) { + for (HostScsiDisk hostScsiDisk : lstHostScsiDisks) { + for (HostScsiTopologyLun hstl : target.getLun()) { + if (hstl.getScsiLun().contains(hostScsiDisk.getUuid())) { + return hostScsiDisk; + } + } + } + } + } + } + } + } + + return null; + } + + private void deleteVmfsDatastore(VmwareHypervisorHost hyperHost, String volumeUuid, + String storageIpAddress, int storagePortNumber, String iqn) throws Exception { + // hyperHost.unmountDatastore(volumeUuid); + + VmwareContext context = getServiceContext(); + ManagedObjectReference morCluster = hyperHost.getHyperHostCluster(); + ClusterMO cluster = new ClusterMO(context, morCluster); + List> lstHosts = cluster.getClusterHosts(); + + HostInternetScsiHbaStaticTarget target = new HostInternetScsiHbaStaticTarget(); + + target.setAddress(storageIpAddress); + target.setPort(storagePortNumber); + target.setIScsiName(iqn); + + final List lstTargets = new ArrayList(); + + lstTargets.add(target); + + final List threads = new ArrayList(); + final List exceptions = new ArrayList(); + + for (Pair hostPair : lstHosts) { + final HostMO host = new HostMO(context, hostPair.first()); + final HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO(); + + for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) { + if (hba instanceof HostInternetScsiHba) { + final String iScsiHbaDevice = hba.getDevice(); + + Thread thread = new Thread() { + @Override + public void run() { + try { + hostStorageSystem.removeInternetScsiStaticTargets(iScsiHbaDevice, lstTargets); + + hostStorageSystem.rescanHba(iScsiHbaDevice); + } + catch (Exception ex) { + exceptions.add(ex); + } + } + }; + + threads.add(thread); + + thread.start(); + } + } + } + + for (Thread thread : threads) { + thread.join(); + } + + if (exceptions.size() > 0) { + throw new Exception(exceptions.get(0).getMessage()); + } + } + protected Answer execute(AttachIsoCommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource AttachIsoCommand: " + _gson.toJson(cmd)); 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 cc839984cd8..e45a854a1e4 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -647,7 +647,7 @@ public class VmwareStorageProcessor implements StorageProcessor { return backupUuid + "/" + backupUuid; } @Override - public Answer backupSnasphot(CopyCommand cmd) { + public Answer backupSnapshot(CopyCommand cmd) { SnapshotObjectTO srcSnapshot = (SnapshotObjectTO)cmd.getSrcTO(); PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)srcSnapshot.getDataStore(); SnapshotObjectTO destSnapshot = (SnapshotObjectTO)cmd.getDestTO(); diff --git a/plugins/hypervisors/vmware/test/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategyTest.java b/plugins/hypervisors/vmware/test/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategyTest.java index 3d2ad57711d..b3ea5d53269 100644 --- a/plugins/hypervisors/vmware/test/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategyTest.java +++ b/plugins/hypervisors/vmware/test/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategyTest.java @@ -37,7 +37,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.framework.async.AsyncRpcConext; +import org.apache.cloudstack.framework.async.AsyncRpcContext; import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.test.utils.SpringUtils; @@ -209,7 +209,7 @@ public class VmwareStorageMotionStrategyTest { assertFalse("Migration across cluster didn't fail.", this.result.isSuccess()); } - private class MockContext extends AsyncRpcConext { + private class MockContext extends AsyncRpcContext { final Map volumeToPool; final AsyncCallFuture future; /** 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 c947af69993..a079fe2dd0e 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 @@ -53,13 +53,6 @@ import javax.ejb.Local; import javax.naming.ConfigurationException; import javax.xml.parsers.DocumentBuilderFactory; -import com.cloud.agent.api.*; -import com.cloud.agent.api.to.*; -import com.cloud.network.rules.FirewallRule; - -import org.apache.cloudstack.storage.command.StorageSubSystemCommand; -import org.apache.cloudstack.storage.to.TemplateObjectTO; -import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.log4j.Logger; import org.apache.xmlrpc.XmlRpcException; import org.w3c.dom.Document; @@ -67,6 +60,45 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; +import com.trilead.ssh2.SCPClient; +import com.xensource.xenapi.Bond; +import com.xensource.xenapi.Connection; +import com.xensource.xenapi.Console; +import com.xensource.xenapi.Host; +import com.xensource.xenapi.HostCpu; +import com.xensource.xenapi.HostMetrics; +import com.xensource.xenapi.Network; +import com.xensource.xenapi.PBD; +import com.xensource.xenapi.PIF; +import com.xensource.xenapi.PIF.Record; +import com.xensource.xenapi.Pool; +import com.xensource.xenapi.SR; +import com.xensource.xenapi.Session; +import com.xensource.xenapi.Task; +import com.xensource.xenapi.Types; +import com.xensource.xenapi.Types.BadAsyncResult; +import com.xensource.xenapi.Types.BadServerResponse; +import com.xensource.xenapi.Types.ConsoleProtocol; +import com.xensource.xenapi.Types.IpConfigurationMode; +import com.xensource.xenapi.Types.OperationNotAllowed; +import com.xensource.xenapi.Types.SrFull; +import com.xensource.xenapi.Types.VbdType; +import com.xensource.xenapi.Types.VmBadPowerState; +import com.xensource.xenapi.Types.VmPowerState; +import com.xensource.xenapi.Types.XenAPIException; +import com.xensource.xenapi.VBD; +import com.xensource.xenapi.VBDMetrics; +import com.xensource.xenapi.VDI; +import com.xensource.xenapi.VIF; +import com.xensource.xenapi.VLAN; +import com.xensource.xenapi.VM; +import com.xensource.xenapi.VMGuestMetrics; +import com.xensource.xenapi.XenAPIObject; + +import org.apache.cloudstack.storage.command.StorageSubSystemCommand; +import org.apache.cloudstack.storage.to.TemplateObjectTO; +import org.apache.cloudstack.storage.to.VolumeObjectTO; + import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; import com.cloud.agent.api.AttachIsoCommand; @@ -208,8 +240,12 @@ import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.agent.api.storage.ResizeVolumeAnswer; import com.cloud.agent.api.storage.ResizeVolumeCommand; +import com.cloud.agent.api.to.DataStoreTO; +import com.cloud.agent.api.to.DataTO; +import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.FirewallRuleTO; import com.cloud.agent.api.to.IpAddressTO; +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; @@ -265,82 +301,6 @@ 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.trilead.ssh2.SCPClient; -import com.xensource.xenapi.Bond; -import com.xensource.xenapi.Connection; -import com.xensource.xenapi.Console; -import com.xensource.xenapi.Host; -import com.xensource.xenapi.HostCpu; -import com.xensource.xenapi.HostMetrics; -import com.xensource.xenapi.Network; -import com.xensource.xenapi.PBD; -import com.xensource.xenapi.PIF; -import com.xensource.xenapi.PIF.Record; -import com.xensource.xenapi.Pool; -import com.xensource.xenapi.SR; -import com.xensource.xenapi.Session; -import com.xensource.xenapi.Task; -import com.xensource.xenapi.Types; -import com.xensource.xenapi.Types.BadAsyncResult; -import com.xensource.xenapi.Types.BadServerResponse; -import com.xensource.xenapi.Types.ConsoleProtocol; -import com.xensource.xenapi.Types.IpConfigurationMode; -import com.xensource.xenapi.Types.OperationNotAllowed; -import com.xensource.xenapi.Types.SrFull; -import com.xensource.xenapi.Types.VbdType; -import com.xensource.xenapi.Types.VmBadPowerState; -import com.xensource.xenapi.Types.VmPowerState; -import com.xensource.xenapi.Types.XenAPIException; -import com.xensource.xenapi.VBD; -import com.xensource.xenapi.VBDMetrics; -import com.xensource.xenapi.VDI; -import com.xensource.xenapi.VIF; -import com.xensource.xenapi.VLAN; -import com.xensource.xenapi.VM; -import com.xensource.xenapi.VMGuestMetrics; -import com.xensource.xenapi.XenAPIObject; -import org.apache.cloudstack.storage.command.StorageSubSystemCommand; -import org.apache.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.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -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.lang.reflect.InvocationTargetException; -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.Collections; -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; /** * CitrixResourceBase encapsulates the calls to the XenServer Xapi process @@ -431,7 +391,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } public XsHost getHost() { - return this._host; + return _host; } protected boolean cleanupHaltedVms(Connection conn) throws XenAPIException, XmlRpcException { @@ -666,7 +626,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } else if (clazz == CheckS2SVpnConnectionsCommand.class) { return execute((CheckS2SVpnConnectionsCommand) cmd); } else if (cmd instanceof StorageSubSystemCommand) { - return this.storageHandler.handleStorageCommands((StorageSubSystemCommand)cmd); + return storageHandler.handleStorageCommands((StorageSubSystemCommand)cmd); } else if (clazz == CreateVMSnapshotCommand.class) { return execute((CreateVMSnapshotCommand)cmd); } else if (clazz == DeleteVMSnapshotCommand.class) { @@ -754,7 +714,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } for (VM vm : vms) { - VM.Record vmr = vm.getRecord(conn); + vm.getRecord(conn); try { scaleVM(conn, vm, vmSpec, host); } catch (Exception e) { @@ -938,6 +898,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe vifr.MAC = "FE:FF:FF:FF:FF:FF"; vifr.network = nw; + vifr.lockingMode = Types.VifLockingMode.NETWORK_DEFAULT; dom0vif = VIF.create(conn, vifr); } // At this stage we surely have a VIF @@ -965,12 +926,16 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe vswitchNw = networks.iterator().next(); } - enableXenServerNetwork(conn, vswitchNw, "vswitch", "vswicth network"); + enableXenServerNetwork(conn, vswitchNw, "vswitch", "vswitch network"); _host.vswitchNetwork = vswitchNw; } return _host.vswitchNetwork; - } catch (Exception e) { - e.printStackTrace(); + } catch (BadServerResponse e) { + s_logger.error("Failed to setup vswitch network", e); + } catch (XenAPIException e) { + s_logger.error("Failed to setup vswitch network", e); + } catch (XmlRpcException e) { + s_logger.error("Failed to setup vswitch network", e); } return null; @@ -1142,6 +1107,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe vifr.qosAlgorithmParams.put("kbps", Integer.toString(nic.getNetworkRateMbps() * 128)); } + vifr.lockingMode = Types.VifLockingMode.NETWORK_DEFAULT; VIF vif = VIF.create(conn, vifr); if (s_logger.isDebugEnabled()) { vifr = vif.getRecord(conn); @@ -3041,14 +3007,11 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe try { host_uuid = host.getUuid(conn); } catch (BadServerResponse e) { - // TODO Auto-generated catch block - e.printStackTrace(); + s_logger.error("Failed to get host uuid for host " + host.toWireString(), e); } catch (XenAPIException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + s_logger.error("Failed to get host uuid for host " + host.toWireString(), e); } catch (XmlRpcException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + s_logger.error("Failed to get host uuid for host " + host.toWireString(), e); } vmStates.put(record.nameLabel, new Pair(host_uuid, state)); } @@ -3139,27 +3102,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } - private String copy_vhd_to_secondarystorage(Connection conn, String mountpoint, String vdiuuid, String sruuid, int wait) { - String results = callHostPluginAsync(conn, "vmopspremium", "copy_vhd_to_secondarystorage", - wait, "mountpoint", mountpoint, "vdiuuid", vdiuuid, "sruuid", sruuid); - String errMsg = null; - if (results == null || results.isEmpty()) { - errMsg = "copy_vhd_to_secondarystorage return null"; - } else { - String[] tmp = results.split("#"); - String status = tmp[0]; - if (status.equals("0")) { - return tmp[1]; - } else { - errMsg = tmp[1]; - } - } - String source = vdiuuid + ".vhd"; - killCopyProcess(conn, source); - s_logger.warn(errMsg); - throw new CloudRuntimeException(errMsg); - } - String upgradeSnapshot(Connection conn, String templatePath, String snapshotPath) { String results = callHostPluginAsync(conn, "vmopspremium", "upgrade_snapshot", 2 * 60 * 60, "templatePath", templatePath, "snapshotPath", snapshotPath); @@ -3540,7 +3482,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe s_logger.warn("There are no Consoles available to the vm : " + record.nameDescription); return -1; } - Iterator i = consoles.iterator(); + consoles.iterator(); } catch (XenAPIException e) { String msg = "Unable to get vnc-port due to " + e.toString(); s_logger.warn(msg, e); @@ -3722,8 +3664,16 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe protected void waitForTask(Connection c, Task task, long pollInterval, long timeout) throws XenAPIException, XmlRpcException { long beginTime = System.currentTimeMillis(); + if (s_logger.isTraceEnabled()) { + s_logger.trace("Task " + task.getNameLabel(c) + " (" + task.getUuid(c) + ") sent to " + c.getSessionReference() + + " is pending completion with a " + timeout + "ms timeout"); + } while (task.getStatus(c) == Types.TaskStatusType.PENDING) { try { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Task " + task.getNameLabel(c) + " (" + task.getUuid(c) + ") is pending, sleeping for " + + pollInterval + "ms"); + } Thread.sleep(pollInterval); } catch (InterruptedException e) { } @@ -3738,6 +3688,9 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe protected void checkForSuccess(Connection c, Task task) throws XenAPIException, XmlRpcException { if (task.getStatus(c) == Types.TaskStatusType.SUCCESS) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Task " + task.getNameLabel(c) + " (" + task.getUuid(c) + ") completed"); + } return; } else { String msg = "Task failed! Task record: " + task.getRecord(c); @@ -4164,11 +4117,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe for (VIF vif : vifs) { networks.add(vif.getNetwork(conn)); } - List vdis = getVdis(conn, vm); vm.destroy(conn); - for( VDI vdi : vdis ){ - umount(conn, vdi); - } state = State.Stopped; SR sr = getISOSRbyVmName(conn, cmd.getVmName()); removeSR(conn, sr); @@ -4215,23 +4164,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return new StopAnswer(cmd, "Stop VM failed", false); } - private List getVdis(Connection conn, VM vm) { - List vdis = new ArrayList(); - try { - Set vbds =vm.getVBDs(conn); - for( VBD vbd : vbds ) { - vdis.add(vbd.getVDI(conn)); - } - } catch (XenAPIException e) { - String msg = "getVdis can not get VPD due to " + e.toString(); - s_logger.warn(msg, e); - } catch (XmlRpcException e) { - String msg = "getVdis can not get VPD due to " + e.getMessage(); - s_logger.warn(msg, e); - } - return vdis; - } - protected String connect(Connection conn, final String vmName, final String ipAddress, final int port) { for (int i = 0; i <= _retry; i++) { try { @@ -4247,7 +4179,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return msg; } if (s_logger.isDebugEnabled()) { - s_logger.debug("Trying to connect to " + ipAddress); + s_logger.debug("Trying to connect to " + ipAddress + " attempt " + i + " of " + _retry); } if (pingdomr(conn, ipAddress, Integer.toString(port))) { return null; @@ -4471,7 +4403,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe throw new CloudRuntimeException("Could not find available VIF slot in VM with name: " + vmName); } - protected VDI mount(Connection conn, StoragePoolType pooltype, String volumeFolder, String volumePath) { + protected VDI mount(Connection conn, StoragePoolType poolType, String volumeFolder, String volumePath) { return getVDIbyUuid(conn, volumePath); } @@ -5000,6 +4932,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe vifr.otherConfig = config; vifr.MAC = "FE:FF:FF:FF:FF:FF"; vifr.network = linkLocal; + vifr.lockingMode = Types.VifLockingMode.NETWORK_DEFAULT; dom0vif = VIF.create(conn, vifr); dom0vif.plug(conn); } else { @@ -5541,7 +5474,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe if (pool.getType() == StoragePoolType.NetworkFilesystem) { getNfsSR(conn, pool); } else if (pool.getType() == StoragePoolType.IscsiLUN) { - getIscsiSR(conn, pool); + getIscsiSR(conn, pool.getUuid(), pool.getHost(), pool.getPath(), null, null, new Boolean[1]); } else if (pool.getType() == StoragePoolType.PreSetup) { } else { return new Answer(cmd, false, "The pool type: " + pool.getType().name() + " is not supported."); @@ -5774,15 +5707,18 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } else { return new Answer(cmd, false, result); } - } catch (Exception e) { - e.printStackTrace(); + } catch (BadServerResponse e) { + s_logger.error("Failed to delete flow", e); + } catch (XenAPIException e) { + s_logger.error("Failed to delete flow", e); + } catch (XmlRpcException e) { + s_logger.error("Failed to delete flow", e); } return new Answer(cmd, false, "failed to delete flow for " + cmd.getVmName()); } private List> ovsFullSyncStates() { Connection conn = getConnection(); - try { String result = callHostPlugin(conn, "ovsgre", "ovs_get_vm_log", "host_uuid", _host.uuid); String [] logs = result != null ?result.split(";"): new String [0]; List> states = new ArrayList>(); @@ -5800,13 +5736,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe states.add(new Pair(info[0], -1L)); } } - return states; - } catch (Exception e) { - e.printStackTrace(); - } - - return null; } private OvsSetTagAndFlowAnswer execute(OvsSetTagAndFlowCommand cmd) { @@ -5831,8 +5761,12 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } else { return new OvsSetTagAndFlowAnswer(cmd, false, result); } - } catch (Exception e) { - e.printStackTrace(); + } catch (BadServerResponse e) { + s_logger.error("Failed to set tag and flow", e); + } catch (XenAPIException e) { + s_logger.error("Failed to set tag and flow", e); + } catch (XmlRpcException e) { + s_logger.error("Failed to set tag and flow", e); } return new OvsSetTagAndFlowAnswer(cmd, false, "EXCEPTION"); @@ -5845,18 +5779,24 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe s_logger.debug("Will look for network with name-label:" + label + " on host " + _host.ip); Connection conn = getConnection(); try { - XsLocalNetwork nw = this.getNetworkByName(conn, label); + XsLocalNetwork nw = getNetworkByName(conn, label); s_logger.debug("Network object:" + nw.getNetwork().getUuid(conn)); PIF pif = nw.getPif(conn); Record pifRec = pif.getRecord(conn); s_logger.debug("PIF object:" + pifRec.uuid + "(" + pifRec.device + ")"); return new OvsFetchInterfaceAnswer(cmd, true, "Interface " + pifRec.device + " retrieved successfully", pifRec.IP, pifRec.netmask, pifRec.MAC); - } catch (Exception e) { - e.printStackTrace(); + } catch (BadServerResponse e) { s_logger.error("An error occurred while fetching the interface for " + - label + " on host " + _host.ip + ":" + e.toString() + - "(" + e.getClass() + ")"); + label + " on host " + _host.ip , e); + return new OvsFetchInterfaceAnswer(cmd, false, "EXCEPTION:" + e.getMessage()); + } catch (XenAPIException e) { + s_logger.error("An error occurred while fetching the interface for " + + label + " on host " + _host.ip , e); + return new OvsFetchInterfaceAnswer(cmd, false, "EXCEPTION:" + e.getMessage()); + } catch (XmlRpcException e) { + s_logger.error("An error occurred while fetching the interface for " + + label + " on host " + _host.ip, e); return new OvsFetchInterfaceAnswer(cmd, false, "EXCEPTION:" + e.getMessage()); } } @@ -5881,12 +5821,15 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } else { return new OvsCreateGreTunnelAnswer(cmd, true, result, _host.ip, bridge, Integer.parseInt(res[1])); } - } catch (Exception e) { - e.printStackTrace(); + } catch (BadServerResponse e) { s_logger.error("An error occurred while creating a GRE tunnel to " + - cmd.getRemoteIp() + " on host " + _host.ip + ":" + e.getMessage() + - "(" + e.getClass() + ")"); - + cmd.getRemoteIp() + " on host " + _host.ip , e); + } catch (XenAPIException e) { + s_logger.error("An error occurred while creating a GRE tunnel to " + + cmd.getRemoteIp() + " on host " + _host.ip , e); + } catch (XmlRpcException e) { + s_logger.error("An error occurred while creating a GRE tunnel to " + + cmd.getRemoteIp() + " on host " + _host.ip , e); } return new OvsCreateGreTunnelAnswer(cmd, false, "EXCEPTION", _host.ip, bridge); @@ -6135,7 +6078,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe CheckXenHostInfo(); - this.storageHandler = getStorageHandler(); + storageHandler = getStorageHandler(); return true; } @@ -6221,7 +6164,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe public Answer execute(ResizeVolumeCommand cmd) { Connection conn = getConnection(); - StorageFilerTO pool = cmd.getPool(); String volid = cmd.getPath(); long newSize = cmd.getNewSize(); @@ -6359,19 +6301,18 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } - protected SR getIscsiSR(Connection conn, StorageFilerTO pool) { - synchronized (pool.getUuid().intern()) { + protected SR getIscsiSR(Connection conn, String srNameLabel, String target, String path, + String chapInitiatorUsername, String chapInitiatorPassword, Boolean[] created) { + synchronized (srNameLabel.intern()) { Map deviceConfig = new HashMap(); try { - String target = pool.getHost(); - String path = pool.getPath(); if (path.endsWith("/")) { path = path.substring(0, path.length() - 1); } String tmp[] = path.split("/"); if (tmp.length != 3) { - String msg = "Wrong iscsi path " + pool.getPath() + " it should be /targetIQN/LUN"; + String msg = "Wrong iscsi path " + path + " it should be /targetIQN/LUN"; s_logger.warn(msg); throw new CloudRuntimeException(msg); } @@ -6379,7 +6320,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe String lunid = tmp[2].trim(); String scsiid = ""; - Set srs = SR.getByNameLabel(conn, pool.getUuid()); + Set srs = SR.getByNameLabel(conn, srNameLabel); for (SR sr : srs) { if (!SRType.LVMOISCSI.equals(sr.getType(conn))) { continue; @@ -6404,19 +6345,24 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } 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:" + _host.uuid); + + dc.get("targetIQN") + ", lunid:" + dc.get("lunid") + " for pool " + srNameLabel + "on host:" + _host.uuid); } } deviceConfig.put("target", target); deviceConfig.put("targetIQN", targetiqn); + if (StringUtils.isNotBlank(chapInitiatorUsername) && + StringUtils.isNotBlank(chapInitiatorPassword)) { + deviceConfig.put("chapuser", chapInitiatorUsername); + deviceConfig.put("chappassword", chapInitiatorPassword); + } + Host host = Host.getByUuid(conn, _host.uuid); Map smConfig = new HashMap(); String type = SRType.LVMOISCSI.toString(); - String poolId = Long.toString(pool.getId()); SR sr = null; try { - sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), poolId, type, "user", true, + sr = SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, type, "user", true, smConfig); } catch (XenAPIException e) { String errmsg = e.toString(); @@ -6455,20 +6401,31 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe if( result.indexOf("") != -1) { pooluuid = result.substring(result.indexOf("") + 6, result.indexOf("")).trim(); } - if( pooluuid == null || pooluuid.length() != 36) { - sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), poolId, type, "user", true, + + if (pooluuid == null || pooluuid.length() != 36) + { + sr = SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, type, "user", true, smConfig); + + created[0] = true; // note that the SR was created (as opposed to introduced) } else { - sr = SR.introduce(conn, pooluuid, pool.getUuid(), poolId, + sr = SR.introduce(conn, pooluuid, srNameLabel, srNameLabel, type, "user", true, smConfig); - Pool.Record pRec = XenServerConnectionPool.getPoolRecord(conn); + + Set setHosts = Host.getAll(conn); + + for (Host currentHost : setHosts) { PBD.Record rec = new PBD.Record(); + rec.deviceConfig = deviceConfig; - rec.host = pRec.master; + rec.host = currentHost; rec.SR = sr; + PBD pbd = PBD.create(conn, rec); + pbd.plug(conn); } + } sr.scan(conn); return sr; } catch (XenAPIException e) { @@ -6628,6 +6585,52 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } + // for about 1 GiB of physical size, about 4 MiB seems to be used for metadata + private long getMetadata(long physicalSize) { + return (long)(physicalSize * 0.00390625); // 1 GiB / 4 MiB = 0.00390625 + } + + protected VDI handleSrAndVdiAttach(String iqn, String storageHostName, + String chapInitiatorName, String chapInitiatorPassword) throws Exception { + VDI vdi = null; + + Connection conn = getConnection(); + + Boolean[] created = { false }; + + SR sr = getIscsiSR(conn, iqn, + storageHostName, iqn, + chapInitiatorName, chapInitiatorPassword, created); + + // if created[0] is true, this means the SR was actually created...as opposed to introduced + if (created[0]) { + VDI.Record vdir = new VDI.Record(); + + vdir.nameLabel = iqn; + vdir.SR = sr; + vdir.type = Types.VdiType.USER; + vdir.virtualSize = sr.getPhysicalSize(conn) - sr.getPhysicalUtilisation(conn) - getMetadata(sr.getPhysicalSize(conn)); + + if (vdir.virtualSize < 0) { + throw new Exception("VDI virtual size cannot be less than 0."); + } + + vdi = VDI.create(conn, vdir); + } + else { + vdi = sr.getVDIs(conn).iterator().next(); + } + + return vdi; + } + + protected void handleSrAndVdiDetach(String iqn) throws Exception { + Connection conn = getConnection(); + + SR sr = getStorageRepository(conn, iqn); + + removeSR(conn, sr); + } protected AttachVolumeAnswer execute(final AttachVolumeCommand cmd) { Connection conn = getConnection(); @@ -6644,7 +6647,16 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe try { // Look up the VDI - VDI vdi = mount(conn, cmd.getPooltype(), cmd.getVolumeFolder(),cmd.getVolumePath()); + VDI vdi = null; + + if (cmd.getAttach() && cmd.isManaged()) { + vdi = handleSrAndVdiAttach(cmd.get_iScsiName(), cmd.getStorageHost(), + cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword()); + } + else { + vdi = getVDIbyUuid(conn, cmd.getVolumePath()); + } + // Look up the VM VM vm = getVM(conn, vmName); /* For HVM guest, if no pv driver installed, no attach/detach */ @@ -6696,7 +6708,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe // Update the VDI's label to include the VM name vdi.setNameLabel(conn, vmName + "-DATA"); - return new AttachVolumeAnswer(cmd, Long.parseLong(diskNumber)); + return new AttachVolumeAnswer(cmd, Long.parseLong(diskNumber), vdi.getUuid(conn)); } else { // Look up all VBDs for this VDI Set vbds = vdi.getVBDs(conn); @@ -6715,7 +6727,9 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe // Update the VDI's label to be "detached" vdi.setNameLabel(conn, "detached"); - umount(conn, vdi); + if (cmd.isManaged()) { + handleSrAndVdiDetach(cmd.get_iScsiName()); + } return new AttachVolumeAnswer(cmd); } @@ -7598,30 +7612,30 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } - protected SR getStorageRepository(Connection conn, String uuid) { + protected SR getStorageRepository(Connection conn, String srNameLabel) { Set srs; try { - srs = SR.getByNameLabel(conn, uuid); + srs = SR.getByNameLabel(conn, srNameLabel); } catch (XenAPIException e) { - throw new CloudRuntimeException("Unable to get SR " + uuid + " due to " + e.toString(), e); + throw new CloudRuntimeException("Unable to get SR " + srNameLabel + " due to " + e.toString(), e); } catch (Exception e) { - throw new CloudRuntimeException("Unable to get SR " + uuid + " due to " + e.getMessage(), e); + throw new CloudRuntimeException("Unable to get SR " + srNameLabel + " due to " + e.getMessage(), e); } if (srs.size() > 1) { - throw new CloudRuntimeException("More than one storage repository was found for pool with uuid: " + uuid); + throw new CloudRuntimeException("More than one storage repository was found for pool with uuid: " + srNameLabel); } else if (srs.size() == 1) { SR sr = srs.iterator().next(); if (s_logger.isDebugEnabled()) { - s_logger.debug("SR retrieved for " + uuid); + s_logger.debug("SR retrieved for " + srNameLabel); } if (checkSR(conn, sr)) { return sr; } - throw new CloudRuntimeException("SR check failed for storage pool: " + uuid + "on host:" + _host.uuid); + throw new CloudRuntimeException("SR check failed for storage pool: " + srNameLabel + "on host:" + _host.uuid); } else { - throw new CloudRuntimeException("Can not see storage pool: " + uuid + " from on host:" + _host.uuid); + throw new CloudRuntimeException("Can not see storage pool: " + srNameLabel + " from on host:" + _host.uuid); } } 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 399e2341b56..074375e128c 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 @@ -18,44 +18,8 @@ */ package com.cloud.hypervisor.xen.resource; -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.io.File; -import java.lang.reflect.InvocationTargetException; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -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.AttachAnswer; -import org.apache.cloudstack.storage.command.AttachCommand; -import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreAnswer; -import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd; -import org.apache.cloudstack.storage.command.CopyCmdAnswer; -import org.apache.cloudstack.storage.command.CopyCommand; -import org.apache.cloudstack.storage.command.CreateObjectAnswer; -import org.apache.cloudstack.storage.command.CreateObjectCommand; -import org.apache.cloudstack.storage.command.DeleteCommand; -import org.apache.cloudstack.storage.command.DettachAnswer; -import org.apache.cloudstack.storage.command.DettachCommand; -import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol; -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.log4j.Logger; -import org.apache.xmlrpc.XmlRpcException; - import com.cloud.agent.api.Answer; import com.cloud.agent.api.CreateStoragePoolCommand; -import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer; import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; @@ -88,6 +52,40 @@ import com.xensource.xenapi.VBD; import com.xensource.xenapi.VDI; import com.xensource.xenapi.VM; import com.xensource.xenapi.VMGuestMetrics; +import org.apache.cloudstack.storage.command.AttachAnswer; +import org.apache.cloudstack.storage.command.AttachCommand; +import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreAnswer; +import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd; +import org.apache.cloudstack.storage.command.CopyCmdAnswer; +import org.apache.cloudstack.storage.command.CopyCommand; +import org.apache.cloudstack.storage.command.CreateObjectAnswer; +import org.apache.cloudstack.storage.command.CreateObjectCommand; +import org.apache.cloudstack.storage.command.DeleteCommand; +import org.apache.cloudstack.storage.command.DettachAnswer; +import org.apache.cloudstack.storage.command.DettachCommand; +import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol; +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.log4j.Logger; +import org.apache.xmlrpc.XmlRpcException; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; public class XenServerStorageProcessor implements StorageProcessor { private static final Logger s_logger = Logger.getLogger(XenServerStorageProcessor.class); @@ -171,7 +169,16 @@ public class XenServerStorageProcessor implements StorageProcessor { try { Connection conn = this.hypervisorResource.getConnection(); // Look up the VDI - VDI vdi = this.hypervisorResource.mount(conn, null, null, data.getPath()); + VDI vdi = null; + + if (cmd.isManaged()) { + vdi = this.hypervisorResource.handleSrAndVdiAttach(cmd.get_iScsiName(), cmd.getStorageHost(), + cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword()); + } + else { + 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 */ @@ -223,7 +230,7 @@ public class XenServerStorageProcessor implements StorageProcessor { // Update the VDI's label to include the VM name vdi.setNameLabel(conn, vmName + "-DATA"); - DiskTO newDisk = new DiskTO(disk.getData(), Long.parseLong(diskNumber), disk.getType()); + DiskTO newDisk = new DiskTO(disk.getData(), Long.parseLong(diskNumber), vdi.getUuid(conn), disk.getType()); return new AttachAnswer(newDisk); } catch (XenAPIException e) { @@ -350,6 +357,10 @@ public class XenServerStorageProcessor implements StorageProcessor { this.hypervisorResource.umount(conn, vdi); + if (cmd.isManaged()) { + this.hypervisorResource.handleSrAndVdiDetach(cmd.get_iScsiName()); + } + return new DettachAnswer(disk); } catch(Exception e) { s_logger.warn("Failed dettach volume: " + data.getPath()); @@ -1209,7 +1220,7 @@ public class XenServerStorageProcessor implements StorageProcessor { } @Override - public Answer backupSnasphot(CopyCommand cmd) { + public Answer backupSnapshot(CopyCommand cmd) { Connection conn = hypervisorResource.getConnection(); DataTO srcData = cmd.getSrcTO(); DataTO cacheData = cmd.getCacheTO(); diff --git a/plugins/network-elements/dns-notifier/resources/components-example.xml b/plugins/network-elements/dns-notifier/resources/components-example.xml index 717c5e063fe..418835a299f 100755 --- a/plugins/network-elements/dns-notifier/resources/components-example.xml +++ b/plugins/network-elements/dns-notifier/resources/components-example.xml @@ -113,7 +113,6 @@ under the License. - @@ -147,7 +146,6 @@ under the License. - 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 263e13b42f3..d25d4160e6b 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 @@ -905,46 +905,27 @@ public class NetscalerResource implements ServerResource { GSLB.createVserverServiceBinding(_netscalerService, serviceName, vserverName); // create a monitor for the service running on the site - lbmonitor newmonitor = new lbmonitor(); - String monitorName = GSLB.generateGslbServiceMonitorName(servicePublicIp); - newmonitor.set_type("TCP"); - newmonitor.set_servicename(serviceName); - newmonitor.set_monitorname(monitorName); - newmonitor.set_state("ENABLED"); - lbmonitor.add(_netscalerService, newmonitor); + GSLB.createGslbServiceMonitor(_netscalerService, servicePublicIp, serviceName); - // bind the monitor to the GSLB servie - try { - gslbservice_lbmonitor_binding monitorBinding = new gslbservice_lbmonitor_binding(); - monitorBinding.set_monitor_name(monitorName); - monitorBinding.set_servicename(serviceName); - gslbservice_lbmonitor_binding.add(_netscalerService, monitorBinding); - } catch (Exception e) { - // TODO: Nitro API version 10.* is not compatible for NetScalers 9.*, so may fail - // against NetScaler version lesser than 10 hence ignore the exception - s_logger.warn("Failed to bind monitor to GSLB service due to " + e.getMessage()); - } + // bind the monitor to the GSLB service + GSLB.createGslbServiceGslbMonitorBinding(_netscalerService, servicePublicIp, serviceName); } else { + + String monitorName = GSLB.generateGslbServiceMonitorName(servicePublicIp); + + // delete GSLB service and GSLB monitor binding + GSLB.deleteGslbServiceGslbMonitorBinding(_netscalerService, monitorName, serviceName); + + // delete the GSLB service monitor + GSLB.deleteGslbServiceMonitor(_netscalerService, monitorName); + // Unbind GSLB service with GSLB virtual server GSLB.deleteVserverServiceBinding(_netscalerService, serviceName, vserverName); // delete 'gslbservice' object gslbservice service = GSLB.getServiceObject(_netscalerService, serviceName); GSLB.deleteService(_netscalerService, serviceName); - - // delete the GSLB service monitor - String monitorName = GSLB.generateGslbServiceMonitorName(servicePublicIp); - try { - lbmonitor serviceMonitor = lbmonitor.get(_netscalerService, monitorName); - if (serviceMonitor != null) { - lbmonitor.delete(_netscalerService, serviceMonitor); - } - } catch (nitro_exception ne) { - if (ne.getErrorCode() != NitroError.NS_RESOURCE_NOT_EXISTS) { - s_logger.warn("Failed to delete monitor "+ monitorName + " for GSLB service due to " + ne.getMessage()); - } - } } if (site.forRevoke()) { // delete the site if its for revoke @@ -969,9 +950,16 @@ public class NetscalerResource implements ServerResource { String servicePublicIp = site.getServicePublicIp(); String servicePublicPort = site.getServicePort(); String siteName = GSLB.generateUniqueSiteName(sitePrivateIP, sitePublicIP, site.getDataCenterId()); + String serviceName = GSLB.generateUniqueServiceName(siteName, servicePublicIp, servicePublicPort); + String monitorName = GSLB.generateGslbServiceMonitorName(servicePublicIp); + + // delete GSLB service and GSLB monitor binding + GSLB.deleteGslbServiceGslbMonitorBinding(_netscalerService, servicePublicIp, serviceName); + + // delete the GSLB service monitor + GSLB.deleteGslbServiceMonitor(_netscalerService, monitorName); // remove binding between virtual server and services - String serviceName = GSLB.generateUniqueServiceName(siteName, servicePublicIp, servicePublicPort); GSLB.deleteVserverServiceBinding(_netscalerService, serviceName, vserverName); // delete service object @@ -1460,6 +1448,75 @@ public class NetscalerResource implements ServerResource { } } + private static void createGslbServiceMonitor(nitro_service nsService, String servicePublicIp, + String serviceName) throws ExecutionException { + try { + lbmonitor newmonitor = new lbmonitor(); + String monitorName = generateGslbServiceMonitorName(servicePublicIp); + newmonitor.set_type("TCP"); + newmonitor.set_servicename(serviceName); + newmonitor.set_monitorname(monitorName); + newmonitor.set_state("ENABLED"); + lbmonitor.add(nsService, newmonitor); + } catch (nitro_exception ne) { + if (ne.getErrorCode() == NitroError.NS_RESOURCE_EXISTS) { + return; + } + } catch (Exception e) { + String errMsg = "Failed to create GSLB monitor for service public ip" + servicePublicIp; + if (s_logger.isDebugEnabled()) { + s_logger.debug(errMsg); + } + throw new ExecutionException(errMsg); + } + } + + private static void deleteGslbServiceMonitor(nitro_service nsService, String monitorName) + throws ExecutionException { + try { + lbmonitor serviceMonitor = lbmonitor.get(nsService, monitorName); + if (serviceMonitor != null) { + lbmonitor.delete(nsService, serviceMonitor); + } + } catch (nitro_exception ne) { + if (ne.getErrorCode() != NitroError.NS_RESOURCE_NOT_EXISTS) { + String errMsg = "Failed to delete monitor "+ monitorName + " for GSLB service due to " + ne.getMessage(); + s_logger.debug(errMsg); + throw new com.cloud.utils.exception.ExecutionException(errMsg); + } + } catch (Exception e) { + String errMsg = "Failed to delete monitor "+ monitorName + " for GSLB service due to " + e.getMessage(); + s_logger.debug(errMsg); + throw new com.cloud.utils.exception.ExecutionException(errMsg); + } + } + + private static void createGslbServiceGslbMonitorBinding(nitro_service nsService, String servicePublicIp, + String serviceName) { + try { + String monitorName = GSLB.generateGslbServiceMonitorName(servicePublicIp); + gslbservice_lbmonitor_binding monitorBinding = new gslbservice_lbmonitor_binding(); + monitorBinding.set_monitor_name(monitorName); + monitorBinding.set_servicename(serviceName); + gslbservice_lbmonitor_binding.add(nsService, monitorBinding); + } catch (Exception e) { + // TODO: Nitro API version 10.* is not compatible for NetScalers 9.*, so may fail + // against NetScaler version lesser than 10 hence ignore the exception + s_logger.warn("Failed to bind monitor to GSLB service due to " + e.getMessage()); + } + } + + private static void deleteGslbServiceGslbMonitorBinding(nitro_service nsService, String monitorName, + String serviceName) { + try { + gslbservice_lbmonitor_binding[] monitorBindings = gslbservice_lbmonitor_binding.get(nsService, serviceName); + gslbservice_lbmonitor_binding.delete(nsService, monitorBindings); + } catch (Exception e) { + s_logger.warn("Failed to delet GSLB monitor " + monitorName + "and GSLB service " + serviceName + + " binding due to " + e.getMessage()); + } + } + // get 'gslbsite' object corresponding to a site name private static gslbsite getSiteObject(nitro_service client, String siteName) { try { diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/api/commands/AddSspCmd.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/api/commands/AddSspCmd.java similarity index 96% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/api/commands/AddSspCmd.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/api/commands/AddSspCmd.java index 5639292b239..8aa0761120d 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/api/commands/AddSspCmd.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/api/commands/AddSspCmd.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.api.commands; +package org.apache.cloudstack.api.commands; import javax.inject.Inject; import org.apache.log4j.Logger; @@ -23,10 +23,11 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.SspResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.network.element.SspService; -import com.cloud.api.response.SspResponse; import com.cloud.dc.dao.DataCenterDao; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; @@ -34,7 +35,6 @@ import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.host.Host; -import com.cloud.network.element.SspService; @APICommand(name="addStratosphereSsp", responseObject=SspResponse.class, description="Adds stratosphere ssp server") diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/api/commands/DeleteSspCmd.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/api/commands/DeleteSspCmd.java similarity index 96% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/api/commands/DeleteSspCmd.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/api/commands/DeleteSspCmd.java index 8ba0355480b..5177dfbe2e7 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/api/commands/DeleteSspCmd.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/api/commands/DeleteSspCmd.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.api.commands; +package org.apache.cloudstack.api.commands; import javax.inject.Inject; @@ -27,13 +27,13 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.network.element.SspService; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; -import com.cloud.network.element.SspService; @APICommand(name="deleteStratosphereSsp", responseObject=SuccessResponse.class, description="Removes stratosphere ssp server") public class DeleteSspCmd extends BaseCmd { diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/api/response/SspResponse.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/api/response/SspResponse.java similarity index 98% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/api/response/SspResponse.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/api/response/SspResponse.java index ac9dee77f25..770ef0f99e3 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/api/response/SspResponse.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/api/response/SspResponse.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.api.response; +package org.apache.cloudstack.api.response; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspCredentialDao.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspCredentialDao.java similarity index 96% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspCredentialDao.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspCredentialDao.java index 213b817bdd9..4927da1c9d9 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspCredentialDao.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspCredentialDao.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.dao; +package org.apache.cloudstack.network.dao; import com.cloud.utils.db.GenericDao; diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspCredentialDaoImpl.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspCredentialDaoImpl.java similarity index 97% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspCredentialDaoImpl.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspCredentialDaoImpl.java index 0206dee7fa6..035fd56e4a5 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspCredentialDaoImpl.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspCredentialDaoImpl.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.dao; +package org.apache.cloudstack.network.dao; import javax.ejb.Local; diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspCredentialVO.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspCredentialVO.java similarity index 97% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspCredentialVO.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspCredentialVO.java index 8bc39467e3b..d05b270ebe2 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspCredentialVO.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspCredentialVO.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.dao; +package org.apache.cloudstack.network.dao; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspTenantDao.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspTenantDao.java similarity index 96% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspTenantDao.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspTenantDao.java index 2a3bfdcddf8..7bccdaa309a 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspTenantDao.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspTenantDao.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.dao; +package org.apache.cloudstack.network.dao; import com.cloud.utils.db.GenericDao; diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspTenantDaoImpl.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspTenantDaoImpl.java similarity index 97% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspTenantDaoImpl.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspTenantDaoImpl.java index 7018ce594f8..8d40256b493 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspTenantDaoImpl.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspTenantDaoImpl.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.dao; +package org.apache.cloudstack.network.dao; import javax.ejb.Local; diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspTenantVO.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspTenantVO.java similarity index 97% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspTenantVO.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspTenantVO.java index 026d338aecf..b573b626bef 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspTenantVO.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspTenantVO.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.dao; +package org.apache.cloudstack.network.dao; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspUuidDao.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspUuidDao.java similarity index 96% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspUuidDao.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspUuidDao.java index 325ba6623a0..039028a335a 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspUuidDao.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspUuidDao.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.dao; +package org.apache.cloudstack.network.dao; import java.util.List; diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspUuidDaoImpl.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspUuidDaoImpl.java similarity index 98% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspUuidDaoImpl.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspUuidDaoImpl.java index 85c84919c44..e8b93403c6f 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspUuidDaoImpl.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspUuidDaoImpl.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.dao; +package org.apache.cloudstack.network.dao; import java.util.List; diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspUuidVO.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspUuidVO.java similarity index 98% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspUuidVO.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspUuidVO.java index 83c9fea280b..f5dc235b168 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/dao/SspUuidVO.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/dao/SspUuidVO.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.dao; +package org.apache.cloudstack.network.dao; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/element/SspClient.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspClient.java similarity index 99% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/element/SspClient.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspClient.java index 5c9c003eaba..ee4d4558bff 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/element/SspClient.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspClient.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.element; +package org.apache.cloudstack.network.element; import java.io.IOException; import java.io.UnsupportedEncodingException; diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/element/SspElement.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspElement.java similarity index 93% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/element/SspElement.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspElement.java index 72add307d00..d145117a7e6 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/element/SspElement.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspElement.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.element; +package org.apache.cloudstack.network.element; import java.net.MalformedURLException; import java.net.URL; @@ -30,10 +30,16 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.api.commands.AddSspCmd; +import org.apache.cloudstack.api.commands.DeleteSspCmd; +import org.apache.cloudstack.network.dao.SspCredentialDao; +import org.apache.cloudstack.network.dao.SspCredentialVO; +import org.apache.cloudstack.network.dao.SspTenantDao; +import org.apache.cloudstack.network.dao.SspTenantVO; +import org.apache.cloudstack.network.dao.SspUuidDao; +import org.apache.cloudstack.network.dao.SspUuidVO; import org.apache.log4j.Logger; -import com.cloud.api.commands.AddSspCmd; -import com.cloud.api.commands.DeleteSspCmd; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.deploy.DeployDestination; @@ -59,12 +65,8 @@ import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; -import com.cloud.network.dao.SspCredentialDao; -import com.cloud.network.dao.SspCredentialVO; -import com.cloud.network.dao.SspTenantDao; -import com.cloud.network.dao.SspTenantVO; -import com.cloud.network.dao.SspUuidDao; -import com.cloud.network.dao.SspUuidVO; +import com.cloud.network.element.ConnectivityProvider; +import com.cloud.network.element.NetworkElement; import com.cloud.offering.NetworkOffering; import com.cloud.resource.ResourceManager; import com.cloud.utils.component.AdapterBase; @@ -179,7 +181,7 @@ public class SspElement extends AdapterBase implements ConnectivityProvider, Ssp } /* (non-Javadoc) - * @see com.cloud.network.element.NetworkElement#isReady(com.cloud.network.PhysicalNetworkServiceProvider) + * @see org.apache.cloudstack.network.element.NetworkElement#isReady(com.cloud.network.PhysicalNetworkServiceProvider) */ @Override public boolean isReady(PhysicalNetworkServiceProvider provider) { @@ -198,7 +200,7 @@ public class SspElement extends AdapterBase implements ConnectivityProvider, Ssp /* (non-Javadoc) * If this element is ready, then it can be enabled. - * @see com.cloud.network.element.SspManager#isEnabled(com.cloud.network.PhysicalNetwork) + * @see org.apache.cloudstack.network.element.SspManager#isEnabled(com.cloud.network.PhysicalNetwork) */ @Override public boolean canHandle(PhysicalNetwork physicalNetwork){ @@ -475,7 +477,7 @@ public class SspElement extends AdapterBase implements ConnectivityProvider, Ssp * * This method will be called right after NetworkGuru#implement(). * see also {@link #shutdown(Network, ReservationContext, boolean)} - * @see com.cloud.network.element.NetworkElement#implement(com.cloud.network.Network, com.cloud.offering.NetworkOffering, com.cloud.deploy.DeployDestination, com.cloud.vm.ReservationContext) + * @see org.apache.cloudstack.network.element.NetworkElement#implement(com.cloud.network.Network, com.cloud.offering.NetworkOffering, com.cloud.deploy.DeployDestination, com.cloud.vm.ReservationContext) */ @Override public boolean implement(Network network, NetworkOffering offering, @@ -491,7 +493,7 @@ public class SspElement extends AdapterBase implements ConnectivityProvider, Ssp * * This method will be called right BEFORE NetworkGuru#shutdown(). * The entities was acquired by {@link #implement(Network, NetworkOffering, DeployDestination, ReservationContext)} - * @see com.cloud.network.element.NetworkElement#shutdown(com.cloud.network.Network, com.cloud.vm.ReservationContext, boolean) + * @see org.apache.cloudstack.network.element.NetworkElement#shutdown(com.cloud.network.Network, com.cloud.vm.ReservationContext, boolean) */ @Override public boolean shutdown(Network network, ReservationContext context, @@ -506,7 +508,7 @@ public class SspElement extends AdapterBase implements ConnectivityProvider, Ssp * * This method will be called right after NetworkGuru#reserve(). * The entities will be released by {@link #release(Network, NicProfile, VirtualMachineProfile, ReservationContext)} - * @see com.cloud.network.element.NetworkElement#prepare(com.cloud.network.Network, com.cloud.vm.NicProfile, com.cloud.vm.VirtualMachineProfile, com.cloud.deploy.DeployDestination, com.cloud.vm.ReservationContext) + * @see org.apache.cloudstack.network.element.NetworkElement#prepare(com.cloud.network.Network, com.cloud.vm.NicProfile, com.cloud.vm.VirtualMachineProfile, com.cloud.deploy.DeployDestination, com.cloud.vm.ReservationContext) */ @Override public boolean prepare(Network network, NicProfile nic, @@ -523,7 +525,7 @@ public class SspElement extends AdapterBase implements ConnectivityProvider, Ssp * * This method will be called right AFTER NetworkGuru#release(). * The entities was acquired in {@link #prepare(Network, NicProfile, VirtualMachineProfile, DeployDestination, ReservationContext)} - * @see com.cloud.network.element.NetworkElement#release(com.cloud.network.Network, com.cloud.vm.NicProfile, com.cloud.vm.VirtualMachineProfile, com.cloud.vm.ReservationContext) + * @see org.apache.cloudstack.network.element.NetworkElement#release(com.cloud.network.Network, com.cloud.vm.NicProfile, com.cloud.vm.VirtualMachineProfile, com.cloud.vm.ReservationContext) */ @Override public boolean release(Network network, NicProfile nic, @@ -538,7 +540,7 @@ public class SspElement extends AdapterBase implements ConnectivityProvider, Ssp * Destroy a network implementation. * * This method will be called right BEFORE NetworkGuru#trash() in "Expunge" phase. - * @see com.cloud.network.element.NetworkElement#destroy(com.cloud.network.Network) + * @see org.apache.cloudstack.network.element.NetworkElement#destroy(com.cloud.network.Network) */ @Override public boolean destroy(Network network, ReservationContext context) diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/element/SspManager.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspManager.java similarity index 97% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/element/SspManager.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspManager.java index ab8b1b2b9bf..d96bd7f1de2 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/element/SspManager.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspManager.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.element; +package org.apache.cloudstack.network.element; import com.cloud.deploy.DeployDestination; import com.cloud.network.Network; diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/element/SspService.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspService.java similarity index 90% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/element/SspService.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspService.java index a5f62cba431..3330045e118 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/element/SspService.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/element/SspService.java @@ -14,10 +14,11 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.element; +package org.apache.cloudstack.network.element; + +import org.apache.cloudstack.api.commands.AddSspCmd; +import org.apache.cloudstack.api.commands.DeleteSspCmd; -import com.cloud.api.commands.AddSspCmd; -import com.cloud.api.commands.DeleteSspCmd; import com.cloud.host.Host; import com.cloud.utils.component.PluggableService; diff --git a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/guru/SspGuestNetworkGuru.java b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/guru/SspGuestNetworkGuru.java similarity index 93% rename from plugins/network-elements/stratosphere-ssp/src/com/cloud/network/guru/SspGuestNetworkGuru.java rename to plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/guru/SspGuestNetworkGuru.java index af673260a32..1057bec376b 100644 --- a/plugins/network-elements/stratosphere-ssp/src/com/cloud/network/guru/SspGuestNetworkGuru.java +++ b/plugins/network-elements/stratosphere-ssp/src/org/apache/cloudstack/network/guru/SspGuestNetworkGuru.java @@ -14,11 +14,13 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.guru; +package org.apache.cloudstack.network.guru; import javax.ejb.Local; import javax.inject.Inject; +import org.apache.cloudstack.network.element.SspElement; +import org.apache.cloudstack.network.element.SspManager; import org.apache.log4j.Logger; import com.cloud.dc.DataCenter.NetworkType; @@ -31,8 +33,8 @@ import com.cloud.network.NetworkProfile; import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetwork.IsolationMethod; import com.cloud.network.dao.NetworkDao; -import com.cloud.network.element.SspElement; -import com.cloud.network.element.SspManager; +import com.cloud.network.guru.GuestNetworkGuru; +import com.cloud.network.guru.NetworkGuru; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.vm.NicProfile; @@ -94,7 +96,7 @@ public class SspGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigr * Effective return object members are: cidr, broadcastUri, gateway, mode, physicalNetworkId * The other members will be silently ignored. * This method is called at DeployVMCmd#execute (running phase) - NetworkManagerImpl#prepare - * @see com.cloud.network.guru.GuestNetworkGuru#implement(com.cloud.network.Network, com.cloud.offering.NetworkOffering, com.cloud.deploy.DeployDestination, com.cloud.vm.ReservationContext) + * @see org.apache.cloudstack.network.guru.GuestNetworkGuru#implement(com.cloud.network.Network, com.cloud.offering.NetworkOffering, com.cloud.deploy.DeployDestination, com.cloud.vm.ReservationContext) */ @Override public Network implement(Network network, NetworkOffering offering, diff --git a/plugins/network-elements/stratosphere-ssp/test/com/cloud/network/element/SspClientTest.java b/plugins/network-elements/stratosphere-ssp/test/org/apache/cloudstack/network/element/SspClientTest.java similarity index 97% rename from plugins/network-elements/stratosphere-ssp/test/com/cloud/network/element/SspClientTest.java rename to plugins/network-elements/stratosphere-ssp/test/org/apache/cloudstack/network/element/SspClientTest.java index 4a2b352055c..795d1c169ab 100644 --- a/plugins/network-elements/stratosphere-ssp/test/com/cloud/network/element/SspClientTest.java +++ b/plugins/network-elements/stratosphere-ssp/test/org/apache/cloudstack/network/element/SspClientTest.java @@ -14,10 +14,11 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.element; +package org.apache.cloudstack.network.element; 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; diff --git a/plugins/network-elements/stratosphere-ssp/test/com/cloud/network/element/SspElementTest.java b/plugins/network-elements/stratosphere-ssp/test/org/apache/cloudstack/network/element/SspElementTest.java similarity index 95% rename from plugins/network-elements/stratosphere-ssp/test/com/cloud/network/element/SspElementTest.java rename to plugins/network-elements/stratosphere-ssp/test/org/apache/cloudstack/network/element/SspElementTest.java index 0020e20ed31..950592f1c39 100644 --- a/plugins/network-elements/stratosphere-ssp/test/com/cloud/network/element/SspElementTest.java +++ b/plugins/network-elements/stratosphere-ssp/test/org/apache/cloudstack/network/element/SspElementTest.java @@ -14,11 +14,16 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.element; +package org.apache.cloudstack.network.element; import java.util.Arrays; import java.util.HashMap; +import org.apache.cloudstack.network.dao.SspCredentialDao; +import org.apache.cloudstack.network.dao.SspCredentialVO; +import org.apache.cloudstack.network.dao.SspTenantDao; +import org.apache.cloudstack.network.dao.SspUuidDao; +import org.apache.cloudstack.network.element.SspElement; import org.junit.Before; import org.junit.Test; @@ -36,10 +41,6 @@ import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; import com.cloud.network.dao.PhysicalNetworkVO; -import com.cloud.network.dao.SspCredentialDao; -import com.cloud.network.dao.SspCredentialVO; -import com.cloud.network.dao.SspTenantDao; -import com.cloud.network.dao.SspUuidDao; import com.cloud.resource.ResourceManager; import com.cloud.vm.dao.NicDao; diff --git a/plugins/pom.xml b/plugins/pom.xml index 9ad56c6f941..04eb55ca86d 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -35,7 +35,7 @@ api/rate-limit api/discovery acl/static-role-based - affinity-group-processors/host-anti-affinity + affinity-group-processors/host-anti-affinity affinity-group-processors/explicit-dedication deployment-planners/user-concentrated-pod deployment-planners/user-dispersing @@ -64,7 +64,8 @@ storage/image/s3 storage/image/swift storage/image/default - storage/image/sample + storage/image/sample + storage/image/simulator storage/volume/solidfire storage/volume/default storage/volume/sample @@ -158,8 +159,8 @@ hypervisors/simulator + storage/image/simulator - 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 7b30575c8d1..21a5e0a7194 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 @@ -16,14 +16,14 @@ // under the License. package org.apache.cloudstack.storage.datastore.lifecycle; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.inject.Inject; - +import com.cloud.agent.api.StoragePoolInfo; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.resource.Discoverer; +import com.cloud.resource.ResourceManager; +import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ScopeType; +import com.cloud.utils.UriUtils; 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; @@ -35,14 +35,12 @@ import org.apache.cloudstack.storage.image.datastore.ImageStoreProviderManager; import org.apache.cloudstack.storage.image.store.lifecycle.ImageStoreLifeCycle; import org.apache.log4j.Logger; -import com.cloud.agent.api.StoragePoolInfo; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.resource.Discoverer; -import com.cloud.resource.ResourceManager; -import com.cloud.storage.DataStoreRole; -import com.cloud.storage.ScopeType; -import com.cloud.utils.UriUtils; +import javax.inject.Inject; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class CloudStackImageStoreLifeCycleImpl implements ImageStoreLifeCycle { @@ -83,7 +81,7 @@ public class CloudStackImageStoreLifeCycleImpl implements ImageStoreLifeCycle { DataStoreRole role = (DataStoreRole) dsInfos.get("role"); Map details = (Map) dsInfos.get("details"); - s_logger.info("Trying to add a new host at " + url + " in data center " + dcId); + s_logger.info("Trying to add a new data store at " + url + " to data center " + dcId); URI uri = null; try { @@ -103,7 +101,7 @@ public class CloudStackImageStoreLifeCycleImpl implements ImageStoreLifeCycle { if (dcId == null) { throw new InvalidParameterValueException( - "DataCenter id is null, and cloudstack default image storehas to be associated with a data center"); + "DataCenter id is null, and cloudstack default image store has to be associated with a data center"); } Map imageStoreParameters = new HashMap(); diff --git a/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java b/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java index 44f94f39ee4..66f4d7782ec 100644 --- a/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java +++ b/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java @@ -39,13 +39,11 @@ public class SampleImageStoreDriverImpl extends BaseImageStoreDriverImpl { @Override public DataStoreTO getStoreTO(DataStore store) { - // TODO Auto-generated method stub return null; } @Override public String createEntityExtractUrl(DataStore store, String installPath, ImageFormat format) { - // TODO Auto-generated method stub return null; } diff --git a/plugins/storage/image/simulator/pom.xml b/plugins/storage/image/simulator/pom.xml new file mode 100644 index 00000000000..d4b6838106c --- /dev/null +++ b/plugins/storage/image/simulator/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + cloud-plugin-storage-image-simulator + Apache CloudStack Plugin - Storage Image Simulator provider + + org.apache.cloudstack + cloudstack-plugins + 4.2.0-SNAPSHOT + ../../../pom.xml + + + + org.apache.cloudstack + cloud-engine-storage + ${project.version} + + + org.apache.cloudstack + cloud-engine-storage-image + ${project.version} + + + org.apache.cloudstack + cloud-engine-storage-volume + ${project.version} + + + org.apache.cloudstack + cloud-engine-storage-snapshot + ${project.version} + + + mysql + mysql-connector-java + ${cs.mysql.version} + provided + + + + install + src + test + + + maven-surefire-plugin + + + integration-test + + test + + + + + + + diff --git a/plugins/storage/image/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java b/plugins/storage/image/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java new file mode 100644 index 00000000000..d5fe8a18a82 --- /dev/null +++ b/plugins/storage/image/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java @@ -0,0 +1,106 @@ +/* + * 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.storage.datastore.driver; + + +import com.cloud.agent.api.storage.DownloadAnswer; +import com.cloud.agent.api.to.DataObjectType; +import com.cloud.agent.api.to.DataStoreTO; +import com.cloud.agent.api.to.NfsTO; +import com.cloud.storage.Storage; +import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VolumeDao; +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.framework.async.AsyncCallbackDispatcher; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; +import org.apache.cloudstack.storage.image.BaseImageStoreDriverImpl; +import org.apache.cloudstack.storage.image.store.ImageStoreImpl; + +import javax.inject.Inject; +import java.util.UUID; + +public class SimulatorImageStoreDriverImpl extends BaseImageStoreDriverImpl { + + @Inject + TemplateDataStoreDao _templateStoreDao; + @Inject + VMTemplateDao _templateDao; + @Inject + VolumeDao _volumeDao; + @Inject + VolumeDataStoreDao _volumeStoreDao; + + @Override + public DataStoreTO getStoreTO(DataStore store) { + ImageStoreImpl nfsStore = (ImageStoreImpl) store; + NfsTO nfsTO = new NfsTO(); + nfsTO.setRole(store.getRole()); + nfsTO.setUrl(nfsStore.getUri()); + return nfsTO; + } + + + + public String createEntityExtractUrl(DataStore store, String installPath, Storage.ImageFormat format) { + return null; + } + + @Override + public void createAsync(DataStore store, DataObject data, AsyncCompletionCallback callback) { + if (data.getType() == DataObjectType.TEMPLATE) { + this.createTemplate(data, callback); + } else if (data.getType() == DataObjectType.VOLUME) { + this.createVolume(data, callback); + } + } + + protected void createTemplate(DataObject data, AsyncCompletionCallback callback) { + CreateContext context = new CreateContext(callback, data); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher + .create(this); + caller.setContext(context); + caller.setCallback(caller.getTarget().createTemplateAsyncCallback(null, null)); + String path = UUID.randomUUID().toString(); + Long size = new Long(5 * 1024L * 1024L); + DownloadAnswer answer = new DownloadAnswer(null, 100, null, VMTemplateStorageResourceAssoc.Status.DOWNLOADED, + path, path, size, size, null); + caller.complete(answer); + return; + } + + protected void createVolume(DataObject data, AsyncCompletionCallback callback) { + CreateContext context = new CreateContext(callback, data); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher + .create(this); + caller.setContext(context); + caller.setCallback(caller.getTarget().createVolumeAsyncCallback(null, null)); + String path = UUID.randomUUID().toString(); + Long size = new Long(5 * 1024L * 1024L); + DownloadAnswer answer = new DownloadAnswer(null, 100, null, VMTemplateStorageResourceAssoc.Status.DOWNLOADED, + path, path, size, size, null); + caller.complete(answer); + return; + } +} \ No newline at end of file diff --git a/plugins/storage/image/simulator/src/org/apache/cloudstack/storage/datastore/lifecycle/SimulatorImageStoreLifeCycleImpl.java b/plugins/storage/image/simulator/src/org/apache/cloudstack/storage/datastore/lifecycle/SimulatorImageStoreLifeCycleImpl.java new file mode 100644 index 00000000000..beaa7a5fbae --- /dev/null +++ b/plugins/storage/image/simulator/src/org/apache/cloudstack/storage/datastore/lifecycle/SimulatorImageStoreLifeCycleImpl.java @@ -0,0 +1,132 @@ +/* + * 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.storage.datastore.lifecycle; + + +import com.cloud.agent.api.StoragePoolInfo; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.hypervisor.Hypervisor; +import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ScopeType; +import com.cloud.utils.UriUtils; +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; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; +import org.apache.cloudstack.storage.image.datastore.ImageStoreHelper; +import org.apache.cloudstack.storage.image.datastore.ImageStoreProviderManager; +import org.apache.cloudstack.storage.image.store.lifecycle.ImageStoreLifeCycle; +import org.apache.log4j.Logger; + +import javax.inject.Inject; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; + +public class SimulatorImageStoreLifeCycleImpl implements ImageStoreLifeCycle { + private static final Logger s_logger = Logger.getLogger(SimulatorImageStoreLifeCycleImpl.class); + + @Inject + ImageStoreHelper imageStoreHelper; + + @Inject + ImageStoreProviderManager imageStoreMgr; + + + @Override + public DataStore initialize(Map dsInfos) { + Long dcId = (Long) dsInfos.get("zoneId"); + String url = (String) dsInfos.get("url"); + String name = (String) dsInfos.get("name"); + if (name == null) { + name = url; + } + String providerName = (String) dsInfos.get("providerName"); + 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); + + URI uri; + try { + uri = new URI(UriUtils.encodeURIComponent(url)); + if (uri.getScheme() == null) { + throw new InvalidParameterValueException("uri.scheme is null " + url + ", add nfs:// as a prefix"); + } else if (uri.getScheme().equalsIgnoreCase("nfs")) { + if (uri.getHost() == null || uri.getHost().equalsIgnoreCase("") || uri.getPath() == null + || uri.getPath().equalsIgnoreCase("")) { + throw new InvalidParameterValueException( + "Your host and/or path is wrong. Make sure it is of the format nfs://hostname/path"); + } + } + } catch (URISyntaxException e) { + throw new InvalidParameterValueException(url + " is not a valid uri"); + } + + if (dcId == null) { + throw new InvalidParameterValueException( + "DataCenter id is null, and simulator image store has to be associated with a data center"); + } + + Map imageStoreParameters = new HashMap(); + imageStoreParameters.put("name", name); + imageStoreParameters.put("zoneId", dcId); + imageStoreParameters.put("url", url); + imageStoreParameters.put("protocol", uri.getScheme().toLowerCase()); + imageStoreParameters.put("scope", ScopeType.ZONE); + imageStoreParameters.put("providerName", providerName); + imageStoreParameters.put("role", role); + + ImageStoreVO ids = imageStoreHelper.createImageStore(imageStoreParameters, details); + return imageStoreMgr.getImageStore(ids.getId()); + } + + @Override + public boolean attachCluster(DataStore store, ClusterScope scope) { + return false; + } + + @Override + public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) { + return false; + } + + @Override + public boolean attachZone(DataStore dataStore, ZoneScope scope, Hypervisor.HypervisorType hypervisorType) { + return false; + } + + @Override + public boolean maintain(DataStore store) { + return false; + } + + @Override + public boolean cancelMaintain(DataStore store) { + return false; + } + + @Override + public boolean deleteDataStore(DataStore store) { + return false; + } +} diff --git a/plugins/storage/image/simulator/src/org/apache/cloudstack/storage/datastore/provider/SimulatorImageStoreProviderImpl.java b/plugins/storage/image/simulator/src/org/apache/cloudstack/storage/datastore/provider/SimulatorImageStoreProviderImpl.java new file mode 100644 index 00000000000..775d7431fad --- /dev/null +++ b/plugins/storage/image/simulator/src/org/apache/cloudstack/storage/datastore/provider/SimulatorImageStoreProviderImpl.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.storage.datastore.provider; + +import com.cloud.storage.ScopeType; +import com.cloud.utils.component.ComponentContext; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageStoreProvider; +import org.apache.cloudstack.storage.datastore.driver.SimulatorImageStoreDriverImpl; +import org.apache.cloudstack.storage.datastore.lifecycle.SimulatorImageStoreLifeCycleImpl; +import org.apache.cloudstack.storage.image.ImageStoreDriver; +import org.apache.cloudstack.storage.image.datastore.ImageStoreHelper; +import org.apache.cloudstack.storage.image.datastore.ImageStoreProviderManager; +import org.apache.cloudstack.storage.image.store.lifecycle.ImageStoreLifeCycle; +import org.springframework.stereotype.Component; + +import javax.inject.Inject; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +@Component +public class SimulatorImageStoreProviderImpl implements ImageStoreProvider { + + private final String _providerName = DataStoreProvider.NFS_IMAGE; + protected ImageStoreLifeCycle lifeCycle; + protected ImageStoreDriver driver; + + @Inject + ImageStoreProviderManager storeMgr; + @Inject + ImageStoreHelper helper; + + @Override + public boolean isScopeSupported(ScopeType scope) { + return true; + } + + @Override + public boolean needDownloadSysTemplate() { + return false; + } + + @Override + public DataStoreLifeCycle getDataStoreLifeCycle() { + return this.lifeCycle; + } + + @Override + public DataStoreDriver getDataStoreDriver() { + return this.driver; + } + + @Override + public HypervisorHostListener getHostListener() { + return null; + } + + @Override + public String getName() { + return this._providerName; + } + + @Override + public boolean configure(Map params) { + lifeCycle = ComponentContext.inject(SimulatorImageStoreLifeCycleImpl.class); + driver = ComponentContext.inject(SimulatorImageStoreDriverImpl.class); + storeMgr.registerDriver(this.getName(), driver); + return true; + } + + @Override + public Set getTypes() { + Set types = new HashSet(); + types.add(DataStoreProviderType.IMAGE); + return types; + } +} 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 8d7c965ee07..a2334074315 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 @@ -95,7 +95,12 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri } @Override - public void createAsync(DataObject data, AsyncCompletionCallback callback) { + public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + return null; + } + + @Override + public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback callback) { String errMsg = null; Answer answer = null; if (data.getType() == DataObjectType.VOLUME) { @@ -118,7 +123,7 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri } @Override - public void deleteAsync(DataObject data, AsyncCompletionCallback callback) { + public void deleteAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback callback) { DeleteCommand cmd = new DeleteCommand(data.getTO()); CommandResult result = new CommandResult(); 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 643c9334964..ece7b260cd4 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 @@ -23,7 +23,7 @@ import com.cloud.storage.dao.StoragePoolHostDao; import org.apache.cloudstack.engine.subsystem.api.storage.*; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.framework.async.AsyncRpcConext; +import org.apache.cloudstack.framework.async.AsyncRpcContext; import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.command.CreateObjectCommand; import org.apache.cloudstack.storage.datastore.DataObjectManager; @@ -54,7 +54,12 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver return null; } - private class CreateVolumeContext extends AsyncRpcConext { + @Override + public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + return null; + } + + private class CreateVolumeContext extends AsyncRpcContext { private final DataObject volume; public CreateVolumeContext(AsyncCompletionCallback callback, DataObject volume) { super(callback); @@ -77,12 +82,12 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver } @Override - public void deleteAsync(DataObject vo, AsyncCompletionCallback callback) { + public void deleteAsync(DataStore dataStore, DataObject vo, AsyncCompletionCallback callback) { /* * DeleteCommand cmd = new DeleteCommand(vo.getUri()); * - * EndPoint ep = selector.select(vo); AsyncRpcConext - * context = new AsyncRpcConext(callback); + * EndPoint ep = selector.select(vo); AsyncRpcContext + * context = new AsyncRpcContext(callback); * AsyncCallbackDispatcher * caller = AsyncCallbackDispatcher.create(this); * caller.setCallback(caller.getTarget().deleteCallback(null, null)) @@ -91,7 +96,7 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver } public Void deleteCallback(AsyncCallbackDispatcher callback, - AsyncRpcConext context) { + AsyncRpcContext context) { CommandResult result = new CommandResult(); Answer answer = callback.getResult(); if (!answer.getResult()) { @@ -103,7 +108,7 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver /* * private class CreateVolumeFromBaseImageContext extends - * AsyncRpcConext { private final VolumeObject volume; + * AsyncRpcContext { private final VolumeObject volume; * * public CreateVolumeFromBaseImageContext(AsyncCompletionCallback * callback, VolumeObject volume) { super(callback); this.volume = volume; } @@ -146,7 +151,7 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver */ @Override - public void createAsync(DataObject vol, AsyncCompletionCallback callback) { + public void createAsync(DataStore dataStore, DataObject vol, AsyncCompletionCallback callback) { EndPoint ep = selector.select(vol); CreateObjectCommand createCmd = new CreateObjectCommand(null); diff --git a/plugins/storage/volume/solidfire/pom.xml b/plugins/storage/volume/solidfire/pom.xml index 9db0685e91b..81af8ace135 100644 --- a/plugins/storage/volume/solidfire/pom.xml +++ b/plugins/storage/volume/solidfire/pom.xml @@ -12,7 +12,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 cloud-plugin-storage-volume-solidfire - Apache CloudStack Plugin - Storage Volume solidfire + Apache CloudStack Plugin - Storage Volume SolidFire Provider org.apache.cloudstack cloudstack-plugins @@ -31,6 +31,11 @@ ${cs.mysql.version} provided + + com.google.code.gson + gson + ${cs.gson.version} + install 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 960378c2821..329f27f7779 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 @@ -16,13 +16,46 @@ // under the License. package org.apache.cloudstack.storage.datastore.driver; -import com.cloud.agent.api.to.DataStoreTO; -import com.cloud.agent.api.to.DataTO; +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; + 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; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; +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.dc.dao.DataCenterDao; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeDetailsDao; +import com.cloud.user.AccountVO; +import com.cloud.user.AccountDetailsDao; +import com.cloud.user.AccountDetailVO; +import com.cloud.user.dao.AccountDao; public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { + private static final Logger s_logger = Logger.getLogger(SolidfirePrimaryDataStoreDriver.class); + + @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; + @Inject private VolumeDao _volumeDao; + @Inject private VolumeDetailsDao _volumeDetailsDao; + @Inject private DataCenterDao _zoneDao; + @Inject private AccountDao _accountDao; + @Inject private AccountDetailsDao _accountDetailsDao; @Override public DataTO getTO(DataObject data) { @@ -34,12 +67,450 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { return null; } - @Override - public void createAsync(DataObject data, AsyncCompletionCallback callback) { + private static class SolidFireConnection { + private final String _managementVip; + private final int _managementPort; + private final String _clusterAdminUsername; + private final String _clusterAdminPassword; + + public SolidFireConnection(String managementVip, int managementPort, + String clusterAdminUsername, String clusterAdminPassword) { + _managementVip = managementVip; + _managementPort = managementPort; + _clusterAdminUsername = clusterAdminUsername; + _clusterAdminPassword = clusterAdminPassword; + } + + public String getManagementVip() { + return _managementVip; + } + + public int getManagementPort() { + return _managementPort; + } + + public String getClusterAdminUsername() { + return _clusterAdminUsername; + } + + public String getClusterAdminPassword() { + return _clusterAdminPassword; + } + } + + private SolidFireConnection getSolidFireConnection(long storagePoolId) { + StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.MANAGEMENT_VIP); + + String mVip = storagePoolDetail.getValue(); + + storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.MANAGEMENT_PORT); + + int mPort = Integer.parseInt(storagePoolDetail.getValue()); + + storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_ADMIN_USERNAME); + + String clusterAdminUsername = storagePoolDetail.getValue(); + + storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_ADMIN_PASSWORD); + + String clusterAdminPassword = storagePoolDetail.getValue(); + + return new SolidFireConnection(mVip, mPort, clusterAdminUsername, clusterAdminPassword); + } + + private SolidFireUtil.SolidFireAccount createSolidFireAccount(String sfAccountName, + SolidFireConnection sfConnection) { + try { + 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); + + return SolidFireUtil.getSolidFireAccountById(mVip, mPort, + clusterAdminUsername, clusterAdminPassword, accountNumber); + } + catch (Exception ex) { + throw new IllegalArgumentException(ex.getMessage()); + } + } + + private void updateCsDbWithAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount) { + AccountDetailVO accountDetails = new AccountDetailVO(csAccountId, + SolidFireUtil.ACCOUNT_ID, + String.valueOf(sfAccount.getId())); + + _accountDetailsDao.persist(accountDetails); + + accountDetails = new AccountDetailVO(csAccountId, + SolidFireUtil.CHAP_INITIATOR_USERNAME, + String.valueOf(sfAccount.getName())); + + _accountDetailsDao.persist(accountDetails); + + accountDetails = new AccountDetailVO(csAccountId, + SolidFireUtil.CHAP_INITIATOR_SECRET, + String.valueOf(sfAccount.getInitiatorSecret())); + + _accountDetailsDao.persist(accountDetails); + + accountDetails = new AccountDetailVO(csAccountId, + SolidFireUtil.CHAP_TARGET_USERNAME, + sfAccount.getName()); + + _accountDetailsDao.persist(accountDetails); + + accountDetails = new AccountDetailVO(csAccountId, + SolidFireUtil.CHAP_TARGET_SECRET, + sfAccount.getTargetSecret()); + + _accountDetailsDao.persist(accountDetails); + } + + private class ChapInfoImpl implements ChapInfo { + private final String _initiatorUsername; + private final String _initiatorSecret; + private final String _targetUsername; + private final String _targetSecret; + + public ChapInfoImpl(String initiatorUsername, String initiatorSecret, + String targetUsername, String targetSecret) { + _initiatorUsername = initiatorUsername; + _initiatorSecret = initiatorSecret; + _targetUsername = targetUsername; + _targetSecret = targetSecret; + } + + public String getInitiatorUsername() { + return _initiatorUsername; + } + + public String getInitiatorSecret() { + return _initiatorSecret; + } + + public String getTargetUsername() { + return _targetUsername; + } + + public String getTargetSecret() { + return _targetSecret; + } } @Override - public void deleteAsync(DataObject data, AsyncCompletionCallback callback) { + public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + long accountId = volumeInfo.getAccountId(); + + AccountDetailVO accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_INITIATOR_USERNAME); + + String chapInitiatorUsername = accountDetail.getValue(); + + accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_INITIATOR_SECRET); + + String chapInitiatorSecret = accountDetail.getValue(); + + 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); + } + + private SolidFireUtil.SolidFireVolume createSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection) + throws StorageUnavailableException, Exception + { + String mVip = sfConnection.getManagementVip(); + int mPort = sfConnection.getManagementPort(); + String clusterAdminUsername = sfConnection.getClusterAdminUsername(); + String clusterAdminPassword = sfConnection.getClusterAdminPassword(); + + AccountDetailVO accountDetail = _accountDetailsDao.findDetail(volumeInfo.getAccountId(), SolidFireUtil.ACCOUNT_ID); + long sfAccountId = Long.parseLong(accountDetail.getValue()); + + final Iops iops; + + Long minIops = volumeInfo.getMinIops(); + Long maxIops = volumeInfo.getMaxIops(); + + if (minIops == null || minIops <= 0 || + maxIops == null || maxIops <= 0) { + iops = new Iops(100, 15000); + } + else { + iops = new Iops(volumeInfo.getMinIops(), volumeInfo.getMaxIops()); + } + + long sfVolumeId = SolidFireUtil.createSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, + volumeInfo.getName(), sfAccountId, volumeInfo.getSize(), true, + iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); + + return SolidFireUtil.getSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId); + } + + private static class Iops + { + private final long _minIops; + private final long _maxIops; + private final long _burstIops; + + public Iops(long minIops, long maxIops) throws Exception + { + if (minIops <= 0 || maxIops <= 0) { + throw new Exception("The 'Min IOPS' and 'Max IOPS' values must be greater than 0."); + } + + if (minIops > maxIops) { + throw new Exception("The 'Min IOPS' value cannot exceed the 'Max IOPS' value."); + } + + _minIops = minIops; + _maxIops = maxIops; + + _burstIops = getBurstIops(_maxIops); + } + + public long getMinIops() + { + return _minIops; + } + + public long getMaxIops() + { + return _maxIops; + } + + public long getBurstIops() + { + return _burstIops; + } + + private static long getBurstIops(long maxIops) + { + return (long)(maxIops * 1.5); + } + } + + private void deleteSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection) + throws StorageUnavailableException, Exception + { + 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 + } + + String mVip = sfConnection.getManagementVip(); + int mPort = sfConnection.getManagementPort(); + String clusterAdminUsername = sfConnection.getClusterAdminUsername(); + String clusterAdminPassword = sfConnection.getClusterAdminPassword(); + + long sfVolumeId = Long.parseLong(volumeInfo.getFolder()); + + SolidFireUtil.deleteSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId); + } + + private String getSfAccountName(String csAccountUuid, long csAccountId) { + return "CloudStack_" + csAccountUuid + "_" + getRandomNumber() + "_" + csAccountId; + } + + private static long getRandomNumber() + { + return Math.round(Math.random() * 1000000000); + } + + private boolean sfAccountExists(String sfAccountName, SolidFireConnection sfConnection) throws Exception { + String mVip = sfConnection.getManagementVip(); + int mPort = sfConnection.getManagementPort(); + String clusterAdminUsername = sfConnection.getClusterAdminUsername(); + String clusterAdminPassword = sfConnection.getClusterAdminPassword(); + + try { + SolidFireUtil.getSolidFireAccountByName(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfAccountName); + } + catch (Exception ex) { + return false; + } + + return true; + } + + @Override + public void createAsync(DataStore dataStore, DataObject dataObject, + AsyncCompletionCallback callback) { + String iqn = null; + String errMsg = null; + + if (dataObject.getType() == DataObjectType.VOLUME) { + try { + VolumeInfo volumeInfo = (VolumeInfo)dataObject; + AccountVO account = _accountDao.findById(volumeInfo.getAccountId()); + String sfAccountName = getSfAccountName(account.getUuid(), account.getAccountId()); + + long storagePoolId = dataStore.getId(); + SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId); + + if (!sfAccountExists(sfAccountName, sfConnection)) { + SolidFireUtil.SolidFireAccount sfAccount = createSolidFireAccount(sfAccountName, + sfConnection); + + updateCsDbWithAccountInfo(account.getId(), sfAccount); + } + + SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(volumeInfo, sfConnection); + + iqn = sfVolume.getIqn(); + + VolumeVO volume = this._volumeDao.findById(volumeInfo.getId()); + + volume.set_iScsiName(iqn); + volume.setFolder(String.valueOf(sfVolume.getId())); + volume.setPoolType(StoragePoolType.IscsiLUN); + volume.setPoolId(storagePoolId); + + _volumeDao.update(volume.getId(), volume); + + StoragePoolVO storagePool = _storagePoolDao.findById(dataStore.getId()); + + long capacityBytes = storagePool.getCapacityBytes(); + long usedBytes = storagePool.getUsedBytes(); + + usedBytes += volumeInfo.getSize(); + + if (usedBytes > capacityBytes) { + usedBytes = capacityBytes; + } + + storagePool.setUsedBytes(usedBytes); + + _storagePoolDao.update(storagePoolId, storagePool); + } catch (StorageUnavailableException e) { + s_logger.error("Failed to create volume (StorageUnavailableException)", e); + errMsg = e.toString(); + } catch (Exception e) { + s_logger.error("Failed to create volume (Exception)", e); + errMsg = e.toString(); + } + } + else { + errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync"; + } + + // path = iqn + // size is pulled from DataObject instance, if errMsg is null + CreateCmdResult result = new CreateCmdResult(iqn, new Answer(null, errMsg == null, errMsg)); + + result.setResult(errMsg); + + callback.complete(result); + } + + private void deleteSolidFireAccount(long sfAccountId, SolidFireConnection sfConnection) throws Exception { + String mVip = sfConnection.getManagementVip(); + int mPort = sfConnection.getManagementPort(); + String clusterAdminUsername = sfConnection.getClusterAdminUsername(); + String clusterAdminPassword = sfConnection.getClusterAdminPassword(); + + List sfVolumes = SolidFireUtil.getDeletedVolumes(mVip, mPort, + clusterAdminUsername, clusterAdminPassword); + + // if there are volumes for this account in the trash, delete them (so the account can be deleted) + if (sfVolumes != null) { + for (SolidFireUtil.SolidFireVolume sfVolume : sfVolumes) { + if (sfVolume.getAccountId() == sfAccountId) { + SolidFireUtil.purgeSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolume.getId()); + } + } + } + + SolidFireUtil.deleteSolidFireAccount(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfAccountId); + } + + private boolean sfAccountHasVolume(long sfAccountId, SolidFireConnection sfConnection) throws Exception { + String mVip = sfConnection.getManagementVip(); + int mPort = sfConnection.getManagementPort(); + String clusterAdminUsername = sfConnection.getClusterAdminUsername(); + String clusterAdminPassword = sfConnection.getClusterAdminPassword(); + + List sfVolumes = SolidFireUtil.getSolidFireVolumesForAccountId(mVip, mPort, + clusterAdminUsername, clusterAdminPassword, sfAccountId); + + if (sfVolumes != null) { + for (SolidFireUtil.SolidFireVolume sfVolume : sfVolumes) { + if (sfVolume.isActive()) { + return true; + } + } + } + + return false; + } + + @Override + public void deleteAsync(DataStore dataStore, DataObject dataObject, + AsyncCompletionCallback callback) { + String errMsg = null; + + if (dataObject.getType() == DataObjectType.VOLUME) { + try { + 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()); + + long storagePoolId = dataStore.getId(); + SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId); + + deleteSolidFireVolume(volumeInfo, sfConnection); + + _volumeDao.deleteVolumesByInstance(volumeInfo.getId()); + + 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()); + } + + StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); + + long usedBytes = storagePool.getUsedBytes(); + + usedBytes -= volumeInfo.getSize(); + + if (usedBytes < 0) { + usedBytes = 0; + } + + storagePool.setUsedBytes(usedBytes); + + _storagePoolDao.update(storagePoolId, storagePool); + } catch (StorageUnavailableException e) { + s_logger.error("Failed to create volume (StorageUnavailableException)", e); + errMsg = e.toString(); + } catch (Exception e) { + s_logger.error("Failed to create volume (Exception)", e); + errMsg = e.toString(); + } + } + else { + errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to deleteAsync"; + } + + CommandResult result = new CommandResult(); + + result.setResult(errMsg); + + callback.complete(result); } @Override @@ -62,5 +533,4 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { @Override public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback) { } - } 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 new file mode 100644 index 00000000000..2e25cd531db --- /dev/null +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java @@ -0,0 +1,274 @@ +/* + * 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.storage.datastore.lifecycle; + +import java.util.Map; +import java.util.StringTokenizer; + +import javax.inject.Inject; + +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; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; +import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper; + +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.agent.api.StoragePoolInfo; +import com.cloud.storage.StoragePoolAutomation; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.utils.exception.CloudRuntimeException; + +public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle { + @Inject PrimaryDataStoreDao storagePoolDao; + @Inject PrimaryDataStoreHelper dataStoreHelper; + @Inject StoragePoolAutomation storagePoolAutomation; + @Inject StoragePoolDetailsDao storagePoolDetailsDao; + @Inject DataCenterDao zoneDao; + + private static final int DEFAULT_MANAGEMENT_PORT = 443; + private static final int DEFAULT_STORAGE_PORT = 3260; + + // invoked to add primary storage that is based on the SolidFire plug-in + @Override + public DataStore initialize(Map dsInfos) { + String url = (String)dsInfos.get("url"); + Long zoneId = (Long)dsInfos.get("zoneId"); + String storagePoolName = (String) dsInfos.get("name"); + String providerName = (String)dsInfos.get("providerName"); + Long capacityBytes = (Long)dsInfos.get("capacityBytes"); + Long capacityIops = (Long)dsInfos.get("capacityIops"); + String tags = (String)dsInfos.get("tags"); + Map details = (Map)dsInfos.get("details"); + + String storageVip = getStorageVip(url); + int storagePort = getStoragePort(url); + + DataCenterVO zone = zoneDao.findById(zoneId); + + String uuid = SolidFireUtil.PROVIDER_NAME + "_" + zone.getUuid() + "_" + storageVip; + + if (capacityBytes == null || capacityBytes <= 0) { + throw new IllegalArgumentException("'capacityBytes' must be present and greater than 0."); + } + + if (capacityIops == null || capacityIops <= 0) { + throw new IllegalArgumentException("'capacityIops' must be present and greater than 0."); + } + + PrimaryDataStoreParameters parameters = new PrimaryDataStoreParameters(); + + parameters.setHost(storageVip); + parameters.setPort(storagePort); + parameters.setPath(getModifiedUrl(url)); + parameters.setType(StoragePoolType.Iscsi); + parameters.setUuid(uuid); + parameters.setZoneId(zoneId); + parameters.setName(storagePoolName); + parameters.setProviderName(providerName); + parameters.setManaged(true); + parameters.setCapacityBytes(capacityBytes); + parameters.setUsedBytes(0); + parameters.setCapacityIops(capacityIops); + parameters.setHypervisorType(HypervisorType.Any); + parameters.setTags(tags); + parameters.setDetails(details); + + String managementVip = getManagementVip(url); + int managementPort = getManagementPort(url); + + details.put(SolidFireUtil.MANAGEMENT_VIP, managementVip); + details.put(SolidFireUtil.MANAGEMENT_PORT, String.valueOf(managementPort)); + + String clusterAdminUsername = getValue(SolidFireUtil.CLUSTER_ADMIN_USERNAME, url); + String clusterAdminPassword = getValue(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, url); + + details.put(SolidFireUtil.CLUSTER_ADMIN_USERNAME, clusterAdminUsername); + details.put(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, clusterAdminPassword); + + // this adds a row in the cloud.storage_pool table for this SolidFire cluster + return dataStoreHelper.createPrimaryDataStore(parameters); + } + + // remove the clusterAdmin and password key/value pairs + private String getModifiedUrl(String originalUrl) + { + StringBuilder sb = new StringBuilder(); + + String delimiter = ";"; + + StringTokenizer st = new StringTokenizer(originalUrl, delimiter); + + while (st.hasMoreElements()) { + String token = st.nextElement().toString(); + + if (!token.startsWith(SolidFireUtil.CLUSTER_ADMIN_USERNAME) && + !token.startsWith(SolidFireUtil.CLUSTER_ADMIN_PASSWORD)) { + sb.append(token).append(delimiter); + } + } + + String modifiedUrl = sb.toString(); + int lastIndexOf = modifiedUrl.lastIndexOf(delimiter); + + if (lastIndexOf == (modifiedUrl.length() - delimiter.length())) { + return modifiedUrl.substring(0, lastIndexOf); + } + + return modifiedUrl; + } + + private String getManagementVip(String url) + { + return getVip(SolidFireUtil.MANAGEMENT_VIP, url); + } + + private String getStorageVip(String url) + { + return getVip(SolidFireUtil.STORAGE_VIP, url); + } + + private int getManagementPort(String url) + { + return getPort(SolidFireUtil.MANAGEMENT_VIP, url, DEFAULT_MANAGEMENT_PORT); + } + + private int getStoragePort(String url) + { + return getPort(SolidFireUtil.STORAGE_VIP, url, DEFAULT_STORAGE_PORT); + } + + private String getVip(String keyToMatch, String url) + { + String delimiter = ":"; + + String storageVip = getValue(keyToMatch, url); + + int index = storageVip.indexOf(delimiter); + + if (index != -1) + { + return storageVip.substring(0, index); + } + + return storageVip; + } + + private int getPort(String keyToMatch, String url, int defaultPortNumber) + { + String delimiter = ":"; + + String storageVip = getValue(keyToMatch, url); + + int index = storageVip.indexOf(delimiter); + + int portNumber = defaultPortNumber; + + if (index != -1) { + String port = storageVip.substring(index + delimiter.length()); + + try { + portNumber = Integer.parseInt(port); + } + catch (NumberFormatException ex) { + throw new IllegalArgumentException("Invalid URL format (port is not an integer)"); + } + } + + return portNumber; + } + + private String getValue(String keyToMatch, String url) + { + String delimiter1 = ";"; + String delimiter2 = "="; + + StringTokenizer st = new StringTokenizer(url, delimiter1); + + while (st.hasMoreElements()) { + String token = st.nextElement().toString(); + + int index = token.indexOf(delimiter2); + + if (index == -1) + { + throw new RuntimeException("Invalid URL format"); + } + + String key = token.substring(0, index); + + if (key.equalsIgnoreCase(keyToMatch)) { + String valueToReturn = token.substring(index + delimiter2.length()); + + return valueToReturn; + } + } + + throw new RuntimeException("Key not found in URL"); + } + + // do not implement this method for SolidFire's plug-in + @Override + public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) { + return true; // should be ignored for zone-wide-only plug-ins like SolidFire's + } + + // do not implement this method for SolidFire's plug-in + @Override + public boolean attachCluster(DataStore store, ClusterScope scope) { + return true; // should be ignored for zone-wide-only plug-ins like SolidFire's + } + + @Override + public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) { + dataStoreHelper.attachZone(dataStore); + + return true; + } + + + @Override + public boolean maintain(DataStore dataStore) { + storagePoolAutomation.maintain(dataStore); + dataStoreHelper.maintain(dataStore); + + return true; + } + + @Override + public boolean cancelMaintain(DataStore store) { + dataStoreHelper.cancelMaintain(store); + storagePoolAutomation.cancelMaintain(store); + + return true; + } + + // invoked to delete primary storage that is based on the SolidFire plug-in + @Override + public boolean deleteDataStore(DataStore store) { + return dataStoreHelper.deletePrimaryDataStore(store); + } +} diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java index 2965e8ff58e..28864ea801e 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java @@ -1,62 +1,91 @@ -// 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. +/* + * 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.storage.datastore.provider; import java.util.Map; import java.util.Set; +import java.util.HashSet; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreProvider; +import org.apache.cloudstack.storage.datastore.driver.SolidfirePrimaryDataStoreDriver; +import org.apache.cloudstack.storage.datastore.lifecycle.SolidFirePrimaryDataStoreLifeCycle; +import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; import org.springframework.stereotype.Component; +import com.cloud.utils.component.ComponentContext; + @Component public class SolidfirePrimaryDataStoreProvider implements PrimaryDataStoreProvider { - private final String name = "Solidfire Primary Data Store Provider"; + protected DataStoreLifeCycle lifecycle; + protected PrimaryDataStoreDriver driver; + protected HypervisorHostListener listener; + + SolidfirePrimaryDataStoreProvider() { + + } @Override public String getName() { - return name; + return SolidFireUtil.PROVIDER_NAME; } @Override public DataStoreLifeCycle getDataStoreLifeCycle() { - return null; + return lifecycle; } @Override - public DataStoreDriver getDataStoreDriver() { - return null; + public PrimaryDataStoreDriver getDataStoreDriver() { + return driver; } @Override public HypervisorHostListener getHostListener() { - return null; + return listener; } @Override public boolean configure(Map params) { - return false; + lifecycle = ComponentContext.inject(SolidFirePrimaryDataStoreLifeCycle.class); + driver = ComponentContext.inject(SolidfirePrimaryDataStoreDriver.class); + listener = ComponentContext.inject(new HypervisorHostListener() { + public boolean hostConnect(long hostId, long poolId) { + return true; + } + + public boolean hostDisconnected(long hostId, long poolId) { + return true; + } + }); + + return true; } @Override public Set getTypes() { - return null; - } + Set types = new HashSet(); + types.add(DataStoreProviderType.PRIMARY); + + return types; + } } 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 new file mode 100644 index 00000000000..26766e8dd70 --- /dev/null +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java @@ -0,0 +1,917 @@ +// 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.storage.datastore.util; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URI; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.ArrayList; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.BasicClientConnectionManager; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class SolidFireUtil +{ + public static final String PROVIDER_NAME = "SolidFire"; + + public static final String MANAGEMENT_VIP = "mVip"; + public static final String STORAGE_VIP = "sVip"; + + public static final String MANAGEMENT_PORT = "mPort"; + public static final String STORAGE_PORT = "sPort"; + + public static final String CLUSTER_ADMIN_USERNAME = "clusterAdminUsername"; + public static final String CLUSTER_ADMIN_PASSWORD = "clusterAdminPassword"; + + public static final String ACCOUNT_ID = "accountId"; + + public static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername"; + public static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret"; + + public static final String CHAP_TARGET_USERNAME = "chapTargetUsername"; + public static final String CHAP_TARGET_SECRET = "chapTargetSecret"; + + public static long createSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, + String strSfVolumeName, long lSfAccountId, long lTotalSize, boolean bEnable512e, + long lMinIops, long lMaxIops, long lBurstIops) throws Exception + { + final Gson gson = new GsonBuilder().create(); + + VolumeToCreate volumeToCreate = new VolumeToCreate(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, + lMinIops, lMaxIops, lBurstIops); + + String strVolumeToCreateJson = gson.toJson(volumeToCreate); + + String strVolumeCreateResultJson = executeJsonRpc(strVolumeToCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + + VolumeCreateResult volumeCreateResult = gson.fromJson(strVolumeCreateResultJson, VolumeCreateResult.class); + + verifyResult(volumeCreateResult.result, strVolumeCreateResultJson, gson); + + return volumeCreateResult.result.volumeID; + } + + public static void deleteSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) throws Exception + { + 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) throws Exception + { + 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) throws Exception + { + final Gson gson = new GsonBuilder().create(); + + VolumeToGet volumeToGet = new VolumeToGet(lVolumeId); + + String strVolumeToGetJson = gson.toJson(volumeToGet); + + String strVolumeGetResultJson = executeJsonRpc(strVolumeToGetJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + + VolumeGetResult volumeGetResult = gson.fromJson(strVolumeGetResultJson, VolumeGetResult.class); + + verifyResult(volumeGetResult.result, strVolumeGetResultJson, gson); + + String strVolumeName = getVolumeName(volumeGetResult, lVolumeId); + String strVolumeIqn = getVolumeIqn(volumeGetResult, lVolumeId); + long lAccountId = getVolumeAccountId(volumeGetResult, lVolumeId); + String strVolumeStatus = getVolumeStatus(volumeGetResult, lVolumeId); + + return new SolidFireVolume(lVolumeId, strVolumeName, strVolumeIqn, lAccountId, strVolumeStatus); + } + + public static List getSolidFireVolumesForAccountId(String strSfMvip, int iSfPort, + String strSfAdmin, String strSfPassword, long lAccountId) throws Exception + { + final Gson gson = new GsonBuilder().create(); + + VolumesToGetForAccount volumesToGetForAccount = new VolumesToGetForAccount(lAccountId); + + String strVolumesToGetForAccountJson = gson.toJson(volumesToGetForAccount); + + String strVolumesGetForAccountResultJson = executeJsonRpc(strVolumesToGetForAccountJson, strSfMvip, iSfPort, + strSfAdmin, strSfPassword); + + VolumeGetResult volumeGetResult = gson.fromJson(strVolumesGetForAccountResultJson, VolumeGetResult.class); + + verifyResult(volumeGetResult.result, strVolumesGetForAccountResultJson, gson); + + 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)); + } + + return sfVolumes; + } + + private static final String ACTIVE = "active"; + + public static class SolidFireVolume + { + private final long _id; + private final String _name; + private final String _iqn; + private final long _accountId; + private final String _status; + + public SolidFireVolume(long id, String name, String iqn, + long accountId, String status) + { + _id = id; + _name = name; + _iqn = "/" + iqn + "/0"; + _accountId = accountId; + _status = status; + } + + public long getId() + { + return _id; + } + + public String getName() + { + return _name; + } + + public String getIqn() + { + return _iqn; + } + + public long getAccountId() + { + return _accountId; + } + + public boolean isActive() + { + return ACTIVE.equalsIgnoreCase(_status); + } + + @Override + public int hashCode() { + return (int)_id; + } + + @Override + public String toString() { + return _name; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof SolidFireVolume)) { + return false; + } + + SolidFireVolume sfv = (SolidFireVolume)obj; + + if (_id == sfv._id && _name.equals(sfv._name) && + _iqn.equals(sfv._iqn) && isActive() == sfv.isActive()) { + return true; + } + + return false; + } + } + + public static long createSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, + String strAccountName) throws Exception + { + final Gson gson = new GsonBuilder().create(); + + AccountToAdd accountToAdd = new AccountToAdd(strAccountName); + + String strAccountAddJson = gson.toJson(accountToAdd); + + String strAccountAddResultJson = executeJsonRpc(strAccountAddJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + + AccountAddResult accountAddResult = gson.fromJson(strAccountAddResultJson, AccountAddResult.class); + + verifyResult(accountAddResult.result, strAccountAddResultJson, gson); + + return accountAddResult.result.accountID; + } + + public static void deleteSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, + long lAccountId) throws Exception + { + 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) throws Exception + { + final Gson gson = new GsonBuilder().create(); + + AccountToGetById accountToGetById = new AccountToGetById(lSfAccountId); + + String strAccountToGetByIdJson = gson.toJson(accountToGetById); + + String strAccountGetByIdResultJson = executeJsonRpc(strAccountToGetByIdJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + + AccountGetResult accountGetByIdResult = gson.fromJson(strAccountGetByIdResultJson, AccountGetResult.class); + + verifyResult(accountGetByIdResult.result, strAccountGetByIdResultJson, gson); + + String strSfAccountName = accountGetByIdResult.result.account.username; + String strSfAccountInitiatorSecret = accountGetByIdResult.result.account.initiatorSecret; + String strSfAccountTargetSecret = accountGetByIdResult.result.account.targetSecret; + + return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret); + } + + public static SolidFireAccount getSolidFireAccountByName(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, + String strSfAccountName) throws Exception + { + final Gson gson = new GsonBuilder().create(); + + AccountToGetByName accountToGetByName = new AccountToGetByName(strSfAccountName); + + String strAccountToGetByNameJson = gson.toJson(accountToGetByName); + + String strAccountGetByNameResultJson = executeJsonRpc(strAccountToGetByNameJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + + AccountGetResult accountGetByNameResult = gson.fromJson(strAccountGetByNameResultJson, AccountGetResult.class); + + verifyResult(accountGetByNameResult.result, strAccountGetByNameResultJson, gson); + + long lSfAccountId = accountGetByNameResult.result.account.accountID; + String strSfAccountInitiatorSecret = accountGetByNameResult.result.account.initiatorSecret; + String strSfAccountTargetSecret = accountGetByNameResult.result.account.targetSecret; + + return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret); + } + + public static class SolidFireAccount + { + private final long _id; + private final String _name; + private final String _initiatorSecret; + private final String _targetSecret; + + public SolidFireAccount(long id, String name, String initiatorSecret, String targetSecret) + { + _id = id; + _name = name; + _initiatorSecret = initiatorSecret; + _targetSecret = targetSecret; + } + + public long getId() + { + return _id; + } + + public String getName() + { + return _name; + } + + public String getInitiatorSecret() + { + return _initiatorSecret; + } + + public String getTargetSecret() + { + return _targetSecret; + } + + @Override + public int hashCode() { + return (int)_id; + } + + @Override + public String toString() { + return _name; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof SolidFireAccount)) { + return false; + } + + 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) throws Exception + { + 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)); + } + + return deletedVolumes; + } + + public static long createSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strVagName) throws Exception + { + final Gson gson = new GsonBuilder().create(); + + VagToCreate vagToCreate = new VagToCreate(strVagName); + + String strVagCreateJson = gson.toJson(vagToCreate); + + String strVagCreateResultJson = executeJsonRpc(strVagCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + + VagCreateResult vagCreateResult = gson.fromJson(strVagCreateResultJson, VagCreateResult.class); + + verifyResult(vagCreateResult.result, strVagCreateResultJson, gson); + + return vagCreateResult.result.volumeAccessGroupID; + } + + public static void deleteSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId) throws Exception + { + final Gson gson = new GsonBuilder().create(); + + VagToDelete vagToDelete = new VagToDelete(lVagId); + + String strVagToDeleteJson = gson.toJson(vagToDelete); + + executeJsonRpc(strVagToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + } + + @SuppressWarnings("unused") + private static final class VolumeToCreate + { + private final String method = "CreateVolume"; + private final VolumeToCreateParams params; + + private VolumeToCreate(final String strVolumeName, final long lAccountId, final long lTotalSize, + final boolean bEnable512e, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) + { + params = new VolumeToCreateParams(strVolumeName, lAccountId, lTotalSize, bEnable512e, + lMinIOPS, lMaxIOPS, lBurstIOPS); + } + + private static final class VolumeToCreateParams + { + private final String name; + private final long accountID; + private final long totalSize; + private final boolean enable512e; + private final VolumeToCreateParamsQoS qos; + + private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize, + final boolean bEnable512e, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) + { + name = strVolumeName; + accountID = lAccountId; + totalSize = lTotalSize; + enable512e = bEnable512e; + + qos = new VolumeToCreateParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS); + } + + private static final class VolumeToCreateParamsQoS + { + private final long minIOPS; + private final long maxIOPS; + private final long burstIOPS; + + private VolumeToCreateParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) + { + minIOPS = lMinIOPS; + maxIOPS = lMaxIOPS; + burstIOPS = lBurstIOPS; + } + } + } + } + + @SuppressWarnings("unused") + private static final class VolumeToDelete + { + private final String method = "DeleteVolume"; + private final VolumeToDeleteParams params; + + private VolumeToDelete(final long lVolumeId) + { + params = new VolumeToDeleteParams(lVolumeId); + } + + private static final class VolumeToDeleteParams + { + private long volumeID; + + private VolumeToDeleteParams(final long lVolumeId) + { + volumeID = lVolumeId; + } + } + } + + @SuppressWarnings("unused") + private static final class ListDeletedVolumes + { + private final String method = "ListDeletedVolumes"; + } + + @SuppressWarnings("unused") + private static final class VolumeToPurge + { + private final String method = "PurgeDeletedVolume"; + private final VolumeToPurgeParams params; + + private VolumeToPurge(final long lVolumeId) + { + params = new VolumeToPurgeParams(lVolumeId); + } + + private static final class VolumeToPurgeParams + { + private long volumeID; + + private VolumeToPurgeParams(final long lVolumeId) + { + volumeID = lVolumeId; + } + } + } + + @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 AccountToAdd + { + private final String method = "AddAccount"; + private final AccountToAddParams params; + + private AccountToAdd(final String strAccountName) + { + params = new AccountToAddParams(strAccountName); + } + + private static final class AccountToAddParams + { + private final String username; + + private AccountToAddParams(final String strAccountName) + { + username = strAccountName; + } + } + } + + @SuppressWarnings("unused") + private static final class AccountToRemove + { + private final String method = "RemoveAccount"; + private final AccountToRemoveParams params; + + private AccountToRemove(final long lAccountId) + { + params = new AccountToRemoveParams(lAccountId); + } + + private static final class AccountToRemoveParams + { + private long accountID; + + private AccountToRemoveParams(final long lAccountId) + { + accountID = lAccountId; + } + } + } + + @SuppressWarnings("unused") + private static final class AccountToGetById + { + private final String method = "GetAccountByID"; + private final AccountToGetByIdParams params; + + private AccountToGetById(final long lAccountId) + { + params = new AccountToGetByIdParams(lAccountId); + } + + private static final class AccountToGetByIdParams + { + private final long accountID; + + private AccountToGetByIdParams(final long lAccountId) + { + accountID = lAccountId; + } + } + } + + @SuppressWarnings("unused") + private static final class AccountToGetByName + { + private final String method = "GetAccountName"; + private final AccountToGetByNameParams params; + + private AccountToGetByName(final String strUsername) + { + params = new AccountToGetByNameParams(strUsername); + } + + private static final class AccountToGetByNameParams + { + private final String username; + + private AccountToGetByNameParams(final String strUsername) + { + username = strUsername; + } + } + } + + @SuppressWarnings("unused") + private static final class VagToCreate + { + private final String method = "CreateVolumeAccessGroup"; + private final VagToCreateParams params; + + private VagToCreate(final String strVagName) + { + params = new VagToCreateParams(strVagName); + } + + private static final class VagToCreateParams + { + private final String name; + + private VagToCreateParams(final String strVagName) + { + name = strVagName; + } + } + } + + @SuppressWarnings("unused") + private static final class VagToDelete + { + private final String method = "DeleteVolumeAccessGroup"; + private final VagToDeleteParams params; + + private VagToDelete(final long lVagId) + { + params = new VagToDeleteParams(lVagId); + } + + private static final class VagToDeleteParams + { + private long volumeAccessGroupID; + + private VagToDeleteParams(final long lVagId) + { + volumeAccessGroupID = lVagId; + } + } + } + + private static final class VolumeCreateResult + { + private Result result; + + private static final class Result + { + private long volumeID; + } + } + + private static final class VolumeGetResult + { + private Result result; + + private static final class Result + { + private Volume[] volumes; + + private static final class Volume + { + private long volumeID; + private String name; + private String iqn; + private long accountID; + private String status; + } + } + } + + private static final class AccountAddResult + { + private Result result; + + private static final class Result + { + private long accountID; + } + } + + private static final class AccountGetResult + { + private Result result; + + private static final class Result + { + private Account account; + + private static final class Account + { + private long accountID; + private String username; + private String initiatorSecret; + private String targetSecret; + } + } + } + + private static final class VagCreateResult + { + private Result result; + + private static final class Result + { + private long volumeAccessGroupID; + } + } + + private static final class JsonError + { + private Error error; + + private static final class Error + { + private String message; + } + } + + private static DefaultHttpClient getHttpClient(int iPort) throws NoSuchAlgorithmException, KeyManagementException { + SSLContext sslContext = SSLContext.getInstance("SSL"); + X509TrustManager tm = new X509TrustManager() { + public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + + sslContext.init(null, new TrustManager[] { tm }, new SecureRandom()); + + SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + SchemeRegistry registry = new SchemeRegistry(); + + registry.register(new Scheme("https", iPort, socketFactory)); + + BasicClientConnectionManager mgr = new BasicClientConnectionManager(registry); + DefaultHttpClient client = new DefaultHttpClient(); + + return new DefaultHttpClient(mgr, client.getParams()); + } + + private static String executeJsonRpc(String strJsonToExecute, String strMvip, int iPort, + String strAdmin, String strPassword) throws Exception + { + DefaultHttpClient httpClient = null; + StringBuilder sb = new StringBuilder(); + + try + { + StringEntity input = new StringEntity(strJsonToExecute); + + input.setContentType("application/json"); + + httpClient = getHttpClient(iPort); + + URI uri = new URI("https://" + strMvip + ":" + iPort + "/json-rpc/1.0"); + AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_SCHEME); + UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(strAdmin, strPassword); + + httpClient.getCredentialsProvider().setCredentials(authScope, credentials); + + HttpPost postRequest = new HttpPost(uri); + + postRequest.setEntity(input); + + HttpResponse response = httpClient.execute(postRequest); + + if (!isSuccess(response.getStatusLine().getStatusCode())) + { + throw new RuntimeException("Failed on JSON-RPC API call. HTTP error code = " + response.getStatusLine().getStatusCode()); + } + + BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); + + String strOutput; + + + while ((strOutput = br.readLine()) != null) + { + sb.append(strOutput); + } + } finally { + if (httpClient != null) { + try { + httpClient.getConnectionManager().shutdown(); + } catch (Throwable t) {} + } + } + + return sb.toString(); + } + + private static boolean isSuccess(int iCode) { + return iCode >= 200 && iCode < 300; + } + + private static void verifyResult(Object obj, String strJson, Gson gson) throws IllegalStateException + { + if (obj != null) + { + return; + } + + JsonError jsonError = gson.fromJson(strJson, JsonError.class); + + if (jsonError != null) + { + throw new IllegalStateException(jsonError.error.message); + } + + throw new IllegalStateException("Problem with the following JSON: " + strJson); + } + + private static String getVolumeName(VolumeGetResult volumeGetResult, long lVolumeId) throws Exception + { + if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && + volumeGetResult.result.volumes[0].volumeID == lVolumeId) + { + return volumeGetResult.result.volumes[0].name; + } + + throw new Exception("Could not determine the name of the volume, " + + "but the volume was created with an ID of " + lVolumeId + "."); + } + + private static String getVolumeIqn(VolumeGetResult volumeGetResult, long lVolumeId) throws Exception + { + if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && + volumeGetResult.result.volumes[0].volumeID == lVolumeId) + { + return volumeGetResult.result.volumes[0].iqn; + } + + throw new Exception("Could not determine the IQN of the volume, " + + "but the volume was created with an ID of " + lVolumeId + "."); + } + + private static long getVolumeAccountId(VolumeGetResult volumeGetResult, long lVolumeId) throws Exception + { + if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && + volumeGetResult.result.volumes[0].volumeID == lVolumeId) + { + return volumeGetResult.result.volumes[0].accountID; + } + + throw new Exception("Could not determine the volume's account ID, " + + "but the volume was created with an ID of " + lVolumeId + "."); + } + + private static String getVolumeStatus(VolumeGetResult volumeGetResult, long lVolumeId) throws Exception + { + if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && + volumeGetResult.result.volumes[0].volumeID == lVolumeId) + { + return volumeGetResult.result.volumes[0].status; + } + + throw new Exception("Could not determine the status of the volume, " + + "but the volume was created with an ID of " + lVolumeId + "."); + } +} diff --git a/server/src/com/cloud/acl/DomainChecker.java b/server/src/com/cloud/acl/DomainChecker.java index c778c501b82..8b20f3def5b 100755 --- a/server/src/com/cloud/acl/DomainChecker.java +++ b/server/src/com/cloud/acl/DomainChecker.java @@ -19,11 +19,11 @@ package com.cloud.acl; import javax.ejb.Local; import javax.inject.Inject; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.api.BaseCmd; +import org.springframework.stereotype.Component; + import com.cloud.dc.DataCenter; import com.cloud.domain.Domain; import com.cloud.domain.dao.DomainDao; @@ -95,6 +95,10 @@ public class DomainChecker extends AdapterBase implements SecurityChecker { if (BaseCmd.isRootAdmin(caller.getType()) || (owner.getId() == caller.getId())) { return true; } + //special handling for the project case + if (owner.getType() == Account.ACCOUNT_TYPE_PROJECT && _projectMgr.canAccessProjectAccount(caller, owner.getId())) { + return true; + } // since the current account is not the owner of the template, check the launch permissions table to see if the // account can launch a VM from this template diff --git a/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java index 7022ee60fbb..385ca3625dc 100644 --- a/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java @@ -67,6 +67,8 @@ public class DiskOfferingJoinDaoImpl extends GenericDaoBase im + private String getTemplateStatus(TemplateJoinVO template){ + boolean isAdmin = false; + Account caller = CallContext.current().getCallingAccount(); + if ((caller == null) || BaseCmd.isAdmin(caller.getType())) { + isAdmin = true; + } + + // If the user is an Admin, add the template download status + String templateStatus = null; + if (isAdmin || caller.getId() == template.getAccountId()) { + // add download status + if (template.getDownloadState() != Status.DOWNLOADED) { + templateStatus = "Processing"; + if (template.getDownloadState() == VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS) { + if (template.getDownloadPercent() == 100) { + templateStatus = "Installing Template"; + } else { + templateStatus = template.getDownloadPercent() + "% Downloaded"; + } + } else { + templateStatus = template.getErrorString(); + } + } else if (template.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) { + templateStatus = "Download Complete"; + } else { + templateStatus = "Successfully Installed"; + } + } + return templateStatus; + } @Override public TemplateResponse newTemplateResponse(TemplateJoinVO template) { @@ -137,33 +167,10 @@ public class TemplateJoinDaoImpl extends GenericDaoBase im templateResponse.setDomainName(template.getDomainName()); - - boolean isAdmin = false; - Account caller = CallContext.current().getCallingAccount(); - if ((caller == null) || BaseCmd.isAdmin(caller.getType())) { - isAdmin = true; - } - // If the user is an Admin, add the template download status - if (isAdmin || caller.getId() == template.getAccountId()) { - // add download status - if (template.getDownloadState() != Status.DOWNLOADED) { - String templateStatus = "Processing"; - if (template.getDownloadState() == VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS) { - if (template.getDownloadPercent() == 100) { - templateStatus = "Installing Template"; - } else { - templateStatus = template.getDownloadPercent() + "% Downloaded"; - } - } else { - templateStatus = template.getErrorString(); - } + String templateStatus = getTemplateStatus(template); + if ( templateStatus != null ){ templateResponse.setStatus(templateStatus); - } else if (template.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) { - templateResponse.setStatus("Download Complete"); - } else { - templateResponse.setStatus("Successfully Installed"); - } } Long templateSize = template.getSize(); @@ -180,6 +187,17 @@ public class TemplateJoinDaoImpl extends GenericDaoBase im // set template zone information if (template.getDataCenterId() > 0 ){ TemplateZoneResponse tmplZoneResp = new TemplateZoneResponse(template.getDataCenterUuid(), template.getDataCenterName()); + tmplZoneResp.setCreated(template.getCreatedOnStore()); + if ( template.getFormat() == Storage.ImageFormat.BAREMETAL ){ + // for baremetal template, we didn't download, but is ready to use. + tmplZoneResp.setReady(true); + } + else{ + tmplZoneResp.setReady(template.getState() == ObjectInDataStoreStateMachine.State.Ready); + } + if ( templateStatus != null ){ + tmplZoneResp.setStatus(templateStatus); + } templateResponse.addZone(tmplZoneResp); // set the first found associated zone directly in TemplateResponse templateResponse.setZoneId(template.getDataCenterUuid()); @@ -260,6 +278,18 @@ public class TemplateJoinDaoImpl extends GenericDaoBase im // update template zone information if (template.getDataCenterId() > 0 ){ TemplateZoneResponse tmplZoneResp = new TemplateZoneResponse(template.getDataCenterUuid(), template.getDataCenterName()); + tmplZoneResp.setCreated(template.getCreatedOnStore()); + if ( template.getFormat() == Storage.ImageFormat.BAREMETAL ){ + // for baremetal template, we didn't download, but is ready to use. + tmplZoneResp.setReady(true); + } + else{ + tmplZoneResp.setReady(template.getState() == ObjectInDataStoreStateMachine.State.Ready); + } + String templateStatus = getTemplateStatus(template); + if ( templateStatus != null ){ + tmplZoneResp.setStatus(templateStatus); + } templateResponse.addZone(tmplZoneResp); if (templateResponse.getZoneId() == null) { // set the first found associated zone directly in diff --git a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java index 562cf65c6b9..6a8ae547601 100644 --- a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java @@ -102,6 +102,9 @@ public class VolumeJoinDaoImpl extends GenericDaoBase implem // Show the virtual size of the volume volResponse.setSize(volume.getSize()); + volResponse.setMinIops(volume.getMinIops()); + volResponse.setMaxIops(volume.getMaxIops()); + volResponse.setCreated(volume.getCreated()); volResponse.setState(volume.getState().toString()); if (volume.getState() == Volume.State.UploadOp) { diff --git a/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java b/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java index 2336a48ad14..58e8370644c 100644 --- a/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java +++ b/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java @@ -61,6 +61,15 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity, @Column(name="customized") private boolean customized; + @Column(name="customized_iops") + private Boolean customizedIops; + + @Column(name="min_iops") + private Long minIops; + + @Column(name="max_iops") + private Long maxIops; + @Column(name="sort_key") int sortKey; @@ -179,6 +188,30 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity, this.customized = customized; } + public Boolean isCustomizedIops() { + return customizedIops; + } + + public void setCustomizedIops(Boolean customizedIops) { + this.customizedIops = customizedIops; + } + + public Long getMinIops() { + return minIops; + } + + public void setMinIops(Long minIops) { + this.minIops = minIops; + } + + public Long getMaxIops() { + return maxIops; + } + + public void setMaxIops(Long maxIops) { + this.maxIops = maxIops; + } + public boolean isDisplayOffering() { return displayOffering; } diff --git a/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java b/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java index c0d5ee990a5..69f2204d0e3 100644 --- a/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java +++ b/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java @@ -60,7 +60,6 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I @Column(name="host_address") private String hostAddress; - @Column(name="status") @Enumerated(value=EnumType.STRING) private StoragePoolStatus status; @@ -109,7 +108,6 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I @Column(name="pod_name") private String podName; - @Column(name="tag") private String tag; @@ -119,7 +117,6 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I @Column(name="disk_reserved_capacity") private long reservedCapacity; - @Column(name="job_id") private Long jobId; @@ -133,6 +130,8 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I @Enumerated(value = EnumType.STRING) private ScopeType scope; + @Column(name="capacity_iops") + private Long capacityIops; @Column(name = "hypervisor") @Enumerated(value = EnumType.STRING) @@ -243,6 +242,14 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I this.capacityBytes = capacityBytes; } + public Long getCapacityIops() { + return capacityIops; + } + + public void setCapacityIops(Long capacityIops) { + this.capacityIops = capacityIops; + } + public long getClusterId() { return clusterId; } diff --git a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java index 1f07f52973a..701e195461d 100644 --- a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java +++ b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java @@ -58,6 +58,12 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity { @Column(name = "size") long size; + @Column(name = "min_iops") + Long minIops; + + @Column(name = "max_iops") + Long maxIops; + @Column(name = "state") @Enumerated(value = EnumType.STRING) private Volume.State state; @@ -337,14 +343,27 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity { this.size = size; } + public Long getMinIops() { + return minIops; + } + public void setMinIops(Long minIops) { + this.minIops = minIops; + } + + public Long getMaxIops() { + return maxIops; + } + + public void setMaxIops(Long maxIops) { + this.maxIops = maxIops; + } public Volume.State getState() { return state; } - public void setState(Volume.State state) { this.state = state; } diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index b2423b73d1c..df75d60849f 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -203,7 +203,7 @@ public enum Config { CPUOverprovisioningFactor("Advanced", ManagementServer.class, String.class, "cpu.overprovisioning.factor", "1", "Used for CPU overprovisioning calculation; available CPU will be (actualCpuCapacity * cpu.overprovisioning.factor)", null, ConfigurationParameterScope.cluster.toString()), MemOverprovisioningFactor("Advanced", ManagementServer.class, String.class, "mem.overprovisioning.factor", "1", "Used for memory overprovisioning calculation", null, ConfigurationParameterScope.cluster.toString()), LinkLocalIpNums("Advanced", ManagementServer.class, Integer.class, "linkLocalIp.nums", "10", "The number of link local ip that needed by domR(in power of 2)", null), - HypervisorList("Advanced", ManagementServer.class, String.class, "hypervisor.list", HypervisorType.KVM + "," + HypervisorType.XenServer + "," + HypervisorType.VMware + "," + HypervisorType.BareMetal + "," + HypervisorType.Ovm + "," + HypervisorType.LXC, "The list of hypervisors that this deployment will use.", "hypervisorList"), + HypervisorList("Advanced", ManagementServer.class, String.class, "hypervisor.list", HypervisorType.Hyperv + "," + HypervisorType.KVM + "," + HypervisorType.XenServer + "," + HypervisorType.VMware + "," + HypervisorType.BareMetal + "," + HypervisorType.Ovm + "," + HypervisorType.LXC, "The list of hypervisors that this deployment will use.", "hypervisorList"), ManagementHostIPAdr("Advanced", ManagementServer.class, String.class, "host", "localhost", "The ip address of management server", null), ManagementNetwork("Advanced", ManagementServer.class, String.class, "management.network.cidr", null, "The cidr of management server network", null), EventPurgeDelay("Advanced", ManagementServer.class, Integer.class, "event.purge.delay", "15", "Events older than specified number days will be purged. Set this value to 0 to never delete events", null), diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index 831b2c8697d..9bbd5379da2 100755 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -101,13 +101,17 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * @param isCustomized * @param localStorageRequired * @param isDisplayOfferingEnabled + * @param isCustomizedIops (is admin allowing users to set custom iops?) + * @param minIops + * @param maxIops * @param bytesReadRate * @param bytesWriteRate * @param iopsReadRate * @param iopsWriteRate * @return newly created disk offering */ - DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired, boolean isDisplayOfferingEnabled, + DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, + boolean localStorageRequired, boolean isDisplayOfferingEnabled, Boolean isCustomizedIops, Long minIops, Long maxIops, Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate); /** diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index a27c103c47e..e1a35ac843b 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -129,7 +129,6 @@ import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; @@ -148,7 +147,6 @@ import com.cloud.network.NetworkService; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PhysicalNetwork; -import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; @@ -2307,7 +2305,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Override @ActionEvent(eventType = EventTypes.EVENT_DISK_OFFERING_CREATE, eventDescription = "creating disk offering") - public DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired, boolean isDisplayOfferingEnabled, + public DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, + boolean localStorageRequired, boolean isDisplayOfferingEnabled, Boolean isCustomizedIops, Long minIops, Long maxIops, Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate) { long diskSize = 0;// special case for custom disk offerings if (numGibibytes != null && (numGibibytes <= 0)) { @@ -2324,8 +2323,44 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati isCustomized = true; } + if (isCustomizedIops != null) { + bytesReadRate = null; + bytesWriteRate = null; + iopsReadRate = null; + iopsWriteRate = null; + + if (isCustomizedIops) { + minIops = null; + maxIops = null; + } + else { + if (minIops == null && maxIops == null) { + minIops = 0L; + maxIops = 0L; + } + else { + if (minIops == null || minIops <= 0) { + throw new InvalidParameterValueException("The min IOPS must be greater than 0."); + } + + if (maxIops == null) { + maxIops = 0L; + } + + if (minIops > maxIops) { + throw new InvalidParameterValueException("The min IOPS must be less than or equal to the max IOPS."); + } + } + } + } + else { + minIops = null; + maxIops = null; + } + tags = cleanupTags(tags); - DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, diskSize, tags, isCustomized); + DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, diskSize, tags, isCustomized, + isCustomizedIops, minIops, maxIops); newDiskOffering.setUseLocalStorage(localStorageRequired); newDiskOffering.setDisplayOffering(isDisplayOfferingEnabled); CallContext.current().setEventDetails("Disk offering id=" + newDiskOffering.getId()); @@ -2365,7 +2400,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati Long domainId = cmd.getDomainId(); if (!isCustomized && numGibibytes == null) { - throw new InvalidParameterValueException("Disksize is required for non-customized disk offering"); + throw new InvalidParameterValueException("Disksize is required for a non-customized disk offering"); } boolean localStorageRequired = false; @@ -2379,11 +2414,17 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } + Boolean isCustomizedIops = cmd.isCustomizedIops(); + Long minIops = cmd.getMinIops(); + Long maxIops = cmd.getMaxIops(); Long bytesReadRate = cmd.getBytesReadRate(); Long bytesWriteRate = cmd.getBytesWriteRate(); Long iopsReadRate = cmd.getIopsReadRate(); Long iopsWriteRate = cmd.getIopsWriteRate(); - return createDiskOffering(domainId, name, description, numGibibytes, tags, isCustomized, localStorageRequired, isDisplayOfferingEnabled, bytesReadRate, bytesWriteRate, iopsReadRate, iopsWriteRate); + + return createDiskOffering(domainId, name, description, numGibibytes, tags, isCustomized, + localStorageRequired, isDisplayOfferingEnabled, isCustomizedIops, minIops, maxIops, + bytesReadRate, bytesWriteRate, iopsReadRate, iopsWriteRate); } @Override @@ -3145,11 +3186,13 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return vlan; } - public boolean removeFromDb (long vlanDbId){ - if (!deletePublicIPRange(vlanDbId)) { - return false; - } - return _vlanDao.expunge(vlanDbId); + @DB + public void deleteVLANFromDb(long vlanDbId) throws SQLException { + Transaction txn = Transaction.currentTxn(); + txn.start(); + _publicIpAddressDao.deletePublicIPRange(vlanDbId); + _vlanDao.expunge(vlanDbId); + txn.commit(); } @Override @@ -3233,34 +3276,31 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati .getVlanType().toString(), ip.getSystem(), ip.getClass().getName(), ip.getUuid()); } } + try { if (_networkModel.areServicesSupportedInNetwork(vlanRange.getNetworkId(), Service.Dhcp)) { Network network = _networkDao.findById(vlanRange.getNetworkId()); DhcpServiceProvider dhcpServiceProvider = _networkMgr.getDhcpServiceProvider(network); if (!dhcpServiceProvider.getProvider().getName().equalsIgnoreCase(Provider.VirtualRouter.getName())) { - Transaction txn = Transaction.currentTxn(); - txn.start(); - if (!removeFromDb(vlanDbId)) { - txn.rollback(); - txn.close(); - return false; + deleteVLANFromDb(vlanDbId); + } else { + return handleIpAliasDeletion(vlanRange, vlanDbId, dhcpServiceProvider, network); } - - else { - txn.commit(); - } - txn.close(); } else { - return handleIpAliasDeletion(vlanRange, vlanDbId, dhcpServiceProvider, network); + deleteVLANFromDb(vlanDbId); } } + catch ( SQLException e) { + throw new CloudRuntimeException(e.getMessage()); + } + } return true; } - private boolean handleIpAliasDeletion(VlanVO vlanRange, long vlanDbId, DhcpServiceProvider dhcpServiceProvider, Network network) { - boolean result_final = false; + @DB + private boolean handleIpAliasDeletion(VlanVO vlanRange, long vlanDbId, DhcpServiceProvider dhcpServiceProvider, Network network) throws SQLException { Transaction txn = Transaction.currentTxn(); txn.start(); IPAddressVO ip = null; @@ -3270,87 +3310,52 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati //search if the vlan has any allocated ips. allocIpCount = _publicIpAddressDao.countIPs(vlanRange.getDataCenterId(), vlanDbId, true); if (allocIpCount > 1) { - throw new InvalidParameterValueException ("cannot delete this range as some of the vlans are in use."); + throw new InvalidParameterValueException ("Cannot delete this range as some of the vlans are in use."); } - if (allocIpCount == 0){ - result_final=true; + else if (allocIpCount == 0){ + deleteVLANFromDb(vlanDbId); } else { ipAlias = _nicIpAliasDao.findByGatewayAndNetworkIdAndState(vlanRange.getVlanGateway(), vlanRange.getNetworkId(), NicIpAlias.state.active); - ipAlias.setState(NicIpAlias.state.revoked); - _nicIpAliasDao.update(ipAlias.getId(), ipAlias); + if (ipAlias == null) { + throw new InvalidParameterValueException ("Cannot delete this range as some of the Ips are in use."); + } + //check if this ip belongs to this vlan and is allocated. ip = _publicIpAddressDao.findByIpAndVlanId(ipAlias.getIp4Address(), vlanDbId); if (ip != null && ip.getState() == IpAddress.State.Allocated) { //check if there any other vlan ranges in the same subnet having free ips List vlanRanges = _vlanDao.listVlansByNetworkIdAndGateway(vlanRange.getNetworkId(), vlanRange.getVlanGateway()); //if there is no other vlanrage in this subnet. free the ip and delete the vlan. - if (vlanRanges.size() == 1){ - boolean result = dhcpServiceProvider.removeDhcpSupportForSubnet(network); - if (result == false) { - result_final = false; + if (vlanRanges.size() == 1) { + ipAlias.setState(NicIpAlias.state.revoked); + _nicIpAliasDao.update(ipAlias.getId(), ipAlias); + if (!dhcpServiceProvider.removeDhcpSupportForSubnet(network)) { s_logger.debug("Failed to delete the vlan range as we could not free the ip used to provide the dhcp service."); - } else { - _publicIpAddressDao.unassignIpAddress(ip.getId()); - result_final = true; - } - } else { - // if there are more vlans in the subnet check if there - // are free ips. - List vlanDbIdList = new ArrayList(); - for (VlanVO vlanrange : vlanRanges) { - if (vlanrange.getId() != vlanDbId) { - vlanDbIdList.add(vlanrange.getId()); - } - } - s_logger.info("vlan Range" - + vlanRange.getId() - + " id being deleted, one of the Ips in this range is used to provide the dhcp service, trying to free this ip and allocate a new one."); - for (VlanVO vlanrange : vlanRanges) { - if (vlanrange.getId() != vlanDbId) { - - long freeIpsInsubnet = _publicIpAddressDao.countFreeIpsInVlan(vlanrange.getId()); - if (freeIpsInsubnet > 0){ - //assign one free ip to the router for creating ip Alias. The ipalias is system managed ip so we are using the system account to allocate the ip not the caller. - boolean result = false; - PublicIp routerPublicIP = _networkMgr.assignPublicIpAddressFromVlans(network.getDataCenterId(), null, _accountDao.findById(Account.ACCOUNT_ID_SYSTEM), Vlan.VlanType.DirectAttached, vlanDbIdList, network.getId(), null, false); - s_logger.info("creating a db entry for the new ip alias."); - NicIpAliasVO newipAlias = new NicIpAliasVO(ipAlias.getNicId(), routerPublicIP.getAddress().addr(), ipAlias.getVmId(), ipAlias.getAccountId(), network.getDomainId(), network.getId(), ipAlias.getGateway(), ipAlias.getNetmask()); - newipAlias.setAliasCount(routerPublicIP.getIpMacAddress()); - _nicIpAliasDao.persist(newipAlias); - //we revoke all the rules and apply all the rules as a part of the removedhcp config. so the new ip will get configured when we delete the old ip. - s_logger.info("removing the old ip alias on router"); - result = dhcpServiceProvider.removeDhcpSupportForSubnet(network); - if (result == false) { - s_logger.debug("could't delete the ip alias on the router"); - result_final = false; + //setting the state back to active + ipAlias.setState(NicIpAlias.state.active); + _nicIpAliasDao.update(ipAlias.getId(), ipAlias); } else { _publicIpAddressDao.unassignIpAddress(ip.getId()); - result_final=true; - } - } - } - } + deleteVLANFromDb(vlanDbId); } + } else { + // if there are more vlans in the subnet, free all the ips in the range except the ip alias. + s_logger.info("vlan Range"+vlanRange.getId()+" id being deleted, one of the Ips in this range is used to provide the dhcp service, will free the rest of the IPs in range."); + _publicIpAddressDao.deletePublicIPRangeExceptAliasIP(vlanDbId, ipAlias.getIp4Address()); + VlanVO vlan = _vlanDao.findById(vlanDbId); + vlan.setIpRange(ipAlias.getIp4Address()+"-"+ipAlias.getIp4Address()); + _vlanDao.update(vlan.getId(), vlan); } } - - } catch (InsufficientAddressCapacityException e) { - throw new InvalidParameterValueException("cannot delete vlan range"+ vlanRange.getId()+"one of the ips in this range is benig used to provide dhcp service. Cannot use some other ip as there are no free ips in this subnet"); } - finally { - if (result_final) { - if (!removeFromDb(vlanDbId)) { + } catch (CloudRuntimeException e) { txn.rollback(); + throw e; } - else { txn.commit(); - } - txn.close(); - } - } - return result_final; + return true; } @Override @@ -3542,25 +3547,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return tags; } - @DB - protected boolean deletePublicIPRange(long vlanDbId) { - Transaction txn = Transaction.currentTxn(); - String deleteSql = "DELETE FROM `cloud`.`user_ip_address` WHERE vlan_db_id = ?"; - - txn.start(); - try { - PreparedStatement stmt = txn.prepareAutoCloseStatement(deleteSql); - stmt.setLong(1, vlanDbId); - stmt.executeUpdate(); - } catch (Exception ex) { - s_logger.error(ex.getMessage()); - return false; - } - txn.commit(); - - return true; - } - @DB protected boolean savePublicIPRange(String startIP, String endIP, long zoneId, long vlanDbId, long sourceNetworkid, long physicalNetworkId) { diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index b4eb8ea6311..4990abb846a 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -450,9 +450,22 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy DedicatedResourceVO dedicatedZone = _dedicatedDao.findByZoneId(dc.getId()); if (dedicatedZone != null) { long accountDomainId = vmProfile.getOwner().getDomainId(); + long accountId = vmProfile.getOwner().getAccountId(); if (dedicatedZone.getDomainId() != null && !dedicatedZone.getDomainId().equals(accountDomainId)) { throw new CloudRuntimeException("Failed to deploy VM. Zone " + dc.getName() + " is dedicated."); } + + // If a zone is dedicated to an account then all hosts in this zone will be explicitly dedicated to + // that account. So there won't be any shared hosts in the zone, the only way to deploy vms from that + // account will be to use explicit dedication affinity group. + if (dedicatedZone.getAccountId() != null) { + if (dedicatedZone.getAccountId().equals(accountId)) { + throw new CloudRuntimeException("Failed to deploy VM. There are no shared hosts available in" + + " this dedicated zone."); + } else { + throw new CloudRuntimeException("Failed to deploy VM. Zone " + dc.getName() + " is dedicated."); + } + } } List podsInDc = _podDao.listByDataCenterId(dc.getId()); diff --git a/server/src/com/cloud/hypervisor/guru/HypervGuru.java b/server/src/com/cloud/hypervisor/guru/HypervGuru.java deleted file mode 100644 index 319c280b429..00000000000 --- a/server/src/com/cloud/hypervisor/guru/HypervGuru.java +++ /dev/null @@ -1,72 +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.hypervisor.guru; - -import javax.ejb.Local; -import javax.inject.Inject; - -import com.cloud.agent.api.Command; -import com.cloud.agent.api.to.VirtualMachineTO; -import com.cloud.host.dao.HostDao; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.hypervisor.HypervisorGuru; -import com.cloud.hypervisor.HypervisorGuruBase; -import com.cloud.storage.GuestOSVO; -import com.cloud.storage.dao.GuestOSDao; -import com.cloud.template.VirtualMachineTemplate.BootloaderType; -import com.cloud.vm.VirtualMachineProfile; - -/** - * Implementation of Hypervisor guru for Hyper-Vr - **/ - -@Local(value=HypervisorGuru.class) -public class HypervGuru extends HypervisorGuruBase implements HypervisorGuru { - - @Inject GuestOSDao _guestOsDao; - @Inject HostDao _hostDao; - - protected HypervGuru() { - super(); - } - - @Override - public HypervisorType getHypervisorType() { - return HypervisorType.Hyperv; - } - - @Override - public VirtualMachineTO implement(VirtualMachineProfile vm) { - VirtualMachineTO to = toVirtualMachineTO(vm); - to.setBootloader(BootloaderType.HVM); - - // Determine the VM's OS description - GuestOSVO guestOS = _guestOsDao.findById(vm.getVirtualMachine().getGuestOSId()); - to.setOs(guestOS.getDisplayName()); - return to; - } - - @Override - public long getCommandHostDelegation(long hostId, Command cmd) { - return hostId; - } - - @Override - public boolean trackVmHostChange() { - return false; - } -} diff --git a/server/src/com/cloud/hypervisor/hyperv/HypervServerDiscoverer.java b/server/src/com/cloud/hypervisor/hyperv/HypervServerDiscoverer.java deleted file mode 100755 index 06658b7f3e2..00000000000 --- a/server/src/com/cloud/hypervisor/hyperv/HypervServerDiscoverer.java +++ /dev/null @@ -1,243 +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.hypervisor.hyperv; - -import java.net.InetAddress; -import java.net.URI; -import java.net.UnknownHostException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.api.Command; -import com.cloud.agent.api.StartupVMMAgentCommand; -import com.cloud.agent.transport.Request; -import com.cloud.alert.AlertManager; -import com.cloud.dc.ClusterDetailsDao; -import com.cloud.dc.ClusterVO; -import com.cloud.dc.dao.ClusterDao; -import com.cloud.exception.DiscoveryException; -import com.cloud.host.Host; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.hypervisor.Hypervisor; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.hypervisor.hyperv.resource.HypervDummyResourceBase; -import com.cloud.resource.Discoverer; -import com.cloud.resource.DiscovererBase; -import com.cloud.resource.ResourceManager; -import com.cloud.resource.ServerResource; -import com.cloud.utils.nio.HandlerFactory; -import com.cloud.utils.nio.Link; -import com.cloud.utils.nio.NioClient; -import com.cloud.utils.nio.Task; -import com.cloud.utils.nio.Task.Type; - -@Local(value=Discoverer.class) -public class HypervServerDiscoverer extends DiscovererBase implements Discoverer, HandlerFactory{ - private static final Logger s_logger = Logger.getLogger(HypervServerDiscoverer.class); - private int _waitTime = 1; - - @Inject ClusterDao _clusterDao; - @Inject AlertManager _alertMgr; - @Inject ClusterDetailsDao _clusterDetailsDao; - @Inject HostDao _hostDao = null; - @Inject ResourceManager _resourceMgr; - Link _link; - - @SuppressWarnings("static-access") - @Override - public Map> find(long dcId, Long podId, Long clusterId, URI url, - String username, String password, List hostTags) throws DiscoveryException { - - if(s_logger.isInfoEnabled()) { - s_logger.info("Discover host. dc: " + dcId + ", pod: " + podId + ", cluster: " + clusterId + ", uri host: " + url.getHost()); - } - - if(podId == null) { - if(s_logger.isInfoEnabled()) { - s_logger.info("No pod is assigned, skipping the discovery in Hyperv discoverer"); - } - return null; - } - - if (!url.getScheme().equals("http")) { - String msg = "urlString is not http so HypervServerDiscoverer taking care of the discovery for this: " + url; - s_logger.debug(msg); - return null; - } - - ClusterVO cluster = _clusterDao.findById(clusterId); - if(cluster == null || cluster.getHypervisorType() != HypervisorType.Hyperv) { - if(s_logger.isInfoEnabled()) { - s_logger.info("invalid cluster id or cluster is not for Hyperv hypervisors"); - } - return null; - } - String clusterName = cluster.getName(); - - try { - - String hostname = url.getHost(); - InetAddress ia = InetAddress.getByName(hostname); - String agentIp = ia.getHostAddress(); - String guid = UUID.nameUUIDFromBytes(agentIp.getBytes()).toString(); - String guidWithTail = guid + "-HypervResource";/*tail added by agent.java*/ - if (_resourceMgr.findHostByGuid(guidWithTail) != null) { - s_logger.debug("Skipping " + agentIp + " because " + guidWithTail + " is already in the database."); - return null; - } - - // bootstrap SCVMM agent to connect back to management server - NioClient _connection = new NioClient("HypervAgentClient", url.getHost(), 9000, 1, this); - _connection.start(); - - StartupVMMAgentCommand cmd = new StartupVMMAgentCommand( - dcId, - podId, - clusterName, - guid, - InetAddress.getLocalHost().getHostAddress(), - "8250", - HypervServerDiscoverer.class.getPackage().getImplementationVersion()); - - // send bootstrap command to agent running on SCVMM host - s_logger.info("sending bootstrap request to SCVMM agent on host "+ url.getHost()); - Request request = new Request(0, 0, cmd, false); - - // :FIXME without sleep link.send failing why?????? - Thread.currentThread().sleep(5000); - _link.send(request.toBytes()); - - //wait for SCVMM agent to connect back - HostVO connectedHost = waitForHostConnect(dcId, podId, clusterId, guidWithTail); - if (connectedHost == null) - { - s_logger.info("SCVMM agent did not connect back after sending bootstrap request"); - return null; - } - - //disconnect - s_logger.info("SCVMM agent connected back after sending bootstrap request"); - _connection.stop(); - - Map> resources = new HashMap>(); - Map details = new HashMap(); - Map params = new HashMap(); - HypervDummyResourceBase resource = new HypervDummyResourceBase(); - - details.put("url", url.getHost()); - details.put("username", username); - details.put("password", password); - resources.put(resource, details); - - params.put("zone", Long.toString(dcId)); - params.put("pod", Long.toString(podId)); - params.put("cluster", Long.toString(clusterId)); - - resource.configure("Hyperv", params); - return resources; - } catch (ConfigurationException e) { - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, "Unable to add " + url.getHost(), "Error is " + e.getMessage()); - s_logger.warn("Unable to instantiate " + url.getHost(), e); - } catch (UnknownHostException e) { - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, "Unable to add " + url.getHost(), "Error is " + e.getMessage()); - s_logger.warn("Unable to instantiate " + url.getHost(), e); - } catch (Exception e) { - s_logger.info("exception " + e.toString()); - } - return null; - } - - @Override - public void postDiscovery(List hosts, long msId) { - // do nothing - } - - @Override - public boolean matchHypervisor(String hypervisor) { - if(hypervisor == null) { - return true; - } - - return Hypervisor.HypervisorType.VMware.toString().equalsIgnoreCase(hypervisor); - } - - @Override - public Hypervisor.HypervisorType getHypervisorType() { - return Hypervisor.HypervisorType.Hyperv; - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - super.configure(name, params); - return true; - } - - @Override - public Task create(Type type, Link link, byte[] data) { - _link = link; - return new BootStrapTakHandler(type, link, data); - } - - private HostVO waitForHostConnect(long dcId, long podId, long clusterId, String guid) { - for (int i = 0; i < _waitTime *2; i++) { - List hosts = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.Routing, clusterId, podId, dcId); - for (HostVO host : hosts) { - if (host.getGuid().equalsIgnoreCase(guid)) { - return host; - } - } - try { - Thread.sleep(30000); - } catch (InterruptedException e) { - s_logger.debug("Failed to sleep: " + e.toString()); - } - } - s_logger.debug("Timeout, to wait for the host connecting to mgt svr, assuming it is failed"); - return null; - } - - // class to handle the bootstrap command from the management server - public class BootStrapTakHandler extends Task { - - public BootStrapTakHandler(Task.Type type, Link link, byte[] data) { - super(type, link, data); - s_logger.info("created new BootStrapTakHandler"); - } - - protected void processRequest(final Link link, final Request request) { - final Command[] cmds = request.getCommands(); - Command cmd = cmds[0]; - } - - @Override - protected void doTask(Task task) throws Exception { - final Type type = task.getType(); - s_logger.info("recieved task of type "+type.toString() +" in BootStrapTakHandler"); - } - } -} - - diff --git a/server/src/com/cloud/network/ExternalLoadBalancerUsageManager.java b/server/src/com/cloud/network/ExternalDeviceUsageManager.java similarity index 84% rename from server/src/com/cloud/network/ExternalLoadBalancerUsageManager.java rename to server/src/com/cloud/network/ExternalDeviceUsageManager.java index 886cd784988..474002ba301 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerUsageManager.java +++ b/server/src/com/cloud/network/ExternalDeviceUsageManager.java @@ -18,10 +18,10 @@ package com.cloud.network; import com.cloud.utils.component.Manager; -/* ExternalLoadBalancerUsageManager implements a periodic task that retrieves and updates the network usage stats from all external load balancer devices. +/* ExternalDeviceUsageManager implements a periodic task that retrieves and updates the network usage stats from all external load balancer and firewall devices. */ -public interface ExternalLoadBalancerUsageManager extends Manager{ +public interface ExternalDeviceUsageManager extends Manager{ /** * updates the network usage stats for a LB rule, associated with an external LB device, that is being revoked as part of Delete LB rule or release IP actions diff --git a/server/src/com/cloud/network/ExternalLoadBalancerUsageManagerImpl.java b/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java similarity index 97% rename from server/src/com/cloud/network/ExternalLoadBalancerUsageManagerImpl.java rename to server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java index 2c8031c64f0..606586e11d8 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerUsageManagerImpl.java +++ b/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java @@ -87,9 +87,10 @@ import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; @Component -@Local(value = { ExternalLoadBalancerUsageManager.class }) -public class ExternalLoadBalancerUsageManagerImpl extends ManagerBase implements ExternalLoadBalancerUsageManager { +@Local(value = { ExternalDeviceUsageManager.class }) +public class ExternalDeviceUsageManagerImpl extends ManagerBase implements ExternalDeviceUsageManager { + String _name; @Inject NetworkExternalLoadBalancerDao _networkExternalLBDao; @Inject @@ -99,8 +100,6 @@ public class ExternalLoadBalancerUsageManagerImpl extends ManagerBase implements @Inject DataCenterDao _dcDao; @Inject - NetworkModel _networkMgr; - @Inject InlineLoadBalancerNicMapDao _inlineLoadBalancerNicMapDao; @Inject NicDao _nicDao; @@ -146,10 +145,13 @@ public class ExternalLoadBalancerUsageManagerImpl extends ManagerBase implements ExternalFirewallDeviceDao _externalFirewallDeviceDao; @Inject protected HostPodDao _podDao = null; - + @Inject + NetworkModel _networkModel; + + ScheduledExecutorService _executor; private int _externalNetworkStatsInterval; - private static final org.apache.log4j.Logger s_logger = Logger.getLogger(ExternalLoadBalancerUsageManagerImpl.class); + private static final org.apache.log4j.Logger s_logger = Logger.getLogger(ExternalDeviceUsageManagerImpl.class); @Override public boolean configure(String name, Map params) throws ConfigurationException { @@ -249,7 +251,7 @@ public class ExternalLoadBalancerUsageManagerImpl extends ManagerBase implements return; } - String publicIp = _networkMgr.getIp(lb.getSourceIpAddressId()).getAddress().addr(); + String publicIp = _networkModel.getIp(lb.getSourceIpAddressId()).getAddress().addr(); DataCenterVO zone = _dcDao.findById(network.getDataCenterId()); String statsEntryIdentifier = "account " + account.getAccountName() + ", zone " + zone.getName() + ", network ID " + networkId + ", host ID " + externalLoadBalancer.getName(); @@ -259,7 +261,7 @@ public class ExternalLoadBalancerUsageManagerImpl extends ManagerBase implements if (publicIp != null) { long[] bytesSentAndReceived = null; statsEntryIdentifier += ", public IP: " + publicIp; - boolean inline = _networkMgr.isNetworkInlineMode(network); + boolean inline = _networkModel.isNetworkInlineMode(network); if (externalLoadBalancer.getType().equals(Host.Type.ExternalLoadBalancer) && inline) { // Look up stats for the guest IP address that's mapped to the public IP address InlineLoadBalancerNicMapVO mapping = _inlineLoadBalancerNicMapDao.findByPublicIpAddress(publicIp); @@ -380,7 +382,7 @@ public class ExternalLoadBalancerUsageManagerImpl extends ManagerBase implements } for (NetworkVO network : networksForAccount) { - if (!_networkMgr.networkIsConfiguredForExternalNetworking(zoneId, network.getId())) { + if (!_networkModel.networkIsConfiguredForExternalNetworking(zoneId, network.getId())) { s_logger.debug("Network " + network.getId() + " is not configured for external networking, so skipping usage check."); continue; } @@ -603,7 +605,7 @@ public class ExternalLoadBalancerUsageManagerImpl extends ManagerBase implements String networkErrorMsg = accountErrorMsg + ", network ID = " + network.getId(); boolean sharedSourceNat = false; - Map sourceNatCapabilities = _networkMgr.getNetworkServiceCapabilities(network.getId(), Network.Service.SourceNat); + Map sourceNatCapabilities = _networkModel.getNetworkServiceCapabilities(network.getId(), Network.Service.SourceNat); if (sourceNatCapabilities != null) { String supportedSourceNatTypes = sourceNatCapabilities.get(Network.Capability.SupportedSourceNatTypes).toLowerCase(); if (supportedSourceNatTypes.contains("zone")) { @@ -634,7 +636,7 @@ public class ExternalLoadBalancerUsageManagerImpl extends ManagerBase implements // Manage one entry for each port forwarding rule in this network List portForwardingRules = _portForwardingRulesDao.listByNetwork(network.getId()); for (PortForwardingRuleVO portForwardingRule : portForwardingRules) { - String publicIp = _networkMgr.getIp(portForwardingRule.getSourceIpAddressId()).getAddress().addr(); + String publicIp = _networkModel.getIp(portForwardingRule.getSourceIpAddressId()).getAddress().addr(); if (!createOrUpdateStatsEntry(create, accountId, zoneId, network.getId(), publicIp, externalFirewall.getId(), firewallAnswer, false)) { throw new ExecutionException(networkErrorMsg + ", port forwarding rule public IP = " + publicIp); } @@ -649,11 +651,10 @@ public class ExternalLoadBalancerUsageManagerImpl extends ManagerBase implements // If an external load balancer is added, manage one entry for each load balancing rule in this network if (externalLoadBalancer != null && lbAnswer != null) { - boolean inline = _networkMgr.isNetworkInlineMode(network); + boolean inline = _networkModel.isNetworkInlineMode(network); List loadBalancers = _loadBalancerDao.listByNetworkIdAndScheme(network.getId(), Scheme.Public); for (LoadBalancerVO loadBalancer : loadBalancers) { - String publicIp = _networkMgr.getIp(loadBalancer.getSourceIpAddressId()).getAddress().addr(); - + String publicIp = _networkModel.getIp(loadBalancer.getSourceIpAddressId()).getAddress().addr(); if (!createOrUpdateStatsEntry(create, accountId, zoneId, network.getId(), publicIp, externalLoadBalancer.getId(), lbAnswer, inline)) { throw new ExecutionException(networkErrorMsg + ", load balancing rule public IP = " + publicIp); } @@ -669,5 +670,4 @@ public class ExternalLoadBalancerUsageManagerImpl extends ManagerBase implements } } } - } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index b2c5a88db69..e4095b2780a 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -2980,6 +2980,11 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L List networkIds = _networksDao.findNetworksToGarbageCollect(); for (Long networkId : networkIds) { + + if (!_networkModel.isNetworkReadyForGc(networkId)) { + continue; + } + Long time = _lastNetworkIdsToFree.remove(networkId); if (time == null) { if (s_logger.isDebugEnabled()) { diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index 9ab8f3f0e2a..21ef8bcf0ea 100755 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -2126,4 +2126,25 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { public boolean getExecuteInSeqNtwkElmtCmd() { return _executeInSequenceNtwkElmtCmd; } + + @Override + public boolean isNetworkReadyForGc(long networkId) { + Network network = getNetwork(networkId); + List networkIds = _networksDao.findNetworksToGarbageCollect(); + List secondaryIps = _nicSecondaryIpDao.listSecondaryIpAddressInNetwork(networkId); + if (!networkIds.contains(networkId)) { + return false; + } + + // add an exception for networks that use external networking devices and has secondary guest IP's allocated. + // On network GC, when network goes through implement phase a new vlan is allocated, based on the acquired VLAN + // id cidr of the network is decided in case of external networking case. While NIC uses reservation strategy 'Start' + // which ensures that new primary ip is allocated for the NiC from the new CIDR. Secondary IP's have hardcoded IP's in + // network rules. So prevent network GC. + if (secondaryIps != null && !secondaryIps.isEmpty() && + networkIsConfiguredForExternalNetworking(network.getDataCenterId(), networkId)) { + } + + return true; + } } diff --git a/server/src/com/cloud/network/NetworkUsageManagerImpl.java b/server/src/com/cloud/network/NetworkUsageManagerImpl.java index 2bd55bb9165..7bd96a477b3 100755 --- a/server/src/com/cloud/network/NetworkUsageManagerImpl.java +++ b/server/src/com/cloud/network/NetworkUsageManagerImpl.java @@ -32,6 +32,10 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import org.apache.cloudstack.api.command.admin.usage.AddTrafficMonitorCmd; +import org.apache.cloudstack.api.command.admin.usage.DeleteTrafficMonitorCmd; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficMonitorsCmd; + import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; import com.cloud.agent.api.AgentControlAnswer; @@ -68,17 +72,9 @@ import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceStateAdapter; import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; - -import org.apache.cloudstack.api.command.admin.usage.AddTrafficMonitorCmd; -import org.apache.cloudstack.api.command.admin.usage.DeleteTrafficMonitorCmd; -import org.apache.cloudstack.api.command.admin.usage.ListTrafficMonitorsCmd; -import org.apache.cloudstack.api.response.TrafficMonitorResponse; -import org.apache.cloudstack.context.CallContext; - import com.cloud.usage.UsageIPAddressVO; import com.cloud.user.AccountManager; import com.cloud.user.AccountVO; -import com.cloud.user.User; import com.cloud.user.UserStatisticsVO; import com.cloud.user.dao.UserStatisticsDao; import com.cloud.utils.NumbersUtil; @@ -189,22 +185,16 @@ public class NetworkUsageManagerImpl extends ManagerBase implements NetworkUsage @Override public boolean deleteTrafficMonitor(DeleteTrafficMonitorCmd cmd) { long hostId = cmd.getId(); - User caller = _accountMgr.getActiveUser(CallContext.current().getCallingUserId()); HostVO trafficMonitor = _hostDao.findById(hostId); if (trafficMonitor == null) { throw new InvalidParameterValueException("Could not find an traffic monitor with ID: " + hostId); } - try { - if (_resourceMgr.maintain(hostId) && _resourceMgr.deleteHost(hostId, false, false)) { + if (_resourceMgr.deleteHost(hostId, false, false)) { return true; } else { return false; } - } catch (AgentUnavailableException e) { - s_logger.debug(e); - return false; - } } @Override @@ -254,7 +244,7 @@ public class NetworkUsageManagerImpl extends ManagerBase implements NetworkUsage private int _interval; - private long mgmtSrvrId = MacAddress.getMacAddress().toLong(); + private final long mgmtSrvrId = MacAddress.getMacAddress().toLong(); protected DirectNetworkStatsListener(int interval) { _interval = interval; @@ -535,7 +525,14 @@ public class NetworkUsageManagerImpl extends ManagerBase implements NetworkUsage return null; } - return new DeleteHostAnswer(true); + long hostId = host.getId(); + _agentMgr.disconnectWithoutInvestigation(hostId, Status.Event.Remove); + _detailsDao.deleteDetails(hostId); + host.setGuid(null); + _hostDao.update(hostId, host); + _hostDao.remove(hostId); + return new DeleteHostAnswer(false); + } } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 113e5e266d2..bc50d9562c8 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -68,7 +68,7 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceUnavailableException; -import com.cloud.network.ExternalLoadBalancerUsageManager; +import com.cloud.network.ExternalDeviceUsageManager; import com.cloud.network.IpAddress; import com.cloud.network.LBHealthCheckPolicyVO; import com.cloud.network.Network; @@ -212,7 +212,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements ConfigurationManager _configMgr; @Inject - ExternalLoadBalancerUsageManager _externalLBUsageMgr; + ExternalDeviceUsageManager _externalDeviceUsageMgr; @Inject NetworkServiceMapDao _ntwkSrvcDao; @Inject @@ -1216,7 +1216,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements NetworkVO network = _networkDao.findById(lb.getNetworkId()); if (network != null) { if (_networkModel.networkIsConfiguredForExternalNetworking(network.getDataCenterId(), network.getId())) { - _externalLBUsageMgr.updateExternalLoadBalancerNetworkUsageStats(loadBalancerId); + _externalDeviceUsageMgr.updateExternalLoadBalancerNetworkUsageStats(loadBalancerId); } } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 554e691306f..c5df621f043 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2843,8 +2843,6 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V network.getId(), DataCenter.class, network.getDataCenterId()); } - boolean agentResults = true; - for (DomainRouterVO router : routers) { if (router.getState() != State.Running) { s_logger.warn("Failed to add/remove VPN users: router not in running state"); @@ -3678,6 +3676,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V private void createFirewallRulesCommands(List rules, VirtualRouter router, Commands cmds, long guestNetworkId) { List rulesTO = null; String systemRule = null; + Boolean defaultEgressPolicy = false; if (rules != null) { if (rules.size() > 0) { if (rules.get(0).getTrafficType() == FirewallRule.TrafficType.Egress && rules.get(0).getType() == FirewallRule.FirewallRuleType.System) { @@ -3692,17 +3691,17 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, sourceIp.getAddress().addr(), Purpose.Firewall, traffictype); rulesTO.add(ruleTO); } else if (rule.getTrafficType() == FirewallRule.TrafficType.Egress){ + NetworkVO network = _networkDao.findById(guestNetworkId); + NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + defaultEgressPolicy = offering.getEgressDefaultPolicy(); assert (rule.getSourceIpAddressId()==null) : "ipAddressId should be null for egress firewall rule. "; - FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null,"",Purpose.Firewall, traffictype); + FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null,"",Purpose.Firewall, traffictype, defaultEgressPolicy); rulesTO.add(ruleTO); } } } - NetworkVO network = _networkDao.findById(guestNetworkId); - NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); - Boolean defaultEgressPolicy = offering.getEgressDefaultPolicy(); SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(rulesTO); cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId())); cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, getRouterIpInNetwork(guestNetworkId, router.getId())); diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 757843ccc56..c0e425475ec 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -545,12 +545,6 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, for (Map.Entry> entry : resources.entrySet()) { ServerResource resource = entry.getKey(); - // For Hyper-V, we are here means agent have already started - // and connected to management server - if (hypervisorType == Hypervisor.HypervisorType.Hyperv) { - break; - } - HostVO host = (HostVO) createHostAndAgent(resource, entry.getValue(), true, null, false); if (host != null) { hosts.add(host); diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index 1ddfcfaaafb..9e79b762e1c 100755 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -932,7 +932,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio diskSize = diskSize * 1024 * 1024 * 1024; tags = cleanupTags(tags); - DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, diskSize, tags, isCustomized); + DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, diskSize, tags, isCustomized, null, null, null); newDiskOffering.setUniqueName("Cloud.Com-" + name); newDiskOffering.setSystemUse(isSystemUse); newDiskOffering = _diskOfferingDao.persistDeafultDiskOffering(newDiskOffering); diff --git a/server/src/com/cloud/storage/StorageManager.java b/server/src/com/cloud/storage/StorageManager.java index 29c7ebcef00..df690929f25 100755 --- a/server/src/com/cloud/storage/StorageManager.java +++ b/server/src/com/cloud/storage/StorageManager.java @@ -99,28 +99,23 @@ public interface StorageManager extends StorageService { void cleanupSecondaryStorage(boolean recurring); - HypervisorType getHypervisorTypeFromFormat(ImageFormat format); + boolean storagePoolHasEnoughIops(List volume, StoragePool pool); + boolean storagePoolHasEnoughSpace(List volume, StoragePool pool); - boolean registerHostListener(String providerUuid, HypervisorHostListener listener); StoragePool findStoragePool(DiskProfile dskCh, DataCenterVO dc, HostPodVO pod, Long clusterId, Long hostId, VMInstanceVO vm, Set avoid); - void connectHostToSharedPool(long hostId, long poolId) throws StorageUnavailableException; void createCapacityEntry(long poolId); - - - - DataStore createLocalStorage(Host host, StoragePoolInfo poolInfo) throws ConnectionException; BigDecimal getStorageOverProvisioningFactor(Long dcId); diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 55b214ff4ec..ac048863dc2 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -58,7 +58,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; -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.HostScope; import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; @@ -68,15 +67,12 @@ 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.StoragePoolAllocator; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory; -import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.async.AsyncCallFuture; -import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; @@ -576,7 +572,6 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } else { s_logger.debug("Storage cleanup is not enabled, so the storage cleanup thread is not being scheduled."); } - return true; } @@ -585,7 +580,6 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C if (_storageCleanupEnabled) { _executor.shutdown(); } - return true; } @@ -597,7 +591,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C if (dc == null || !dc.isLocalStorageEnabled()) { return null; } - DataStore store = null; + DataStore store; try { StoragePoolVO pool = _storagePoolDao.findPoolByHostPath(host.getDataCenterId(), host.getPodId(), pInfo.getHost(), pInfo.getHostPath(), pInfo.getUuid()); @@ -666,7 +660,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C try { scopeType = Enum.valueOf(ScopeType.class, scope.toUpperCase()); } catch (Exception e) { - throw new InvalidParameterValueException("invalid scope" + scope); + throw new InvalidParameterValueException("invalid scope for pool " + scope); } } @@ -686,33 +680,20 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C try { hypervisorType = HypervisorType.getType(hypervisor); } catch (Exception e) { - throw new InvalidParameterValueException("invalid hypervisor type" + hypervisor); + throw new InvalidParameterValueException("invalid hypervisor type " + hypervisor); } } else { throw new InvalidParameterValueException( "Missing parameter hypervisor. Hypervisor type is required to create zone wide primary storage."); } - if (hypervisorType != HypervisorType.KVM && hypervisorType != HypervisorType.VMware) { + if (hypervisorType != HypervisorType.KVM && hypervisorType != HypervisorType.VMware && + hypervisorType != HypervisorType.Any) { throw new InvalidParameterValueException( - "zone wide storage pool is not suported for hypervisor type " + hypervisor); - } - } - - Map ds = cmd.getDetails(); - Map details = new HashMap(); - if (ds != null) { - Collection detailsCollection = ds.values(); - Iterator it = detailsCollection.iterator(); - while (it.hasNext()) { - HashMap d = (HashMap) it.next(); - Iterator it2 = d.entrySet().iterator(); - while (it2.hasNext()) { - Map.Entry entry = (Map.Entry) it2.next(); - details.put((String) entry.getKey(), (String) entry.getValue()); - } + "zone wide storage pool is not supported for hypervisor type " + hypervisor); } } + Map details = extractApiParamAsMap(cmd.getDetails()); DataCenterVO zone = _dcDao.findById(cmd.getZoneId()); if (zone == null) { throw new InvalidParameterValueException("unable to find zone by id " + zoneId); @@ -732,12 +713,14 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C params.put("name", cmd.getStoragePoolName()); params.put("details", details); params.put("providerName", storeProvider.getName()); + params.put("managed", cmd.isManaged()); + params.put("capacityBytes", cmd.getCapacityBytes()); + params.put("capacityIops", cmd.getCapacityIops()); DataStoreLifeCycle lifeCycle = storeProvider.getDataStoreLifeCycle(); - DataStore store = null; + DataStore store; try { store = lifeCycle.initialize(params); - if (scopeType == ScopeType.CLUSTER) { ClusterScope clusterScope = new ClusterScope(clusterId, podId, zoneId); lifeCycle.attachCluster(store, clusterScope); @@ -753,6 +736,23 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return (PrimaryDataStoreInfo) dataStoreMgr.getDataStore(store.getId(), DataStoreRole.Primary); } + private Map extractApiParamAsMap(Map ds) { + Map details = new HashMap(); + if (ds != null) { + Collection detailsCollection = ds.values(); + Iterator it = detailsCollection.iterator(); + while (it.hasNext()) { + HashMap d = (HashMap) it.next(); + Iterator it2 = d.entrySet().iterator(); + while (it2.hasNext()) { + Map.Entry entry = (Map.Entry) it2.next(); + details.put((String) entry.getKey(), (String) entry.getValue()); + } + } + } + return details; + } + @Override public PrimaryDataStoreInfo updateStoragePool(UpdateStoragePoolCmd cmd) throws IllegalArgumentException { // Input validation @@ -814,9 +814,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C try { future.get(); } catch (InterruptedException e) { - s_logger.debug("expunge volume failed" + vol.getId(), e); + s_logger.debug("expunge volume failed:" + vol.getId(), e); } catch (ExecutionException e) { - s_logger.debug("expunge volume failed" + vol.getId(), e); + s_logger.debug("expunge volume failed:" + vol.getId(), e); } } } @@ -824,7 +824,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C // Check if the pool has associated volumes in the volumes table // If it does , then you cannot delete the pool if (vlms.first() > 0) { - throw new CloudRuntimeException("Cannot delete pool " + sPool.getName() + " as there are associated vols" + " for this pool"); + throw new CloudRuntimeException("Cannot delete pool " + sPool.getName() + " as there are associated volumes for this pool"); } } @@ -1097,63 +1097,34 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Override @DB public void cleanupSecondaryStorage(boolean recurring) { + // NOTE that object_store refactor will immediately delete the object from secondary storage when deleteTemplate etc api is issued. + // so here we don't need to issue DeleteCommand to resource anymore, only need to remove db entry. try { - // Cleanup templates in secondary storage hosts + // Cleanup templates in template_store_ref List imageStores = dataStoreMgr.getImageStoresByScope(new ZoneScope(null)); for (DataStore store : imageStores) { try { long storeId = store.getId(); List destroyedTemplateStoreVOs = _templateStoreDao.listDestroyed(storeId); s_logger.debug("Secondary storage garbage collector found " + destroyedTemplateStoreVOs.size() - + " templates to cleanup on secondary storage host: " + store.getName()); + + " templates to cleanup on template_store_ref for store: " + store.getName()); for (TemplateDataStoreVO destroyedTemplateStoreVO : destroyedTemplateStoreVOs) { - if (!_tmpltMgr.templateIsDeleteable(destroyedTemplateStoreVO.getTemplateId())) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Not deleting template at: " + destroyedTemplateStoreVO); - } - continue; - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("Deleting template store: " + destroyedTemplateStoreVO); + s_logger.debug("Deleting template store DB entry: " + destroyedTemplateStoreVO); } - - VMTemplateVO destroyedTemplate = _vmTemplateDao.findById(destroyedTemplateStoreVO.getTemplateId()); - if (destroyedTemplate == null) { - s_logger.error("Cannot find template : " + destroyedTemplateStoreVO.getTemplateId() + " from template table"); - throw new CloudRuntimeException("Template " + destroyedTemplateStoreVO.getTemplateId() - + " is found in secondary storage, but not found in template table"); - } - String installPath = destroyedTemplateStoreVO.getInstallPath(); - - TemplateInfo tmpl = tmplFactory.getTemplate(destroyedTemplateStoreVO.getTemplateId(), store); - if (installPath != null) { - EndPoint ep = _epSelector.select(store); - Command cmd = new DeleteCommand(tmpl.getTO()); - Answer answer = ep.sendMessage(cmd); - - if (answer == null || !answer.getResult()) { - s_logger.debug("Failed to delete " + destroyedTemplateStoreVO + " due to " - + ((answer == null) ? "answer is null" : answer.getDetails())); - } else { _templateStoreDao.remove(destroyedTemplateStoreVO.getId()); - s_logger.debug("Deleted template at: " + destroyedTemplateStoreVO.getInstallPath()); - } - } else { - _templateStoreDao.remove(destroyedTemplateStoreVO.getId()); - } } } catch (Exception e) { - s_logger.warn("problem cleaning up templates in secondary storage store " + store.getName(), e); + s_logger.warn("problem cleaning up templates in template_store_ref for store: " + store.getName(), e); } } - // CleanUp snapshots on Secondary Storage. + // CleanUp snapshots on snapshot_store_ref for (DataStore store : imageStores) { try { List destroyedSnapshotStoreVOs = _snapshotStoreDao.listDestroyed(store.getId()); s_logger.debug("Secondary storage garbage collector found " + destroyedSnapshotStoreVOs.size() - + " snapshots to cleanup on secondary storage host: " + store.getName()); + + " snapshots to cleanup on snapshot_store_ref for store: " + store.getName()); for (SnapshotDataStoreVO destroyedSnapshotStoreVO : destroyedSnapshotStoreVOs) { // check if this snapshot has child SnapshotInfo snap = snapshotFactory.getSnapshot(destroyedSnapshotStoreVO.getSnapshotId(), store); @@ -1163,70 +1134,37 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } if (s_logger.isDebugEnabled()) { - s_logger.debug("Deleting snapshot on store: " + destroyedSnapshotStoreVO); + s_logger.debug("Deleting snapshot store DB entry: " + destroyedSnapshotStoreVO); } - String installPath = destroyedSnapshotStoreVO.getInstallPath(); - - if (installPath != null) { - EndPoint ep = _epSelector.select(store); - DeleteCommand cmd = new DeleteCommand(snap.getTO()); - Answer answer = ep.sendMessage(cmd); - if (answer == null || !answer.getResult()) { - s_logger.debug("Failed to delete " + destroyedSnapshotStoreVO + " due to " - + ((answer == null) ? "answer is null" : answer.getDetails())); - } else { - _volumeStoreDao.remove(destroyedSnapshotStoreVO.getId()); - s_logger.debug("Deleted snapshot at: " + destroyedSnapshotStoreVO.getInstallPath()); - } - } else { _snapshotStoreDao.remove(destroyedSnapshotStoreVO.getId()); } - } } catch (Exception e2) { - s_logger.warn("problem cleaning up snapshots in secondary storage store " + store.getName(), e2); + s_logger.warn("problem cleaning up snapshots in snapshot_store_ref for store: " + store.getName(), e2); } } - // CleanUp volumes on Secondary Storage. + // CleanUp volumes on volume_store_ref for (DataStore store : imageStores) { try { List destroyedStoreVOs = _volumeStoreDao.listDestroyed(store.getId()); s_logger.debug("Secondary storage garbage collector found " + destroyedStoreVOs.size() - + " volumes to cleanup on secondary storage host: " + store.getName()); + + " volumes to cleanup on volume_store_ref for store: " + store.getName()); for (VolumeDataStoreVO destroyedStoreVO : destroyedStoreVOs) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Deleting volume on store: " + destroyedStoreVO); + s_logger.debug("Deleting volume store DB entry: " + destroyedStoreVO); } - - String installPath = destroyedStoreVO.getInstallPath(); - - VolumeInfo vol = volFactory.getVolume(destroyedStoreVO.getVolumeId(), store); - - if (installPath != null) { - EndPoint ep = _epSelector.select(store); - DeleteCommand cmd = new DeleteCommand(vol.getTO()); - Answer answer = ep.sendMessage(cmd); - if (answer == null || !answer.getResult()) { - s_logger.debug("Failed to delete " + destroyedStoreVO + " due to " - + ((answer == null) ? "answer is null" : answer.getDetails())); - } else { _volumeStoreDao.remove(destroyedStoreVO.getId()); - s_logger.debug("Deleted volume at: " + destroyedStoreVO.getInstallPath()); - } - } else { - _volumeStoreDao.remove(destroyedStoreVO.getId()); - } } } catch (Exception e2) { - s_logger.warn("problem cleaning up volumes in secondary storage store " + store.getName(), e2); + s_logger.warn("problem cleaning up volumes in volume_store_ref for store: " + store.getName(), e2); } } } catch (Exception e3) { - s_logger.warn("problem cleaning up secondary storage ", e3); + s_logger.warn("problem cleaning up secondary storage DB entries. ", e3); } } @@ -1341,7 +1279,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C public void onManagementNodeLeft(List nodeList, long selfNodeId) { for (ManagementServerHost vo : nodeList) { if (vo.getMsid() == _serverId) { - s_logger.info("Cleaning up storage maintenance jobs associated with Management server" + vo.getMsid()); + s_logger.info("Cleaning up storage maintenance jobs associated with Management server: " + vo.getMsid()); List poolIds = _storagePoolWorkDao.searchForPoolIdsForPendingWorkJobs(vo.getMsid()); if (poolIds.size() > 0) { for (Long poolId : poolIds) { @@ -1559,12 +1497,49 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } @Override - public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) { - if (volumes == null || volumes.isEmpty()) + public boolean storagePoolHasEnoughIops(List requestedVolumes, + StoragePool pool) { + if (requestedVolumes == null || requestedVolumes.isEmpty() || pool == null) { return false; + } - if (!checkUsagedSpace(pool)) + long currentIops = 0; + + List volumesInPool = _volumeDao.findByPoolId(pool.getId(), null); + + for (VolumeVO volumeInPool : volumesInPool) { + Long minIops = volumeInPool.getMinIops(); + + if (minIops != null && minIops > 0) { + currentIops += minIops; + } + } + + long requestedIops = 0; + + for (Volume requestedVolume : requestedVolumes) { + Long minIops = requestedVolume.getMinIops(); + + if (minIops != null && minIops > 0) { + requestedIops += minIops; + } + } + + long futureIops = currentIops + requestedIops; + + return futureIops <= pool.getCapacityIops(); + } + + @Override + public boolean storagePoolHasEnoughSpace(List volumes, + StoragePool pool) { + if (volumes == null || volumes.isEmpty()){ return false; + } + + if (!checkUsagedSpace(pool)) { + return false; + } // allocated space includes template of specified volume StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); @@ -1577,9 +1552,10 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, tmpl); } } - if (volume.getState() != Volume.State.Ready) + if (volume.getState() != Volume.State.Ready) { totalAskingSize = totalAskingSize + volume.getSize(); } + } long totalOverProvCapacity; if (pool.getPoolType() == StoragePoolType.NetworkFilesystem) { @@ -1663,7 +1639,6 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } Long dcId = cmd.getZoneId(); - String url = cmd.getUrl(); Map details = cmd.getDetails(); ScopeType scopeType = ScopeType.ZONE; if (dcId == null) { @@ -1712,7 +1687,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C params.put("role", DataStoreRole.Image); DataStoreLifeCycle lifeCycle = storeProvider.getDataStoreLifeCycle(); - DataStore store = null; + DataStore store; try { store = lifeCycle.initialize(params); } catch (Exception e) { @@ -1829,7 +1804,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C scopeType = Enum.valueOf(ScopeType.class, scope.toUpperCase()); } catch (Exception e) { - throw new InvalidParameterValueException("invalid scope" + scope); + throw new InvalidParameterValueException("invalid scope for cache store " + scope); } if (scopeType != ScopeType.ZONE) { diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java index da2f9c461c3..585468b94b0 100644 --- a/server/src/com/cloud/storage/VolumeManagerImpl.java +++ b/server/src/com/cloud/storage/VolumeManagerImpl.java @@ -44,6 +44,7 @@ import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; import org.apache.cloudstack.api.command.user.volume.UpdateVolumeCmd; import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; import org.apache.cloudstack.context.CallContext; +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.DataStoreProviderManager; @@ -67,6 +68,7 @@ import org.apache.cloudstack.storage.command.AttachCommand; import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; @@ -223,6 +225,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { @Inject protected StoragePoolHostDao _storagePoolHostDao; @Inject + StoragePoolDetailsDao storagePoolDetailsDao; + @Inject protected AlertManager _alertMgr; @Inject protected TemplateDataStoreDao _vmTemplateStoreDao = null; @@ -505,7 +509,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(), oldVol.getName(), oldVol.getDataCenterId(), oldVol.getDomainId(), oldVol.getAccountId(), - oldVol.getDiskOfferingId(), oldVol.getSize()); + oldVol.getDiskOfferingId(), oldVol.getSize(), + oldVol.getMinIops(), oldVol.getMaxIops(), oldVol.get_iScsiName()); if (templateId != null) { newVol.setTemplateId(templateId); } else { @@ -520,7 +525,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { @DB protected VolumeInfo createVolumeFromSnapshot(VolumeVO volume, - SnapshotVO snapshot) { + SnapshotVO snapshot) throws StorageUnavailableException { Account account = _accountDao.findById(volume.getAccountId()); final HashSet poolsToAvoid = new HashSet(); @@ -548,6 +553,12 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } } + 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); + } + VolumeInfo vol = volFactory.getVolume(volume.getId()); DataStore store = dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary); SnapshotInfo snapInfo = snapshotFactory.getSnapshot(snapshot.getId(), DataStoreRole.Image); @@ -598,7 +609,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } } - protected VolumeVO createVolumeFromSnapshot(VolumeVO volume, long snapshotId) { + protected VolumeVO createVolumeFromSnapshot(VolumeVO volume, long snapshotId) throws StorageUnavailableException { VolumeInfo createdVolume = null; SnapshotVO snapshot = _snapshotDao.findById(snapshotId); createdVolume = createVolumeFromSnapshot(volume, @@ -678,9 +689,9 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { pool = storageMgr.findStoragePool(dskCh, dc, pod, clusterId, vm.getHostId(), vm, avoidPools); if (pool == null) { - s_logger.warn("Unable to find storage poll when create volume " + s_logger.warn("Unable to find storage pool when create volume " + volume.getName()); - throw new CloudRuntimeException("Unable to find storage poll when create volume" + volume.getName()); + throw new CloudRuntimeException("Unable to find storage pool when create volume" + volume.getName()); } if (s_logger.isDebugEnabled()) { @@ -729,8 +740,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { Transaction txn = Transaction.currentTxn(); txn.start(); - VolumeVO volume = new VolumeVO(volumeName, zoneId, -1L, -1L, -1, - new Long(-1), null, null, 0, Volume.Type.DATADISK); + VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1, + new Long(-1), null, null, 0, null, null, null, Volume.Type.DATADISK); volume.setPoolId(null); volume.setDataCenterId(zoneId); volume.setPodId(null); @@ -833,6 +844,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { Long diskOfferingId = null; DiskOfferingVO diskOffering = null; Long size = null; + Long minIops = null; + Long maxIops = null; // Volume VO used for extracting the source template id VolumeVO parentVolume = null; @@ -894,6 +907,37 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { size = diskOffering.getDiskSize(); } + Boolean isCustomizedIops = diskOffering.isCustomizedIops(); + + if (isCustomizedIops != null) { + if (isCustomizedIops) { + minIops = cmd.getMinIops(); + maxIops = cmd.getMaxIops(); + + if (minIops == null && maxIops == null) { + minIops = 0L; + maxIops = 0L; + } + else { + if (minIops == null || minIops <= 0) { + throw new InvalidParameterValueException("The min IOPS must be greater than 0."); + } + + if (maxIops == null) { + maxIops = 0L; + } + + if (minIops > maxIops) { + throw new InvalidParameterValueException("The min IOPS must be less than or equal to the max IOPS."); + } + } + } + else { + minIops = diskOffering.getMinIops(); + maxIops = diskOffering.getMaxIops(); + } + } + if (!validateVolumeSizeRange(size)) {// convert size from mb to gb // for validation throw new InvalidParameterValueException( @@ -968,8 +1012,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { Transaction txn = Transaction.currentTxn(); txn.start(); - VolumeVO volume = new VolumeVO(userSpecifiedName, -1L, -1L, -1, -1, - new Long(-1), null, null, 0, Volume.Type.DATADISK); + VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1, + new Long(-1), null, null, 0, null, null, null, Volume.Type.DATADISK); volume.setPoolId(null); volume.setDataCenterId(zoneId); volume.setPodId(null); @@ -978,6 +1022,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { .getDomainId())); volume.setDiskOfferingId(diskOfferingId); volume.setSize(size); + volume.setMinIops(minIops); + volume.setMaxIops(maxIops); volume.setInstanceId(null); volume.setUpdated(new Date()); volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller @@ -1169,7 +1215,6 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { UserVmVO userVm = _userVmDao.findById(volume.getInstanceId()); - PrimaryDataStoreInfo pool = (PrimaryDataStoreInfo)dataStoreMgr.getDataStore(volume.getPoolId(), DataStoreRole.Primary); long currentSize = volume.getSize(); /* @@ -1356,7 +1401,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { size = (size * 1024 * 1024 * 1024); } VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), - owner.getDomainId(), owner.getId(), offering.getId(), size); + owner.getDomainId(), owner.getId(), offering.getId(), size, + offering.getMinIops(), offering.getMaxIops(), null); if (vm != null) { vol.setInstanceId(vm.getId()); } @@ -1396,7 +1442,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { Long size = _tmpltMgr.getTemplateSize(template.getId(), vm.getDataCenterId()); VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), - owner.getDomainId(), owner.getId(), offering.getId(), size); + owner.getDomainId(), owner.getId(), offering.getId(), size, + offering.getMinIops(), offering.getMaxIops(), null); vol.setFormat(getSupportedImageFormatForCluster(template.getHypervisorType())); if (vm != null) { vol.setInstanceId(vm.getId()); @@ -1540,8 +1587,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { return !storeForRootStoreScope.isSameScope(storeForDataStoreScope); } - private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volume, Long deviceId) { - String errorMsg = "Failed to attach volume: " + volume.getName() + private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volumeToAttach, Long deviceId) { + String errorMsg = "Failed to attach volume: " + volumeToAttach.getName() + " to VM: " + vm.getHostName(); boolean sendCommand = (vm.getState() == State.Running); AttachAnswer answer = null; @@ -1555,12 +1602,37 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } } + StoragePoolVO volumeToAttachStoragePool = null; + if (sendCommand) { - DataTO volTO = volFactory.getVolume(volume.getId()).getTO(); - DiskTO disk = new DiskTO(volTO, deviceId, volume.getVolumeType()); + volumeToAttachStoragePool = _storagePoolDao.findById(volumeToAttach.getPoolId()); + long storagePoolId = volumeToAttachStoragePool.getId(); + + DataTO volTO = volFactory.getVolume(volumeToAttach.getId()).getTO(); + DiskTO disk = new DiskTO(volTO, deviceId, null, volumeToAttach.getVolumeType()); + AttachCommand cmd = new AttachCommand(disk, vm.getInstanceName()); + + cmd.setManaged(volumeToAttachStoragePool.isManaged()); + + cmd.setStorageHost(volumeToAttachStoragePool.getHostAddress()); + cmd.setStoragePort(volumeToAttachStoragePool.getPort()); + + cmd.set_iScsiName(volumeToAttach.get_iScsiName()); + + VolumeInfo volumeInfo = volFactory.getVolume(volumeToAttach.getId()); + DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + ChapInfo chapInfo = volService.getChapInfo(volumeInfo, dataStore); + + if (chapInfo != null) { + cmd.setChapInitiatorUsername(chapInfo.getInitiatorUsername()); + cmd.setChapInitiatorPassword(chapInfo.getInitiatorSecret()); + cmd.setChapTargetUsername(chapInfo.getTargetUsername()); + cmd.setChapTargetPassword(chapInfo.getTargetSecret()); + } + try { - answer = (AttachAnswer) _agentMgr.send(hostId, cmd); + answer = (AttachAnswer)_agentMgr.send(hostId, cmd); } catch (Exception e) { throw new CloudRuntimeException(errorMsg + " due to: " + e.getMessage()); @@ -1571,19 +1643,29 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { // Mark the volume as attached if (sendCommand) { DiskTO disk = answer.getDisk(); - _volsDao.attachVolume(volume.getId(), vm.getId(), + _volsDao.attachVolume(volumeToAttach.getId(), vm.getId(), disk.getDiskSeq()); + + volumeToAttach = _volsDao.findById(volumeToAttach.getId()); + + if (volumeToAttachStoragePool.isManaged() && + volumeToAttach.getPath() == null) { + volumeToAttach.setPath(answer.getDisk().getVdiUuid()); + + _volsDao.update(volumeToAttach.getId(), volumeToAttach); + } } else { - _volsDao.attachVolume(volume.getId(), vm.getId(), deviceId); + _volsDao.attachVolume(volumeToAttach.getId(), vm.getId(), deviceId); } + // insert record for disk I/O statistics - VmDiskStatisticsVO diskstats = _vmDiskStatsDao.findBy(vm.getAccountId(), vm.getDataCenterId(),vm.getId(), volume.getId()); + VmDiskStatisticsVO diskstats = _vmDiskStatsDao.findBy(vm.getAccountId(), vm.getDataCenterId(),vm.getId(), volumeToAttach.getId()); if (diskstats == null) { - diskstats = new VmDiskStatisticsVO(vm.getAccountId(), vm.getDataCenterId(),vm.getId(), volume.getId()); + diskstats = new VmDiskStatisticsVO(vm.getAccountId(), vm.getDataCenterId(),vm.getId(), volumeToAttach.getId()); _vmDiskStatsDao.persist(diskstats); } - return _volsDao.findById(volume.getId()); + return _volsDao.findById(volumeToAttach.getId()); } else { if (answer != null) { String details = answer.getDetails(); @@ -1900,9 +1982,17 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { Answer answer = null; if (sendCommand) { + StoragePoolVO volumePool = _storagePoolDao.findById(volume.getPoolId()); + DataTO volTO = volFactory.getVolume(volume.getId()).getTO(); - DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), volume.getVolumeType()); + DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), null, volume.getVolumeType()); + DettachCommand cmd = new DettachCommand(disk, vm.getInstanceName()); + + cmd.setManaged(volumePool.isManaged()); + + cmd.set_iScsiName(volume.get_iScsiName()); + try { answer = _agentMgr.send(vm.getHostId(), cmd); } catch (Exception e) { @@ -1914,6 +2004,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { if (!sendCommand || (answer != null && answer.getResult())) { // Mark the volume as detached _volsDao.detachVolume(volume.getId()); + return _volsDao.findById(volumeId); } else { @@ -1928,11 +2019,6 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } } - - - - - @DB protected VolumeVO switchVolume(VolumeVO existingVolume, VirtualMachineProfile vm) @@ -2217,7 +2303,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { for (VolumeVO vol : vols) { DataTO volTO = volFactory.getVolume(vol.getId()).getTO(); - DiskTO disk = new DiskTO(volTO, vol.getDeviceId(), vol.getVolumeType()); + DiskTO disk = new DiskTO(volTO, vol.getDeviceId(), null, vol.getVolumeType()); vm.addDisk(disk); } @@ -2225,7 +2311,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { UserVm userVM = _entityMgr.findById(UserVm.class, vm.getId()); if (userVM.getIsoId() != null) { DataTO dataTO = tmplFactory.getTemplate(userVM.getIsoId(), DataStoreRole.Image, userVM.getDataCenterId()).getTO(); - DiskTO iso = new DiskTO(dataTO, 3L, Volume.Type.ISO); + DiskTO iso = new DiskTO(dataTO, 3L, null, Volume.Type.ISO); vm.addDisk(iso); } } @@ -2443,7 +2529,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { vol = result.first(); } DataTO volumeTO = volFactory.getVolume(vol.getId()).getTO(); - DiskTO disk = new DiskTO(volumeTO, vol.getDeviceId(), vol.getVolumeType()); + DiskTO disk = new DiskTO(volumeTO, vol.getDeviceId(), null, vol.getVolumeType()); vm.addDisk(disk); } } @@ -2730,7 +2816,6 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { @Override public String getVmNameFromVolumeId(long volumeId) { - Long instanceId; VolumeVO volume = _volsDao.findById(volumeId); return getVmNameOnVolume(volume); } diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java index 59aa6b3e724..c179faceaa0 100755 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java @@ -1031,10 +1031,7 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar buf.append(" guid=").append(profile.getVirtualMachine().getHostName()); if (_configDao.isPremium()) { - if (profile.getHypervisorType() == HypervisorType.Hyperv) { - s_logger.debug("Hyperv hypervisor configured, telling the ssvm to load the CifsSecondaryStorageResource"); - buf.append(" resource=com.cloud.storage.resource.CifsSecondaryStorageResource"); - } else if (profile.getHypervisorType() == HypervisorType.VMware) { + if (profile.getHypervisorType() == HypervisorType.VMware) { s_logger.debug("VmWare hypervisor configured, telling the ssvm to load the PremiumSecondaryStorageResource"); buf.append(" resource=com.cloud.storage.resource.PremiumSecondaryStorageResource"); } else { diff --git a/server/src/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/com/cloud/template/HypervisorTemplateAdapter.java index 92148c3f83c..869231a87ae 100755 --- a/server/src/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/com/cloud/template/HypervisorTemplateAdapter.java @@ -39,10 +39,10 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.framework.async.AsyncRpcConext; +import org.apache.cloudstack.framework.async.AsyncRpcContext; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; -import org.apache.log4j.Logger; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; +import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; @@ -54,14 +54,13 @@ import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceAllocationException; -import com.cloud.host.HostVO; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.TemplateProfile; -import com.cloud.storage.VMTemplateZoneVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateZoneVO; import com.cloud.storage.dao.VMTemplateZoneDao; import com.cloud.storage.download.DownloadMonitor; import com.cloud.user.Account; @@ -71,9 +70,9 @@ import com.cloud.utils.exception.CloudRuntimeException; @Local(value=TemplateAdapter.class) public class HypervisorTemplateAdapter extends TemplateAdapterBase { - private final static Logger s_logger = Logger.getLogger(HypervisorTemplateAdapter.class); - @Inject DownloadMonitor _downloadMonitor; - @Inject AgentManager _agentMgr; + private final static Logger s_logger = Logger.getLogger(HypervisorTemplateAdapter.class); + @Inject DownloadMonitor _downloadMonitor; + @Inject AgentManager _agentMgr; @Inject DataStoreManager storeMgr; @Inject TemplateService imageService; @@ -90,86 +89,86 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { } - @Override - public TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationException { - TemplateProfile profile = super.prepare(cmd); - String url = profile.getUrl(); + @Override + public TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationException { + TemplateProfile profile = super.prepare(cmd); + String url = profile.getUrl(); - if((!url.toLowerCase().endsWith("iso"))&&(!url.toLowerCase().endsWith("iso.zip"))&&(!url.toLowerCase().endsWith("iso.bz2")) - &&(!url.toLowerCase().endsWith("iso.gz"))){ - throw new InvalidParameterValueException("Please specify a valid iso"); + if((!url.toLowerCase().endsWith("iso"))&&(!url.toLowerCase().endsWith("iso.zip"))&&(!url.toLowerCase().endsWith("iso.bz2")) + &&(!url.toLowerCase().endsWith("iso.gz"))){ + throw new InvalidParameterValueException("Please specify a valid iso"); } - UriUtils.validateUrl(url); - profile.setUrl(url); - // Check that the resource limit for secondary storage won't be exceeded - _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()), - ResourceType.secondary_storage, UriUtils.getRemoteSize(url)); - return profile; - } + UriUtils.validateUrl(url); + profile.setUrl(url); + // Check that the resource limit for secondary storage won't be exceeded + _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()), + ResourceType.secondary_storage, UriUtils.getRemoteSize(url)); + return profile; + } - @Override - public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException { - TemplateProfile profile = super.prepare(cmd); - String url = profile.getUrl(); + @Override + public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException { + TemplateProfile profile = super.prepare(cmd); + String url = profile.getUrl(); - if((!url.toLowerCase().endsWith("vhd"))&&(!url.toLowerCase().endsWith("vhd.zip")) - &&(!url.toLowerCase().endsWith("vhd.bz2"))&&(!url.toLowerCase().endsWith("vhd.gz")) - &&(!url.toLowerCase().endsWith("qcow2"))&&(!url.toLowerCase().endsWith("qcow2.zip")) - &&(!url.toLowerCase().endsWith("qcow2.bz2"))&&(!url.toLowerCase().endsWith("qcow2.gz")) - &&(!url.toLowerCase().endsWith("ova"))&&(!url.toLowerCase().endsWith("ova.zip")) - &&(!url.toLowerCase().endsWith("ova.bz2"))&&(!url.toLowerCase().endsWith("ova.gz")) - &&(!url.toLowerCase().endsWith("tar"))&&(!url.toLowerCase().endsWith("tar.zip")) - &&(!url.toLowerCase().endsWith("tar.bz2"))&&(!url.toLowerCase().endsWith("tar.gz")) - &&(!url.toLowerCase().endsWith("img"))&&(!url.toLowerCase().endsWith("raw"))){ - throw new InvalidParameterValueException("Please specify a valid "+ cmd.getFormat().toLowerCase()); - } + if((!url.toLowerCase().endsWith("vhd"))&&(!url.toLowerCase().endsWith("vhd.zip")) + &&(!url.toLowerCase().endsWith("vhd.bz2"))&&(!url.toLowerCase().endsWith("vhd.gz")) + &&(!url.toLowerCase().endsWith("qcow2"))&&(!url.toLowerCase().endsWith("qcow2.zip")) + &&(!url.toLowerCase().endsWith("qcow2.bz2"))&&(!url.toLowerCase().endsWith("qcow2.gz")) + &&(!url.toLowerCase().endsWith("ova"))&&(!url.toLowerCase().endsWith("ova.zip")) + &&(!url.toLowerCase().endsWith("ova.bz2"))&&(!url.toLowerCase().endsWith("ova.gz")) + &&(!url.toLowerCase().endsWith("tar"))&&(!url.toLowerCase().endsWith("tar.zip")) + &&(!url.toLowerCase().endsWith("tar.bz2"))&&(!url.toLowerCase().endsWith("tar.gz")) + &&(!url.toLowerCase().endsWith("img"))&&(!url.toLowerCase().endsWith("raw"))){ + throw new InvalidParameterValueException("Please specify a valid "+ cmd.getFormat().toLowerCase()); + } - if ((cmd.getFormat().equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith("vhd") && !url.toLowerCase().endsWith("vhd.zip") && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase().endsWith("vhd.gz") )) - || (cmd.getFormat().equalsIgnoreCase("qcow2") && (!url.toLowerCase().endsWith("qcow2") && !url.toLowerCase().endsWith("qcow2.zip") && !url.toLowerCase().endsWith("qcow2.bz2") && !url.toLowerCase().endsWith("qcow2.gz") )) - || (cmd.getFormat().equalsIgnoreCase("ova") && (!url.toLowerCase().endsWith("ova") && !url.toLowerCase().endsWith("ova.zip") && !url.toLowerCase().endsWith("ova.bz2") && !url.toLowerCase().endsWith("ova.gz"))) - || (cmd.getFormat().equalsIgnoreCase("tar") && (!url.toLowerCase().endsWith("tar") && !url.toLowerCase().endsWith("tar.zip") && !url.toLowerCase().endsWith("tar.bz2") && !url.toLowerCase().endsWith("tar.gz"))) - || (cmd.getFormat().equalsIgnoreCase("raw") && (!url.toLowerCase().endsWith("img") && !url.toLowerCase().endsWith("raw")))) { - throw new InvalidParameterValueException("Please specify a valid URL. URL:" + url + " is an invalid for the format " + cmd.getFormat().toLowerCase()); - } + if ((cmd.getFormat().equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith("vhd") && !url.toLowerCase().endsWith("vhd.zip") && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase().endsWith("vhd.gz") )) + || (cmd.getFormat().equalsIgnoreCase("qcow2") && (!url.toLowerCase().endsWith("qcow2") && !url.toLowerCase().endsWith("qcow2.zip") && !url.toLowerCase().endsWith("qcow2.bz2") && !url.toLowerCase().endsWith("qcow2.gz") )) + || (cmd.getFormat().equalsIgnoreCase("ova") && (!url.toLowerCase().endsWith("ova") && !url.toLowerCase().endsWith("ova.zip") && !url.toLowerCase().endsWith("ova.bz2") && !url.toLowerCase().endsWith("ova.gz"))) + || (cmd.getFormat().equalsIgnoreCase("tar") && (!url.toLowerCase().endsWith("tar") && !url.toLowerCase().endsWith("tar.zip") && !url.toLowerCase().endsWith("tar.bz2") && !url.toLowerCase().endsWith("tar.gz"))) + || (cmd.getFormat().equalsIgnoreCase("raw") && (!url.toLowerCase().endsWith("img") && !url.toLowerCase().endsWith("raw")))) { + throw new InvalidParameterValueException("Please specify a valid URL. URL:" + url + " is an invalid for the format " + cmd.getFormat().toLowerCase()); + } - UriUtils.validateUrl(url); - profile.setUrl(url); - // Check that the resource limit for secondary storage won't be exceeded - _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()), - ResourceType.secondary_storage, UriUtils.getRemoteSize(url)); - return profile; - } + UriUtils.validateUrl(url); + profile.setUrl(url); + // Check that the resource limit for secondary storage won't be exceeded + _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()), + ResourceType.secondary_storage, UriUtils.getRemoteSize(url)); + return profile; + } - @Override - public VMTemplateVO create(TemplateProfile profile) { - // persist entry in vm_template, vm_template_details and template_zone_ref tables, not that entry at template_store_ref is not created here, and created in createTemplateAsync. - VMTemplateVO template = persistTemplate(profile); + @Override + public VMTemplateVO create(TemplateProfile profile) { + // persist entry in vm_template, vm_template_details and template_zone_ref tables, not that entry at template_store_ref is not created here, and created in createTemplateAsync. + VMTemplateVO template = persistTemplate(profile); - if (template == null) { - throw new CloudRuntimeException("Unable to persist the template " + profile.getTemplate()); - } + if (template == null) { + throw new CloudRuntimeException("Unable to persist the template " + profile.getTemplate()); + } - // find all eligible image stores for this zone scope - List imageStores = this.storeMgr.getImageStoresByScope(new ZoneScope(profile.getZoneId())); - if ( imageStores == null || imageStores.size() == 0 ){ - throw new CloudRuntimeException("Unable to find image store to download template "+ profile.getTemplate()); - } + // find all eligible image stores for this zone scope + List imageStores = this.storeMgr.getImageStoresByScope(new ZoneScope(profile.getZoneId())); + if ( imageStores == null || imageStores.size() == 0 ){ + throw new CloudRuntimeException("Unable to find image store to download template "+ profile.getTemplate()); + } for (DataStore imageStore : imageStores) { - TemplateInfo tmpl = this.imageFactory.getTemplate(template.getId(), imageStore); - CreateTemplateContext context = new CreateTemplateContext(null, tmpl); - AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); - caller.setCallback(caller.getTarget().createTemplateAsyncCallBack(null, null)); - caller.setContext(context); - this.imageService - .createTemplateAsync(tmpl, imageStore, caller); + TemplateInfo tmpl = this.imageFactory.getTemplate(template.getId(), imageStore); + CreateTemplateContext context = new CreateTemplateContext(null, tmpl); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().createTemplateAsyncCallBack(null, null)); + caller.setContext(context); + this.imageService + .createTemplateAsync(tmpl, imageStore, caller); } _resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template); return template; } - private class CreateTemplateContext extends AsyncRpcConext { + private class CreateTemplateContext extends AsyncRpcContext { final TemplateInfo template; public CreateTemplateContext(AsyncCompletionCallback callback, TemplateInfo template) { super(callback); @@ -193,73 +192,80 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { } } - return null; - } + return null; + } - @Override @DB - public boolean delete(TemplateProfile profile) { - boolean success = true; + @Override @DB + public boolean delete(TemplateProfile profile) { + boolean success = true; - VMTemplateVO template = profile.getTemplate(); + VMTemplateVO template = profile.getTemplate(); // find all eligible image stores for this template List imageStores = this.templateMgr.getImageStoreByTemplate(template.getId(), profile.getZoneId()); - if ( imageStores == null || imageStores.size() == 0 ){ - throw new CloudRuntimeException("Unable to find image store to delete template "+ profile.getTemplate()); - } - - // Make sure the template is downloaded to all found image stores - for (DataStore store : imageStores) { - long storeId = store.getId(); - List templateStores = _tmpltStoreDao.listByTemplateStore(template.getId(), storeId); - for (TemplateDataStoreVO templateStore : templateStores) { - if (templateStore.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) { - String errorMsg = "Please specify a template that is not currently being downloaded."; - s_logger.debug("Template: " + template.getName() + " is currently being downloaded to secondary storage host: " + store.getName() + "; cant' delete it."); - throw new CloudRuntimeException(errorMsg); - } - } - } - - String eventType = ""; - if (template.getFormat().equals(ImageFormat.ISO)) { - eventType = EventTypes.EVENT_ISO_DELETE; + if (imageStores == null || imageStores.size() == 0) { + // already destroyed on image stores + s_logger.info("Unable to find image store still having template: " + template.getName() + + ", so just mark the template removed"); } else { - eventType = EventTypes.EVENT_TEMPLATE_DELETE; - } - - for (DataStore imageStore : imageStores) { - // publish zone-wide usage event - Long sZoneId = ((ImageStoreEntity)imageStore).getDataCenterId(); - if (sZoneId != null) { - UsageEventUtils.publishUsageEvent(eventType, template.getAccountId(), sZoneId, template.getId(), null, null, null); - } - - s_logger.info("Delete template from image store: " + imageStore.getName()); - AsyncCallFuture future = this.imageService - .deleteTemplateAsync(this.imageFactory.getTemplate(template.getId(), imageStore)); - try { - TemplateApiResult result = future.get(); - success = result.isSuccess(); - if ( !success ) - break; - - // remove from template_zone_ref - List templateZones = templateZoneDao.listByZoneTemplate(sZoneId, template.getId()); - if (templateZones != null) { - for (VMTemplateZoneVO templateZone : templateZones) { - templateZoneDao.remove(templateZone.getId()); + // Make sure the template is downloaded to all found image stores + for (DataStore store : imageStores) { + long storeId = store.getId(); + List templateStores = _tmpltStoreDao + .listByTemplateStore(template.getId(), storeId); + for (TemplateDataStoreVO templateStore : templateStores) { + if (templateStore.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) { + String errorMsg = "Please specify a template that is not currently being downloaded."; + s_logger.debug("Template: " + template.getName() + + " is currently being downloaded to secondary storage host: " + store.getName() + + "; cant' delete it."); + throw new CloudRuntimeException(errorMsg); } } - } catch (InterruptedException e) { - s_logger.debug("delete template Failed", e); - throw new CloudRuntimeException("delete template Failed", e); - } catch (ExecutionException e) { - s_logger.debug("delete template Failed", e); - throw new CloudRuntimeException("delete template Failed", e); + } + + String eventType = ""; + if (template.getFormat().equals(ImageFormat.ISO)) { + eventType = EventTypes.EVENT_ISO_DELETE; + } else { + eventType = EventTypes.EVENT_TEMPLATE_DELETE; + } + + for (DataStore imageStore : imageStores) { + // publish zone-wide usage event + Long sZoneId = ((ImageStoreEntity) imageStore).getDataCenterId(); + if (sZoneId != null) { + UsageEventUtils.publishUsageEvent(eventType, template.getAccountId(), sZoneId, template.getId(), + null, null, null); + } + + s_logger.info("Delete template from image store: " + imageStore.getName()); + AsyncCallFuture future = this.imageService.deleteTemplateAsync(this.imageFactory + .getTemplate(template.getId(), imageStore)); + try { + TemplateApiResult result = future.get(); + success = result.isSuccess(); + if (!success) { + break; + } + + // remove from template_zone_ref + List templateZones = templateZoneDao + .listByZoneTemplate(sZoneId, template.getId()); + if (templateZones != null) { + for (VMTemplateZoneVO templateZone : templateZones) { + templateZoneDao.remove(templateZone.getId()); + } + } + } catch (InterruptedException e) { + s_logger.debug("delete template Failed", e); + throw new CloudRuntimeException("delete template Failed", e); + } catch (ExecutionException e) { + s_logger.debug("delete template Failed", e); + throw new CloudRuntimeException("delete template Failed", e); + } } } - if (success) { s_logger.info("Delete template from template table"); // remove template from vm_templates table @@ -275,93 +281,99 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { return success; - } + } - @Override + @Override public TemplateProfile prepareDelete(DeleteTemplateCmd cmd) { - TemplateProfile profile = super.prepareDelete(cmd); - VMTemplateVO template = profile.getTemplate(); - Long zoneId = profile.getZoneId(); + TemplateProfile profile = super.prepareDelete(cmd); + VMTemplateVO template = profile.getTemplate(); + Long zoneId = profile.getZoneId(); - if (template.getTemplateType() == TemplateType.SYSTEM) { - throw new InvalidParameterValueException("The DomR template cannot be deleted."); - } + if (template.getTemplateType() == TemplateType.SYSTEM) { + throw new InvalidParameterValueException("The DomR template cannot be deleted."); + } - if (zoneId != null && (this.storeMgr.getImageStore(zoneId) == null)) { - throw new InvalidParameterValueException("Failed to find a secondary storage in the specified zone."); - } + if (zoneId != null && (this.storeMgr.getImageStore(zoneId) == null)) { + throw new InvalidParameterValueException("Failed to find a secondary storage in the specified zone."); + } - return profile; - } + return profile; + } - @Override + @Override public TemplateProfile prepareDelete(DeleteIsoCmd cmd) { - TemplateProfile profile = super.prepareDelete(cmd); - Long zoneId = profile.getZoneId(); + TemplateProfile profile = super.prepareDelete(cmd); + Long zoneId = profile.getZoneId(); - if (zoneId != null && (this.storeMgr.getImageStore(zoneId) == null)) { - throw new InvalidParameterValueException("Failed to find a secondary storage in the specified zone."); - } + if (zoneId != null && (this.storeMgr.getImageStore(zoneId) == null)) { + throw new InvalidParameterValueException("Failed to find a secondary storage in the specified zone."); + } - return profile; - } + return profile; + } @Override public TemplateProfile prepareExtractTemplate(ExtractTemplateCmd extractcmd) { - TemplateProfile profile = super.prepareExtractTemplate(extractcmd); - VMTemplateVO template = profile.getTemplate(); - Long zoneId = profile.getZoneId(); - Long templateId = template.getId(); + TemplateProfile profile = super.prepareExtractTemplate(extractcmd); + VMTemplateVO template = profile.getTemplate(); + Long zoneId = profile.getZoneId(); + Long templateId = template.getId(); - if (template.getHypervisorType() == HypervisorType.VMware) { - PrepareOVAPackingCommand cmd = null; - String zoneName=""; - List secondaryStorageHosts; - if (!template.isCrossZones() && zoneId != null) { - DataCenterVO zone = _dcDao.findById(zoneId); - zoneName = zone.getName(); - List imageStores = this.storeMgr.getImageStoresByScope(new ZoneScope(profile.getZoneId())); - if (imageStores == null || imageStores.size() == 0) { - throw new CloudRuntimeException("Unable to find image store to download template " + profile.getTemplate()); + // Simply return profile if non-ESX hypervisor. + if (template.getHypervisorType() == HypervisorType.VMware) { + PrepareOVAPackingCommand cmd = null; + String zoneName=""; + List imageStores = null; + + if (!template.isCrossZones()) { + if (zoneId == null) { + throw new CloudRuntimeException("ZoneId cannot be null for a template that is not available across zones"); } + // Else get the list of image stores in this zone's scope. + DataCenterVO zone = _dcDao.findById(zoneId); + zoneName = zone.getName(); + imageStores = this.storeMgr.getImageStoresByScope(new ZoneScope(profile.getZoneId())); + } else { + // template is available across zones. Get a list of all image stores. + imageStores = this.storeMgr.listImageStores(); + } - s_logger.debug("Attempting to mark template host refs for template: " + template.getName() + " as destroyed in zone: " + zoneName); + if (imageStores == null || imageStores.size() == 0) { + throw new CloudRuntimeException("Unable to find an image store zone when trying to download template " + profile.getTemplate()); + } - // Make sure the template is downloaded to all the necessary secondary storage hosts + s_logger.debug("Attempting to mark template host refs for template: " + template.getName() + " as destroyed in zone: " + zoneName); - for (DataStore store : imageStores) { - long storeId = store.getId(); - List templateStoreVOs = _tmpltStoreDao.listByTemplateStore(templateId, storeId); - for (TemplateDataStoreVO templateStoreVO : templateStoreVOs) { - if (templateStoreVO.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) { - String errorMsg = "Please specify a template that is not currently being downloaded."; - s_logger.debug("Template: " + template.getName() + " is currently being downloaded to secondary storage host: " + store.getName() + "."); - throw new CloudRuntimeException(errorMsg); + // Make sure the template is downloaded to all the necessary secondary storage hosts + + for (DataStore store : imageStores) { + long storeId = store.getId(); + List templateStoreVOs = _tmpltStoreDao.listByTemplateStore(templateId, storeId); + for (TemplateDataStoreVO templateStoreVO : templateStoreVOs) { + if (templateStoreVO.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) { + String errorMsg = "Please specify a template that is not currently being downloaded."; + s_logger.debug("Template: " + template.getName() + " is currently being downloaded to secondary storage host: " + store.getName() + "."); + throw new CloudRuntimeException(errorMsg); + } + String installPath = templateStoreVO.getInstallPath(); + if (installPath != null) { + EndPoint ep = _epSelector.select(store); + if (ep == null) { + s_logger.warn("prepareOVAPacking (hyervisorTemplateAdapter): There is no secondary storage VM for secondary storage host " + store.getName()); + throw new CloudRuntimeException("PrepareExtractTemplate: can't locate ssvm for SecStorage Host."); } - String installPath = templateStoreVO.getInstallPath(); - if (installPath != null) { - EndPoint ep = _epSelector.select(store); - if (ep == null) { - s_logger.warn("prepareOVAPacking (hyervisorTemplateAdapter): There is no secondary storage VM for secondary storage host " + store.getName()); - throw new CloudRuntimeException("PrepareExtractTemplate: can't locate ssvm for SecStorage Host."); - } - //Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, new PrepareOVAPackingCommand(secondaryStorageHost.getStorageUrl(), installPath)); - cmd = new PrepareOVAPackingCommand(store.getUri(), installPath); - cmd.setContextParam("hypervisor", HypervisorType.VMware.toString()); - Answer answer = ep.sendMessage(cmd); + cmd = new PrepareOVAPackingCommand(store.getUri(), installPath); + cmd.setContextParam("hypervisor", HypervisorType.VMware.toString()); + Answer answer = ep.sendMessage(cmd); - if (answer == null || !answer.getResult()) { - s_logger.debug("Failed to create OVA for template " + templateStoreVO + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); - throw new CloudRuntimeException("PrepareExtractTemplate: Failed to create OVA for template extraction. "); - } - } - } - } - } else { - s_logger.debug("Failed to create OVA for template " + template + " due to zone non-existing."); - throw new CloudRuntimeException("PrepareExtractTemplate: Failed to create OVA for template extraction. "); + if (answer == null || !answer.getResult()) { + s_logger.debug("Failed to create OVA for template " + templateStoreVO + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); + throw new CloudRuntimeException("PrepareExtractTemplate: Failed to create OVA for template extraction. "); + } + } + } + } } - } return profile; - } + } } diff --git a/server/src/com/cloud/template/TemplateAdapterBase.java b/server/src/com/cloud/template/TemplateAdapterBase.java index 25b298477cc..88909d8ab46 100755 --- a/server/src/com/cloud/template/TemplateAdapterBase.java +++ b/server/src/com/cloud/template/TemplateAdapterBase.java @@ -227,13 +227,13 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId()); _accountMgr.checkAccess(caller, null, true, owner); - + boolean isRouting = (cmd.isRoutingType() == null) ? false : cmd.isRoutingType(); return prepare(false, CallContext.current().getCallingUserId(), cmd.getTemplateName(), cmd.getDisplayText(), cmd.getBits(), cmd.isPasswordEnabled(), cmd.getRequiresHvm(), cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), cmd.getFormat(), cmd.getOsTypeId(), cmd.getZoneId(), HypervisorType.getType(cmd.getHypervisor()), cmd.getChecksum(), true, cmd.getTemplateTag(), owner, cmd.getDetails(), cmd.isSshKeyEnabled(), null, cmd.isDynamicallyScalable(), - cmd.isRoutingType() ? TemplateType.ROUTING : TemplateType.USER); + isRouting ? TemplateType.ROUTING : TemplateType.USER); } diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 6f8f9921864..d2a4730231e 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -1009,7 +1009,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } DataTO isoTO = tmplt.getTO(); - DiskTO disk = new DiskTO(isoTO, null, Volume.Type.ISO); + DiskTO disk = new DiskTO(isoTO, null, null, Volume.Type.ISO); Command cmd = null; if (attach) { cmd = new AttachCommand(disk, vmName); diff --git a/server/src/com/cloud/test/DatabaseConfig.java b/server/src/com/cloud/test/DatabaseConfig.java index ef0259d7c60..63f77b66520 100755 --- a/server/src/com/cloud/test/DatabaseConfig.java +++ b/server/src/com/cloud/test/DatabaseConfig.java @@ -979,7 +979,7 @@ public class DatabaseConfig { newTags.delete(newTags.length() - 1, newTags.length()); tags = newTags.toString(); } - DiskOfferingVO diskOffering = new DiskOfferingVO(domainId, name, displayText, diskSpace , tags, false); + DiskOfferingVO diskOffering = new DiskOfferingVO(domainId, name, displayText, diskSpace, tags, false, null, null, null); diskOffering.setUseLocalStorage(local); Long bytesReadRate = Long.parseLong(_currentObjectParams.get("bytesReadRate")); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index c9bd37ce942..d34ba7de142 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2902,12 +2902,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use TemplateObjectTO iso = (TemplateObjectTO)template.getTO(); iso.setGuestOsType(displayName); - DiskTO disk = new DiskTO(iso, 3L, Volume.Type.ISO); + DiskTO disk = new DiskTO(iso, 3L, null, Volume.Type.ISO); profile.addDisk(disk); } else { TemplateObjectTO iso = new TemplateObjectTO(); iso.setFormat(ImageFormat.ISO); - DiskTO disk = new DiskTO(iso, 3L, Volume.Type.ISO); + DiskTO disk = new DiskTO(iso, 3L, null, Volume.Type.ISO); profile.addDisk(disk); } diff --git a/server/src/org/apache/cloudstack/region/PortableIpDaoImpl.java b/server/src/org/apache/cloudstack/region/PortableIpDaoImpl.java index 488761bc35f..4e1810fbd56 100755 --- a/server/src/org/apache/cloudstack/region/PortableIpDaoImpl.java +++ b/server/src/org/apache/cloudstack/region/PortableIpDaoImpl.java @@ -69,7 +69,7 @@ public class PortableIpDaoImpl extends GenericDaoBase implem listByRangeIDAndStateSearch.done(); listByRegionIDAndStateSearch = createSearchBuilder(); - listByRegionIDAndStateSearch.and("regionId", listByRegionIDAndStateSearch.entity().getRangeId(), SearchCriteria.Op.EQ); + listByRegionIDAndStateSearch.and("regionId", listByRegionIDAndStateSearch.entity().getRegionId(), SearchCriteria.Op.EQ); listByRegionIDAndStateSearch.and("state", listByRegionIDAndStateSearch.entity().getState(), SearchCriteria.Op.EQ); listByRegionIDAndStateSearch.done(); diff --git a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java b/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java index 8747ee17ee2..20e75cc8e01 100644 --- a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java +++ b/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java @@ -661,8 +661,9 @@ public class GlobalLoadBalancingRulesServiceImpl implements GlobalLoadBalancingR try { _gslbProvider.applyGlobalLoadBalancerRule(zoneId.first(), zoneId.second(), gslbConfigCmd); } catch (ResourceUnavailableException e) { - s_logger.warn("Failed to configure GSLB rul in the zone " + zoneId + " due to " + e.getMessage()); - throw new CloudRuntimeException("Failed to configure GSLB rul in the zone"); + String msg = "Failed to configure GSLB rule in the zone " + zoneId.first() + " due to " + e.getMessage(); + s_logger.warn(msg); + throw new CloudRuntimeException(msg); } } diff --git a/server/test/com/cloud/network/MockNetworkModelImpl.java b/server/test/com/cloud/network/MockNetworkModelImpl.java index bab9df8dd6d..92e4cb1c5bf 100644 --- a/server/test/com/cloud/network/MockNetworkModelImpl.java +++ b/server/test/com/cloud/network/MockNetworkModelImpl.java @@ -885,4 +885,9 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel { // TODO Auto-generated method stub return false; } + + @Override + public boolean isNetworkReadyForGc(long networkId) { + return true; + } } diff --git a/server/test/com/cloud/network/UpdatePhysicalNetworkTest.java b/server/test/com/cloud/network/UpdatePhysicalNetworkTest.java index ca9d149214f..25c023e683e 100644 --- a/server/test/com/cloud/network/UpdatePhysicalNetworkTest.java +++ b/server/test/com/cloud/network/UpdatePhysicalNetworkTest.java @@ -22,6 +22,7 @@ import com.cloud.network.NetworkServiceImpl; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.utils.Pair; +import com.cloud.utils.db.Transaction; import org.junit.Test; import org.junit.*; import org.mockito.ArgumentCaptor; @@ -54,6 +55,7 @@ public class UpdatePhysicalNetworkTest { @Test public void updatePhysicalNetworkTest(){ + Transaction txn = Transaction.open("updatePhysicalNetworkTest"); NetworkServiceImpl networkService = setUp(); existingRange.add(new Pair(520, 524)); when(_physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetworkVO); @@ -61,6 +63,7 @@ public class UpdatePhysicalNetworkTest { when(_physicalNetworkDao.update(anyLong(), any(physicalNetworkVO.getClass()))).thenReturn(true); when(physicalNetworkVO.getVnet()).thenReturn(existingRange); networkService.updatePhysicalNetwork(1l, null, null, "525-530", null, null); + txn.close("updatePhysicalNetworkTest"); verify(physicalNetworkVO).setVnet(argumentCaptor.capture()); assertEquals("520-530", argumentCaptor.getValue()); } diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java index c7675c8f79d..f71067dca3f 100755 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -604,7 +604,8 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu * @see com.cloud.configuration.ConfigurationManager#createDiskOffering(java.lang.Long, java.lang.String, java.lang.String, java.lang.Long, java.lang.String, boolean, boolean, boolean) */ @Override - public DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired, boolean isDisplayOfferingEnabled, + public DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, + boolean localStorageRequired, boolean isDisplayOfferingEnabled, Boolean isCustomizedIops, Long minIops, Long maxIops, Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate) { // TODO Auto-generated method stub return null; diff --git a/server/test/com/cloud/vpc/MockNetworkModelImpl.java b/server/test/com/cloud/vpc/MockNetworkModelImpl.java index a6ab1261c3c..9fbc65a8cb9 100644 --- a/server/test/com/cloud/vpc/MockNetworkModelImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkModelImpl.java @@ -898,4 +898,8 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel { return false; } + @Override + public boolean isNetworkReadyForGc(long networkId) { + return true; + } } diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index d016a01c324..578148fd3e5 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -430,6 +430,20 @@ ALTER TABLE `cloud`.`nics` ADD COLUMN `display_nic` tinyint(1) NOT NULL DEFAULT ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `display_offering` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should disk offering be displayed to the end user'; +ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `customized_iops` tinyint(1) unsigned COMMENT 'Should customized IOPS be displayed to the end user'; + +ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `min_iops` bigint(20) unsigned COMMENT 'Minimum IOPS'; + +ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `max_iops` bigint(20) unsigned COMMENT 'Maximum IOPS'; + +ALTER TABLE `cloud`.`volumes` ADD COLUMN `min_iops` bigint(20) unsigned COMMENT 'Minimum IOPS'; + +ALTER TABLE `cloud`.`volumes` ADD COLUMN `max_iops` bigint(20) unsigned COMMENT 'Maximum IOPS'; + +ALTER TABLE `cloud`.`storage_pool` ADD COLUMN `managed` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT 'Should CloudStack manage this storage'; + +ALTER TABLE `cloud`.`storage_pool` ADD COLUMN `capacity_iops` bigint(20) unsigned DEFAULT NULL COMMENT 'IOPS CloudStack can provision from this storage pool'; + ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `bytes_read_rate` bigint(20); ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `bytes_write_rate` bigint(20); @@ -872,6 +886,8 @@ CREATE VIEW `cloud`.`volume_view` AS volumes.device_id, volumes.volume_type, volumes.size, + volumes.min_iops, + volumes.max_iops, volumes.created, volumes.state, volumes.attached, @@ -982,6 +998,7 @@ CREATE VIEW `cloud`.`storage_pool_view` AS storage_pool.created, storage_pool.removed, storage_pool.capacity_bytes, + storage_pool.capacity_iops, storage_pool.scope, storage_pool.hypervisor, cluster.id cluster_id, @@ -1589,9 +1606,12 @@ CREATE VIEW `cloud`.`disk_offering_view` AS disk_offering.name, disk_offering.display_text, disk_offering.disk_size, + disk_offering.min_iops, + disk_offering.max_iops, disk_offering.created, disk_offering.tags, disk_offering.customized, + disk_offering.customized_iops, disk_offering.removed, disk_offering.use_local_storage, disk_offering.system_use, @@ -1804,6 +1824,8 @@ CREATE VIEW `cloud`.`volume_view` AS volumes.device_id, volumes.volume_type, volumes.size, + volumes.min_iops, + volumes.max_iops, volumes.created, volumes.state, volumes.attached, diff --git a/test/integration/component/test_accounts.py b/test/integration/component/test_accounts.py index ee38c6ddc66..65c0c6ff49e 100644 --- a/test/integration/component/test_accounts.py +++ b/test/integration/component/test_accounts.py @@ -753,7 +753,7 @@ class TestServiceOfferingHierarchy(cloudstackTestCase): domainid=cls.domain_2.id ) - cls._cleanup = [ + cls._cleanup = [ cls.account_2, cls.domain_2, cls.service_offering, diff --git a/test/integration/component/test_advancedsg_networks.py b/test/integration/component/test_advancedsg_networks.py index f8774be9e48..483435188ca 100644 --- a/test/integration/component/test_advancedsg_networks.py +++ b/test/integration/component/test_advancedsg_networks.py @@ -24,9 +24,8 @@ from marvin.cloudstackAPI import * from marvin.integration.lib.utils import * from marvin.integration.lib.base import * from marvin.integration.lib.common import * -from marvin.remoteSSHClient import remoteSSHClient -import datetime import netaddr +from nose.plugins.attrib import attr class Services: """ Test networks in advanced zone with security groups""" @@ -156,7 +155,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase): @classmethod def setUpClass(cls): cls.api_client = super( - TestSharedNetworks, + TestNetworksInAdvancedSG, cls ).getClsTestClient().getApiClient() @@ -687,7 +686,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase): "The network offering state should get updated to Enabled." ) - physical_network = list_physical_networks_response[0] + physical_network = PhysicalNetwork.list(self.api_client)[0] #create network using the shared network offering created self.services["shared_network_sg"]["acltype"] = "domain" diff --git a/test/integration/component/test_affinity_groups.py b/test/integration/component/test_affinity_groups.py index 79e35e0d61d..44bf90c26dd 100644 --- a/test/integration/component/test_affinity_groups.py +++ b/test/integration/component/test_affinity_groups.py @@ -304,15 +304,14 @@ class TestListAffinityGroups(cloudstackTestCase): def tearDown(self): try: - cls.api_client = super(TestListAffinityGroups, cls).getClsTestClient().getApiClient() + self.api_client = super(TestListAffinityGroups, self).getClsTestClient().getApiClient() #Clean up, terminate the created templates - cleanup_resources(cls.api_client, cls.cleanup) + cleanup_resources(self.api_client, self.cleanup) except Exception as e: raise Exception("Warning: Exception during cleanup : %s" % e) @classmethod def tearDownClass(cls): - try: cls.api_client = super(TestListAffinityGroups, cls).getClsTestClient().getApiClient() #Clean up, terminate the created templates @@ -327,10 +326,6 @@ class TestListAffinityGroups(cloudstackTestCase): api_client = self.api_client if aff_grp == None: self.services["host_anti_affinity_0"] - #if acc == None: - # acc = self.account.name - #if domainid == None: - # domainid = self.domain.id try: self.aff_grp.append(AffinityGroup.create(api_client, @@ -339,34 +334,25 @@ class TestListAffinityGroups(cloudstackTestCase): raise Exception("Error: Creation of Affinity Group failed : %s" %e) def create_vm_in_aff_grps(self, ag_list): - #try: - self.debug('Creating VM in AffinityGroup=%s' % ag_list[0]) - vm = VirtualMachine.create( - self.api_client, - self.services["virtual_machine"], - templateid=self.template.id, - #accountid=self.account.name, - #domainid=self.account.domainid, - serviceofferingid=self.service_offering.id, - affinitygroupnames=ag_list - ) - self.debug('Created VM=%s in Affinity Group=%s' % - (vm.id, ag_list[0])) - #except Exception: - #self.debug('Unable to create VM in a Affinity Group=%s' - # % ag_list[0]) - - list_vm = list_virtual_machines(self.api_client, id=vm.id) + self.debug('Creating VM in AffinityGroup=%s' % ag_list[0]) + vm = VirtualMachine.create( + self.api_client, + self.services["virtual_machine"], + templateid=self.template.id, + serviceofferingid=self.service_offering.id, + affinitygroupnames=ag_list + ) + self.debug('Created VM=%s in Affinity Group=%s' % + (vm.id, ag_list[0])) + list_vm = list_virtual_machines(self.api_client, id=vm.id) self.assertEqual(isinstance(list_vm, list), True, "Check list response returns a valid list") self.assertNotEqual(len(list_vm),0, "Check VM available in List Virtual Machines") - vm_response = list_vm[0] self.assertEqual(vm_response.state, 'Running', msg="VM is not in Running state") - return vm, vm_response.hostid def test_01_list_aff_grps_for_vm(self): @@ -543,11 +529,6 @@ class TestDeleteAffinityGroups(cloudstackTestCase): api_client = self.api_client if aff_grp == None: self.services["host_anti_affinity_0"] - #if acc == None: - # acc = self.account.name - #if domainid == None: - # domainid = self.domain.id - try: self.aff_grp.append(AffinityGroup.create(api_client, aff_grp, acc, domainid)) @@ -555,24 +536,18 @@ class TestDeleteAffinityGroups(cloudstackTestCase): raise Exception("Error: Creation of Affinity Group failed : %s" %e) def create_vm_in_aff_grps(self, ag_list): - #try: - self.debug('Creating VM in AffinityGroup=%s' % ag_list[0]) - vm = VirtualMachine.create( - self.api_client, - self.services["virtual_machine"], - templateid=self.template.id, - #accountid=self.account.name, - #domainid=self.account.domainid, - serviceofferingid=self.service_offering.id, - affinitygroupnames=ag_list - ) - self.debug('Created VM=%s in Affinity Group=%s' % - (vm.id, ag_list[0])) - #except Exception: - #self.debug('Unable to create VM in a Affinity Group=%s' - # % ag_list[0]) + self.debug('Creating VM in AffinityGroup=%s' % ag_list[0]) + vm = VirtualMachine.create( + self.api_client, + self.services["virtual_machine"], + templateid=self.template.id, + serviceofferingid=self.service_offering.id, + affinitygroupnames=ag_list + ) + self.debug('Created VM=%s in Affinity Group=%s' % + (vm.id, ag_list[0])) - list_vm = list_virtual_machines(self.api_client, id=vm.id) + list_vm = list_virtual_machines(self.api_client, id=vm.id) self.assertEqual(isinstance(list_vm, list), True, "Check list response returns a valid list") @@ -817,11 +792,6 @@ class TestUpdateVMAffinityGroups(cloudstackTestCase): api_client = self.api_client if aff_grp == None: self.services["host_anti_affinity_0"] - #if acc == None: - # acc = self.account.name - #if domainid == None: - # domainid = self.domain.id - try: self.aff_grp.append(AffinityGroup.create(api_client, aff_grp, acc, domainid)) @@ -829,24 +799,18 @@ class TestUpdateVMAffinityGroups(cloudstackTestCase): raise Exception("Error: Creation of Affinity Group failed : %s" %e) def create_vm_in_aff_grps(self, ag_list): - #try: - self.debug('Creating VM in AffinityGroup=%s' % ag_list[0]) - vm = VirtualMachine.create( - self.api_client, + self.debug('Creating VM in AffinityGroup=%s' % ag_list[0]) + vm = VirtualMachine.create( + self.api_client, self.services["virtual_machine"], templateid=self.template.id, - #accountid=self.account.name, - #domainid=self.account.domainid, serviceofferingid=self.service_offering.id, affinitygroupnames=ag_list ) - self.debug('Created VM=%s in Affinity Group=%s' % - (vm.id, ag_list[0])) - #except Exception: - #self.debug('Unable to create VM in a Affinity Group=%s' - # % ag_list[0]) + self.debug('Created VM=%s in Affinity Group=%s' % + (vm.id, ag_list[0])) - list_vm = list_virtual_machines(self.api_client, id=vm.id) + list_vm = list_virtual_machines(self.api_client, id=vm.id) self.assertEqual(isinstance(list_vm, list), True, "Check list response returns a valid list") @@ -996,7 +960,7 @@ class TestUpdateVMAffinityGroups(cloudstackTestCase): vm1.start(self.api_client) list_aff_grps = AffinityGroup.list(self.api_client, - virtualmachineid=vm.id) + virtualmachineid=vm1.id) self.assertEqual(list_aff_grps, [], "The affinity groups list is not empyty") vm1.delete(self.api_client) @@ -1096,10 +1060,6 @@ class TestDeployVMAffinityGroups(cloudstackTestCase): api_client = self.api_client if aff_grp == None: self.services["host_anti_affinity_0"] - #if acc == None: - # acc = self.account.name - #if domainid == None: - # domainid = self.domain.id try: self.aff_grp.append(AffinityGroup.create(api_client, @@ -1111,21 +1071,19 @@ class TestDeployVMAffinityGroups(cloudstackTestCase): if api_client == None: api_client = self.api_client - self.debug('Creating VM in AffinityGroup=%s' % ag_list) - vm = VirtualMachine.create( + self.debug('Creating VM in AffinityGroup=%s' % ag_list) + vm = VirtualMachine.create( api_client, self.services["virtual_machine"], templateid=self.template.id, - #accountid=self.account.name, - #domainid=self.account.domainid, serviceofferingid=self.service_offering.id, affinitygroupnames=ag_list, affinitygroupids=ag_ids ) - self.debug('Created VM=%s in Affinity Group=%s' % - (vm.id, ag_list)) + self.debug('Created VM=%s in Affinity Group=%s' % + (vm.id, ag_list)) - list_vm = list_virtual_machines(self.api_client, id=vm.id) + list_vm = list_virtual_machines(self.api_client, id=vm.id) self.assertEqual(isinstance(list_vm, list), True, "Check list response returns a valid list") @@ -1143,7 +1101,6 @@ class TestDeployVMAffinityGroups(cloudstackTestCase): """ Deploy VM without affinity group """ - vm1, hostid1 = self.create_vm_in_aff_grps() vm1.delete(self.api_client) @@ -1441,10 +1398,6 @@ class TestAffinityGroupsAdminUser(cloudstackTestCase): api_client = self.api_client if aff_grp == None: self.services["host_anti_affinity_0"] - #if acc == None: - # acc = self.account.name - #if domainid == None: - # domainid = self.domain.id try: self.aff_grp.append(AffinityGroup.create(api_client, @@ -1456,21 +1409,19 @@ class TestAffinityGroupsAdminUser(cloudstackTestCase): if api_client == None: api_client = self.api_client - self.debug('Creating VM in AffinityGroup=%s' % ag_list) - vm = VirtualMachine.create( + self.debug('Creating VM in AffinityGroup=%s' % ag_list) + vm = VirtualMachine.create( api_client, self.services["virtual_machine"], templateid=self.template.id, - #accountid=self.account.name, - #domainid=self.account.domainid, serviceofferingid=self.service_offering.id, affinitygroupnames=ag_list, affinitygroupids=ag_ids ) - self.debug('Created VM=%s in Affinity Group=%s' % - (vm.id, ag_list)) + self.debug('Created VM=%s in Affinity Group=%s' % + (vm.id, ag_list)) - list_vm = list_virtual_machines(self.api_client, id=vm.id) + list_vm = list_virtual_machines(self.api_client, id=vm.id) self.assertEqual(isinstance(list_vm, list), True, "Check list response returns a valid list") diff --git a/test/integration/component/test_assign_vm.py b/test/integration/component/test_assign_vm.py index 1dc93a81417..8bc98fec55c 100644 --- a/test/integration/component/test_assign_vm.py +++ b/test/integration/component/test_assign_vm.py @@ -40,13 +40,14 @@ from marvin.integration.lib.common import (get_domain, list_virtual_machines) def log_test_exceptions(func): - def _log_test_exceptions(self, *args, **kwargs): + def test_wrap_exception_log(self, *args, **kwargs): try: func(self, *args, **kwargs) except Exception as e: self.debug('Test %s Failed due to Exception=%s' % (func, e)) raise e - return _log_test_exceptions + test_wrap_exception_log.__doc__ = func.__doc__ + return test_wrap_exception_log class Services: """Test service data for:Change the ownershop of @@ -229,6 +230,7 @@ class TestVMOwnership(cloudstackTestCase): except Exception as e: self.debug("Warning! Exception in tearDown: %s" % e) + @attr(tags = ["advanced"]) @log_test_exceptions def test_01_move_across_different_domains(self): diff --git a/test/integration/component/test_ldap.py b/test/integration/component/test_ldap.py index 1b933dbccf7..fc3bd486266 100644 --- a/test/integration/component/test_ldap.py +++ b/test/integration/component/test_ldap.py @@ -185,7 +185,7 @@ class TestLdap(cloudstackTestCase): raise Exception("Warning: Exception during cleanup : %s" % e) return - + @attr(tags=["advanced", "basic"]) def test_01_configLDAP(self): ''' This test is to verify ldapConfig API with valid values.(i.e query fileter as email) @@ -215,7 +215,7 @@ class TestLdap(cloudstackTestCase): self.debug("end test") - + @attr(tags=["advanced", "basic"]) def test_02_configLDAP(self): ''' This test is to verify ldapConfig API with valid values.(i.e query fileter as displayName) @@ -236,7 +236,7 @@ class TestLdap(cloudstackTestCase): self.debug("LDAP Configuration failed with exception") self.debug("end test") - + @attr(tags=["advanced", "basic"]) def test_03_configLDAP(self): ''' @@ -250,7 +250,7 @@ class TestLdap(cloudstackTestCase): self.ldapconfRes=self._testldapConfig(self.services["ldapCon_3"]) self.assertEquals(self.ldapconfRes,0,"LDAP configuration successful with invalid value.API failed") self.debug("end test") - + @attr(tags=["advanced", "basic"]) def test_04_configLDAP(self): ''' This test is to verify ldapConfig API with invalid configuration values(by passing wrong query filter) @@ -263,7 +263,7 @@ class TestLdap(cloudstackTestCase): self.assertEquals(self.ldapconfRes,0,"API failed") - + @attr(tags=["advanced", "basic"]) def test_05_configLDAP(self): ''' @@ -281,6 +281,7 @@ class TestLdap(cloudstackTestCase): self.assertNotEqual(loginRes,1,"login API failed") self.debug("end test") + @attr(tags=["advanced", "basic"]) def test_06_removeLDAP(self): ''' This test is to verify ldapRemove API functionality diff --git a/test/integration/component/test_netscaler_configs.py b/test/integration/component/test_netscaler_configs.py index 5de0843b49b..d26da47a5f5 100644 --- a/test/integration/component/test_netscaler_configs.py +++ b/test/integration/component/test_netscaler_configs.py @@ -730,9 +730,9 @@ class TestNetScalerDedicated(cloudstackTestCase): networkofferingid=self.network_offering.id, zoneid=self.zone.id ) - self.debug("Deploying an instance in account: %s" % self.account_2.account.name) + self.debug("Deploying an instance in account: %s" % self.account_2.account.name) with self.assertRaises(Exception): - VirtualMachine.create( + VirtualMachine.create( self.apiclient, self.services["virtual_machine"], accountid=self.account_2.account.name, @@ -740,7 +740,7 @@ class TestNetScalerDedicated(cloudstackTestCase): serviceofferingid=self.service_offering.id, networkids=[str(self.network.id)] ) - self.debug("Deply instacne in dedicated Network offering mode failed") + self.debug("Deply instance in dedicated Network offering mode failed") return @@ -1285,7 +1285,7 @@ class TestNetScalerNoCapacity(cloudstackTestCase): ) if isinstance(physical_networks, list): physical_network = physical_networks[0] - cls.services["netscaler"]["lbdevicecapacity"] = 2 + cls.services["netscaler"]["lbdevicecapacity"] = 2 cls.netscaler = NetScaler.add( cls.api_client, cls.services["netscaler"], diff --git a/test/integration/component/test_shared_networks.py b/test/integration/component/test_shared_networks.py index 6bcfbfdfb39..8f59dfe82cb 100644 --- a/test/integration/component/test_shared_networks.py +++ b/test/integration/component/test_shared_networks.py @@ -2098,7 +2098,7 @@ class TestSharedNetworks(cloudstackTestCase): networkofferingid=self.shared_network_offering.id, zoneid=self.zone.id, ) - self.cleanup_networks.append(self.network1) + self.cleanup_networks.append(self.network1) self.fail("Network got created with used vlan id, which is invalid") except Exception as e: self.debug("Network creation failed because the valn id being used by another network.") diff --git a/test/integration/component/test_vpc_network_lbrules.py b/test/integration/component/test_vpc_network_lbrules.py index b0357fa8de1..865cf0e2a78 100644 --- a/test/integration/component/test_vpc_network_lbrules.py +++ b/test/integration/component/test_vpc_network_lbrules.py @@ -65,8 +65,8 @@ class Services: "name": "Tiny Instance", "displaytext": "Tiny Instance", "cpunumber": 1, - "cpuspeed": 1000, - "memory": 512, + "cpuspeed": 100, + "memory": 128, }, "network_offering": { "name": 'VPC Network offering', diff --git a/test/integration/component/test_vpc_network_pfrules.py b/test/integration/component/test_vpc_network_pfrules.py index b478b6a1780..ad7bbae7fe7 100644 --- a/test/integration/component/test_vpc_network_pfrules.py +++ b/test/integration/component/test_vpc_network_pfrules.py @@ -62,8 +62,8 @@ class Services: "name": "Tiny Instance", "displaytext": "Tiny Instance", "cpunumber": 1, - "cpuspeed": 1000, - "memory": 512, + "cpuspeed": 100, + "memory": 128, }, "network_offering": { "name": 'VPC Network offering', diff --git a/test/integration/component/test_vpc_network_staticnatrule.py b/test/integration/component/test_vpc_network_staticnatrule.py index c5d9e57434d..1410f5e50c5 100644 --- a/test/integration/component/test_vpc_network_staticnatrule.py +++ b/test/integration/component/test_vpc_network_staticnatrule.py @@ -61,8 +61,8 @@ class Services: "name": "Tiny Instance", "displaytext": "Tiny Instance", "cpunumber": 1, - "cpuspeed": 1000, - "memory": 512, + "cpuspeed": 100, + "memory": 128, }, "network_offering": { "name": 'VPC Network offering', diff --git a/test/integration/component/test_vpc_routers.py b/test/integration/component/test_vpc_routers.py index a8559e5cc6c..3501110bca1 100644 --- a/test/integration/component/test_vpc_routers.py +++ b/test/integration/component/test_vpc_routers.py @@ -49,7 +49,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, - "memory": 64, + "memory": 128, }, "service_offering_new": { "name": "Small Instance", @@ -424,9 +424,9 @@ class TestVPCRoutersBasic(cloudstackTestCase): @attr(tags=["advanced", "intervlan"]) def test_02_reboot_router_after_creating_vpc(self): - """ Test to reboot the router after creating a VPC - """ - # Validate the following + """ Test to reboot the router after creating a VPC + """ + # Validate the following # 1. Create a VPC with cidr - 10.1.1.1/16 # 2. Reboot the VPC Virtual Router which is created as a result of VPC creation. # Stop the VPC Router @@ -473,9 +473,9 @@ class TestVPCRoutersBasic(cloudstackTestCase): @attr(tags=["advanced", "intervlan"]) def test_03_destroy_router_after_creating_vpc(self): - """ Test to destroy the router after creating a VPC - """ - # Validate the following + """ Test to destroy the router after creating a VPC + """ + # Validate the following # 1. Create a VPC with cidr - 10.1.1.1/16 # 2. Destroy the VPC Virtual Router which is created as a result of VPC creation. self.validate_vpc_offering(self.vpc_off) @@ -528,15 +528,15 @@ class TestVPCRoutersBasic(cloudstackTestCase): "List Routers should return a valid list" ) self.migrate_router(routers[0]) - return + return @attr(tags=["advanced", "intervlan"]) def test_05_change_service_offerring_vpc(self): - """ Tests to change service offering of the Router after - creating a vpc - """ + """ Tests to change service offering of the Router after + creating a vpc + """ - # Validate the following + # Validate the following # 1. Create a VPC with cidr - 10.1.1.1/16 # 2. Change the service offerings of the VPC Virtual Router which is created as a result of VPC creation. @@ -568,7 +568,7 @@ class TestVPCRoutersBasic(cloudstackTestCase): ) self.debug("Changing service offering for the Router %s" % router.id) try: - router = Router.change_service_offering(self.apiclient, + router = Router.change_service_offering(self.apiclient, router.id, service_offering.id ) @@ -589,7 +589,7 @@ class TestVPCRoutersBasic(cloudstackTestCase): "Changing service offering failed as id is %s and expected" "is %s" % (router.serviceofferingid, service_offering.id) ) - return + return class TestVPCRouterOneNetwork(cloudstackTestCase): @@ -748,18 +748,6 @@ class TestVPCRouterOneNetwork(cloudstackTestCase): account=cls.account.name, domainid=cls.account.domainid ) -# cls.assertEqual( -# isinstance(public_ips, list), -# True, -# "List public Ip for network should list the Ip addr" -# ) -# cls.assertEqual( -# public_ips[0].ipaddress, -# public_ip_2.ipaddress.ipaddress, -# "List public Ip for network should list the Ip addr" -# ) -# - public_ip_3 = PublicIPAddress.create( cls.apiclient, accountid=cls.account.name, @@ -917,8 +905,8 @@ class TestVPCRouterOneNetwork(cloudstackTestCase): return def validate_network_rules(self): - """ Validate network rules - """ + """ Validate network rules + """ vms = VirtualMachine.list( self.apiclient, account=self.account.name, @@ -1014,8 +1002,8 @@ class TestVPCRouterOneNetwork(cloudstackTestCase): @attr(tags=["advanced", "intervlan"]) def test_01_start_stop_router_after_addition_of_one_guest_network(self): - """ Test start/stop of router after addition of one guest network - """ + """ Test start/stop of router after addition of one guest network + """ # Validations #1. Create a VPC with cidr - 10.1.1.1/16 #2. Add network1(10.1.1.1/24) to this VPC. @@ -1031,7 +1019,6 @@ class TestVPCRouterOneNetwork(cloudstackTestCase): self.validate_vpc_offering(self.vpc_off) self.validate_vpc_network(self.vpc) - #self.validate_network_rules() self.assertEqual( isinstance(self.gateways, list), True, @@ -1063,7 +1050,7 @@ class TestVPCRouterOneNetwork(cloudstackTestCase): cmd.id = router.id self.apiclient.stopRouter(cmd) - #List routers to check state of router + #List routers to check state of router router_response = list_routers( self.apiclient, id=router.id @@ -1082,13 +1069,13 @@ class TestVPCRouterOneNetwork(cloudstackTestCase): self.debug("Stopped the router with ID: %s" % router.id) - # Start The Router + # Start The Router self.debug("Starting the router with ID: %s" % router.id) cmd = startRouter.startRouterCmd() cmd.id = router.id self.apiclient.startRouter(cmd) - #List routers to check state of router + #List routers to check state of router router_response = list_routers( self.apiclient, id=router.id @@ -1110,8 +1097,8 @@ class TestVPCRouterOneNetwork(cloudstackTestCase): @attr(tags=["advanced", "intervlan"]) def test_02_reboot_router_after_addition_of_one_guest_network(self): - """ Test reboot of router after addition of one guest network - """ + """ Test reboot of router after addition of one guest network + """ # Validations #1. Create a VPC with cidr - 10.1.1.1/16 #2. Add network1(10.1.1.1/24) to this VPC. @@ -1177,8 +1164,8 @@ class TestVPCRouterOneNetwork(cloudstackTestCase): @attr(tags=["advanced", "intervlan"]) def test_03_destroy_router_after_addition_of_one_guest_network(self): - """ Test destroy of router after addition of one guest network - """ + """ Test destroy of router after addition of one guest network + """ # Validations #1. Create a VPC with cidr - 10.1.1.1/16 #2. Add network1(10.1.1.1/24) to this VPC. @@ -1236,8 +1223,8 @@ class TestVPCRouterOneNetwork(cloudstackTestCase): @attr(tags=["advanced", "intervlan"]) def test_04_migrate_router_after_addition_of_one_guest_network(self): - """ Test migrate of router after addition of one guest network - """ + """ Test migrate of router after addition of one guest network + """ # Validations #1. Create a VPC with cidr - 10.1.1.1/16 #2. Add network1(10.1.1.1/24) to this VPC. @@ -1275,12 +1262,12 @@ class TestVPCRouterOneNetwork(cloudstackTestCase): "List Routers should return a valid list" ) self.migrate_router(routers[0]) - return + return @attr(tags=["advanced", "intervlan"]) def test_05_chg_srv_off_router_after_addition_of_one_guest_network(self): - """ Test to change service offering of router after addition of one guest network - """ + """ Test to change service offering of router after addition of one guest network + """ # Validations #1. Create a VPC with cidr - 10.1.1.1/16 #2. Add network1(10.1.1.1/24) to this VPC. @@ -1332,7 +1319,7 @@ class TestVPCRouterOneNetwork(cloudstackTestCase): ) self.debug("Changing service offering for the Router %s" % router.id) try: - router = Router.change_service_offering(self.apiclient, + router = Router.change_service_offering(self.apiclient, router.id, service_offering.id ) @@ -1353,5 +1340,4 @@ class TestVPCRouterOneNetwork(cloudstackTestCase): "Changing service offering failed as id is %s and expected" "is %s" % (router.serviceofferingid, service_offering.id) ) - return - + return diff --git a/test/integration/smoke/test_deploy_vms_with_varied_deploymentplanners.py b/test/integration/smoke/test_deploy_vms_with_varied_deploymentplanners.py index fc8e71648af..ab44a2be083 100644 --- a/test/integration/smoke/test_deploy_vms_with_varied_deploymentplanners.py +++ b/test/integration/smoke/test_deploy_vms_with_varied_deploymentplanners.py @@ -23,30 +23,30 @@ from nose.plugins.attrib import attr class Services: def __init__(self): - self.services = { - "account": { - "email": "test@test.com", - "firstname": "Test", - "lastname": "User", - "username": "test", - # Random characters are appended for unique - # username - "password": "password", - }, - "service_offering": { - "name": "Planner Service Offering", - "displaytext": "Planner Service Offering", - "cpunumber": 1, - "cpuspeed": 100, - # in MHz - "memory": 128, - # In MBs - }, - "ostype": 'CentOS 5.3 (64-bit)', - "virtual_machine": { - "hypervisor": "XenServer", - } - } + self.services = { + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended for unique + # username + "password": "password", + }, + "service_offering": { + "name": "Planner Service Offering", + "displaytext": "Planner Service Offering", + "cpunumber": 1, + "cpuspeed": 100, + # in MHz + "memory": 128, + # In MBs + }, + "ostype": 'CentOS 5.3 (64-bit)', + "virtual_machine": { + "hypervisor": "XenServer", + } + } class TestDeployVmWithVariedPlanners(cloudstackTestCase): diff --git a/test/integration/smoke/test_network.py b/test/integration/smoke/test_network.py index 121bda03506..6788dca393a 100644 --- a/test/integration/smoke/test_network.py +++ b/test/integration/smoke/test_network.py @@ -669,7 +669,7 @@ class TestLoadBalancingRule(cloudstackTestCase): self.debug( "SSH into VM (IPaddress: %s) & NAT Rule (Public IP: %s)" % (self.vm_1.ipaddress, src_nat_ip_addr.ipaddress) - ) + ) ssh_1 = remoteSSHClient( src_nat_ip_addr.ipaddress, @@ -804,20 +804,20 @@ class TestLoadBalancingRule(cloudstackTestCase): ) - hostnames = [] - self.try_ssh(src_nat_ip_addr, hostnames) - self.try_ssh(src_nat_ip_addr, hostnames) - self.try_ssh(src_nat_ip_addr, hostnames) - self.try_ssh(src_nat_ip_addr, hostnames) - self.try_ssh(src_nat_ip_addr, hostnames) + hostnames = [] + self.try_ssh(src_nat_ip_addr, hostnames) + self.try_ssh(src_nat_ip_addr, hostnames) + self.try_ssh(src_nat_ip_addr, hostnames) + self.try_ssh(src_nat_ip_addr, hostnames) + self.try_ssh(src_nat_ip_addr, hostnames) - self.debug("Hostnames: %s" % str(hostnames)) - self.assertIn( + self.debug("Hostnames: %s" % str(hostnames)) + self.assertIn( self.vm_1.name, hostnames, "Check if ssh succeeded for server1" ) - self.assertIn( + self.assertIn( self.vm_2.name, hostnames, "Check if ssh succeeded for server2" @@ -826,8 +826,8 @@ class TestLoadBalancingRule(cloudstackTestCase): #SSH should pass till there is a last VM associated with LB rule lb_rule.remove(self.apiclient, [self.vm_2]) - # making hostnames list empty - hostnames[:] = [] + # making hostnames list empty + hostnames[:] = [] try: self.debug("SSHing into IP address: %s after removing VM (ID: %s)" % @@ -837,13 +837,11 @@ class TestLoadBalancingRule(cloudstackTestCase): )) self.try_ssh(src_nat_ip_addr, hostnames) - - self.assertIn( - self.vm_1.name, - hostnames, - "Check if ssh succeeded for server1" - ) - + self.assertIn( + self.vm_1.name, + hostnames, + "Check if ssh succeeded for server1" + ) except Exception as e: self.fail("%s: SSH failed for VM with IP Address: %s" % (e, src_nat_ip_addr.ipaddress)) @@ -958,23 +956,23 @@ class TestLoadBalancingRule(cloudstackTestCase): ) try: hostnames = [] - self.try_ssh(self.non_src_nat_ip, hostnames) - self.try_ssh(self.non_src_nat_ip, hostnames) - self.try_ssh(self.non_src_nat_ip, hostnames) - self.try_ssh(self.non_src_nat_ip, hostnames) - self.try_ssh(self.non_src_nat_ip, hostnames) + self.try_ssh(self.non_src_nat_ip, hostnames) + self.try_ssh(self.non_src_nat_ip, hostnames) + self.try_ssh(self.non_src_nat_ip, hostnames) + self.try_ssh(self.non_src_nat_ip, hostnames) + self.try_ssh(self.non_src_nat_ip, hostnames) - self.debug("Hostnames: %s" % str(hostnames)) - self.assertIn( - self.vm_1.name, - hostnames, - "Check if ssh succeeded for server1" - ) - self.assertIn( - self.vm_2.name, - hostnames, - "Check if ssh succeeded for server2" - ) + self.debug("Hostnames: %s" % str(hostnames)) + self.assertIn( + self.vm_1.name, + hostnames, + "Check if ssh succeeded for server1" + ) + self.assertIn( + self.vm_2.name, + hostnames, + "Check if ssh succeeded for server2" + ) #SSH should pass till there is a last VM associated with LB rule lb_rule.remove(self.apiclient, [self.vm_2]) @@ -984,19 +982,16 @@ class TestLoadBalancingRule(cloudstackTestCase): self.non_src_nat_ip.ipaddress.ipaddress, self.vm_2.id )) - # Making host list empty + # Making host list empty hostnames[:] = [] - self.try_ssh(self.non_src_nat_ip, hostnames) - - self.assertIn( - self.vm_1.name, - hostnames, - "Check if ssh succeeded for server1" - ) - + self.try_ssh(self.non_src_nat_ip, hostnames) + self.assertIn( + self.vm_1.name, + hostnames, + "Check if ssh succeeded for server1" + ) self.debug("Hostnames after removing VM2: %s" % str(hostnames)) - except Exception as e: self.fail("%s: SSH failed for VM with IP Address: %s" % (e, self.non_src_nat_ip.ipaddress.ipaddress)) @@ -1017,7 +1012,6 @@ class TestLoadBalancingRule(cloudstackTestCase): ssh_1.execute("hostname")[0] return - class TestRebootRouter(cloudstackTestCase): def setUp(self): @@ -1336,31 +1330,29 @@ class TestAssignRemoveLB(cloudstackTestCase): ) lb_rule.assign(self.apiclient, [self.vm_1, self.vm_2]) - hostnames = [] - self.try_ssh(self.non_src_nat_ip, hostnames) - self.try_ssh(self.non_src_nat_ip, hostnames) - self.try_ssh(self.non_src_nat_ip, hostnames) - self.try_ssh(self.non_src_nat_ip, hostnames) - self.try_ssh(self.non_src_nat_ip, hostnames) - - self.debug("Hostnames: %s" % str(hostnames)) - self.assertIn( - self.vm_1.name, - hostnames, - "Check if ssh succeeded for server1" - ) - self.assertIn( - self.vm_2.name, - hostnames, - "Check if ssh succeeded for server2" - ) - + hostnames = [] + self.try_ssh(self.non_src_nat_ip, hostnames) + self.try_ssh(self.non_src_nat_ip, hostnames) + self.try_ssh(self.non_src_nat_ip, hostnames) + self.try_ssh(self.non_src_nat_ip, hostnames) + self.try_ssh(self.non_src_nat_ip, hostnames) + self.debug("Hostnames: %s" % str(hostnames)) + self.assertIn( + self.vm_1.name, + hostnames, + "Check if ssh succeeded for server1" + ) + self.assertIn( + self.vm_2.name, + hostnames, + "Check if ssh succeeded for server2" + ) #Removing VM and assigning another VM to LB rule lb_rule.remove(self.apiclient, [self.vm_2]) - # making hostnames list empty - hostnames[:] = [] + # making hostnames list empty + hostnames[:] = [] try: self.debug("SSHing again into IP address: %s with VM (ID: %s) added to LB rule" % @@ -1370,38 +1362,35 @@ class TestAssignRemoveLB(cloudstackTestCase): )) self.try_ssh(self.non_src_nat_ip, hostnames) - self.assertIn( - self.vm_1.name, - hostnames, - "Check if ssh succeeded for server1" - ) - + self.assertIn( + self.vm_1.name, + hostnames, + "Check if ssh succeeded for server1" + ) except Exception as e: self.fail("SSH failed for VM with IP: %s" % self.non_src_nat_ip.ipaddress) lb_rule.assign(self.apiclient, [self.vm_3]) - # Making hostnames list empty + # Making hostnames list empty hostnames[:] = [] - - self.try_ssh(self.non_src_nat_ip, hostnames) - self.try_ssh(self.non_src_nat_ip, hostnames) - self.try_ssh(self.non_src_nat_ip, hostnames) - self.try_ssh(self.non_src_nat_ip, hostnames) - self.try_ssh(self.non_src_nat_ip, hostnames) - - self.debug("Hostnames: %s" % str(hostnames)) - self.assertIn( - self.vm_1.name, - hostnames, - "Check if ssh succeeded for server1" - ) - self.assertIn( - self.vm_3.name, - hostnames, - "Check if ssh succeeded for server3" - ) + self.try_ssh(self.non_src_nat_ip, hostnames) + self.try_ssh(self.non_src_nat_ip, hostnames) + self.try_ssh(self.non_src_nat_ip, hostnames) + self.try_ssh(self.non_src_nat_ip, hostnames) + self.try_ssh(self.non_src_nat_ip, hostnames) + self.debug("Hostnames: %s" % str(hostnames)) + self.assertIn( + self.vm_1.name, + hostnames, + "Check if ssh succeeded for server1" + ) + self.assertIn( + self.vm_3.name, + hostnames, + "Check if ssh succeeded for server3" + ) return class TestReleaseIP(cloudstackTestCase): diff --git a/test/integration/smoke/test_vm_snapshots.py b/test/integration/smoke/test_vm_snapshots.py index cca4cfb767f..dd709828a60 100644 --- a/test/integration/smoke/test_vm_snapshots.py +++ b/test/integration/smoke/test_vm_snapshots.py @@ -29,282 +29,283 @@ class Services: """ def __init__(self): - self.services = { - "account": { - "email": "test@test.com", - "firstname": "Test", - "lastname": "User", - "username": "test", - # Random characters are appended for unique - # username - "password": "password", - }, - "service_offering": { - "name": "Tiny Instance", - "displaytext": "Tiny Instance", - "cpunumber": 1, - "cpuspeed": 200, # in MHz - "memory": 256, # In MBs - }, - "server": { - "displayname": "TestVM", - "username": "root", - "password": "password", - "ssh_port": 22, - "hypervisor": 'XenServer', - "privateport": 22, - "publicport": 22, - "protocol": 'TCP', - }, - "mgmt_server": { - "ipaddress": '1.2.2.152', - "username": "root", - "password": "password", - "port": 22, - }, - "templates": { - "displaytext": 'Template', - "name": 'Template', - "ostype": "CentOS 5.3 (64-bit)", - "templatefilter": 'self', - }, - "test_dir": "/tmp", - "random_data": "random.data", - "snapshot_name":"TestSnapshot", - "snapshot_displaytext":"Test", - "ostype": "CentOS 5.3 (64-bit)", - "sleep": 60, - "timeout": 10, - "mode": 'advanced', # Networking mode: Advanced, Basic - } + self.services = { + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended for unique + # username + "password": "password", + }, + "service_offering": { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 200, # in MHz + "memory": 256, # In MBs + }, + "server": { + "displayname": "TestVM", + "username": "root", + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "mgmt_server": { + "ipaddress": '1.2.2.152', + "username": "root", + "password": "password", + "port": 22, + }, + "templates": { + "displaytext": 'Template', + "name": 'Template', + "ostype": "CentOS 5.3 (64-bit)", + "templatefilter": 'self', + }, + "test_dir": "/tmp", + "random_data": "random.data", + "snapshot_name": "TestSnapshot", + "snapshot_displaytext": "Test", + "ostype": "CentOS 5.3 (64-bit)", + "sleep": 60, + "timeout": 10, + "mode": 'advanced', # Networking mode: Advanced, Basic + } class TestVmSnapshot(cloudstackTestCase): + @classmethod def setUpClass(cls): - cls.api_client = super(TestVmSnapshot, cls).getClsTestClient().getApiClient() - cls.services = Services().services - # Get Zone, Domain and templates - cls.domain = get_domain(cls.api_client, cls.services) - cls.zone = get_zone(cls.api_client, cls.services) + cls.api_client = super(TestVmSnapshot, cls).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) - template = get_template( - cls.api_client, - cls.zone.id, - cls.services["ostype"] - ) - cls.services["domainid"] = cls.domain.id - cls.services["server"]["zoneid"] = cls.zone.id - cls.services["templates"]["ostypeid"] = template.ostypeid - cls.services["zoneid"] = cls.zone.id + template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls.services["domainid"] = cls.domain.id + cls.services["server"]["zoneid"] = cls.zone.id + cls.services["templates"]["ostypeid"] = template.ostypeid + cls.services["zoneid"] = cls.zone.id - # Create VMs, NAT Rules etc - cls.account = Account.create( - cls.api_client, - cls.services["account"], - domainid=cls.domain.id - ) + # Create VMs, NAT Rules etc + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) - cls.services["account"] = cls.account.name + cls.services["account"] = cls.account.name - cls.service_offering = ServiceOffering.create( - cls.api_client, - cls.services["service_offering"] - ) - cls.virtual_machine = VirtualMachine.create( - cls.api_client, - cls.services["server"], - templateid=template.id, - accountid=cls.account.name, - domainid=cls.account.domainid, - serviceofferingid=cls.service_offering.id, - mode=cls.services["mode"] - ) - cls.random_data_0 = random_gen(100) - cls._cleanup = [ - cls.service_offering, - cls.account, - ] - return + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) + cls.virtual_machine = VirtualMachine.create( + cls.api_client, + cls.services["server"], + templateid=template.id, + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering.id, + mode=cls.services["mode"] + ) + cls.random_data_0 = random_gen(100) + cls._cleanup = [ + cls.service_offering, + cls.account, + ] + return @classmethod def tearDownClass(cls): - try: - # Cleanup resources used - cleanup_resources(cls.api_client, cls._cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return def setUp(self): - self.apiclient = self.testClient.getApiClient() - self.dbclient = self.testClient.getDbConnection() - self.cleanup = [] - return + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return def tearDown(self): - try: - # Clean up, terminate the created instance, volumes and snapshots - cleanup_resources(self.apiclient, self.cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return + try: + # Clean up, terminate the created instance, volumes and snapshots + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return @attr(tags=["advanced", "advancedns", "smoke"]) def test_01_create_vm_snapshots(self): - """Test to create VM snapshots - """ + """Test to create VM snapshots + """ - try: - # Login to VM and write data to file system - ssh_client = self.virtual_machine.get_ssh_client() + try: + # Login to VM and write data to file system + ssh_client = self.virtual_machine.get_ssh_client() - cmds = [ - "echo %s > %s/%s" % (self.random_data_0, self.services["test_dir"], self.services["random_data"]), - "cat %s/%s" % (self.services["test_dir"], self.services["random_data"]) - ] + cmds = [ + "echo %s > %s/%s" % (self.random_data_0, self.services["test_dir"], self.services["random_data"]), + "cat %s/%s" % (self.services["test_dir"], self.services["random_data"]) + ] - for c in cmds: - self.debug(c) - result = ssh_client.execute(c) - self.debug(result) + for c in cmds: + self.debug(c) + result = ssh_client.execute(c) + self.debug(result) - except Exception: - self.fail("SSH failed for Virtual machine: %s" % - self.virtual_machine.ipaddress) - self.assertEqual( - self.random_data_0, - result[0], - "Check the random data has be write into temp file!" - ) + except Exception: + self.fail("SSH failed for Virtual machine: %s" % + self.virtual_machine.ipaddress) + self.assertEqual( + self.random_data_0, + result[0], + "Check the random data has be write into temp file!" + ) - time.sleep(self.services["sleep"]) + time.sleep(self.services["sleep"]) - vm_snapshot = VmSnapshot.create( - self.apiclient, - self.virtual_machine.id, - "false", - self.services["snapshot_name"], - self.services["snapshot_displaytext"] - ) - self.assertEqual( - vm_snapshot.state, - "Ready", - "Check the snapshot of vm is ready!" - ) - return + vm_snapshot = VmSnapshot.create( + self.apiclient, + self.virtual_machine.id, + "false", + self.services["snapshot_name"], + self.services["snapshot_displaytext"] + ) + self.assertEqual( + vm_snapshot.state, + "Ready", + "Check the snapshot of vm is ready!" + ) + return @attr(tags=["advanced", "advancedns", "smoke"]) def test_02_revert_vm_snapshots(self): - """Test to revert VM snapshots - """ + """Test to revert VM snapshots + """ - try: - ssh_client = self.virtual_machine.get_ssh_client() + try: + ssh_client = self.virtual_machine.get_ssh_client() - cmds = [ - "rm -rf %s/%s" % (self.services["test_dir"], self.services["random_data"]), - "ls %s/%s" % (self.services["test_dir"], self.services["random_data"]) - ] + cmds = [ + "rm -rf %s/%s" % (self.services["test_dir"], self.services["random_data"]), + "ls %s/%s" % (self.services["test_dir"], self.services["random_data"]) + ] - for c in cmds: - self.debug(c) - result = ssh_client.execute(c) - self.debug(result) + for c in cmds: + self.debug(c) + result = ssh_client.execute(c) + self.debug(result) - except Exception: - self.fail("SSH failed for Virtual machine: %s" % - self.virtual_machine.ipaddress) + except Exception: + self.fail("SSH failed for Virtual machine: %s" % + self.virtual_machine.ipaddress) - if str(result[0]).index("No such file or directory") == -1: - self.fail("Check the random data has be delete from temp file!") + if str(result[0]).index("No such file or directory") == -1: + self.fail("Check the random data has be delete from temp file!") - time.sleep(self.services["sleep"]) + time.sleep(self.services["sleep"]) - list_snapshot_response = VmSnapshot.list(self.apiclient,vmid=self.virtual_machine.id,listall=True) + list_snapshot_response = VmSnapshot.list(self.apiclient, vmid=self.virtual_machine.id, listall=True) - self.assertEqual( - isinstance(list_snapshot_response, list), - True, - "Check list response returns a valid list" - ) - self.assertNotEqual( - list_snapshot_response, - None, - "Check if snapshot exists in ListSnapshot" - ) + self.assertEqual( + isinstance(list_snapshot_response, list), + True, + "Check list response returns a valid list" + ) + self.assertNotEqual( + list_snapshot_response, + None, + "Check if snapshot exists in ListSnapshot" + ) - self.assertEqual( - list_snapshot_response[0].state, - "Ready", - "Check the snapshot of vm is ready!" - ) + self.assertEqual( + list_snapshot_response[0].state, + "Ready", + "Check the snapshot of vm is ready!" + ) - VmSnapshot.revertToSnapshot(self.apiclient,list_snapshot_response[0].id) + VmSnapshot.revertToSnapshot(self.apiclient, list_snapshot_response[0].id) - list_vm_response = list_virtual_machines( - self.apiclient, - id=self.virtual_machine.id - ) + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.virtual_machine.id + ) - self.assertEqual( - list_vm_response[0].state, - "Stopped", - "Check the state of vm is Stopped!" - ) + self.assertEqual( + list_vm_response[0].state, + "Stopped", + "Check the state of vm is Stopped!" + ) - cmd = startVirtualMachine.startVirtualMachineCmd() - cmd.id = list_vm_response[0].id - self.apiclient.startVirtualMachine(cmd) + cmd = startVirtualMachine.startVirtualMachineCmd() + cmd.id = list_vm_response[0].id + self.apiclient.startVirtualMachine(cmd) - time.sleep(self.services["sleep"]) + time.sleep(self.services["sleep"]) - try: - ssh_client = self.virtual_machine.get_ssh_client(reconnect=True) + try: + ssh_client = self.virtual_machine.get_ssh_client(reconnect=True) - cmds = [ - "cat %s/%s" % (self.services["test_dir"], self.services["random_data"]) - ] + cmds = [ + "cat %s/%s" % (self.services["test_dir"], self.services["random_data"]) + ] - for c in cmds: - self.debug(c) - result = ssh_client.execute(c) - self.debug(result) + for c in cmds: + self.debug(c) + result = ssh_client.execute(c) + self.debug(result) - except Exception: - self.fail("SSH failed for Virtual machine: %s" % - self.virtual_machine.ipaddress) + except Exception: + self.fail("SSH failed for Virtual machine: %s" % + self.virtual_machine.ipaddress) - self.assertEqual( - self.random_data_0, - result[0], - "Check the random data is equal with the ramdom file!" - ) + self.assertEqual( + self.random_data_0, + result[0], + "Check the random data is equal with the ramdom file!" + ) @attr(tags=["advanced", "advancedns", "smoke"]) def test_03_delete_vm_snapshots(self): - """Test to delete vm snapshots - """ + """Test to delete vm snapshots + """ - list_snapshot_response = VmSnapshot.list(self.apiclient,vmid=self.virtual_machine.id,listall=True) + list_snapshot_response = VmSnapshot.list(self.apiclient, vmid=self.virtual_machine.id, listall=True) - self.assertEqual( - isinstance(list_snapshot_response, list), - True, - "Check list response returns a valid list" - ) - self.assertNotEqual( - list_snapshot_response, - None, - "Check if snapshot exists in ListSnapshot" - ) - VmSnapshot.deleteVMSnapshot(self.apiclient,list_snapshot_response[0].id) + self.assertEqual( + isinstance(list_snapshot_response, list), + True, + "Check list response returns a valid list" + ) + self.assertNotEqual( + list_snapshot_response, + None, + "Check if snapshot exists in ListSnapshot" + ) + VmSnapshot.deleteVMSnapshot(self.apiclient, list_snapshot_response[0].id) - time.sleep(self.services["sleep"]*3) + time.sleep(self.services["sleep"] * 3) - list_snapshot_response = VmSnapshot.list(self.apiclient,vmid=self.virtual_machine.id,listall=True) + list_snapshot_response = VmSnapshot.list(self.apiclient, vmid=self.virtual_machine.id, listall=True) - self.assertEqual( - list_snapshot_response, - None, - "Check list vm snapshot has be deleted" - ) + self.assertEqual( + list_snapshot_response, + None, + "Check list vm snapshot has be deleted" + ) diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index 6c08d173f60..33a7e75c7b1 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -152,7 +152,9 @@ known_categories = { 'PortableIp': 'Portable IP', 'dedicateHost': 'Dedicate Resources', 'releaseDedicatedHost': 'Dedicate Resources', - 'Baremetal' : 'Baremetal' + 'Baremetal' : 'Baremetal', + 'UCS' : 'UCS', + 'Ucs' : 'UCS' } diff --git a/tools/appliance/build.sh b/tools/appliance/build.sh index f9a5b592699..f01cff6d281 100644 --- a/tools/appliance/build.sh +++ b/tools/appliance/build.sh @@ -97,8 +97,9 @@ echo "$appliance exported for VMWare: dist/$appliance-$build_date-$branch-vmware # Export for HyperV vboxmanage clonehd $hdd_uuid $appliance-$build_date-$branch-hyperv.vhd --format VHD -bzip2 $appliance-$build_date-$branch-hyperv.vhd -echo "$appliance exported for HyperV: dist/$appliance-$build_date-$branch-hyperv.vhd.bz2" +# HyperV doesn't support import a zipped image from S3 +#bzip2 $appliance-$build_date-$branch-hyperv.vhd +echo "$appliance exported for HyperV: dist/$appliance-$build_date-$branch-hyperv.vhd" -mv *.bz2 *.ova dist/ +mv *-hyperv.vhd *.bz2 *.ova dist/ diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py index 9ccf5e27368..8129396813a 100644 --- a/tools/marvin/marvin/cloudstackConnection.py +++ b/tools/marvin/marvin/cloudstackConnection.py @@ -172,8 +172,7 @@ class cloudConnection(object): requests = {} required = [] for attribute in dir(cmd): - if attribute != "__doc__" and attribute != "__init__" and\ - attribute != "__module__": + if not attribute.startswith('__'): if attribute == "isAsync": isAsync = getattr(cmd, attribute) elif attribute == "required": @@ -204,7 +203,7 @@ class cloudConnection(object): i = i + 1 return cmdname, isAsync, requests - def marvin_request(self, cmd, response_type=None, method='GET'): + def marvin_request(self, cmd, response_type=None, method='GET', data=''): """ Requester for marvin command objects @param cmd: marvin's command from cloudstackAPI diff --git a/tools/marvin/marvin/codegenerator.py b/tools/marvin/marvin/codegenerator.py index 1f25e5379be..632b8c670b1 100644 --- a/tools/marvin/marvin/codegenerator.py +++ b/tools/marvin/marvin/codegenerator.py @@ -33,7 +33,7 @@ class cmdParameterProperty(object): self.subProperties = [] -class cloudStackCmd: +class cloudStackCmd(object): def __init__(self): self.name = "" self.desc = "" @@ -42,7 +42,7 @@ class cloudStackCmd: self.response = [] -class codeGenerator: +class codeGenerator(object): """ Apache CloudStack- marvin python classes can be generated from the json returned by API discovery or from the xml spec of commands generated by @@ -184,7 +184,7 @@ class codeGenerator: imports = "import copy\n" initCmdsList = '__all__ = [' body = '' - body += "class CloudStackAPIClient:\n" + body += "class CloudStackAPIClient(object):\n" body += self.space + 'def __init__(self, connection):\n' body += self.space + self.space + 'self.connection = connection\n' body += "\n" @@ -224,7 +224,7 @@ class codeGenerator: fp = open(self.outputFolder + '/cloudstackAPI/baseCmd.py', 'w') basecmd = self.license basecmd += '"""Base Command"""\n' - basecmd += 'class baseCmd:\n' + basecmd += 'class baseCmd(object):\n' basecmd += self.space + 'pass\n' fp.write(basecmd) fp.close() @@ -232,7 +232,7 @@ class codeGenerator: fp = open(self.outputFolder + '/cloudstackAPI/baseResponse.py', 'w') basecmd = self.license basecmd += '"""Base class for response"""\n' - basecmd += 'class baseResponse:\n' + basecmd += 'class baseResponse(object):\n' basecmd += self.space + 'pass\n' fp.write(basecmd) fp.close() diff --git a/tools/marvin/marvin/configGenerator.py b/tools/marvin/marvin/configGenerator.py index a33a3f47e15..a966ae089e4 100644 --- a/tools/marvin/marvin/configGenerator.py +++ b/tools/marvin/marvin/configGenerator.py @@ -21,7 +21,7 @@ from optparse import OptionParser import jsonHelper -class managementServer(): +class managementServer(object): def __init__(self): self.mgtSvrIp = None self.port = 8096 @@ -29,7 +29,7 @@ class managementServer(): self.securityKey = None -class dbServer(): +class dbServer(object): def __init__(self): self.dbSvr = None self.port = 3306 @@ -38,20 +38,20 @@ class dbServer(): self.db = "cloud" -class configuration(): +class configuration(object): def __init__(self): self.name = None self.value = None -class logger(): +class logger(object): def __init__(self): '''TestCase/TestClient''' self.name = None self.file = None -class cloudstackConfiguration(): +class cloudstackConfiguration(object): def __init__(self): self.zones = [] self.mgtSvr = [] @@ -60,7 +60,7 @@ class cloudstackConfiguration(): self.logger = [] -class zone(): +class zone(object): def __init__(self): self.dns1 = None self.internaldns1 = None @@ -79,7 +79,7 @@ class zone(): self.cacheStorages = [] -class traffictype(): +class traffictype(object): def __init__(self, typ, labeldict=None): self.typ = typ # Guest/Management/Public if labeldict: @@ -96,7 +96,7 @@ class traffictype(): #} -class pod(): +class pod(object): def __init__(self): self.gateway = None self.name = None @@ -105,11 +105,21 @@ class pod(): self.endip = None self.zoneid = None self.clusters = [] + self.vmwaredc = [] '''Used in basic network mode''' self.guestIpRanges = [] -class cluster(): +class VmwareDc(object): + def __init__(self): + self.zoneid = None + self.name = None + self.vcenter = None + self.username = None + self.password = None + + +class cluster(object): def __init__(self): self.clustername = None self.clustertype = None @@ -123,7 +133,7 @@ class cluster(): self.primaryStorages = [] -class host(): +class host(object): def __init__(self): self.hypervisor = None self.password = None @@ -140,7 +150,7 @@ class host(): self.memory = None -class physical_network(): +class physical_network(object): def __init__(self): self.name = None self.tags = [] @@ -154,7 +164,7 @@ class physical_network(): self.providers = [vrouter] -class provider(): +class provider(object): def __init__(self, name=None): self.name = name self.state = None @@ -164,7 +174,7 @@ class provider(): self.devices = [] -class network(): +class network(object): def __init__(self): self.displaytext = None self.name = None @@ -176,7 +186,7 @@ class network(): self.ipranges = [] -class iprange(): +class iprange(object): def __init__(self): '''tagged/untagged''' self.gateway = None @@ -189,27 +199,27 @@ class iprange(): self.domain = None -class primaryStorage(): +class primaryStorage(object): def __init__(self): self.name = None self.url = None -class secondaryStorage(): +class secondaryStorage(object): def __init__(self): self.url = None self.provider = None self.details = None -class cacheStorage(): +class cacheStorage(object): def __init__(self): self.url = None self.provider = None self.details = None -class s3(): +class s3(object): def __init__(self): self.accesskey = None self.secretkey = None @@ -221,7 +231,7 @@ class s3(): self.usehttps = None -class netscaler(): +class netscaler(object): def __init__(self, hostname=None, username='nsroot', password='nsroot'): self.hostname = hostname self.username = username @@ -242,7 +252,7 @@ class netscaler(): for r in req]) -class srx(): +class srx(object): def __init__(self, hostname=None, username='root', password='admin'): self.hostname = hostname self.username = username @@ -265,7 +275,7 @@ class srx(): for r in req]) -class bigip(): +class bigip(object): def __init__(self, hostname=None, username='root', password='default'): self.hostname = hostname self.username = username diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py index b5317874228..d704375559a 100644 --- a/tools/marvin/marvin/deployDataCenter.py +++ b/tools/marvin/marvin/deployDataCenter.py @@ -25,7 +25,7 @@ from os import path from optparse import OptionParser -class deployDataCenters(): +class deployDataCenters(object): def __init__(self, cfgFile): if not path.exists(cfgFile) \ @@ -54,10 +54,22 @@ specify a valid config file" % cfgFile) hostcmd.hypervisor = hypervisor self.apiClient.addHost(hostcmd) - def createClusters(self, clusters, zoneId, podId): + def addVmWareDataCenter(self, vmwareDc): + vdc = addVmwareDc.addVmwareDcCmd() + vdc.zoneid = vmwareDc.zoneid + vdc.name = vmwareDc.name + vdc.vcenter = vmwareDc.vcenter + vdc.username = vmwareDc.username + vdc.password = vmwareDc.password + self.apiClient.addVmwareDc(vdc) + + def createClusters(self, clusters, zoneId, podId, vmwareDc=None): if clusters is None: return + if vmwareDc: + self.addVmWareDataCenter(vmwareDc) + for cluster in clusters: clustercmd = addCluster.addClusterCmd() clustercmd.clustername = cluster.clustername @@ -108,7 +120,8 @@ specify a valid config file" % cfgFile) self.createVlanIpRanges("Basic", pod.guestIpRanges, zoneId, podId, networkId) - self.createClusters(pod.clusters, zoneId, podId) + self.createClusters(pod.clusters, zoneId, podId, + vmwareDc=pod.vmwaredc) def createVlanIpRanges(self, mode, ipranges, zoneId, podId=None, networkId=None, forvirtualnetwork=None): @@ -133,7 +146,6 @@ specify a valid config file" % cfgFile) vlanipcmd.forvirtualnetwork = "false" else: vlanipcmd.forvirtualnetwork = "true" - self.apiClient.createVlanIpRange(vlanipcmd) def createSecondaryStorages(self, secondaryStorages, zoneId): @@ -145,9 +157,12 @@ specify a valid config file" % cfgFile) secondarycmd.provider = secondary.provider secondarycmd.details = [] - if isinstance(secondary.details, list): - for item in secondary.details: - secondarycmd.details.append(item.__dict__) + if secondarycmd.provider == 'S3': + for key, value in vars(secondary.details).iteritems(): + secondarycmd.details.append({ + 'key': key, + 'value': value + }) if secondarycmd.provider == "NFS": secondarycmd.zoneid = zoneId self.apiClient.addImageStore(secondarycmd) @@ -161,8 +176,13 @@ specify a valid config file" % cfgFile) cachecmd.provider = cache.provider cachecmd.zoneid = zoneId cachecmd.details = [] - for item in cache.details: - cachecmd.details.append(item.__dict__) + + if cache.details: + for key, value in vars(cache.details).iteritems(): + cachecmd.details.append({ + 'key': key, + 'value': value + }) self.apiClient.createCacheStore(cachecmd) def createnetworks(self, networks, zoneId): diff --git a/tools/marvin/marvin/jsonHelper.py b/tools/marvin/marvin/jsonHelper.py index f9405086d3b..ae40b8dabf0 100644 --- a/tools/marvin/marvin/jsonHelper.py +++ b/tools/marvin/marvin/jsonHelper.py @@ -21,7 +21,7 @@ import inspect from cloudstackAPI import * -class jsonLoader: +class jsonLoader(object): '''The recursive class for building and representing objects with.''' def __init__(self, obj): for k in obj: @@ -51,7 +51,7 @@ class jsonLoader: in self.__dict__.iteritems())) -class jsonDump: +class jsonDump(object): @staticmethod def __serialize(obj): """Recursively walk object's hierarchy.""" diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp index 7809cdb6c9d..af64228ab04 100644 --- a/ui/dictionary.jsp +++ b/ui/dictionary.jsp @@ -25,6 +25,9 @@ under the License. <% long now = System.currentTimeMillis(); %>