From 882e5fa4e0c54ff53172b132c6184edadbc38b42 Mon Sep 17 00:00:00 2001 From: Laszlo Hornyak Date: Wed, 19 Jun 2013 22:54:51 +0200 Subject: [PATCH 01/69] FileUtil simplified - writeToFile removed since no references to it - readFileAsString replaced with FileUtils.readFileToString - minor code duplication removed in dependent method getNicStats - unit test added Signed-off-by: Laszlo Hornyak --- .../resource/LibvirtComputingResource.java | 28 +++++-------- .../LibvirtComputingResourceTest.java | 14 +++++++ utils/src/com/cloud/utils/FileUtil.java | 41 +------------------ 3 files changed, 26 insertions(+), 57 deletions(-) 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 b1bc99d0218..e0c00fc8f50 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 @@ -64,6 +64,7 @@ import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat; import org.apache.cloudstack.utils.qemu.QemuImgException; import org.apache.cloudstack.utils.qemu.QemuImgFile; import org.apache.log4j.Logger; +import org.apache.commons.io.FileUtils; import org.libvirt.Connect; import org.libvirt.Domain; import org.libvirt.DomainBlockStats; @@ -229,7 +230,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; @@ -4847,24 +4847,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); - } - rx = Double.parseDouble(rxContent); + static Pair getNicStats(String nicName) { + return new Pair(readDouble(nicName, "rx_bytes"), readDouble(nicName, "tx_bytes")); + } - 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/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/utils/src/com/cloud/utils/FileUtil.java b/utils/src/com/cloud/utils/FileUtil.java index 74f40886e36..a6f0c9167ef 100644 --- a/utils/src/com/cloud/utils/FileUtil.java +++ b/utils/src/com/cloud/utils/FileUtil.java @@ -16,54 +16,15 @@ // under the License. package com.cloud.utils; -import java.io.BufferedInputStream; -import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class FileUtil { - - public static String readFileAsString(String filePath) { - File file = new File(filePath); - if(!file.exists()) - return null; - - try { - byte[] buffer = new byte[(int)file.length()]; - BufferedInputStream f = null; - try { - f = new BufferedInputStream(new FileInputStream(filePath)); - f.read(buffer); - } finally { - if (f != null) { - try { - f.close(); - } catch (IOException ignored) { - } - } - } - return new String(buffer); - } catch(IOException e) { - return null; - } - } - - public static void writeToFile(String content, String filePath) throws IOException { - BufferedWriter out = null; - try { - out = new BufferedWriter(new FileWriter(filePath)); - out.write(content); - } finally { - if(out != null) - out.close(); - } - } - + public static void copyfile(File f1, File f2) throws IOException { InputStream in = new FileInputStream(f1); OutputStream out = new FileOutputStream(f2); From 77fd76acb47fd56ff0c265c6b15b4497a57e40c7 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Thu, 27 Jun 2013 11:31:21 -0700 Subject: [PATCH 02/69] CLOUDSTACK-3242: fixed updateTemplate and updateTemplate permissions security checks for project based templates --- server/src/com/cloud/acl/DomainChecker.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 From 4361418e415b81567423367c0bd3aff263cc15c8 Mon Sep 17 00:00:00 2001 From: Donal Lafferty Date: Thu, 27 Jun 2013 11:46:02 -0700 Subject: [PATCH 03/69] Removed Dead Code from Management Server Hyper-V 2012 Support Update ImageFormat enum to include VHDX format introduced with Hyper-V Server 2012. Remove existing Hyper-V plugin, because it does not work and is dead code. Remove references to existing Hyper-V plugin from config files. Remove Hypervisor.HypervisorType.Hyperv special cases from manager code that are unused or unsupported. Specifically, there is no CIFS secondary storage class "CifsSecondaryStorageResource". Also, the Hyper-V plugin's ServerResource is contacted by the management server and not the other way around. Add Hyperv-V support to ListHypervisorsCmd API call Signed-off-by: Edison Su --- agent/src/com/cloud/agent/VmmAgentShell.java | 504 --------- api/src/com/cloud/storage/Storage.java | 1 + client/tomcatconf/applicationContext.xml.in | 4 - .../hyperv/resource/HypervResource.java | 978 ------------------ .../test/resource/component.xml | 9 - .../resources/components-example.xml | 2 - .../src/com/cloud/configuration/Config.java | 2 +- .../com/cloud/hypervisor/guru/HypervGuru.java | 73 -- .../hyperv/HypervServerDiscoverer.java | 243 ----- .../cloud/resource/ResourceManagerImpl.java | 6 - .../SecondaryStorageManagerImpl.java | 5 +- 11 files changed, 3 insertions(+), 1824 deletions(-) delete mode 100644 agent/src/com/cloud/agent/VmmAgentShell.java delete mode 100755 core/src/com/cloud/hypervisor/hyperv/resource/HypervResource.java delete mode 100644 server/src/com/cloud/hypervisor/guru/HypervGuru.java delete mode 100755 server/src/com/cloud/hypervisor/hyperv/HypervServerDiscoverer.java 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/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/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index ac1f3e46fdb..2b2d8341f5e 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -537,10 +537,6 @@ - - - - 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 725f0cc1ae2..00000000000 --- a/core/src/com/cloud/hypervisor/hyperv/resource/HypervResource.java +++ /dev/null @@ -1,978 +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.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/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/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/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index ba508495c35..1a2c6208fb3 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -202,7 +202,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/hypervisor/guru/HypervGuru.java b/server/src/com/cloud/hypervisor/guru/HypervGuru.java deleted file mode 100644 index 630080e21cb..00000000000 --- a/server/src/com/cloud/hypervisor/guru/HypervGuru.java +++ /dev/null @@ -1,73 +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.HypervisorGuru; -import com.cloud.hypervisor.HypervisorGuruBase; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.storage.GuestOSVO; -import com.cloud.storage.dao.GuestOSDao; -import com.cloud.template.VirtualMachineTemplate.BootloaderType; -import com.cloud.vm.VirtualMachine; -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/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index fe91cb337d0..a0ea54e1e60 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -541,12 +541,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/storage/secondary/SecondaryStorageManagerImpl.java b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java index 954c7e970f0..05256a8582a 100755 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java @@ -1046,10 +1046,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 { From 0d788681809f720f8ad55eb27c995d7f09ed7106 Mon Sep 17 00:00:00 2001 From: Saksham Srivastava Date: Fri, 28 Jun 2013 00:16:02 +0530 Subject: [PATCH 04/69] CLOUDSTACK-3064: Able to create an instance from different account of the same domain without using affinity group even if the zone is dedicated to an account. The check to make sure that explicit resources are not picked up for non-explicit deployment was present only at the domain level for zones. Added a check at account level too. --- .../cloud/deploy/DeploymentPlanningManagerImpl.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index 4ef2152dd7b..142e63f2db0 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -452,9 +452,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()); From cf4dba34a4acb2fd8ecd7cf8bfc0268749942780 Mon Sep 17 00:00:00 2001 From: Edison Su Date: Thu, 27 Jun 2013 12:09:20 -0700 Subject: [PATCH 05/69] Don't generate bzipped hyperv image --- tools/appliance/build.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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/ From c8692f2e4a9760a58dbf457bf128fa484a491d0d Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Fri, 28 Jun 2013 00:11:54 +0530 Subject: [PATCH 06/69] CLOUDSTACK-3245: non admin user not able to register template Reviewed-by: Alena Prokharchyk --- .../api/command/user/template/RegisterTemplateCmd.java | 2 +- server/src/com/cloud/template/TemplateAdapterBase.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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 13bd5da7b72..c1d3f59f974 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 @@ -212,7 +212,7 @@ public class RegisterTemplateCmd extends BaseCmd { } public Boolean isRoutingType() { - return isRoutingType == null ? false : isRoutingType; + return isRoutingType; } ///////////////////////////////////////////////////// diff --git a/server/src/com/cloud/template/TemplateAdapterBase.java b/server/src/com/cloud/template/TemplateAdapterBase.java index 7835680b9b8..c5d4a6b7d15 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, UserContext.current().getCallerUserId(), 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); } From 3160a0c2da8036d861594d2286f6a595a41da270 Mon Sep 17 00:00:00 2001 From: Min Chen Date: Thu, 27 Jun 2013 14:02:25 -0700 Subject: [PATCH 07/69] Add template zone related information into TemplateZoneResponse. --- .../api/response/TemplateZoneResponse.java | 53 ++++++++++-- .../api/query/dao/TemplateJoinDaoImpl.java | 84 +++++++++++++------ 2 files changed, 104 insertions(+), 33 deletions(-) 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/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java index d4c9560430d..a31a0360624 100644 --- a/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java @@ -38,8 +38,8 @@ import com.cloud.api.query.vo.ResourceTagJoinVO; import com.cloud.api.query.vo.TemplateJoinVO; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.storage.Storage; -import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.Storage.TemplateType; +import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; @@ -96,6 +96,36 @@ public class TemplateJoinDaoImpl extends GenericDaoBase im + private String getTemplateStatus(TemplateJoinVO template){ + boolean isAdmin = false; + Account caller = UserContext.current().getCaller(); + 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) { @@ -136,33 +166,10 @@ public class TemplateJoinDaoImpl extends GenericDaoBase im templateResponse.setDomainName(template.getDomainName()); - - boolean isAdmin = false; - Account caller = UserContext.current().getCaller(); - 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(); - } - templateResponse.setStatus(templateStatus); - } else if (template.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) { - templateResponse.setStatus("Download Complete"); - } else { - templateResponse.setStatus("Successfully Installed"); - } + String templateStatus = getTemplateStatus(template); + if ( templateStatus != null ){ + templateResponse.setStatus(templateStatus); } Long templateSize = template.getSize(); @@ -179,6 +186,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()); @@ -259,6 +277,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 From 329c6eb4d3566cdefd6bf624acac5607e3399930 Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Thu, 27 Jun 2013 10:27:53 -0700 Subject: [PATCH 08/69] Adding tracelogging to CitrixResourceBase xapi task handling. Currently it is very hard to see which tasks are pending in cloudstack that need to be executed by xapi. Ideally we would like to have a central overview of all tasks centrally. But for now being able to enable tracelogging should give some insight in what is going on. --- .../hypervisor/xen/resource/CitrixResourceBase.java | 9 +++++++++ 1 file changed, 9 insertions(+) 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 af640a259bc..cbbec7ce7e6 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 @@ -3721,8 +3721,14 @@ 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.getType(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.getType(c) + ") is pending, sleeping for " + pollInterval + "ms"); + } Thread.sleep(pollInterval); } catch (InterruptedException e) { } @@ -3737,6 +3743,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.getType(c) + ") completed"); + } return; } else { String msg = "Task failed! Task record: " + task.getRecord(c); From 7e44f81273a3fa2781f80e7a5e6c7410fd9e0ebe Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Thu, 27 Jun 2013 14:51:51 -0700 Subject: [PATCH 09/69] UCS: Add missing beans Also move the API to the right place --- client/tomcatconf/applicationContext.xml.in | 2 ++ client/tomcatconf/commands.properties.in | 6 ++++++ client/tomcatconf/componentContext.xml.in | 6 ++++++ client/tomcatconf/nonossComponentContext.xml.in | 6 ++++++ .../ucs/src/com/cloud/ucs/manager/UcsManager.java | 8 ++++++++ .../ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java | 8 ++++++++ .../apache/cloudstack/api}/AddUcsManagerCmd.java | 4 +++- .../cloudstack/api}/AssociateUcsProfileToBladeCmd.java | 7 +++++-- .../apache/cloudstack/api}/ListUcsBladeCmd.java | 5 ++++- .../apache/cloudstack/api}/ListUcsManagerCmd.java | 4 +++- .../apache/cloudstack/api}/ListUcsProfileCmd.java | 5 ++++- .../apache/cloudstack/api/response}/UcsBladeResponse.java | 2 +- .../cloudstack/api/response}/UcsManagerResponse.java | 2 +- .../cloudstack/api/response}/UcsProfileResponse.java | 2 +- tools/apidoc/gen_toc.py | 4 +++- 15 files changed, 61 insertions(+), 10 deletions(-) rename plugins/hypervisors/ucs/src/{com/cloud/ucs/manager => org/apache/cloudstack/api}/AddUcsManagerCmd.java (96%) rename plugins/hypervisors/ucs/src/{com/cloud/ucs/manager => org/apache/cloudstack/api}/AssociateUcsProfileToBladeCmd.java (93%) rename plugins/hypervisors/ucs/src/{com/cloud/ucs/manager => org/apache/cloudstack/api}/ListUcsBladeCmd.java (94%) rename plugins/hypervisors/ucs/src/{com/cloud/ucs/manager => org/apache/cloudstack/api}/ListUcsManagerCmd.java (96%) rename plugins/hypervisors/ucs/src/{com/cloud/ucs/manager => org/apache/cloudstack/api}/ListUcsProfileCmd.java (94%) rename plugins/hypervisors/ucs/src/{com/cloud/ucs/manager => org/apache/cloudstack/api/response}/UcsBladeResponse.java (98%) rename plugins/hypervisors/ucs/src/{com/cloud/ucs/manager => org/apache/cloudstack/api/response}/UcsManagerResponse.java (97%) rename plugins/hypervisors/ucs/src/{com/cloud/ucs/manager => org/apache/cloudstack/api/response}/UcsProfileResponse.java (96%) diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 2b2d8341f5e..09948f443cf 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -855,6 +855,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 61bca4850b2..c720155bcf0 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -83,6 +83,12 @@ + + + + + + + - - - - + + + + - + 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 3034f9bd5fe..d42ee676ac2 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,17 +14,18 @@ // 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.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.response.SspResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.network.element.SspService; import org.apache.log4j.Logger; -import com.cloud.api.response.SspResponse; import com.cloud.dc.dao.DataCenterDao; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; @@ -32,7 +33,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; import com.cloud.user.UserContext; 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 1f3bba6b726..bfbd5d9f409 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; @@ -24,6 +24,7 @@ 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.network.element.SspService; import org.apache.log4j.Logger; import com.cloud.exception.ConcurrentOperationException; @@ -31,7 +32,6 @@ 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; import com.cloud.user.UserContext; @APICommand(name="deleteStratosphereSsp", responseObject=SuccessResponse.class, description="Removes stratosphere ssp server") 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 9511e84825a..9c6cf14ef7f 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 016ae14f430..823c16b15e8 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.utils.component.AdapterBase; import com.cloud.utils.exception.CloudRuntimeException; @@ -180,7 +182,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) { @@ -199,7 +201,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){ @@ -472,7 +474,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, @@ -488,7 +490,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, @@ -503,7 +505,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, @@ -520,7 +522,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, @@ -535,7 +537,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 b504a4bc250..6d5d871eb99 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; @@ -95,7 +97,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; From 9e8cf60b34cdbe8f0e409cad8adae5bbb743c1ac Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Fri, 28 Jun 2013 19:00:45 +0530 Subject: [PATCH 21/69] upgrade marvin classes to new style python objects Signed-off-by: Prasanna Santhanam --- tools/marvin/marvin/cloudstackConnection.py | 3 +- tools/marvin/marvin/codegenerator.py | 10 ++--- tools/marvin/marvin/configGenerator.py | 42 ++++++++++----------- tools/marvin/marvin/deployDataCenter.py | 21 +++++++---- tools/marvin/marvin/jsonHelper.py | 4 +- 5 files changed, 43 insertions(+), 37 deletions(-) diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py index 9ccf5e27368..9d60ff91026 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": 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..812bfec4a9a 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 @@ -109,7 +109,7 @@ class pod(): self.guestIpRanges = [] -class cluster(): +class cluster(object): def __init__(self): self.clustername = None self.clustertype = None @@ -123,7 +123,7 @@ class cluster(): self.primaryStorages = [] -class host(): +class host(object): def __init__(self): self.hypervisor = None self.password = None @@ -140,7 +140,7 @@ class host(): self.memory = None -class physical_network(): +class physical_network(object): def __init__(self): self.name = None self.tags = [] @@ -154,7 +154,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 +164,7 @@ class provider(): self.devices = [] -class network(): +class network(object): def __init__(self): self.displaytext = None self.name = None @@ -176,7 +176,7 @@ class network(): self.ipranges = [] -class iprange(): +class iprange(object): def __init__(self): '''tagged/untagged''' self.gateway = None @@ -189,27 +189,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 +221,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 +242,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 +265,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..413712474b6 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) \ @@ -133,7 +133,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 +144,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 +163,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.""" From 9e474d018b0e01290759a54924d8340e09521f68 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Fri, 28 Jun 2013 19:02:59 +0530 Subject: [PATCH 22/69] do not flout pep8 Signed-off-by: Prasanna Santhanam --- tools/marvin/marvin/deployDataCenter.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py index 413712474b6..941b6e9316c 100644 --- a/tools/marvin/marvin/deployDataCenter.py +++ b/tools/marvin/marvin/deployDataCenter.py @@ -147,9 +147,9 @@ specify a valid config file" % cfgFile) if secondarycmd.provider == 'S3': for key, value in vars(secondary.details).iteritems(): secondarycmd.details.append({ - 'key': key, - 'value': value - }) + 'key': key, + 'value': value + }) if secondarycmd.provider == "NFS": secondarycmd.zoneid = zoneId self.apiClient.addImageStore(secondarycmd) @@ -167,9 +167,9 @@ specify a valid config file" % cfgFile) if cache.details: for key, value in vars(cache.details).iteritems(): cachecmd.details.append({ - 'key': key, - 'value': value - }) + 'key': key, + 'value': value + }) self.apiClient.createCacheStore(cachecmd) def createnetworks(self, networks, zoneId): From 3096261c05df4921c751a336ecff15ceeffcdda5 Mon Sep 17 00:00:00 2001 From: Jayapal Date: Thu, 27 Jun 2013 16:21:33 +0530 Subject: [PATCH 23/69] Updated to show same value in log msg SetFirewallRulesCommand and accessdetails for egress default policy --- api/src/com/cloud/agent/api/to/FirewallRuleTO.java | 6 ++++++ .../router/VirtualNetworkApplianceManagerImpl.java | 9 +++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java index 29d9c6f8a57..8c7b5529ed9 100644 --- a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java +++ b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java @@ -109,6 +109,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/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 5a8cf5dcd93..5327f0bb4dd 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -3682,6 +3682,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) { @@ -3696,17 +3697,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())); From 7f2f25d640b47c8e72381bfc318a7bbbb1ca2bfd Mon Sep 17 00:00:00 2001 From: Bharat Kumar Date: Wed, 26 Jun 2013 20:55:30 +0530 Subject: [PATCH 24/69] Cloudstack-2150 DB table entries of phisical network is not proper.Shows Duplicate entries Cloudstack-2980 Adding a VLAN range that overlaps with two existing ranges results in inconsistent DB entries Signed-off-by: Jayapal --- .../cloud/dc/dao/DataCenterVnetDaoImpl.java | 2 +- .../com/cloud/network/NetworkServiceImpl.java | 85 +++++++------------ 2 files changed, 34 insertions(+), 53 deletions(-) diff --git a/engine/schema/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java index e97f2c62ee3..a2f7cde9872 100755 --- a/engine/schema/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java +++ b/engine/schema/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java @@ -113,7 +113,7 @@ public class DataCenterVnetDaoImpl extends GenericDaoBase tokens = processVlanRange(network,removeVlan); - boolean result = removeVlanRange(network, tokens.get(0), tokens.get(1)); + removeVlanRange(network, tokens.get(0), tokens.get(1)); } if (tags != null && tags.size() > 1) { @@ -2589,7 +2589,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { network.setSpeed(networkSpeed); } - // Vnet range can be extended only boolean AddVnet = true; List> vnetsToAdd = new ArrayList>(); @@ -2606,7 +2605,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { int existingStartVnet = existingRanges.get(j).first(); int existingEndVnet = existingRanges.get(j).second(); - // check if vnet is being extended if (newStartVnet.intValue() >= existingStartVnet & newEndVnet.intValue() <= existingEndVnet) { throw new InvalidParameterValueException("The vlan range you trying to add already exists."); } @@ -2630,80 +2628,63 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { vnetsToAdd.add(new Pair(existingEndVnet+1,newEndVnet)); existingRanges.get(j).first(newStartVnet); existingRanges.get(j).second(newEndVnet); + AddVnet = false; break; } } } if (AddVnet){ - vnetsToAdd.add(new Pair(newStartVnet, newEndVnet)); - existingRanges.add(new Pair(newStartVnet,newEndVnet)); + vnetsToAdd.add(new Pair(newStartVnet, newEndVnet)); + existingRanges.add(new Pair(newStartVnet,newEndVnet)); + j= existingRanges.size()-1; } - - Map vnetMap = new HashMap(existingRanges.size()); - Map IndexMap = new HashMap(existingRanges.size()); - for (int i=0; i< existingRanges.size(); i++){ - vnetMap.put(existingRanges.get(i).first(),existingRanges.get(i).second()); - IndexMap.put(existingRanges.get(i).first(),i); - } - Integer value; - Integer index; String vnetString = ""; + + Integer changed_entry_start = existingRanges.get(j).first(); + Integer changed_entry_end = existingRanges.get(j).second(); for (int i=0; i < existingRanges.size(); i++){ - value = vnetMap.get((existingRanges.get(i).second()+1)); - if (value != null) { - vnetMap.remove((existingRanges.get(i).second()+1)); - vnetMap.remove(existingRanges.get(i).first()); - vnetMap.put(existingRanges.get(i).first(),value); - existingRanges.add(new Pair(existingRanges.get(i).first(),value)); - index = IndexMap.get(existingRanges.get(i).second()+1); - existingRanges.get(index).first(-1); - existingRanges.get(index).second(-1); - existingRanges.get(i).first(-1); - existingRanges.get(i).second(-1); - } - value = vnetMap.get((existingRanges.get(i).second())); - if (value != null && ( (existingRanges.get(i).second()) != (existingRanges.get(i).first()) )) { - vnetMap.remove((existingRanges.get(i).second())); - vnetMap.remove(existingRanges.get(i).first()); - vnetMap.put(existingRanges.get(i).first(),value); - existingRanges.add(new Pair(existingRanges.get(i).first(),value)); - index = IndexMap.get(existingRanges.get(i).second()); - existingRanges.get(index).first(-1); - existingRanges.get(index).second(-1); + if (i !=j && existingRanges.get(i).first()<=changed_entry_end && existingRanges.get(i).second() >= changed_entry_end) { + existingRanges.get(j).second(existingRanges.get(i).second()); existingRanges.get(i).first(-1); existingRanges.get(i).second(-1); + } else if ((i !=j && changed_entry_end > existingRanges.get(i).second()) && changed_entry_start <= existingRanges.get(i).first()) { + existingRanges.get(i).first(-1); + existingRanges.get(i).second(-1); + }else if ((i != j ) && changed_entry_end > existingRanges.get(i).second() && changed_entry_start <= existingRanges.get(i).second() && existingRanges.get(i).first() <= changed_entry_start) { + existingRanges.get(j).first(existingRanges.get(i).first()); + existingRanges.get(i).first(-1); + existingRanges.get(i).first(-1); } } - - if (newVnetRangeString != null) { - for (Pair vnetRange : existingRanges ){ - value=vnetMap.get(vnetRange.first()); - if (value != null){ - vnetString = vnetString+vnetRange.first().toString()+"-"+value.toString()+";"; - } - } - if (vnetString.length() > 0 && vnetString.charAt(vnetString.length()-1)==';') { - vnetString = vnetString.substring(0, vnetString.length()-1); - } - network.setVnet(vnetString); + for (Pair vnetRange : existingRanges ){ + value=vnetRange.first(); + if (value != -1){ + vnetString = vnetString+vnetRange.first().toString()+"-"+vnetRange.second().toString()+";"; + } } - + if (vnetString.length() > 0 && vnetString.charAt(vnetString.length()-1)==';') { + vnetString = vnetString.substring(0, vnetString.length()-1); + } + network.setVnet(vnetString); + Transaction txn = Transaction.currentTxn(); + txn.start(); for (Pair vnetToAdd : vnetsToAdd) { s_logger.debug("Adding vnet range " + vnetToAdd.first() + "-" + vnetToAdd.second() + " for the physicalNetwork id= " + id + " and zone id=" + network.getDataCenterId() - + " as a part of updatePhysicalNetwork call"); + + " as a part of updatePhysicalNetwork call"); _dcDao.addVnet(network.getDataCenterId(), network.getId(), vnetToAdd.first(), vnetToAdd.second()); } + _physicalNetworkDao.update(id, network); + txn.commit(); } - _physicalNetworkDao.update(id, network); - - return network; + return network; } + private List processVlanRange(PhysicalNetworkVO network, String removeVlan) { Integer StartVnet; Integer EndVnet; From 6b0df2566db34eb87c9603e6effcad2ad2b366c6 Mon Sep 17 00:00:00 2001 From: Bharat Kumar Date: Fri, 28 Jun 2013 14:14:43 +0530 Subject: [PATCH 25/69] Cloudstack-3106 Delete all ips except ipAlias. Cloudstack-3119 Shared network removal doesn't cleanup corresponding IP ranges Signed-off-by: Jayapal --- engine/schema/src/com/cloud/dc/VlanVO.java | 4 + .../com/cloud/network/dao/IPAddressDao.java | 6 + .../cloud/network/dao/IPAddressDaoImpl.java | 23 +++ .../ConfigurationManagerImpl.java | 153 ++++++------------ .../VirtualNetworkApplianceManagerImpl.java | 2 - 5 files changed, 79 insertions(+), 109 deletions(-) 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/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 041f29a6d52..51c323dad80 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -123,7 +123,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; @@ -142,7 +141,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; @@ -3138,11 +3136,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 @@ -3226,34 +3226,31 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati .getVlanType().toString(), ip.getSystem(), ip.getClass().getName(), ip.getUuid()); } } - 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; + 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())) { + 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; @@ -3263,87 +3260,48 @@ 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); //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 { + //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 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; - } - else { - _publicIpAddressDao.unassignIpAddress(ip.getId()); - result_final=true; - } - } - } - } + // 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"); + } catch (CloudRuntimeException e) { + txn.rollback(); + throw e; } - finally { - if (result_final) { - if (!removeFromDb(vlanDbId)) { - txn.rollback(); - } - else { - txn.commit(); - } - txn.close(); - } - } - return result_final; + txn.commit(); + return true; } @Override @@ -3565,25 +3523,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/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 5327f0bb4dd..ddfa9989fe6 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2849,8 +2849,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"); From 974245991c4c3fe51e63fe18b19853f5f8a0c6fa Mon Sep 17 00:00:00 2001 From: Bharat Kumar Date: Thu, 27 Jun 2013 19:12:20 +0530 Subject: [PATCH 26/69] Cloudstack-2732 [Multiple_IP_Ranges] Deleting guest IP range is not throwing any error message to user while the ip addresses are being used Signed-off-by: Jayapal --- .../src/com/cloud/configuration/ConfigurationManagerImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 51c323dad80..3840c120630 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -3267,6 +3267,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } else { ipAlias = _nicIpAliasDao.findByGatewayAndNetworkIdAndState(vlanRange.getVlanGateway(), vlanRange.getNetworkId(), NicIpAlias.state.active); + 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) { From 1c924e5ab5bf4c9059e1121105c436cd7d06c700 Mon Sep 17 00:00:00 2001 From: Bharat Kumar Date: Fri, 28 Jun 2013 18:11:59 +0530 Subject: [PATCH 27/69] Assertion failure in updatephysicalnetwork Test. Signed-off-by: Jayapal --- server/test/com/cloud/network/UpdatePhysicalNetworkTest.java | 3 +++ 1 file changed, 3 insertions(+) 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()); } From 78922589bbdc7914b9d4ce3b97a9fcf03d4b7b57 Mon Sep 17 00:00:00 2001 From: Vijayendra Bhamidipati Date: Thu, 27 Jun 2013 12:37:20 -0700 Subject: [PATCH 28/69] CLOUDSTACK-2385: template download fails with Unexpected failure in Vmware. Description: Putting in fix to allow download of guest VM templates that are available across zones. --- .../template/HypervisorTemplateAdapter.java | 100 ++++++++++-------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/server/src/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/com/cloud/template/HypervisorTemplateAdapter.java index 92148c3f83c..569d947dd48 100755 --- a/server/src/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/com/cloud/template/HypervisorTemplateAdapter.java @@ -308,60 +308,66 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { @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; - } + } } From dfb2e1d4f5bbb4e1be0160a4a65dc324ead27fbb Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Fri, 28 Jun 2013 12:16:22 -0700 Subject: [PATCH 29/69] CLOUDSTACK-3255: UI > VPC section - IP Address - Load Balancing - autoscale - fix a bug that failed to get zoneid for createAutoScaleVmProfile API. --- ui/scripts/autoscaler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/scripts/autoscaler.js b/ui/scripts/autoscaler.js index 05011a3c4ff..15a9dac6530 100644 --- a/ui/scripts/autoscaler.js +++ b/ui/scripts/autoscaler.js @@ -1069,7 +1069,7 @@ var apiCmd, apiCmdRes; if(!('multiRules' in args.context)) { //from a new LB var data = { - zoneid: args.context.networks[0].zoneid, + zoneid: args.context.ipAddresses[0].zoneid, //args.context.networks[0] doesn't have zoneid property, so use args.context.ipAddresses[0] instead serviceofferingid: args.data.serviceOfferingId, templateid: args.data.templateNames, destroyvmgraceperiod: args.data.destroyVMgracePeriod, From 02ab2eb3848df2703399bdda7fa1608a52ec156c Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Fri, 28 Jun 2013 14:58:32 -0700 Subject: [PATCH 30/69] Revert "Cloudstack-2150 DB table entries of phisical network is not proper.Shows Duplicate entries Cloudstack-2980 Adding a VLAN range that overlaps with two existing ranges results in inconsistent DB entries" This reverts commit 7f2f25d640b47c8e72381bfc318a7bbbb1ca2bfd. --- .../cloud/dc/dao/DataCenterVnetDaoImpl.java | 2 +- .../com/cloud/network/NetworkServiceImpl.java | 85 ++++++++++++------- 2 files changed, 53 insertions(+), 34 deletions(-) diff --git a/engine/schema/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java index a2f7cde9872..e97f2c62ee3 100755 --- a/engine/schema/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java +++ b/engine/schema/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java @@ -113,7 +113,7 @@ public class DataCenterVnetDaoImpl extends GenericDaoBase tokens = processVlanRange(network,removeVlan); - removeVlanRange(network, tokens.get(0), tokens.get(1)); + boolean result = removeVlanRange(network, tokens.get(0), tokens.get(1)); } if (tags != null && tags.size() > 1) { @@ -2589,6 +2589,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { network.setSpeed(networkSpeed); } + // Vnet range can be extended only boolean AddVnet = true; List> vnetsToAdd = new ArrayList>(); @@ -2605,6 +2606,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { int existingStartVnet = existingRanges.get(j).first(); int existingEndVnet = existingRanges.get(j).second(); + // check if vnet is being extended if (newStartVnet.intValue() >= existingStartVnet & newEndVnet.intValue() <= existingEndVnet) { throw new InvalidParameterValueException("The vlan range you trying to add already exists."); } @@ -2628,62 +2630,79 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { vnetsToAdd.add(new Pair(existingEndVnet+1,newEndVnet)); existingRanges.get(j).first(newStartVnet); existingRanges.get(j).second(newEndVnet); - AddVnet = false; break; } } } if (AddVnet){ - vnetsToAdd.add(new Pair(newStartVnet, newEndVnet)); - existingRanges.add(new Pair(newStartVnet,newEndVnet)); - j= existingRanges.size()-1; + vnetsToAdd.add(new Pair(newStartVnet, newEndVnet)); + existingRanges.add(new Pair(newStartVnet,newEndVnet)); } + + Map vnetMap = new HashMap(existingRanges.size()); + Map IndexMap = new HashMap(existingRanges.size()); + for (int i=0; i< existingRanges.size(); i++){ + vnetMap.put(existingRanges.get(i).first(),existingRanges.get(i).second()); + IndexMap.put(existingRanges.get(i).first(),i); + } + Integer value; + Integer index; String vnetString = ""; - - Integer changed_entry_start = existingRanges.get(j).first(); - Integer changed_entry_end = existingRanges.get(j).second(); for (int i=0; i < existingRanges.size(); i++){ - if (i !=j && existingRanges.get(i).first()<=changed_entry_end && existingRanges.get(i).second() >= changed_entry_end) { - existingRanges.get(j).second(existingRanges.get(i).second()); + value = vnetMap.get((existingRanges.get(i).second()+1)); + if (value != null) { + vnetMap.remove((existingRanges.get(i).second()+1)); + vnetMap.remove(existingRanges.get(i).first()); + vnetMap.put(existingRanges.get(i).first(),value); + existingRanges.add(new Pair(existingRanges.get(i).first(),value)); + index = IndexMap.get(existingRanges.get(i).second()+1); + existingRanges.get(index).first(-1); + existingRanges.get(index).second(-1); + existingRanges.get(i).first(-1); + existingRanges.get(i).second(-1); + } + value = vnetMap.get((existingRanges.get(i).second())); + if (value != null && ( (existingRanges.get(i).second()) != (existingRanges.get(i).first()) )) { + vnetMap.remove((existingRanges.get(i).second())); + vnetMap.remove(existingRanges.get(i).first()); + vnetMap.put(existingRanges.get(i).first(),value); + existingRanges.add(new Pair(existingRanges.get(i).first(),value)); + index = IndexMap.get(existingRanges.get(i).second()); + existingRanges.get(index).first(-1); + existingRanges.get(index).second(-1); existingRanges.get(i).first(-1); existingRanges.get(i).second(-1); - } else if ((i !=j && changed_entry_end > existingRanges.get(i).second()) && changed_entry_start <= existingRanges.get(i).first()) { - existingRanges.get(i).first(-1); - existingRanges.get(i).second(-1); - }else if ((i != j ) && changed_entry_end > existingRanges.get(i).second() && changed_entry_start <= existingRanges.get(i).second() && existingRanges.get(i).first() <= changed_entry_start) { - existingRanges.get(j).first(existingRanges.get(i).first()); - existingRanges.get(i).first(-1); - existingRanges.get(i).first(-1); } } - for (Pair vnetRange : existingRanges ){ - value=vnetRange.first(); - if (value != -1){ - vnetString = vnetString+vnetRange.first().toString()+"-"+vnetRange.second().toString()+";"; - } + + if (newVnetRangeString != null) { + for (Pair vnetRange : existingRanges ){ + value=vnetMap.get(vnetRange.first()); + if (value != null){ + vnetString = vnetString+vnetRange.first().toString()+"-"+value.toString()+";"; + } + } + if (vnetString.length() > 0 && vnetString.charAt(vnetString.length()-1)==';') { + vnetString = vnetString.substring(0, vnetString.length()-1); + } + network.setVnet(vnetString); } - if (vnetString.length() > 0 && vnetString.charAt(vnetString.length()-1)==';') { - vnetString = vnetString.substring(0, vnetString.length()-1); - } - network.setVnet(vnetString); - Transaction txn = Transaction.currentTxn(); - txn.start(); + for (Pair vnetToAdd : vnetsToAdd) { s_logger.debug("Adding vnet range " + vnetToAdd.first() + "-" + vnetToAdd.second() + " for the physicalNetwork id= " + id + " and zone id=" + network.getDataCenterId() - + " as a part of updatePhysicalNetwork call"); + + " as a part of updatePhysicalNetwork call"); _dcDao.addVnet(network.getDataCenterId(), network.getId(), vnetToAdd.first(), vnetToAdd.second()); } - _physicalNetworkDao.update(id, network); - txn.commit(); } - return network; - } + _physicalNetworkDao.update(id, network); + return network; + } private List processVlanRange(PhysicalNetworkVO network, String removeVlan) { Integer StartVnet; From 99227f7b3e824caeb89035982793ad510e460249 Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Fri, 28 Jun 2013 14:05:12 -0600 Subject: [PATCH 31/69] SolidFire plug-in and related changes SolidFire plug-in SolidFire plug-in related --- api/src/com/cloud/agent/api/to/DiskTO.java | 12 +- api/src/com/cloud/offering/DiskOffering.java | 16 +- api/src/com/cloud/storage/StoragePool.java | 2 + api/src/com/cloud/storage/Volume.java | 6 + .../apache/cloudstack/api/ApiConstants.java | 6 + .../admin/offering/CreateDiskOfferingCmd.java | 27 +- .../admin/storage/CreateStoragePoolCmd.java | 24 + .../command/user/volume/CreateVolumeCmd.java | 14 + .../api/response/DiskOfferingResponse.java | 33 + .../api/response/StoragePoolResponse.java | 11 + .../api/response/VolumeResponse.java | 16 + .../classes/resources/messages.properties | 7 +- client/pom.xml | 5 + client/tomcatconf/applicationContext.xml.in | 1 + .../cloud/agent/api/AttachVolumeAnswer.java | 16 +- .../cloud/agent/api/AttachVolumeCommand.java | 114 ++- .../agent/test/AttachVolumeAnswerTest.java | 6 +- .../agent/test/AttachVolumeCommandTest.java | 10 +- .../agent/test/BackupSnapshotCommandTest.java | 5 + .../agent/test/CheckNetworkAnswerTest.java | 5 + .../api/agent/test/SnapshotCommandTest.java | 4 + .../subsystem/api/storage/ChapInfo.java | 26 + .../api/storage/DataStoreDriver.java | 16 +- .../api/storage/PrimaryDataStoreDriver.java | 6 +- .../storage/PrimaryDataStoreParameters.java | 50 + .../subsystem/api/storage/VolumeService.java | 2 + .../storage/command/AttachCommand.java | 71 ++ .../storage/command/DettachCommand.java | 17 + .../storage/datastore/db/StoragePoolVO.java | 26 +- .../src/com/cloud/storage/DiskOfferingVO.java | 46 +- .../src/com/cloud/storage/VolumeVO.java | 57 +- .../src/com/cloud/storage/dao/VolumeDao.java | 2 + .../com/cloud/storage/dao/VolumeDaoImpl.java | 13 + .../storage/image/TemplateServiceImpl.java | 4 +- .../storage/image/store/ImageStoreImpl.java | 2 +- .../allocator/StorageAllocatorTest.java | 3 +- .../cloudstack/storage/test/SnapshotTest.java | 2 +- .../cloudstack/storage/test/VolumeTest.java | 2 +- .../storage/test/VolumeTestVmware.java | 2 +- .../storage/test/volumeServiceTest.java | 2 +- .../storage/snapshot/SnapshotServiceImpl.java | 2 +- .../ZoneWideStoragePoolAllocator.java | 36 +- .../datastore/DataObjectManagerImpl.java | 4 +- .../datastore/PrimaryDataStoreEntityImpl.java | 6 + .../image/BaseImageStoreDriverImpl.java | 4 +- .../datastore/PrimaryDataStoreHelper.java | 5 + .../datastore/PrimaryDataStoreImpl.java | 5 + .../storage/volume/VolumeObject.java | 15 + .../storage/volume/VolumeServiceImpl.java | 19 +- .../resource/LibvirtComputingResource.java | 2 +- .../agent/manager/MockStorageManagerImpl.java | 2 +- .../vmware/resource/VmwareResource.java | 274 +++++- .../xen/resource/CitrixResourceBase.java | 143 ++- .../resource/XenServerStorageProcessor.java | 18 +- .../CloudStackPrimaryDataStoreDriverImpl.java | 9 +- .../SamplePrimaryDataStoreDriverImpl.java | 9 +- plugins/storage/volume/solidfire/pom.xml | 7 +- .../SolidfirePrimaryDataStoreDriver.java | 482 +++++++++- .../SolidFirePrimaryDataStoreLifeCycle.java | 274 ++++++ .../SolidfirePrimaryDataStoreProvider.java | 81 +- .../storage/datastore/util/SolidFireUtil.java | 901 ++++++++++++++++++ .../query/dao/DiskOfferingJoinDaoImpl.java | 3 + .../api/query/dao/StoragePoolJoinDaoImpl.java | 2 + .../api/query/dao/VolumeJoinDaoImpl.java | 3 + .../api/query/vo/DiskOfferingJoinVO.java | 33 + .../cloud/api/query/vo/StoragePoolJoinVO.java | 13 +- .../com/cloud/api/query/vo/VolumeJoinVO.java | 21 +- .../configuration/ConfigurationManager.java | 8 +- .../ConfigurationManagerImpl.java | 53 +- .../cloud/server/ConfigurationServerImpl.java | 2 +- .../src/com/cloud/storage/StorageManager.java | 9 +- .../com/cloud/storage/StorageManagerImpl.java | 44 +- .../src/com/cloud/storage/VolumeManager.java | 1 - .../com/cloud/storage/VolumeManagerImpl.java | 139 ++- .../cloud/template/TemplateManagerImpl.java | 2 +- server/src/com/cloud/test/DatabaseConfig.java | 2 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 4 +- .../vpc/MockConfigurationManagerImpl.java | 5 +- setup/db/db/schema-410to420.sql | 22 + tools/marvin/marvin/cloudstackConnection.py | 2 +- ui/dictionary.jsp | 5 + ui/scripts/configuration.js | 179 +++- ui/scripts/docs.js | 16 + ui/scripts/sharedFunctions.js | 4 +- ui/scripts/storage.js | 56 +- ui/scripts/system.js | 19 +- utils/src/com/cloud/utils/StringUtils.java | 8 + .../vmware/mo/HostDatastoreSystemMO.java | 20 +- .../cloud/hypervisor/vmware/mo/HostMO.java | 15 +- .../vmware/mo/HostStorageSystemMO.java | 51 + 90 files changed, 3434 insertions(+), 294 deletions(-) create mode 100644 engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ChapInfo.java create mode 100644 plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java create mode 100644 plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java create mode 100644 vmware-base/src/com/cloud/hypervisor/vmware/mo/HostStorageSystemMO.java 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/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/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 a2c5f77f583..47415911e9b 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 @@ -52,7 +52,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, @@ -62,6 +62,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; @@ -74,8 +77,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 /////////////////////// @@ -101,6 +110,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 74eb2b9bf8f..f5750b99284 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 @@ -80,6 +80,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; @@ -124,6 +136,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/volume/CreateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java index 6f0bf3a6ca7..f293a03da91 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 @@ -68,6 +68,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; @@ -104,6 +110,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 35cf21a3b17..4291d854142 100644 --- a/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java +++ b/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java @@ -52,6 +52,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; @@ -154,6 +163,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 00500007c18..7321d98b476 100644 --- a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java +++ b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java @@ -74,6 +74,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; @@ -237,6 +240,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/VolumeResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java index b643de12585..338fcaae5a4 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/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..d1eeb3b0e52 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 diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 82ce9e944fb..7052fd7f30a 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -806,6 +806,7 @@ + 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/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/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/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/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/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index 96c35f36f34..da6271236f9 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 @@ -166,7 +166,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 +511,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/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java index 631d220f69d..48ec51265b9 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 @@ -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 29b3400bbbb..300d932a31c 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java @@ -49,26 +49,38 @@ 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 - protected List select(DiskProfile dskCh, VirtualMachineProfile vmProfile, - 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; + @Override + protected List select(DiskProfile dskCh, + VirtualMachineProfile vmProfile, + DeploymentPlan plan, ExcludeList avoid, int returnUpTo) { + s_logger.debug("ZoneWideStoragePoolAllocator to find storage pool"); + List suitablePools = new ArrayList(); + + 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..7878d8d144d 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java @@ -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; } @@ -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/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/image/BaseImageStoreDriverImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java index 93b0c2b373d..97c167164b0 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java @@ -81,7 +81,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); @@ -184,7 +184,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 56b0b08c0ea..de1e423f126 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 @@ -35,8 +35,11 @@ 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; @@ -143,6 +146,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(); @@ -154,7 +167,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; } @@ -238,7 +251,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; } @@ -935,7 +948,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/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index e0c00fc8f50..914017cf23f 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 @@ -2573,7 +2573,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) { 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..a59949f80a9 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 " 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 5c51585552c..52f41901418 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 @@ -36,6 +36,9 @@ import java.util.Map; import java.util.Random; import java.util.TimeZone; import java.util.UUID; +import java.util.HashSet; +import java.util.Set; +import java.util.Map.Entry; import javax.inject.Inject; import javax.naming.ConfigurationException; @@ -216,6 +219,8 @@ import com.cloud.hypervisor.vmware.mo.HostMO; import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper; import com.cloud.hypervisor.vmware.mo.NetworkDetails; import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType; +import com.cloud.hypervisor.vmware.mo.HostDatastoreSystemMO; +import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO; import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; import com.cloud.hypervisor.vmware.mo.VirtualSwitchType; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; @@ -229,7 +234,6 @@ import com.cloud.network.HAProxyConfigurator; import com.cloud.network.LoadBalancerConfigurator; import com.cloud.network.Networks; import com.cloud.network.Networks.BroadcastDomainType; -import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.VmwareTrafficLabel; import com.cloud.network.rules.FirewallRule; @@ -272,8 +276,16 @@ import com.vmware.vim25.GuestInfo; import com.vmware.vim25.HostCapability; import com.vmware.vim25.HostFirewallInfo; import com.vmware.vim25.HostFirewallRuleset; -import com.vmware.vim25.HostNetworkTrafficShapingPolicy; -import com.vmware.vim25.HostPortGroupSpec; +import com.vmware.vim25.HostHostBusAdapter; +import com.vmware.vim25.HostInternetScsiTargetTransport; +import com.vmware.vim25.HostScsiTopology; +import com.vmware.vim25.HostInternetScsiHba; +import com.vmware.vim25.HostInternetScsiHbaAuthenticationProperties; +import com.vmware.vim25.HostInternetScsiHbaStaticTarget; +import com.vmware.vim25.HostScsiDisk; +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; @@ -304,10 +316,6 @@ import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator; import com.vmware.vim25.VirtualMachineRuntimeInfo; import com.vmware.vim25.VirtualSCSISharing; -import java.util.HashSet; -import java.util.Set; -import java.util.Map.Entry; - public class VmwareResource implements StoragePoolResource, ServerResource, VmwareHostService { private static final Logger s_logger = Logger.getLogger(VmwareResource.class); @@ -593,7 +601,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) { @@ -3244,7 +3251,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) { @@ -3750,8 +3757,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; @@ -3903,6 +3908,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)); @@ -3922,7 +3966,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); @@ -3933,12 +3985,16 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa 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()); + 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; @@ -3954,6 +4010,198 @@ 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() { + 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() { + 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/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index cbbec7ce7e6..d9c357d073b 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 @@ -4172,11 +4172,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); @@ -4479,7 +4475,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); } @@ -5549,7 +5545,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."); @@ -6229,7 +6225,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(); @@ -6367,19 +6362,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); } @@ -6387,7 +6381,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; @@ -6412,19 +6406,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(); @@ -6463,19 +6462,30 @@ 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, - type, "user", true, smConfig); - Pool.Record pRec = XenServerConnectionPool.getPoolRecord(conn); - PBD.Record rec = new PBD.Record(); - rec.deviceConfig = deviceConfig; - rec.host = pRec.master; - rec.SR = sr; - PBD pbd = PBD.create(conn, rec); - pbd.plug(conn); + sr = SR.introduce(conn, pooluuid, srNameLabel, srNameLabel, + type, "user", true, smConfig); + + Set setHosts = Host.getAll(conn); + + for (Host currentHost : setHosts) { + PBD.Record rec = new PBD.Record(); + + rec.deviceConfig = deviceConfig; + rec.host = currentHost; + rec.SR = sr; + + PBD pbd = PBD.create(conn, rec); + + pbd.plug(conn); + } } sr.scan(conn); return sr; @@ -6636,6 +6646,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(); @@ -6652,7 +6708,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 */ @@ -6704,7 +6769,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); @@ -6723,7 +6788,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); } @@ -7606,30 +7673,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..e6358f26690 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 @@ -55,7 +55,6 @@ 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; @@ -171,7 +170,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 +231,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 +358,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()); 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..78f22630b91 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 @@ -54,6 +54,11 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver return null; } + @Override + public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + return null; + } + private class CreateVolumeContext extends AsyncRpcConext { private final DataObject volume; public CreateVolumeContext(AsyncCompletionCallback callback, DataObject volume) { @@ -77,7 +82,7 @@ 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()); * @@ -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..839c5a5e297 --- /dev/null +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java @@ -0,0 +1,901 @@ +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/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 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/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index 98eae37cde1..1b99b63afdf 100755 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -102,14 +102,18 @@ 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, - Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate); + 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); /** * Creates a new pod diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 3840c120630..2089f82dfe9 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -2297,8 +2297,9 @@ 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, - Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate) { + 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)) { throw new InvalidParameterValueException("Please specify a disk size of at least 1 Gb."); @@ -2314,8 +2315,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); @@ -2355,7 +2392,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; @@ -2369,11 +2406,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 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 b3e8b96e745..241f6e627f6 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -694,9 +694,10 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C 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); + "zone wide storage pool is not supported for hypervisor type " + hypervisor); } } @@ -734,6 +735,9 @@ 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; @@ -1561,7 +1565,41 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } @Override - public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) { + public boolean storagePoolHasEnoughIops(List requestedVolumes, + StoragePool pool) { + if (requestedVolumes == null || requestedVolumes.isEmpty() || pool == null) + return false; + + 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; diff --git a/server/src/com/cloud/storage/VolumeManager.java b/server/src/com/cloud/storage/VolumeManager.java index c84bb67e038..2e44a3c35b3 100644 --- a/server/src/com/cloud/storage/VolumeManager.java +++ b/server/src/com/cloud/storage/VolumeManager.java @@ -45,7 +45,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/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java index 4e7b3353ba0..a293da5c9a7 100644 --- a/server/src/com/cloud/storage/VolumeManagerImpl.java +++ b/server/src/com/cloud/storage/VolumeManagerImpl.java @@ -55,6 +55,7 @@ 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.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; @@ -65,6 +66,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; @@ -227,6 +229,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { @Inject protected StoragePoolHostDao _storagePoolHostDao; @Inject + StoragePoolDetailsDao storagePoolDetailsDao; + @Inject protected AlertManager _alertMgr; @Inject protected TemplateDataStoreDao _vmTemplateStoreDao = null; @@ -507,7 +511,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 { @@ -680,9 +685,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()) { @@ -731,8 +736,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); @@ -835,6 +840,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; @@ -896,6 +903,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( @@ -970,8 +1008,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); @@ -980,6 +1018,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 @@ -1171,7 +1211,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(); /* @@ -1358,7 +1397,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()); } @@ -1398,7 +1438,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(this.getSupportedImageFormatForCluster(template.getHypervisorType())); if (vm != null) { vol.setInstanceId(vm.getId()); @@ -1542,8 +1583,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; @@ -1557,12 +1598,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()); @@ -1573,19 +1639,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(); @@ -1912,9 +1988,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) { @@ -1926,6 +2010,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 { @@ -1940,11 +2025,6 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } } - - - - - @DB protected VolumeVO switchVolume(VolumeVO existingVolume, VirtualMachineProfile vm) @@ -2232,7 +2312,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); } @@ -2240,7 +2320,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { UserVmVO userVM = (UserVmVO) vm.getVirtualMachine(); 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); } } @@ -2458,7 +2538,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); } } @@ -2745,7 +2825,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/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index f70d44de65a..ca644af270c 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -1023,7 +1023,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 3cef1827557..a59fa5b629d 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2910,12 +2910,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/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java index 95230a5353b..7a61978f289 100755 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -655,8 +655,9 @@ 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, - Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate) { + 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/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 2d0f8defa79..0c1d753486e 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -429,6 +429,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); @@ -871,6 +885,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, @@ -981,6 +997,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, @@ -1521,9 +1538,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, @@ -1736,6 +1756,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/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py index 9d60ff91026..8129396813a 100644 --- a/tools/marvin/marvin/cloudstackConnection.py +++ b/tools/marvin/marvin/cloudstackConnection.py @@ -203,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/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(); %>