From 6317f0bd33605c4943dcf472415e9d5c7a443d93 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Fri, 1 Mar 2013 17:46:46 -0700 Subject: [PATCH 01/21] Summary: Update cloud user's home dir during RPM install for 4.1+ Signed-off-by: Marcus Sorensen 1362185206 -0700 --- packaging/centos63/cloud.spec | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index 24ec2455c3f..74055ac496e 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -318,6 +318,10 @@ if [ ! -f %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/vhd-util echo %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/ fi +# change cloud user's home to 4.1+ version if needed. Would do this via 'usermod', but it +# requires that cloud user not be in use, so RPM could not be installed while management is running +getent passwd cloud | grep -q /var/lib/cloud && sed -i 's/\/var\/lib\/cloud\/management/\/var\/cloudstack\/management/g' /etc/passwd + %post awsapi if [ -d "%{_datadir}/%{name}-management" ] ; then ln -s %{_datadir}/%{name}-bridge/webapps %{_datadir}/%{name}-management/webapps7080 From cec4d8b59c33858c99a4ead29b66d9aff5f0af6f Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Fri, 1 Mar 2013 17:16:31 -0800 Subject: [PATCH 02/21] CLOUDSTACK-1262: update default built-in systemvm.iso search patch to be consistent with RPM location --- .../vmware/manager/VmwareManagerImpl.java | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index 2cf1248c12a..60b5ce4d4cd 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -528,29 +528,37 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw private File getSystemVMPatchIsoFile() { // locate systemvm.iso - URL url = this.getClass().getProtectionDomain().getCodeSource().getLocation(); - File file = new File(url.getFile()); - File isoFile = new File(file.getParent() + "/vms/systemvm.iso"); - if (!isoFile.exists()) { - isoFile = new File("/usr/lib64/cloud/common/" + "/vms/systemvm.iso"); - if (!isoFile.exists()) { - isoFile = new File("/usr/lib/cloud/common/" + "/vms/systemvm.iso"); - } + URL url = this.getClass().getClassLoader().getResource("vms/systemvm.iso"); + File isoFile = null; + if (url != null) { + isoFile = new File(url.getPath()); + } + + if(isoFile == null || !isoFile.exists()) { + isoFile = new File("/usr/share/cloudstack-common/vms/systemvm.iso"); + } + + assert(isoFile != null); + if(!isoFile.exists()) { + s_logger.error("Unable to locate systemvm.iso in your setup at " + isoFile.toString()); } return isoFile; } @Override public File getSystemVMKeyFile() { - URL url = this.getClass().getProtectionDomain().getCodeSource().getLocation(); - File file = new File(url.getFile()); - - File keyFile = new File(file.getParent(), "/scripts/vm/systemvm/id_rsa.cloud"); - if (!keyFile.exists()) { - keyFile = new File("/usr/lib64/cloud/common" + "/scripts/vm/systemvm/id_rsa.cloud"); - if (!keyFile.exists()) { - keyFile = new File("/usr/lib/cloud/common" + "/scripts/vm/systemvm/id_rsa.cloud"); - } + URL url = this.getClass().getClassLoader().getResource("scripts/vm/systemvm/id_rsa.cloud"); + File keyFile = null; + if ( url != null ){ + keyFile = new File(url.getPath()); + } + + if (keyFile == null || !keyFile.exists()) { + keyFile = new File("/usr/share/cloudstack-common/scripts/vm/systemvm/id_rsa.cloud"); + } + assert(keyFile != null); + if(!keyFile.exists()) { + s_logger.error("Unable to locate id_rsa.cloud in your setup at " + keyFile.toString()); } return keyFile; } From 31d6e5465e8c395f310e9cfb5575b2207a8b6e4e Mon Sep 17 00:00:00 2001 From: frank Date: Fri, 1 Mar 2013 17:51:52 -0800 Subject: [PATCH 03/21] CloudStack CLOUDSTACK-774 Supporting kickstart in CloudStack baremetal make kikcstart working with ubuntu --- .../BaremetalKickStartPxeResource.java | 2 +- .../BaremetalKickStartServiceImpl.java | 33 +++++++++-- .../PrepareKickstartPxeServerCommand.java | 31 +++++++---- .../ping/prepare_kickstart_kernel_initrd.py | 55 ++++++++++--------- 4 files changed, 80 insertions(+), 41 deletions(-) diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java index 2b9b140607b..58c6e862d9f 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java @@ -175,7 +175,7 @@ public class BaremetalKickStartPxeResource extends BaremetalPxeResourceBase { } String copyTo = String.format("%s/%s", _tftpDir, cmd.getTemplateUuid()); - String script = String.format("python /usr/bin/prepare_kickstart_kernel_initrd.py %s %s", cmd.getRepo(), copyTo); + String script = String.format("python /usr/bin/prepare_kickstart_kernel_initrd.py %s %s %s", cmd.getKernel(), cmd.getInitrd(), copyTo); if (!SSHCmdHelper.sshExecuteCmd(sshConnection, script)) { return new Answer(cmd, false, "prepare kickstart at pxe server " + _ip + " failed, command:" + script); diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java index ba5fb0d0b6c..8a5ac78729e 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java @@ -95,11 +95,36 @@ public class BaremetalKickStartServiceImpl extends BareMetalPxeServiceBase imple try { String tpl = profile.getTemplate().getUrl(); assert tpl != null : "How can a null template get here!!!"; - String[] tpls = tpl.split(";"); - assert tpls.length == 2 : "Template is not correctly encoded. " + tpl; + String[] tpls = tpl.split(";"); + CloudRuntimeException err = new CloudRuntimeException(String.format("template url[%s] is not correctly encoded. it must be in format of ks=http_link_to_kickstartfile;kernel=nfs_path_to_pxe_kernel;initrd=nfs_path_to_pxe_initrd", tpl)); + if (tpls.length != 3) { + throw err; + } + + String ks = null; + String kernel = null; + String initrd = null; + + for (String t : tpls) { + String[] kv = t.split("="); + if (kv.length != 2) { + throw err; + } + if (kv[0].equals("ks")) { + ks = kv[1]; + } else if (kv[0].equals("kernel")) { + kernel = kv[1]; + } else if (kv[0].equals("initrd")) { + initrd = kv[1]; + } else { + throw err; + } + } + PrepareKickstartPxeServerCommand cmd = new PrepareKickstartPxeServerCommand(); - cmd.setKsFile(tpls[0]); - cmd.setRepo(tpls[1]); + cmd.setKsFile(ks); + cmd.setInitrd(initrd); + cmd.setKernel(kernel); cmd.setMac(nic.getMacAddress()); cmd.setTemplateUuid(template.getUuid()); Answer aws = _agentMgr.send(pxeVo.getHostId(), cmd); diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/PrepareKickstartPxeServerCommand.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/PrepareKickstartPxeServerCommand.java index 89515475062..25dfeb70d30 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/PrepareKickstartPxeServerCommand.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/PrepareKickstartPxeServerCommand.java @@ -22,10 +22,11 @@ import com.cloud.agent.api.Command; public class PrepareKickstartPxeServerCommand extends Command { private String ksFile; - private String repo; private String templateUuid; private String mac; - private String ksDevice; + private String ksDevice; + private String kernel; + private String initrd; @Override public boolean executeInSequence() { @@ -39,15 +40,23 @@ public class PrepareKickstartPxeServerCommand extends Command { public void setKsFile(String ksFile) { this.ksFile = ksFile; } - - public String getRepo() { - return repo; - } - - public void setRepo(String repo) { - this.repo = repo; - } - + + public String getKernel() { + return kernel; + } + + public void setKernel(String kernel) { + this.kernel = kernel; + } + + public String getInitrd() { + return initrd; + } + + public void setInitrd(String initrd) { + this.initrd = initrd; + } + public String getTemplateUuid() { return templateUuid; } diff --git a/scripts/network/ping/prepare_kickstart_kernel_initrd.py b/scripts/network/ping/prepare_kickstart_kernel_initrd.py index b234a62de70..ff618480e69 100755 --- a/scripts/network/ping/prepare_kickstart_kernel_initrd.py +++ b/scripts/network/ping/prepare_kickstart_kernel_initrd.py @@ -21,50 +21,55 @@ import tempfile import os.path import os -iso_folder = '' -copy_to = '' +kernel = None +initrd = None +copy_to = None def cmd(cmdstr, err=True): + print cmdstr if os.system(cmdstr) != 0 and err: raise Exception("Failed to run shell command: %s" % cmdstr) def prepare(): + global kernel, initrd, copy_to try: - kernel = os.path.join(copy_to, "vmlinuz") - initrd = os.path.join(copy_to, "initrd.img") - if os.path.exists(kernel) and os.path.exists(initrd): + k = os.path.join(copy_to, "vmlinuz") + i = os.path.join(copy_to, "initrd.img") + if os.path.exists(k) and os.path.exists(i): print "Having template(%s) prepared already, skip copying" % copy_to return 0 else: if not os.path.exists(copy_to): os.makedirs(copy_to) - mnt_path = tempfile.mkdtemp() - try: - mnt = "mount %s %s" % (iso_folder, mnt_path) - cmd(mnt) - - kernel = os.path.join(mnt_path, "vmlinuz") - initrd = os.path.join(mnt_path, "initrd.img") - cp = "cp -f %s %s/" % (kernel, copy_to) - cmd(cp) - cp = "cp -f %s %s/" % (initrd, copy_to) - cmd(cp) - finally: - umnt = "umount %s" % mnt_path - cmd(umnt, False) - rm = "rm -r %s" % mnt_path - cmd(rm, False) - return 0 + + def copy_from_nfs(src, dst): + mnt_path = tempfile.mkdtemp() + try: + nfs_path = os.path.dirname(src) + filename = os.path.basename(src) + t = os.path.join(mnt_path, filename) + mnt = "mount %s %s" % (nfs_path, mnt_path) + cmd(mnt) + cp = "cp -f %s %s" % (t, dst) + cmd(cp) + finally: + umnt = "umount %s" % mnt_path + cmd(umnt, False) + rm = "rm -r %s" % mnt_path + cmd(rm, False) + + copy_from_nfs(kernel, copy_to) + copy_from_nfs(initrd, copy_to) except Exception, e: print e return 1 if __name__ == "__main__": - if len(sys.argv) < 3: - print "Usage: prepare_kickstart_kerneal_initrd.py path_to_kernel_initrd_iso path_kernel_initrd_copy_to" + if len(sys.argv) < 4: + print "Usage: prepare_kickstart_kerneal_initrd.py path_to_kernel path_to_initrd path_kernel_initrd_copy_to" sys.exit(1) - (iso_folder, copy_to) = sys.argv[1:] + (kernel, initrd, copy_to) = sys.argv[1:] sys.exit(prepare()) From e08281838a428a26f1993519de96fc45a26c0920 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Fri, 1 Mar 2013 19:26:38 -0700 Subject: [PATCH 04/21] Summary: Add EOF to agent.properties for proper parsing Detail: lack of newline at end of file was keeping cloudstack-setup-agent from properly editing/creating new config. BUG-ID: CLOUDSTACK-1487 Signed-off-by: Marcus Sorensen 1362191198 -0700 --- agent/conf/agent.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties index 74cfd1c21d6..f7eac674712 100644 --- a/agent/conf/agent.properties +++ b/agent/conf/agent.properties @@ -79,4 +79,4 @@ domr.scripts.dir=scripts/network/domr/kvm # be overridden here. # native = com.cloud.hypervisor.kvm.resource.BridgeVifDriver # openvswitch = com.cloud.hypervisor.kvm.resource.OvsBridgeDriver -#libvirt.vif.driver=com.cloud.hypervisor.kvm.resource.BridgeVifDriver \ No newline at end of file +#libvirt.vif.driver=com.cloud.hypervisor.kvm.resource.BridgeVifDriver From 6a1ecae552e8857c8e97c283962d14db4479a9a1 Mon Sep 17 00:00:00 2001 From: Chiradeep Vittal Date: Sat, 2 Mar 2013 16:49:02 +0530 Subject: [PATCH 05/21] Ensure RAT does not report marvin generated files as noncompliant in developer environment Signed-off-by: Prasanna Santhanam --- pom.xml | 2 ++ tools/marvin/marvin/codegenerator.py | 49 +++++++++++++++------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/pom.xml b/pom.xml index dde205f6d7c..3219ab0f06f 100644 --- a/pom.xml +++ b/pom.xml @@ -382,8 +382,10 @@ tools/appliance/definitions/systemvmtemplate/definition.rb tools/appliance/definitions/systemvmtemplate/preseed.cfg tools/appliance/definitions/systemvmtemplate/zerodisk.sh + tools/cli/cloudmonkey.egg-info/* tools/devcloud/src/deps/boxes/basebox-build/definition.rb tools/devcloud/src/deps/boxes/basebox-build/preseed.cfg + tools/marvin/Marvin.egg-info/* ui/lib/flot/jquery.colorhelpers.js ui/lib/flot/jquery.flot.crosshair.js ui/lib/flot/jquery.flot.fillbetween.js diff --git a/tools/marvin/marvin/codegenerator.py b/tools/marvin/marvin/codegenerator.py index cce91008dba..ed9248c49a3 100644 --- a/tools/marvin/marvin/codegenerator.py +++ b/tools/marvin/marvin/codegenerator.py @@ -48,6 +48,26 @@ class codeGenerator: self.subclass = [] self.outputFolder = outputFolder self.apiSpecFile = apiSpecFile + lic = """\ + # 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. + + """ + self.license = dedent(lic) def addAttribute(self, attr, pro): value = pro.value @@ -81,25 +101,7 @@ class codeGenerator: self.cmd = cmd self.cmdsName.append(self.cmd.name) - 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. - """ - self.code = dedent(license) + self.code = self.license self.code += "\n" self.code += '"""%s"""\n'%self.cmd.desc self.code += 'from baseCmd import *\n' @@ -186,25 +188,28 @@ class codeGenerator: initCmdsList += '"%s",'%cmdName fp = open(self.outputFolder + '/cloudstackAPI/cloudstackAPIClient.py', 'w') + fp.write(self.license) for item in [header, imports, body]: fp.write(item) fp.close() '''generate __init__.py''' - initCmdsList += '"cloudstackAPIClient"]' + initCmdsList = self.license + initCmdsList + '"cloudstackAPIClient"]' fp = open(self.outputFolder + '/cloudstackAPI/__init__.py', 'w') fp.write(initCmdsList) fp.close() fp = open(self.outputFolder + '/cloudstackAPI/baseCmd.py', 'w') - basecmd = '"""Base Command"""\n' + basecmd = self.license + basecmd += '"""Base Command"""\n' basecmd += 'class baseCmd:\n' basecmd += self.space + 'pass\n' fp.write(basecmd) fp.close() fp = open(self.outputFolder + '/cloudstackAPI/baseResponse.py', 'w') - basecmd = '"""Base class for response"""\n' + basecmd = self.license + basecmd += '"""Base class for response"""\n' basecmd += 'class baseResponse:\n' basecmd += self.space + 'pass\n' fp.write(basecmd) From 7c52d7d1c92e57335958cd43f5185481043eb1aa Mon Sep 17 00:00:00 2001 From: Sateesh Chodapuneedi Date: Sun, 3 Mar 2013 08:22:40 +0530 Subject: [PATCH 06/21] In basic zone, skip checks for physical network configuration with multiple virtual switches. Signed-off-by: Sateesh Chodapuneedi --- .../vmware/VmwareServerDiscoverer.java | 75 +++++++++++-------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java index 90fe461e5cb..e6d708cbfed 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java @@ -159,10 +159,12 @@ public class VmwareServerDiscoverer extends DiscovererBase implements VmwareTrafficLabel guestTrafficLabelObj = new VmwareTrafficLabel(TrafficType.Guest); VmwareTrafficLabel publicTrafficLabelObj = new VmwareTrafficLabel(TrafficType.Public); Map clusterDetails = _clusterDetailsDao.findDetails(clusterId); + DataCenterVO zone = _dcDao.findById(dcId); + NetworkType zoneType = zone.getNetworkType(); _readGlobalConfigParameters(); // Set default physical network end points for public and guest traffic - // Private traffic will be only on standard vSwitch for now. See below TODO. + // Private traffic will be only on standard vSwitch for now. if (useDVS) { // Parse url parameters for type of vswitch and name of vswitch specified at cluster level paramGuestVswitchType = _urlParams.get(ApiConstants.VSWITCH_TYPE_GUEST_TRAFFIC); @@ -171,13 +173,6 @@ public class VmwareServerDiscoverer extends DiscovererBase implements paramPublicVswitchName = _urlParams.get(ApiConstants.VSWITCH_NAME_PUBLIC_TRAFFIC); defaultVirtualSwitchType = getDefaultVirtualSwitchType(); } - // Get zone wide traffic labels for Guest traffic and Public traffic - guestTrafficLabel = _netmgr.getDefaultGuestTrafficLabel(dcId, HypervisorType.VMware); - publicTrafficLabel = _netmgr.getDefaultPublicTrafficLabel(dcId, HypervisorType.VMware); - - // Process traffic label information provided at zone level and cluster level - guestTrafficLabelObj = getTrafficInfo(TrafficType.Guest, guestTrafficLabel, defaultVirtualSwitchType, paramGuestVswitchType, paramGuestVswitchName, clusterId); - publicTrafficLabelObj = getTrafficInfo(TrafficType.Public, publicTrafficLabel, defaultVirtualSwitchType, paramPublicVswitchType, paramPublicVswitchName, clusterId); // Zone level vSwitch Type depends on zone level traffic labels // @@ -196,28 +191,50 @@ public class VmwareServerDiscoverer extends DiscovererBase implements // 'vmwaresvs' is for vmware standard vswitch // 'vmwaredvs' is for vmware distributed virtual switch // 'nexusdvs' is for cisco nexus distributed virtual switch + // Get zone wide traffic labels for Guest traffic and Public traffic + guestTrafficLabel = _netmgr.getDefaultGuestTrafficLabel(dcId, HypervisorType.VMware); - // Configuration Check: A physical network cannot be shared by different types of virtual switches. - // - // Check if different vswitch types are chosen for same physical network - // 1. Get physical network for guest traffic - multiple networks - // 2. Get physical network for public traffic - single network - // See if 2 is in 1 - // if no - pass - // if yes - compare publicTrafficLabelObj.getVirtualSwitchType() == guestTrafficLabelObj.getVirtualSwitchType() - // true - pass - // false - throw exception - fail cluster add operation - List pNetworkListGuestTraffic = _netmgr.getPhysicalNtwksSupportingTrafficType(dcId, TrafficType.Guest); - List pNetworkListPublicTraffic = _netmgr.getPhysicalNtwksSupportingTrafficType(dcId, TrafficType.Public); - // Public network would be on single physical network hence getting first object of the list would suffice. - PhysicalNetwork pNetworkPublic = pNetworkListPublicTraffic.get(0); - if (pNetworkListGuestTraffic.contains(pNetworkPublic)) { - if (publicTrafficLabelObj.getVirtualSwitchType() != guestTrafficLabelObj.getVirtualSwitchType()) { - String msg = "Both public traffic and guest traffic is over same physical network " + pNetworkPublic + - ". And virtual switch type chosen for each traffic is different" + - ". A physical network cannot be shared by different types of virtual switches."; + // Process traffic label information provided at zone level and cluster level + guestTrafficLabelObj = getTrafficInfo(TrafficType.Guest, guestTrafficLabel, defaultVirtualSwitchType, paramGuestVswitchType, paramGuestVswitchName, clusterId); + + if (zoneType == NetworkType.Advanced) { + // Get zone wide traffic label for Public traffic + publicTrafficLabel = _netmgr.getDefaultPublicTrafficLabel(dcId, HypervisorType.VMware); + + // Process traffic label information provided at zone level and cluster level + publicTrafficLabelObj = getTrafficInfo(TrafficType.Public, publicTrafficLabel, defaultVirtualSwitchType, paramPublicVswitchType, paramPublicVswitchName, clusterId); + + // Configuration Check: A physical network cannot be shared by different types of virtual switches. + // + // Check if different vswitch types are chosen for same physical network + // 1. Get physical network for guest traffic - multiple networks + // 2. Get physical network for public traffic - single network + // See if 2 is in 1 + // if no - pass + // if yes - compare publicTrafficLabelObj.getVirtualSwitchType() == guestTrafficLabelObj.getVirtualSwitchType() + // true - pass + // false - throw exception - fail cluster add operation + + List pNetworkListGuestTraffic = _netmgr.getPhysicalNtwksSupportingTrafficType(dcId, TrafficType.Guest); + List pNetworkListPublicTraffic = _netmgr.getPhysicalNtwksSupportingTrafficType(dcId, TrafficType.Public); + // Public network would be on single physical network hence getting first object of the list would suffice. + PhysicalNetwork pNetworkPublic = pNetworkListPublicTraffic.get(0); + if (pNetworkListGuestTraffic.contains(pNetworkPublic)) { + if (publicTrafficLabelObj.getVirtualSwitchType() != guestTrafficLabelObj.getVirtualSwitchType()) { + String msg = "Both public traffic and guest traffic is over same physical network " + pNetworkPublic + + ". And virtual switch type chosen for each traffic is different" + + ". A physical network cannot be shared by different types of virtual switches."; + s_logger.error(msg); + throw new InvalidParameterValueException(msg); + } + } + } else { + // Distributed virtual switch is not supported in Basic zone for now. + // Private / Management network traffic is not yet supported over distributed virtual switch. + if (guestTrafficLabelObj.getVirtualSwitchType() != VirtualSwitchType.StandardVirtualSwitch) { + String msg = "Detected that Guest traffic is over Distributed virtual switch in Basic zone. Only Standard vSwitch is supported in Basic zone."; s_logger.error(msg); - throw new InvalidParameterValueException(msg); + throw new DiscoveredWithErrorException(msg); } } @@ -227,8 +244,6 @@ public class VmwareServerDiscoverer extends DiscovererBase implements } if (nexusDVS) { - DataCenterVO zone = _dcDao.findById(dcId); - NetworkType zoneType = zone.getNetworkType(); if (zoneType != NetworkType.Basic) { publicTrafficLabel = _netmgr.getDefaultPublicTrafficLabel(dcId, HypervisorType.VMware); if (publicTrafficLabel != null) { From d73cd031eb9f7851790cf5af2d48b848e0f4876c Mon Sep 17 00:00:00 2001 From: Joe Brockmeier Date: Sun, 3 Mar 2013 22:39:49 -0600 Subject: [PATCH 07/21] CLOUDSTACK-313: fixing a cross-reference in zone-add.xml --- docs/en-US/zone-add.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en-US/zone-add.xml b/docs/en-US/zone-add.xml index 2a85bb0b432..4f6606fce03 100644 --- a/docs/en-US/zone-add.xml +++ b/docs/en-US/zone-add.xml @@ -63,7 +63,7 @@ Basic. For AWS-style networking. Provides a single network where each VM instance is assigned an IP directly from the network. Guest isolation can be provided through layer-3 means such as security groups (IP address source filtering). Advanced. For more sophisticated network topologies. This network model provides the most flexibility in defining guest networks and providing custom network offerings such as firewall, VPN, or load balancer support. - For more information about the network types, see Network Setup. + For more information about the network types, see . The rest of the steps differ depending on whether you chose Basic or Advanced. Continue with the steps that apply to you: From 13c952e6153120e6cdcb24bab02c040e59ce8511 Mon Sep 17 00:00:00 2001 From: Joe Brockmeier Date: Sun, 3 Mar 2013 22:48:21 -0600 Subject: [PATCH 08/21] CLOUDSTACK-313: fixing cross-references in accessing-vms.xml --- docs/en-US/accessing-vms.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en-US/accessing-vms.xml b/docs/en-US/accessing-vms.xml index ce780cff080..67d9d774172 100644 --- a/docs/en-US/accessing-vms.xml +++ b/docs/en-US/accessing-vms.xml @@ -32,9 +32,9 @@ To access a VM directly over the network: - The VM must have some port open to incoming traffic. For example, in a basic zone, a new VM might be assigned to a security group which allows incoming traffic. This depends on what security group you picked when creating the VM. In other cases, you can open a port by setting up a port forwarding policy. See IP Forwarding and Firewalling. + The VM must have some port open to incoming traffic. For example, in a basic zone, a new VM might be assigned to a security group which allows incoming traffic. This depends on what security group you picked when creating the VM. In other cases, you can open a port by setting up a port forwarding policy. See . If a port is open but you can not access the VM using ssh, it’s possible that ssh is not already enabled on the VM. This will depend on whether ssh is enabled in the template you picked when creating the VM. Access the VM through the &PRODUCT; UI and enable ssh on the machine using the commands for the VM’s operating system. - If the network has an external firewall device, you will need to create a firewall rule to allow access. See IP Forwarding and Firewalling. + If the network has an external firewall device, you will need to create a firewall rule to allow access. See . From fe649f6c45f92f9cf3a01f219d27188b50cf3b8e Mon Sep 17 00:00:00 2001 From: Joe Brockmeier Date: Sun, 3 Mar 2013 23:14:33 -0600 Subject: [PATCH 09/21] CLOUDSTACK-313: fixing a cross-reference. --- docs/en-US/deployment-architecture-overview.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/en-US/deployment-architecture-overview.xml b/docs/en-US/deployment-architecture-overview.xml index fba36eb85a3..e3103c52c1c 100644 --- a/docs/en-US/deployment-architecture-overview.xml +++ b/docs/en-US/deployment-architecture-overview.xml @@ -48,7 +48,8 @@ A more full-featured installation consists of a highly-available multi-node Management Server installation and up to tens of thousands of hosts using any of several advanced networking setups. For - information about deployment options, see Choosing a Deployment Architecture. + information about deployment options, see the "Choosing a Deployment Architecture" + section of the $PRODUCT; Installation Guide. From aedb8c478e88ad393246b9fa08a7fdac53e8e2d9 Mon Sep 17 00:00:00 2001 From: Jayapal Uradi Date: Mon, 4 Mar 2013 11:02:09 +0530 Subject: [PATCH 10/21] CLOUDSTACK-24: mipn feature for isolated and vpc networks https://cwiki.apache.org/confluence/display/CLOUDSTACK/Multiple+IP+address+per+NIC https://issues.apache.org/jira/browse/CLOUDSTACK-24 --- api/src/com/cloud/network/IpAddress.java | 3 + api/src/com/cloud/network/NetworkService.java | 15 +- .../com/cloud/network/rules/RulesService.java | 5 +- api/src/com/cloud/vm/Nic.java | 1 + api/src/com/cloud/vm/NicSecondaryIp.java | 36 ++++ .../apache/cloudstack/api/ApiConstants.java | 1 + .../cloudstack/api/ResponseGenerator.java | 7 + .../firewall/CreatePortForwardingRuleCmd.java | 19 +- .../command/user/nat/EnableStaticNatCmd.java | 12 +- .../api/command/user/vm/AddIpToVmNicCmd.java | 176 ++++++++++++++++++ .../api/command/user/vm/ListNicsCmd.java | 133 +++++++++++++ .../command/user/vm/RemoveIpFromVmNicCmd.java | 123 ++++++++++++ .../api/response/AddIpToVmNicResponse.java | 85 +++++++++ .../api/response/IPAddressResponse.java | 8 + .../cloudstack/api/response/NicResponse.java | 12 +- .../api/response/NicSecondaryIpResponse.java | 85 +++++++++ .../api/command/test/AddIpToVmNicTest.java | 132 +++++++++++++ client/tomcatconf/commands.properties.in | 5 + server/src/com/cloud/api/ApiDBUtils.java | 10 + .../src/com/cloud/api/ApiResponseHelper.java | 56 ++++++ .../src/com/cloud/network/NetworkManager.java | 12 ++ .../com/cloud/network/NetworkManagerImpl.java | 76 +++++++- .../com/cloud/network/NetworkModelImpl.java | 5 + .../com/cloud/network/NetworkServiceImpl.java | 170 +++++++++++++++++ .../src/com/cloud/network/addr/PublicIp.java | 34 ++-- .../com/cloud/network/dao/IPAddressDao.java | 7 +- .../cloud/network/dao/IPAddressDaoImpl.java | 17 +- .../com/cloud/network/dao/IPAddressVO.java | 16 +- .../VirtualNetworkApplianceManagerImpl.java | 3 +- .../cloud/network/rules/RulesManagerImpl.java | 113 ++++++++--- .../rules/dao/PortForwardingRulesDao.java | 2 + .../rules/dao/PortForwardingRulesDaoImpl.java | 8 + .../cloud/server/ManagementServerImpl.java | 3 + server/src/com/cloud/vm/NicVO.java | 11 ++ .../src/com/cloud/vm/UserVmManagerImpl.java | 8 + server/src/com/cloud/vm/dao/NicDao.java | 2 + server/src/com/cloud/vm/dao/NicDaoImpl.java | 12 +- .../com/cloud/vm/dao/NicSecondaryIpDao.java | 53 ++++++ .../cloud/vm/dao/NicSecondaryIpDaoImpl.java | 138 ++++++++++++++ .../com/cloud/vm/dao/NicSecondaryIpVO.java | 160 ++++++++++++++++ .../cloud/network/MockNetworkManagerImpl.java | 47 +++++ .../cloud/network/MockRulesManagerImpl.java | 19 +- .../com/cloud/vpc/MockNetworkManagerImpl.java | 73 ++++++++ setup/db/db/schema-410to420.sql | 21 +++ 44 files changed, 1866 insertions(+), 68 deletions(-) create mode 100644 api/src/com/cloud/vm/NicSecondaryIp.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/vm/ListNicsCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java create mode 100644 api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java create mode 100644 api/src/org/apache/cloudstack/api/response/NicSecondaryIpResponse.java create mode 100644 api/test/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java create mode 100644 server/src/com/cloud/vm/dao/NicSecondaryIpDao.java create mode 100644 server/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java create mode 100644 server/src/com/cloud/vm/dao/NicSecondaryIpVO.java diff --git a/api/src/com/cloud/network/IpAddress.java b/api/src/com/cloud/network/IpAddress.java index 47df4d6523b..fce8f38c2f2 100644 --- a/api/src/com/cloud/network/IpAddress.java +++ b/api/src/com/cloud/network/IpAddress.java @@ -87,4 +87,7 @@ public interface IpAddress extends ControlledEntity, Identity, InternalIdentity * @param vpcId */ void setVpcId(Long vpcId); + String getVmIp(); + void setVmIp(String vmIp); + } diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 95bcc42b17a..ab6d7bfd882 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -19,9 +19,10 @@ package com.cloud.network; import java.util.List; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; +import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; -import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientAddressCapacityException; @@ -33,6 +34,8 @@ import com.cloud.network.Networks.TrafficType; import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.utils.Pair; +import com.cloud.vm.Nic; +import com.cloud.vm.NicSecondaryIp; /** * The NetworkService interface is the "public" api to entities that make requests to the orchestration engine @@ -153,5 +156,13 @@ public interface NetworkService { Network createPrivateNetwork(String networkName, String displayText, long physicalNetworkId, String vlan, String startIp, String endIP, String gateway, String netmask, long networkOwnerId, Long vpcId) throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException; - + + /* Requests an IP address for the guest nic */ + String allocateSecondaryGuestIP(Account account, long zoneId, Long nicId, + Long networkId, String ipaddress) throws InsufficientAddressCapacityException; + + boolean releaseSecondaryIpFromNic(long ipAddressId); + + /* lists the nic informaton */ + List listNics(ListNicsCmd listNicsCmd); } diff --git a/api/src/com/cloud/network/rules/RulesService.java b/api/src/com/cloud/network/rules/RulesService.java index 921a86e865f..d47b38f9d43 100644 --- a/api/src/com/cloud/network/rules/RulesService.java +++ b/api/src/com/cloud/network/rules/RulesService.java @@ -25,6 +25,7 @@ import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.user.Account; import com.cloud.utils.Pair; +import com.cloud.utils.net.Ip; public interface RulesService { Pair, Integer> searchStaticNatRules(Long ipId, Long id, Long vmId, Long start, Long size, String accountName, Long domainId, Long projectId, boolean isRecursive, boolean listAll); @@ -43,7 +44,7 @@ public interface RulesService { * @throws NetworkRuleConflictException * if conflicts in the network rules are detected. */ - PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, boolean openFirewall) throws NetworkRuleConflictException; + PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, Ip vmIp, boolean openFirewall) throws NetworkRuleConflictException; /** * Revokes a port forwarding rule @@ -66,7 +67,7 @@ public interface RulesService { boolean applyPortForwardingRules(long ipAdddressId, Account caller) throws ResourceUnavailableException; - boolean enableStaticNat(long ipAddressId, long vmId, long networkId, boolean isSystemVm) throws NetworkRuleConflictException, ResourceUnavailableException; + boolean enableStaticNat(long ipAddressId, long vmId, long networkId, boolean isSystemVm, String vmGuestIp) throws NetworkRuleConflictException, ResourceUnavailableException; PortForwardingRule getPortForwardigRule(long ruleId); diff --git a/api/src/com/cloud/vm/Nic.java b/api/src/com/cloud/vm/Nic.java index 9d21130327a..b2f6976240c 100644 --- a/api/src/com/cloud/vm/Nic.java +++ b/api/src/com/cloud/vm/Nic.java @@ -151,4 +151,5 @@ public interface Nic extends Identity, InternalIdentity { String getIp6Cidr(); String getIp6Address(); + boolean getSecondaryIp(); } diff --git a/api/src/com/cloud/vm/NicSecondaryIp.java b/api/src/com/cloud/vm/NicSecondaryIp.java new file mode 100644 index 00000000000..655d172b33f --- /dev/null +++ b/api/src/com/cloud/vm/NicSecondaryIp.java @@ -0,0 +1,36 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.vm; + +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + + +/** + * Nic represents one nic on the VM. + */ +public interface NicSecondaryIp extends ControlledEntity, Identity, InternalIdentity { + /** + * @return id in the CloudStack database + */ + long getId(); + long getNicId(); + String getIp4Address(); + long getNetworkId(); + long getVmId(); +} diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 4fdc91edef2..1b544fd1641 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -458,6 +458,7 @@ public class ApiConstants { public static final String UCS_PROFILE_DN = "profiledn"; public static final String UCS_BLADE_DN = "bladedn"; public static final String UCS_BLADE_ID = "bladeid"; + public static final String VM_GUEST_IP = "vmguestip"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java index 267238af37b..a6025149846 100644 --- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java @@ -53,6 +53,8 @@ import org.apache.cloudstack.api.response.LoadBalancerResponse; import org.apache.cloudstack.api.response.NetworkACLResponse; import org.apache.cloudstack.api.response.NetworkOfferingResponse; import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.api.response.NicResponse; +import org.apache.cloudstack.api.response.NicSecondaryIpResponse; import org.apache.cloudstack.api.response.PhysicalNetworkResponse; import org.apache.cloudstack.api.response.PodResponse; import org.apache.cloudstack.api.response.PrivateGatewayResponse; @@ -163,6 +165,8 @@ import com.cloud.user.User; import com.cloud.user.UserAccount; import com.cloud.uservm.UserVm; import com.cloud.vm.InstanceGroup; +import com.cloud.vm.Nic; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.VirtualMachine; import com.cloud.vm.snapshot.VMSnapshot; @@ -385,4 +389,7 @@ public interface ResponseGenerator { TrafficMonitorResponse createTrafficMonitorResponse(Host trafficMonitor); VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot); + NicSecondaryIpResponse createSecondaryIPToNicResponse(String ip, + Long nicId, Long networkId); + public NicResponse createNicResponse(Nic result); } diff --git a/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java index 39ab812909d..40128526ce0 100644 --- a/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java @@ -94,6 +94,9 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P description="The network of the vm the Port Forwarding rule will be created for. " + "Required when public Ip address is not associated with any Guest network yet (VPC case)") private Long networkId; + @Parameter(name = ApiConstants.VM_GUEST_IP, type = CommandType.STRING, required = false, + description = "VM guest nic Secondary ip address for the port forwarding rule") + private String vmSecondaryIp; // /////////////////////////////////////////////////// // ///////////////// Accessors /////////////////////// @@ -104,6 +107,13 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P return ipAddressId; } + public Ip getVmSecondaryIp() { + if (vmSecondaryIp == null) { + return null; + } + return new Ip(vmSecondaryIp); + } + @Override public String getProtocol() { return protocol.trim(); @@ -300,8 +310,15 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P throw new InvalidParameterValueException("Parameter cidrList is deprecated; if you need to open firewall rule for the specific cidr, please refer to createFirewallRule command"); } + Ip privateIp = getVmSecondaryIp(); + if (privateIp != null) { + if ( !privateIp.isIp4()) { + throw new InvalidParameterValueException("Invalid vm ip address"); + } + } + try { - PortForwardingRule result = _rulesService.createPortForwardingRule(this, virtualMachineId, getOpenFirewall()); + PortForwardingRule result = _rulesService.createPortForwardingRule(this, virtualMachineId, privateIp, getOpenFirewall()); setEntityId(result.getId()); setEntityUuid(result.getUuid()); } catch (NetworkRuleConflictException ex) { diff --git a/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java b/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java index ce6ea1663b9..a0ec68ef5dd 100644 --- a/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java @@ -59,6 +59,9 @@ public class EnableStaticNatCmd extends BaseCmd{ description="The network of the vm the static nat will be enabled for." + " Required when public Ip address is not associated with any Guest network yet (VPC case)") private Long networkId; + @Parameter(name = ApiConstants.VM_GUEST_IP, type = CommandType.STRING, required = false, + description = "VM guest nic Secondary ip address for the port forwarding rule") + private String vmSecondaryIp; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -72,6 +75,13 @@ public class EnableStaticNatCmd extends BaseCmd{ return virtualMachineId; } + public String getVmSecondaryIp() { + if (vmSecondaryIp == null) { + return null; + } + return vmSecondaryIp; + } + public long getNetworkId() { IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId()); Long ntwkId = null; @@ -110,7 +120,7 @@ public class EnableStaticNatCmd extends BaseCmd{ @Override public void execute() throws ResourceUnavailableException{ try { - boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId, getNetworkId(), false); + boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId, getNetworkId(), false, getVmSecondaryIp()); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java new file mode 100644 index 00000000000..0f992743f6d --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java @@ -0,0 +1,176 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.vm; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.NicResponse; +import org.apache.cloudstack.api.response.NicSecondaryIpResponse; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.user.Account; +import com.cloud.user.UserContext; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.Nic; + +@APICommand(name = "addIpToNic", description = "Assigns secondary IP to NIC", responseObject = NicSecondaryIpResponse.class) +public class AddIpToVmNicCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(AddIpToVmNicCmd.class.getName()); + private static final String s_name = "addiptovmnicresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @Parameter(name=ApiConstants.NIC_ID, type=CommandType.UUID, entityType = NicResponse.class, required = true, + description="the ID of the nic to which you want to assign private IP") + private Long nicId; + + @Parameter(name = ApiConstants.IP_ADDRESS, type = CommandType.STRING, required = false, + description = "Secondary IP Address") + private String ipAddr; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getEntityTable() { + return "nic_secondary_ips"; + } + + public String getAccountName() { + return UserContext.current().getCaller().getAccountName(); + } + + public long getDomainId() { + return UserContext.current().getCaller().getDomainId(); + } + + private long getZoneId() { + Network ntwk = _entityMgr.findById(Network.class, getNetworkId()); + if (ntwk == null) { + throw new InvalidParameterValueException("Can't find zone id for specified"); + } + return ntwk.getDataCenterId(); + } + + public Long getNetworkId() { + Nic nic = _entityMgr.findById(Nic.class, nicId); + Long networkId = nic.getNetworkId(); + return networkId; + } + + public Long getNicId() { + return nicId; + } + + public String getIpaddress () { + if (ipAddr != null) { + return ipAddr; + } else { + return null; + } + } + @Override + public long getEntityOwnerId() { + Account caller = UserContext.current().getCaller(); + return caller.getAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_NET_IP_ASSIGN; + } + + @Override + public String getEventDescription() { + return "associating ip to nic id: " + getNetworkId() + " in zone " + getZoneId(); + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + + @Override + public String getCommandName() { + return s_name; + } + + public static String getResultObjectName() { + return "addressinfo"; + } + + @Override + public void execute() throws ResourceUnavailableException, ResourceAllocationException, + ConcurrentOperationException, InsufficientCapacityException { + + UserContext.current().setEventDetails("Nic Id: " + getNicId() ); + String ip; + String SecondaryIp = null; + if ((ip = getIpaddress()) != null) { + if (!NetUtils.isValidIp(ip)) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Invalid ip address " + ip); + } + } + + try { + SecondaryIp = _networkService.allocateSecondaryGuestIP(_accountService.getAccount(getEntityOwnerId()), getZoneId(), getNicId(), getNetworkId(), getIpaddress()); + } catch (InsufficientAddressCapacityException e) { + throw new InvalidParameterValueException("Allocating guest ip for nic failed"); + } + + if (SecondaryIp != null) { + s_logger.info("Associated ip address to NIC : " + SecondaryIp); + NicSecondaryIpResponse response = new NicSecondaryIpResponse(); + response = _responseGenerator.createSecondaryIPToNicResponse(ip, getNicId(), getNetworkId()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to assign secondary ip to nic"); + } + } + + @Override + public String getSyncObjType() { + return BaseAsyncCmd.networkSyncObject; + } + + @Override + public Long getSyncObjId() { + return getNetworkId(); + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.IpAddress; + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/ListNicsCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/ListNicsCmd.java new file mode 100644 index 00000000000..9af044ebb70 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/vm/ListNicsCmd.java @@ -0,0 +1,133 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.vm; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NicResponse; +import org.apache.cloudstack.api.response.UserVmResponse; + +import com.cloud.async.AsyncJob; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.user.UserContext; +import com.cloud.vm.Nic; +import com.cloud.vm.NicSecondaryIp; + +@APICommand(name = "listNics", description = "list the vm nics IP to NIC", responseObject = NicResponse.class) +public class ListNicsCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(ListNicsCmd.class.getName()); + private static final String s_name = "listnics"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.NIC_ID, type=CommandType.UUID, entityType = NicResponse.class, required = false, + description="the ID of the nic to to list IPs") + private Long nicId; + + @Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.UUID, entityType = UserVmResponse.class, required = true, + description="the ID of the vm") + private Long vmId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getEntityTable() { + return "nics"; + } + + public String getAccountName() { + return UserContext.current().getCaller().getAccountName(); + } + + public long getDomainId() { + return UserContext.current().getCaller().getDomainId(); + } + + public Long getNicId() { + return nicId; + } + + public Long getVmId() { + return vmId; + } + + @Override + public long getEntityOwnerId() { + Account caller = UserContext.current().getCaller(); + return caller.getAccountId(); + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + + @Override + public String getCommandName() { + return s_name; + } + + public static String getResultObjectName() { + return "addressinfo"; + } + + @Override + public void execute() throws ResourceUnavailableException, ResourceAllocationException, + ConcurrentOperationException, InsufficientCapacityException { + + try { + List results = _networkService.listNics(this); + ListResponse response = new ListResponse(); + List resList = new ArrayList(results.size()); + for (Nic r : results) { + NicResponse resp = _responseGenerator.createNicResponse(r); + resp.setObjectName("nic"); + resList.add(resp); + } + response.setResponses(resList); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + + } catch (Exception e) { + s_logger.warn("Failed to list secondary ip address per nic "); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); + } + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.IpAddress; + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java new file mode 100644 index 00000000000..cb5e0855f64 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java @@ -0,0 +1,123 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.vm; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.NicSecondaryIpResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "removeIpFromNic", description="Assigns secondary IP to NIC.", responseObject=SuccessResponse.class) +public class RemoveIpFromVmNicCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(RemoveIpFromVmNicCmd.class.getName()); + private static final String s_name = "unassignsecondaryipaddrtonicresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, required = true, entityType = NicSecondaryIpResponse.class, + description="the ID of the secondary ip address to nic") + private long id; + + // unexposed parameter needed for events logging + @Parameter(name=ApiConstants.ACCOUNT_ID, type=CommandType.UUID, expose=false) + private Long ownerId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getEntityTable() { + return "nic_secondary_ips"; + } + + public long getIpAddressId() { + return id; + } + + public String getAccountName() { + return UserContext.current().getCaller().getAccountName(); + } + + public long getDomainId() { + return UserContext.current().getCaller().getDomainId(); + } + + @Override + public long getEntityOwnerId() { + Account caller = UserContext.current().getCaller(); + return caller.getAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_NET_IP_ASSIGN; + } + + @Override + public String getEventDescription() { + return ("Disassociating ip address with id=" + id); + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public static String getResultObjectName() { + return "addressinfo"; + } + + @Override + public void execute() throws InvalidParameterValueException { + UserContext.current().setEventDetails("Ip Id: " + getIpAddressId()); + boolean result = _networkService.releaseSecondaryIpFromNic(getIpAddressId()); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to remove secondary ip address for the nic"); + } + } + + @Override + public String getSyncObjType() { + return BaseAsyncCmd.networkSyncObject; + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.IpAddress; + } + +} diff --git a/api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java b/api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java new file mode 100644 index 00000000000..9af20b23871 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java @@ -0,0 +1,85 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response; +import java.util.Date; +import java.util.List; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("unused") +public class AddIpToVmNicResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) @Param(description="the ID of the secondary private IP addr") + private Long id; + + @SerializedName(ApiConstants.IP_ADDRESS) @Param(description="Secondary IP address") + private String ipAddr; + + @SerializedName(ApiConstants.NIC_ID) @Param(description="the ID of the nic") + private Long nicId; + + @SerializedName(ApiConstants.NETWORK_ID) @Param(description="the ID of the network") + private Long nwId; + + @SerializedName(ApiConstants.VIRTUAL_MACHINE_ID) @Param(description="the ID of the vm") + private Long vmId; + + public Long getId() { + return id; + } + + public String getIpAddr() { + return ipAddr; + } + + public void setIpAddr(String ipAddr) { + this.ipAddr = ipAddr; + } + + public Long getNicId() { + return nicId; + } + + public void setNicId(Long nicId) { + this.nicId = nicId; + } + + public Long getNwId() { + return nwId; + } + + public void setNwId(Long nwId) { + this.nwId = nwId; + } + + public Long getVmId() { + return vmId; + } + + public void setVmId(Long vmId) { + this.vmId = vmId; + } + + public Long setId(Long id) { + return id; + } + + +} diff --git a/api/src/org/apache/cloudstack/api/response/IPAddressResponse.java b/api/src/org/apache/cloudstack/api/response/IPAddressResponse.java index 251b2dd09e8..cede84f931e 100644 --- a/api/src/org/apache/cloudstack/api/response/IPAddressResponse.java +++ b/api/src/org/apache/cloudstack/api/response/IPAddressResponse.java @@ -82,6 +82,10 @@ public class IPAddressResponse extends BaseResponse implements ControlledEntityR @SerializedName(ApiConstants.VIRTUAL_MACHINE_ID) @Param(description="virutal machine id the ip address is assigned to (not null only for static nat Ip)") private String virtualMachineId; + @SerializedName("vmipaddress") @Param(description="virutal machine (dnat) ip address (not null only for static nat Ip)") + private String virtualMachineIp; + + @SerializedName("virtualmachinename") @Param(description="virutal machine name the ip address is assigned to (not null only for static nat Ip)") private String virtualMachineName; @@ -185,6 +189,10 @@ public class IPAddressResponse extends BaseResponse implements ControlledEntityR this.virtualMachineId = virtualMachineId; } + public void setVirtualMachineIp(String virtualMachineIp) { + this.virtualMachineIp = virtualMachineIp; + } + public void setVirtualMachineName(String virtualMachineName) { this.virtualMachineName = virtualMachineName; } diff --git a/api/src/org/apache/cloudstack/api/response/NicResponse.java b/api/src/org/apache/cloudstack/api/response/NicResponse.java index a7d1a0d068e..a1ceaf63798 100644 --- a/api/src/org/apache/cloudstack/api/response/NicResponse.java +++ b/api/src/org/apache/cloudstack/api/response/NicResponse.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.response; +import java.util.List; + import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; @@ -75,7 +77,10 @@ public class NicResponse extends BaseResponse { @SerializedName(ApiConstants.IP6_ADDRESS) @Param(description="the IPv6 address of network") private String ip6Address; - + + @SerializedName("secondaryip") @Param(description="the Secondary ipv4 addr of nic") + private List secondaryIps; + public String getId() { return id; } @@ -167,4 +172,9 @@ public class NicResponse extends BaseResponse { return false; return true; } + + public void setSecondaryIps(List ipList) { + this.secondaryIps = ipList; + } + } diff --git a/api/src/org/apache/cloudstack/api/response/NicSecondaryIpResponse.java b/api/src/org/apache/cloudstack/api/response/NicSecondaryIpResponse.java new file mode 100644 index 00000000000..3464a63540e --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/NicSecondaryIpResponse.java @@ -0,0 +1,85 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response; +import java.util.Date; +import java.util.List; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("unused") +public class NicSecondaryIpResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) @Param(description="the ID of the secondary private IP addr") + private Long id; + + @SerializedName(ApiConstants.IP_ADDRESS) @Param(description="Secondary IP address") + private String ipAddr; + + @SerializedName(ApiConstants.NIC_ID) @Param(description="the ID of the nic") + private Long nicId; + + @SerializedName(ApiConstants.NETWORK_ID) @Param(description="the ID of the network") + private Long nwId; + + @SerializedName(ApiConstants.VIRTUAL_MACHINE_ID) @Param(description="the ID of the vm") + private Long vmId; + + public Long getId() { + return id; + } + + public String getIpAddr() { + return ipAddr; + } + + public void setIpAddr(String ipAddr) { + this.ipAddr = ipAddr; + } + + public Long getNicId() { + return nicId; + } + + public void setNicId(Long nicId) { + this.nicId = nicId; + } + + public Long getNwId() { + return nwId; + } + + public void setNwId(Long nwId) { + this.nwId = nwId; + } + + public Long getVmId() { + return vmId; + } + + public void setVmId(Long vmId) { + this.vmId = vmId; + } + + public Long setId(Long id) { + return id; + } + + +} diff --git a/api/test/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java b/api/test/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java new file mode 100644 index 00000000000..106589d10cc --- /dev/null +++ b/api/test/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java @@ -0,0 +1,132 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.test; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.cloudstack.api.ResponseGenerator; +import org.apache.cloudstack.api.command.user.vm.AddIpToVmNicCmd; +import org.apache.cloudstack.api.command.user.vm.RemoveIpFromVmNicCmd; +import org.apache.cloudstack.api.response.NicSecondaryIpResponse; +import org.apache.cloudstack.api.response.SuccessResponse; + + + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.NetworkService; +import com.cloud.user.Account; + +public class AddIpToVmNicTest extends TestCase { + + private AddIpToVmNicCmd addIpToVmNicCmd; + private RemoveIpFromVmNicCmd removeIpFromVmNicCmd; + private ResponseGenerator responseGenerator; + private SuccessResponse successResponseGenerator; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Before + public void setUp() { + addIpToVmNicCmd = new AddIpToVmNicCmd() { + }; + removeIpFromVmNicCmd = new RemoveIpFromVmNicCmd(); + } + + @Test + public void testCreateSuccess() throws ResourceAllocationException, ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException { + + NetworkService networkService = Mockito.mock(NetworkService.class); + AddIpToVmNicCmd ipTonicCmd = Mockito.mock(AddIpToVmNicCmd.class); + + Mockito.when( + networkService.allocateSecondaryGuestIP(Mockito.any(Account.class), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString())).thenReturn("10.1.1.2"); + + ipTonicCmd._networkService = networkService; + responseGenerator = Mockito.mock(ResponseGenerator.class); + + NicSecondaryIpResponse ipres = Mockito.mock(NicSecondaryIpResponse.class); + Mockito.when(responseGenerator.createSecondaryIPToNicResponse(Mockito.anyString(), Mockito.anyLong(), Mockito.anyLong())).thenReturn(ipres); + + ipTonicCmd._responseGenerator = responseGenerator; + ipTonicCmd.execute(); + } + + @Test + public void testCreateFailure() throws ResourceAllocationException, ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException { + + NetworkService networkService = Mockito.mock(NetworkService.class); + AddIpToVmNicCmd ipTonicCmd = Mockito.mock(AddIpToVmNicCmd.class); + + Mockito.when( + networkService.allocateSecondaryGuestIP(Mockito.any(Account.class), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString())).thenReturn(null); + + ipTonicCmd._networkService = networkService; + + try { + ipTonicCmd.execute(); + } catch (InsufficientAddressCapacityException e) { + throw new InvalidParameterValueException("Allocating guest ip for nic failed"); + } + } + + @Test + public void testRemoveIpFromVmNicSuccess() throws ResourceAllocationException, ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException { + + NetworkService networkService = Mockito.mock(NetworkService.class); + RemoveIpFromVmNicCmd removeIpFromNic = Mockito.mock(RemoveIpFromVmNicCmd.class); + + Mockito.when( + networkService.releaseSecondaryIpFromNic(Mockito.anyInt())).thenReturn(true); + + removeIpFromNic._networkService = networkService; + successResponseGenerator = Mockito.mock(SuccessResponse.class); + + removeIpFromNic.execute(); + } + + @Test + public void testRemoveIpFromVmNicFailure() throws InsufficientAddressCapacityException { + NetworkService networkService = Mockito.mock(NetworkService.class); + RemoveIpFromVmNicCmd removeIpFromNic = Mockito.mock(RemoveIpFromVmNicCmd.class); + + Mockito.when( + networkService.releaseSecondaryIpFromNic(Mockito.anyInt())).thenReturn(false); + + removeIpFromNic._networkService = networkService; + successResponseGenerator = Mockito.mock(SuccessResponse.class); + + try { + removeIpFromNic.execute(); + } catch (InvalidParameterValueException exception) { + Assert.assertEquals("Failed to remove secondary ip address for the nic", + exception.getLocalizedMessage()); + } + } +} diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index f03e8d50adb..bbb3d3078ec 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -326,6 +326,11 @@ addNicToVirtualMachine=15 removeNicFromVirtualMachine=15 updateDefaultNicForVirtualMachine=15 +#### +addIpToNic=15; +removeIpFromNic=15; +listNics=15; + #### SSH key pair commands registerSSHKeyPair=15 createSSHKeyPair=15 diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index ffee22fa1ae..95879ee0238 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -201,6 +201,7 @@ import com.cloud.vm.DomainRouterVO; import com.cloud.vm.InstanceGroup; import com.cloud.vm.InstanceGroupVO; import com.cloud.vm.NicProfile; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.UserVmDetailVO; import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmVO; @@ -209,6 +210,8 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VmStats; import com.cloud.vm.dao.ConsoleProxyDao; import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.NicSecondaryIpDao; +import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; @@ -319,6 +322,7 @@ public class ApiDBUtils { static HostDetailsDao _hostDetailsDao; static VMSnapshotDao _vmSnapshotDao; static ClusterDetailsDao _clusterDetailsDao; + static NicSecondaryIpDao _nicSecondaryIpDao; @Inject private ManagementServer ms; @Inject public AsyncJobManager asyncMgr; @@ -421,6 +425,7 @@ public class ApiDBUtils { @Inject private HostDetailsDao hostDetailsDao; @Inject private ClusterDetailsDao clusterDetailsDao; @Inject private VMSnapshotDao vmSnapshotDao; + @Inject private NicSecondaryIpDao nicSecondaryIpDao; @PostConstruct void init() { _ms = ms; @@ -521,6 +526,7 @@ public class ApiDBUtils { _hostDetailsDao = hostDetailsDao; _clusterDetailsDao = clusterDetailsDao; _vmSnapshotDao = vmSnapshotDao; + _nicSecondaryIpDao = nicSecondaryIpDao; // Note: stats collector should already have been initialized by this time, otherwise a null instance is returned _statsCollector = StatsCollector.getInstance(); } @@ -1519,4 +1525,8 @@ public class ApiDBUtils { public static Map findHostDetailsById(long hostId){ return _hostDetailsDao.findDetails(hostId); } + + public static List findNicSecondaryIps(long nicId) { + return _nicSecondaryIpDao.listByNicId(nicId); + } } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index eafee8a2a4a..fbfc9554111 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -19,6 +19,7 @@ package com.cloud.api; import com.cloud.api.query.ViewResponseHelper; import com.cloud.api.query.vo.*; import com.cloud.api.response.ApiResponseSerializer; + import org.apache.cloudstack.api.response.AsyncJobResponse; import org.apache.cloudstack.api.response.AutoScalePolicyResponse; import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse; @@ -52,6 +53,7 @@ import org.apache.cloudstack.api.response.LoadBalancerResponse; import org.apache.cloudstack.api.response.NetworkACLResponse; import org.apache.cloudstack.api.response.NetworkOfferingResponse; import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.api.response.NicResponse; import org.apache.cloudstack.api.response.PhysicalNetworkResponse; import org.apache.cloudstack.api.response.PodResponse; import org.apache.cloudstack.api.response.PrivateGatewayResponse; @@ -180,10 +182,14 @@ import com.cloud.utils.StringUtils; import com.cloud.utils.net.NetUtils; import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.InstanceGroup; +import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; +import com.cloud.vm.dao.NicSecondaryIpVO; + import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.api.ApiConstants.HostDetails; @@ -551,6 +557,9 @@ public class ApiResponseHelper implements ResponseGenerator { } } } + if (ipAddr.getVmIp() != null) { + ipResponse.setVirtualMachineIp(ipAddr.getVmIp()); + } if (ipAddr.getAssociatedWithNetworkId() != null) { Network ntwk = ApiDBUtils.findNetworkById(ipAddr.getAssociatedWithNetworkId()); @@ -3435,4 +3444,51 @@ public class ApiResponseHelper implements ResponseGenerator { response.setTimeout(tmDetails.get("timeout")); return response; } + + public NicSecondaryIpResponse createSecondaryIPToNicResponse(String ipAddr, Long nicId, Long networkId) { + NicSecondaryIpResponse response = new NicSecondaryIpResponse(); + response.setIpAddr(ipAddr); + response.setNicId(nicId); + response.setNwId(networkId); + response.setObjectName("nicsecondaryip"); + return response; + } + + public NicResponse createNicResponse(Nic result) { + NicResponse response = new NicResponse(); + response.setId(result.getUuid()); + response.setIpaddress(result.getIp4Address()); + + if (result.getSecondaryIp()) { + List secondaryIps = ApiDBUtils.findNicSecondaryIps(result.getId()); + if (secondaryIps != null) { + List ipList = new ArrayList(); + for (NicSecondaryIpVO ip: secondaryIps) { + NicSecondaryIpResponse ipRes = new NicSecondaryIpResponse(); + ipRes.setId(ip.getId()); + ipRes.setIpAddr(ip.getIp4Address()); + ipList.add(ipRes); + } + response.setSecondaryIps(ipList); + } + } + + response.setGateway(result.getGateway()); + response.setId(result.getUuid()); + response.setGateway(result.getGateway()); + response.setNetmask(result.getNetmask()); + response.setMacAddress(result.getMacAddress()); + if (result.getBroadcastUri() != null) { + response.setBroadcastUri(result.getBroadcastUri().toString()); + } + if (result.getIsolationUri() != null) { + response.setIsolationUri(result.getIsolationUri().toString()); + } + if (result.getIp6Address() != null) { + response.setId(result.getIp6Address()); + } + + response.setIsDefault(result.isDefaultNic()); + return response; + } } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 2904183911e..8b6bf9a7402 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -49,6 +49,7 @@ import com.cloud.user.User; import com.cloud.utils.Pair; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.ReservationContext; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; @@ -331,4 +332,15 @@ public interface NetworkManager { int getRuleCountForIp(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state); LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network); + + + boolean isSecondaryIpSetForNic(long nicId); + + public String allocateGuestIP(Account ipOwner, boolean isSystem, long zoneId, Long networkId, String requestedIp) + throws InsufficientAddressCapacityException; + + boolean removeVmSecondaryIps(long vmId); + + List listVmNics(Long vmId, Long nicId); + } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index f527b73d481..a575183a152 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -140,8 +140,19 @@ import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; import com.cloud.vm.*; +import com.cloud.vm.Nic; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicSecondaryIp; +import com.cloud.vm.NicVO; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.ReservationContextImpl; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.NicSecondaryIpDao; +import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; @@ -240,6 +251,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L UsageEventDao _usageEventDao; @Inject NetworkModel _networkModel; + @Inject + NicSecondaryIpDao _nicSecondaryIpDao; @Inject UserIpv6AddressDao _ipv6Dao; @Inject @@ -1750,6 +1763,14 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L guru.deallocate(network, profile, vm); _nicDao.remove(nic.getId()); s_logger.debug("Removed nic id=" + nic.getId()); + //remove the secondary ip addresses corresponding to to this nic + List secondaryIps = _nicSecondaryIpDao.listByNicId(nic.getId()); + if (secondaryIps != null) { + for (NicSecondaryIpVO ip : secondaryIps) { + _nicSecondaryIpDao.remove(ip.getId()); + } + s_logger.debug("Removed nic " + nic.getId() + " secondary ip addreses"); + } } @Override @@ -2792,6 +2813,33 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L Random _rand = new Random(System.currentTimeMillis()); + public List listVmNics(Long vmId, Long nicId) { + List result = null; + if (nicId == null) { + result = _nicDao.listByVmId(vmId); + } else { + result = _nicDao.listByVmIdAndNicId(vmId, nicId); + } + return result; + } + + public String allocateGuestIP(Account ipOwner, boolean isSystem, long zoneId, Long networkId, String requestedIp) + throws InsufficientAddressCapacityException { + String ipaddr = null; + Account caller = UserContext.current().getCaller(); + long callerUserId = UserContext.current().getCallerUserId(); + // check permissions + DataCenter zone = _configMgr.getZone(zoneId); + Network network = _networksDao.findById(networkId); + + _accountMgr.checkAccess(caller, null, false, network); + + //return acquireGuestIpAddress(network, requestedIp); + ipaddr = acquireGuestIpAddress(network, requestedIp); + return ipaddr; + } + + @Override @DB public String acquireGuestIpAddress(Network network, String requestedIp) { @@ -2802,7 +2850,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L Set availableIps = _networkModel.getAvailableIps(network, requestedIp); - if (availableIps.isEmpty()) { + if (availableIps == null || availableIps.isEmpty()) { return null; } @@ -3032,9 +3080,9 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L throw new InvalidParameterValueException("Source ip address of the rule id=" + firewallStaticNatRule.getId() + " is not static nat enabled"); } - String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), firewallStaticNatRule.getNetworkId()); + //String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), firewallStaticNatRule.getNetworkId()); ruleVO.setState(FirewallRule.State.Revoke); - staticNatRules.add(new StaticNatRuleImpl(ruleVO, dstIp)); + staticNatRules.add(new StaticNatRuleImpl(ruleVO, ip.getVmIp())); } try { @@ -3598,4 +3646,26 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } return rules.size(); } + + @Override + public boolean isSecondaryIpSetForNic(long nicId) { + NicVO nic = _nicDao.findById(nicId); + return nic.getSecondaryIp(); + } + + @Override + public boolean removeVmSecondaryIps(long vmId) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + List ipList = _nicSecondaryIpDao.listByVmId(vmId); + if (ipList != null) { + for (NicSecondaryIpVO ip: ipList) { + _nicSecondaryIpDao.remove(ip.getId()); + } + s_logger.debug("Revoving nic secondary ip entry ..."); + } + txn.commit(); + return true; + } + } diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index ac1bc874f9c..05258884db9 100644 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -109,6 +109,7 @@ import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.VMInstanceDao; @Component @@ -170,6 +171,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { PrivateIpDao _privateIpDao; @Inject UserIpv6AddressDao _ipv6Dao; + @Inject + NicSecondaryIpDao _nicSecondaryIpDao;; private final HashMap _systemNetworks = new HashMap(5); @@ -1624,6 +1627,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { public Set getAvailableIps(Network network, String requestedIp) { String[] cidr = network.getCidr().split("/"); List ips = _nicDao.listIpAddressInNetwork(network.getId()); + List secondaryIps = _nicSecondaryIpDao.listSecondaryIpAddressInNetwork(network.getId()); + ips.addAll(secondaryIps); Set allPossibleIps = NetUtils.getAllIpsFromCidr(cidr[0], Integer.parseInt(cidr[1])); Set usedIps = new TreeSet(); diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 1708224b47e..4c61aec284f 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -37,23 +37,28 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; +import org.bouncycastle.util.IPAddress; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenter; +import com.cloud.dc.Pod; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.VlanVO; import com.cloud.dc.dao.AccountVlanMapDao; import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.VlanDao; import com.cloud.deploy.DeployDestination; import com.cloud.domain.Domain; @@ -65,6 +70,8 @@ import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.*; +import com.cloud.host.Host; +import com.cloud.host.dao.HostDao; import com.cloud.network.IpAddress.State; import com.cloud.vm.Nic; import com.cloud.network.Network.Capability; @@ -82,7 +89,9 @@ import com.cloud.network.element.VirtualRouterElement; import com.cloud.network.element.VpcVirtualRouterElement; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.PortForwardingRuleVO; import com.cloud.network.rules.RulesManager; import com.cloud.network.vpc.PrivateIpVO; import com.cloud.network.vpc.VpcManager; @@ -112,6 +121,8 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.*; import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.NicSecondaryIpDao; +import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; import java.util.*; @@ -203,6 +214,16 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { @Inject NetworkModel _networkModel; + @Inject + NicSecondaryIpDao _nicSecondaryIpDao; + + @Inject + PortForwardingRulesDao _portForwardingDao; + @Inject + HostDao _hostDao; + @Inject + HostPodDao _hostPodDao; + int _cidrLimit; boolean _allowSubdomainNetworkAccess; @@ -449,6 +470,138 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } + public String allocateSecondaryGuestIP (Account ipOwner, long zoneId, Long nicId, Long networkId, String requestedIp) throws InsufficientAddressCapacityException { + + Long accountId = null; + Long domainId = null; + Long vmId = null; + String ipaddr = null; + + if (networkId == null) { + throw new InvalidParameterValueException("Invalid network id is given"); + } + + Network network = _networksDao.findById(networkId); + if (network == null) { + throw new InvalidParameterValueException("Invalid network id is given"); + } + accountId = network.getAccountId(); + domainId = network.getDomainId(); + + // verify permissions + _accountMgr.checkAccess(ipOwner, null, true, network); + + //check whether the nic belongs to user vm. + NicVO nicVO = _nicDao.findById(nicId); + if (nicVO == null) { + throw new InvalidParameterValueException("There is no nic for the " + nicId); + } + + if (nicVO.getVmType() != VirtualMachine.Type.User) { + throw new InvalidParameterValueException("The nic is not belongs to user vm"); + } + + DataCenter dc = _dcDao.findById(network.getDataCenterId()); + Long id = nicVO.getInstanceId(); + + DataCenter zone = _configMgr.getZone(zoneId); + if (zone == null) { + throw new InvalidParameterValueException("Invalid zone Id is given"); + } + + s_logger.debug("Calling the ip allocation ..."); + if (dc.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Isolated) { + try { + ipaddr = _networkMgr.allocateGuestIP(ipOwner, false, zoneId, networkId, requestedIp); + } catch (InsufficientAddressCapacityException e) { + throw new InvalidParameterValueException("Allocating guest ip for nic failed"); + } + } else { + throw new InvalidParameterValueException("AddIpToVMNic is not supported in this network..."); + } + + if (ipaddr != null) { + // we got the ip addr so up the nics table and secodary ip + Transaction txn = Transaction.currentTxn(); + txn.start(); + + boolean nicSecondaryIpSet = nicVO.getSecondaryIp(); + if (!nicSecondaryIpSet) { + nicVO.setSecondaryIp(true); + // commit when previously set ?? + s_logger.debug("Setting nics table ..."); + _nicDao.update(nicId, nicVO); + } + + s_logger.debug("Setting nic_secondary_ip table ..."); + vmId = nicVO.getInstanceId(); + NicSecondaryIpVO secondaryIpVO = new NicSecondaryIpVO(nicId, ipaddr, vmId, accountId, domainId, networkId); + _nicSecondaryIpDao.persist(secondaryIpVO); + txn.commit(); + } + return ipaddr; + } + + @DB + public boolean releaseSecondaryIpFromNic (long ipAddressId) { + Account caller = UserContext.current().getCaller(); + boolean success = false; + + // Verify input parameters + NicSecondaryIpVO ipVO= _nicSecondaryIpDao.findById(ipAddressId); + if (ipVO == null) { + throw new InvalidParameterValueException("Unable to find ip address by id"); + } + + Network network = _networksDao.findById(ipVO.getNetworkId()); + + // verify permissions + _accountMgr.checkAccess(caller, null, true, network); + + Long nicId = ipVO.getNicId(); + s_logger.debug("ip id and nic id" + ipAddressId + "..." + nicId); + //check is this the last secondary ip for NIC + List ipList = _nicSecondaryIpDao.listByNicId(nicId); + boolean lastIp = false; + if (ipList.size() == 1) { + // this is the last secondary ip to nic + lastIp = true; + } + //check PF or static NAT is configured on this ip address + String secondaryIp = ipVO.getIp4Address(); + List pfRuleList = _portForwardingDao.listByDestIpAddr(secondaryIp); + if (pfRuleList.size() != 0) { + s_logger.debug("VM nic IP " + secondaryIp + " is associated with the port forwarding rule"); + throw new InvalidParameterValueException("Can't remove the secondary ip " + secondaryIp + " is associate with the port forwarding rule"); + } + //check if the secondary ip associated with any static nat rule + IPAddressVO publicIpVO = _ipAddressDao.findByVmIp(secondaryIp); + if (publicIpVO != null) { + s_logger.debug("VM nic IP " + secondaryIp + " is associated with the static NAT rule public IP address id " + publicIpVO.getId()); + throw new InvalidParameterValueException("Can' remove the ip " + secondaryIp + "is associate with static NAT rule public IP address id " + publicIpVO.getId()); + } + success = removeNicSecondaryIP(ipVO, lastIp); + return success; + } + + boolean removeNicSecondaryIP(NicSecondaryIpVO ipVO, boolean lastIp) { + Transaction txn = Transaction.currentTxn(); + long nicId = ipVO.getNicId(); + NicVO nic = _nicDao.findById(nicId); + + txn.start(); + + if (lastIp) { + nic.setSecondaryIp(false); + s_logger.debug("Setting nics secondary ip to false ..."); + _nicDao.update(nicId, nic); + } + + s_logger.debug("Revoving nic secondary ip entry ..."); + _nicSecondaryIpDao.remove(ipVO.getId()); + txn.commit(); + return true; + } @Override @DB @@ -3025,4 +3178,21 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { public Network getNetwork(String networkUuid) { return _networksDao.findByUuid(networkUuid); } + + @Override + public List listNics(ListNicsCmd cmd) { + Account caller = UserContext.current().getCaller(); + Long nicId = cmd.getNicId(); + Long vmId = cmd.getVmId(); + + UserVmVO userVm = _userVmDao.findById(vmId); + + if (userVm == null) { + InvalidParameterValueException ex = new InvalidParameterValueException("Virtual mahine id does not exist"); + ex.addProxyObject(userVm, vmId, "vmId"); + throw ex; + } + _accountMgr.checkAccess(caller, null, true, userVm); + return _networkMgr.listVmNics(vmId, nicId); + } } diff --git a/server/src/com/cloud/network/addr/PublicIp.java b/server/src/com/cloud/network/addr/PublicIp.java index 61351a64050..8217e4e47b9 100644 --- a/server/src/com/cloud/network/addr/PublicIp.java +++ b/server/src/com/cloud/network/addr/PublicIp.java @@ -211,18 +211,28 @@ public class PublicIp implements PublicIpAddress { _addr.setVpcId(vpcId); } - @Override - public String getIp6Gateway() { - return _vlan.getIp6Gateway(); - } + @Override + public String getIp6Gateway() { + return _vlan.getIp6Gateway(); + } - @Override - public String getIp6Cidr() { - return _vlan.getIp6Cidr(); - } + @Override + public String getIp6Cidr() { + return _vlan.getIp6Cidr(); + } - @Override - public String getIp6Range() { - return _vlan.getIp6Range(); - } + @Override + public String getIp6Range() { + return _vlan.getIp6Range(); + } + + @Override + public String getVmIp() { + return _addr.getVmIp(); + } + + @Override + public void setVmIp(String vmIp) { + _addr.setVmIp(vmIp); + } } diff --git a/server/src/com/cloud/network/dao/IPAddressDao.java b/server/src/com/cloud/network/dao/IPAddressDao.java index 9cdb975d208..1052639ebf2 100755 --- a/server/src/com/cloud/network/dao/IPAddressDao.java +++ b/server/src/com/cloud/network/dao/IPAddressDao.java @@ -62,5 +62,8 @@ public interface IPAddressDao extends GenericDao { long countFreePublicIPs(); - long countFreeIPsInNetwork(long networkId); -} + long countFreeIPsInNetwork(long networkId); + IPAddressVO findByVmIp(String vmIp); + + IPAddressVO findByAssociatedVmIdAndVmIp(long vmId, String vmIp); +} diff --git a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java index e7067d98156..691e46047de 100755 --- a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java @@ -80,6 +80,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen AllFieldsSearch.and("sourcenetwork", AllFieldsSearch.entity().getSourceNetworkId(), Op.EQ); AllFieldsSearch.and("physicalNetworkId", AllFieldsSearch.entity().getPhysicalNetworkId(), Op.EQ); AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), Op.EQ); + AllFieldsSearch.and("associatedVmIp", AllFieldsSearch.entity().getVmIp(), Op.EQ); AllFieldsSearch.done(); VlanDbIdSearchUnallocated = createSearchBuilder(); @@ -232,6 +233,12 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen return findOneBy(sc); } + @Override + public IPAddressVO findByVmIp(String vmIp) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("associatedVmIp", vmIp); + return findOneBy(sc); + } @Override public int countIPs(long dcId, long vlanId, boolean onlyCountAllocated) { SearchCriteria sc = onlyCountAllocated ? AllocatedIpCount.create() : AllIpCount.create(); @@ -347,5 +354,13 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen boolean result = super.remove(id); txn.commit(); return result; - } + } + + @Override + public IPAddressVO findByAssociatedVmIdAndVmIp(long vmId, String vmIp) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("associatedWithVmId", vmId); + sc.setParameters("associatedVmIp", vmIp); + return findOneBy(sc); + } } diff --git a/server/src/com/cloud/network/dao/IPAddressVO.java b/server/src/com/cloud/network/dao/IPAddressVO.java index 00da5eb9a39..8ce8d3382b2 100644 --- a/server/src/com/cloud/network/dao/IPAddressVO.java +++ b/server/src/com/cloud/network/dao/IPAddressVO.java @@ -112,6 +112,10 @@ public class IPAddressVO implements IpAddress { @Column(name="vpc_id") private Long vpcId; + @Column(name="dnat_vmip") + private String vmIp; + + protected IPAddressVO() { this.uuid = UUID.randomUUID().toString(); } @@ -288,8 +292,18 @@ public class IPAddressVO implements IpAddress { return vpcId; } - @Override + @Override public void setVpcId(Long vpcId) { this.vpcId = vpcId; } + + @Override + public String getVmIp() { + return vmIp; + } + + @Override + public void setVmIp(String vmIp) { + this.vmIp = vmIp; + } } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 0e2eb63793c..b387ab5934c 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2318,8 +2318,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V if (_networkModel.isProviderSupportServiceInNetwork(guestNetworkId, Service.StaticNat, provider)) { if (ip.isOneToOneNat()) { - String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), guestNetworkId); - StaticNatImpl staticNat = new StaticNatImpl(ip.getAccountId(), ip.getDomainId(), guestNetworkId, ip.getId(), dstIp, false); + StaticNatImpl staticNat = new StaticNatImpl(ip.getAccountId(), ip.getDomainId(), guestNetworkId, ip.getId(), ip.getVmIp(), false); staticNats.add(staticNat); } } diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 614d30820b4..29ed5f36d5e 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -78,10 +78,13 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.Ip; import com.cloud.vm.Nic; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.UserVmVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.NicSecondaryIpDao; +import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; @Component @@ -123,6 +126,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules ResourceTagDao _resourceTagDao; @Inject VpcManager _vpcMgr; + @Inject + NicSecondaryIpDao _nicSecondaryDao; @Override public void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller) { @@ -172,7 +177,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules @Override @DB @ActionEvent(eventType = EventTypes.EVENT_NET_RULE_ADD, eventDescription = "creating forwarding rule", create = true) - public PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, boolean openFirewall) + public PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, Ip vmIp, boolean openFirewall) throws NetworkRuleConflictException { UserContext ctx = UserContext.current(); Account caller = ctx.getCaller(); @@ -192,6 +197,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules Network network = _networkModel.getNetwork(networkId); //associate ip address to network (if needed) boolean performedIpAssoc = false; + Nic guestNic; if (ipAddress.getAssociatedWithNetworkId() == null) { boolean assignToVpcNtwk = network.getVpcId() != null && ipAddress.getVpcId() != null && ipAddress.getVpcId().longValue() == network.getVpcId(); @@ -244,13 +250,26 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules // Verify that vm has nic in the network Ip dstIp = rule.getDestinationIpAddress(); - Nic guestNic = _networkModel.getNicInNetwork(vmId, networkId); + guestNic = _networkModel.getNicInNetwork(vmId, networkId); if (guestNic == null || guestNic.getIp4Address() == null) { throw new InvalidParameterValueException("Vm doesn't belong to network associated with ipAddress"); } else { dstIp = new Ip(guestNic.getIp4Address()); } + if (vmIp != null) { + //vm ip is passed so it can be primary or secondary ip addreess. + if (!dstIp.equals(vmIp)) { + //the vm ip is secondary ip to the nic. + // is vmIp is secondary ip or not + NicSecondaryIp secondaryIp = _nicSecondaryDao.findByIp4AddressAndNicId(vmIp.toString(), guestNic.getId()); + if (secondaryIp == null) { + throw new InvalidParameterValueException("IP Address is not in the VM nic's network "); + } + dstIp = vmIp; + } + } + //if start port and end port are passed in, and they are not equal to each other, perform the validation boolean validatePortRange = false; if (rule.getSourcePortStart().intValue() != rule.getSourcePortEnd().intValue() @@ -350,8 +369,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules throw new InvalidParameterValueException("Can't create ip forwarding rules for the network where elasticIP service is enabled"); } - String dstIp = _networkModel.getIpInNetwork(ipAddress.getAssociatedWithVmId(), networkId); - + //String dstIp = _networkModel.getIpInNetwork(ipAddress.getAssociatedWithVmId(), networkId); + String dstIp = ipAddress.getVmIp(); Transaction txn = Transaction.currentTxn(); txn.start(); @@ -397,14 +416,13 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules @Override @ActionEvent(eventType = EventTypes.EVENT_ENABLE_STATIC_NAT, eventDescription = "enabling static nat") - public boolean enableStaticNat(long ipId, long vmId, long networkId, boolean isSystemVm) + public boolean enableStaticNat(long ipId, long vmId, long networkId, boolean isSystemVm, String vmGuestIp) throws NetworkRuleConflictException, ResourceUnavailableException { UserContext ctx = UserContext.current(); Account caller = ctx.getCaller(); UserContext.current().setEventDetails("Ip Id: " + ipId); // Verify input parameters - IPAddressVO ipAddress = _ipAddressDao.findById(ipId); if (ipAddress == null) { throw new InvalidParameterValueException("Unable to find ip address by id " + ipId); @@ -414,6 +432,10 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules boolean performedIpAssoc = false; boolean isOneToOneNat = ipAddress.isOneToOneNat(); Long associatedWithVmId = ipAddress.getAssociatedWithVmId(); + Nic guestNic; + NicSecondaryIpVO nicSecIp = null; + String dstIp = null; + try { Network network = _networkModel.getNetwork(networkId); if (network == null) { @@ -421,11 +443,11 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules } // Check that vm has a nic in the network - Nic guestNic = _networkModel.getNicInNetwork(vmId, networkId); + guestNic = _networkModel.getNicInNetwork(vmId, networkId); if (guestNic == null) { throw new InvalidParameterValueException("Vm doesn't belong to the network with specified id"); } - + dstIp = guestNic.getIp4Address(); if (!_networkModel.areServicesSupportedInNetwork(network.getId(), Service.StaticNat)) { throw new InvalidParameterValueException("Unable to create static nat rule; StaticNat service is not " + @@ -466,13 +488,36 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules // Check permissions checkIpAndUserVm(ipAddress, vm, caller); + //is static nat is for vm secondary ip + //dstIp = guestNic.getIp4Address(); + if (vmGuestIp != null) { + //dstIp = guestNic.getIp4Address(); + + if (!dstIp.equals(vmGuestIp)) { + //check whether the secondary ip set to the vm or not + boolean secondaryIpSet = _networkMgr.isSecondaryIpSetForNic(guestNic.getId()); + if (!secondaryIpSet) { + throw new InvalidParameterValueException("VM ip " + vmGuestIp + " address not belongs to the vm"); + } + //check the ip belongs to the vm or not + nicSecIp = _nicSecondaryDao.findByIp4AddressAndNicId(vmGuestIp, guestNic.getId()); + if (nicSecIp == null) { + throw new InvalidParameterValueException("VM ip " + vmGuestIp + " address not belongs to the vm"); + } + dstIp = nicSecIp.getIp4Address(); + // Set public ip column with the vm ip + } + } + // Verify ip address parameter - isIpReadyForStaticNat(vmId, ipAddress, caller, ctx.getCallerUserId()); + // checking vm id is not sufficient, check for the vm ip + isIpReadyForStaticNat(vmId, ipAddress, dstIp, caller, ctx.getCallerUserId()); } ipAddress.setOneToOneNat(true); ipAddress.setAssociatedWithVmId(vmId); + ipAddress.setVmIp(dstIp); if (_ipAddressDao.update(ipAddress.getId(), ipAddress)) { // enable static nat on the backend s_logger.trace("Enabling static nat for ip address " + ipAddress + " and vm id=" + vmId + " on the backend"); @@ -483,6 +528,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules s_logger.warn("Failed to enable static nat rule for ip address " + ipId + " on the backend"); ipAddress.setOneToOneNat(isOneToOneNat); ipAddress.setAssociatedWithVmId(associatedWithVmId); + ipAddress.setVmIp(null); _ipAddressDao.update(ipAddress.getId(), ipAddress); } } else { @@ -490,16 +536,17 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules } } finally { - if (performedIpAssoc) { - //if the rule is the last one for the ip address assigned to VPC, unassign it from the network - IpAddress ip = _ipAddressDao.findById(ipAddress.getId()); - _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), networkId); + if (performedIpAssoc) { + //if the rule is the last one for the ip address assigned to VPC, unassign it from the network + IpAddress ip = _ipAddressDao.findById(ipAddress.getId()); + _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), networkId); } } return false; } - protected void isIpReadyForStaticNat(long vmId, IPAddressVO ipAddress, Account caller, long callerUserId) + protected void isIpReadyForStaticNat(long vmId, IPAddressVO ipAddress, + String vmIp, Account caller, long callerUserId) throws NetworkRuleConflictException, ResourceUnavailableException { if (ipAddress.isSourceNat()) { throw new InvalidParameterValueException("Can't enable static, ip address " + ipAddress + " is a sourceNat ip address"); @@ -519,7 +566,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules throw new NetworkRuleConflictException("Failed to enable static for the ip address " + ipAddress + " and vm id=" + vmId + " as it's already assigned to antoher vm"); } - IPAddressVO oldIP = _ipAddressDao.findByAssociatedVmId(vmId); + //check wether the vm ip is alreday associated with any public ip address + IPAddressVO oldIP = _ipAddressDao.findByAssociatedVmIdAndVmIp(vmId, vmIp); if (oldIP != null) { // If elasticIP functionality is supported in the network, we always have to disable static nat on the old @@ -538,9 +586,9 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules if (!reassignStaticNat) { throw new InvalidParameterValueException("Failed to enable static nat for the ip address id=" + ipAddress.getId() + " as vm id=" + vmId + " is already associated with ip id=" + oldIP.getId()); } - // unassign old static nat rule - s_logger.debug("Disassociating static nat for ip " + oldIP); - if (!disableStaticNat(oldIP.getId(), caller, callerUserId, true)) { + // unassign old static nat rule + s_logger.debug("Disassociating static nat for ip " + oldIP); + if (!disableStaticNat(oldIP.getId(), caller, callerUserId, true)) { throw new CloudRuntimeException("Failed to disable old static nat rule for vm id=" + vmId + " and ip " + oldIP); } } @@ -890,8 +938,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules List staticNats = new ArrayList(); for (IPAddressVO ip : ips) { // Get nic IP4 address - String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), networkId); - StaticNatImpl staticNat = new StaticNatImpl(ip.getAllocatedToAccountId(), ip.getAllocatedInDomainId(), networkId, ip.getId(), dstIp, false); + //String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), networkId); + StaticNatImpl staticNat = new StaticNatImpl(ip.getAllocatedToAccountId(), ip.getAllocatedInDomainId(), networkId, ip.getId(), ip.getVmIp(), false); staticNats.add(staticNat); } @@ -1209,6 +1257,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules boolean isIpSystem = ipAddress.getSystem(); ipAddress.setOneToOneNat(false); ipAddress.setAssociatedWithVmId(null); + ipAddress.setVmIp(null); if (isIpSystem && !releaseIpIfElastic) { ipAddress.setSystem(false); } @@ -1248,11 +1297,11 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules throw ex; } - String dstIp; - if (forRevoke) { - dstIp = _networkModel.getIpInNetworkIncludingRemoved(ip.getAssociatedWithVmId(), rule.getNetworkId()); - } else { - dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), rule.getNetworkId()); + String dstIp = ip.getVmIp(); + if (dstIp == null) { + InvalidParameterValueException ex = new InvalidParameterValueException("VM ip address of the specified public ip is not set "); + ex.addProxyObject(ruleVO, rule.getId(), "ruleId"); + throw ex; } return new StaticNatRuleImpl(ruleVO, dstIp); @@ -1333,12 +1382,16 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules // create new static nat rule // Get nic IP4 address + Nic guestNic = _networkModel.getNicInNetwork(vm.getId(), networkId); + if (guestNic == null) { + throw new InvalidParameterValueException("Vm doesn't belong to the network with specified id"); + } String dstIp; - if (forRevoke) { - dstIp = _networkModel.getIpInNetworkIncludingRemoved(sourceIp.getAssociatedWithVmId(), networkId); - } else { - dstIp = _networkModel.getIpInNetwork(sourceIp.getAssociatedWithVmId(), networkId); + + dstIp = sourceIp.getVmIp(); + if (dstIp == null) { + throw new InvalidParameterValueException("Vm ip is not set as dnat ip for this public ip"); } StaticNatImpl staticNat = new StaticNatImpl(sourceIp.getAllocatedToAccountId(), sourceIp.getAllocatedInDomainId(), @@ -1373,7 +1426,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules boolean isSystemVM = (vm.getType() == Type.ConsoleProxy || vm.getType() == Type.SecondaryStorageVm); try { - success = enableStaticNat(ip.getId(), vm.getId(), guestNetwork.getId(), isSystemVM); + success = enableStaticNat(ip.getId(), vm.getId(), guestNetwork.getId(), isSystemVM, null); } catch (NetworkRuleConflictException ex) { s_logger.warn("Failed to enable static nat as a part of enabling elasticIp and staticNat for vm " + vm + " in guest network " + guestNetwork + " due to exception ", ex); diff --git a/server/src/com/cloud/network/rules/dao/PortForwardingRulesDao.java b/server/src/com/cloud/network/rules/dao/PortForwardingRulesDao.java index 91f08e7a8ff..682a941856c 100644 --- a/server/src/com/cloud/network/rules/dao/PortForwardingRulesDao.java +++ b/server/src/com/cloud/network/rules/dao/PortForwardingRulesDao.java @@ -41,5 +41,7 @@ public interface PortForwardingRulesDao extends GenericDao listByNetwork(long networkId); List listByAccount(long accountId); + + List listByDestIpAddr(String ip4Address); } diff --git a/server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java b/server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java index 5406ab624e0..1d2e991ab39 100644 --- a/server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java +++ b/server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java @@ -32,6 +32,7 @@ import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.vm.dao.NicSecondaryIpVO; @Component @Local(value=PortForwardingRulesDao.class) @@ -55,6 +56,7 @@ public class PortForwardingRulesDaoImpl extends GenericDaoBase listByDestIpAddr(String ip4Address) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("address", ip4Address); + return listBy(sc); + } } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index e80d48c6512..95b2973a384 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -2165,6 +2165,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(CreateVMSnapshotCmd.class); cmdList.add(RevertToSnapshotCmd.class); cmdList.add(DeleteVMSnapshotCmd.class); + cmdList.add(AddIpToVmNicCmd.class); + cmdList.add(RemoveIpFromVmNicCmd.class); + cmdList.add(ListNicsCmd.class); return cmdList; } diff --git a/server/src/com/cloud/vm/NicVO.java b/server/src/com/cloud/vm/NicVO.java index 8e2edda40aa..987596cff32 100644 --- a/server/src/com/cloud/vm/NicVO.java +++ b/server/src/com/cloud/vm/NicVO.java @@ -122,6 +122,9 @@ public class NicVO implements Nic { @Column(name = "uuid") String uuid = UUID.randomUUID().toString(); + @Column(name = "secondary_ip") + boolean secondaryIp; + public NicVO(String reserver, Long instanceId, long configurationId, VirtualMachine.Type vmType) { this.reserver = reserver; this.instanceId = instanceId; @@ -349,4 +352,12 @@ public class NicVO implements Nic { public void setIp6Cidr(String ip6Cidr) { this.ip6Cidr = ip6Cidr; } + + public boolean getSecondaryIp() { + return secondaryIp; + } + + public void setSecondaryIp(boolean secondaryIp) { + this.secondaryIp = secondaryIp; + } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index ce53c4579fd..ca9c13fd1c4 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -360,6 +360,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use protected ProjectManager _projectMgr; @Inject protected ResourceManager _resourceMgr; + @Inject protected NetworkServiceMapDao _ntwkSrvcDao; @Inject @@ -1359,6 +1360,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use + " as a part of vm id=" + vmId + " expunge because resource is unavailable", e); } + //remove vm secondary ip addresses + if (_networkMgr.removeVmSecondaryIps(vmId)) { + s_logger.debug("Removed vm " + vmId + " secondary ip address of the VM Nics as a part of expunge process"); + } else { + success = false; + s_logger.warn("Fail to remove secondary ip address of vm " + vmId + " Nics as a part of expunge process"); + } return success; } diff --git a/server/src/com/cloud/vm/dao/NicDao.java b/server/src/com/cloud/vm/dao/NicDao.java index 762048b65bf..794bacc6e8b 100644 --- a/server/src/com/cloud/vm/dao/NicDao.java +++ b/server/src/com/cloud/vm/dao/NicDao.java @@ -58,4 +58,6 @@ public interface NicDao extends GenericDao { NicVO findByNetworkIdInstanceIdAndBroadcastUri(long networkId, long instanceId, String broadcastUri); NicVO findByIp4AddressAndNetworkIdAndInstanceId(long networkId, long instanceId, String ip4Address); + + List listByVmIdAndNicId(Long vmId, Long nicId); } diff --git a/server/src/com/cloud/vm/dao/NicDaoImpl.java b/server/src/com/cloud/vm/dao/NicDaoImpl.java index 5cf152f9f90..44911740e96 100644 --- a/server/src/com/cloud/vm/dao/NicDaoImpl.java +++ b/server/src/com/cloud/vm/dao/NicDaoImpl.java @@ -53,8 +53,10 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { AllFieldsSearch.and("address", AllFieldsSearch.entity().getIp4Address(), Op.EQ); AllFieldsSearch.and("isDefault", AllFieldsSearch.entity().isDefaultNic(), Op.EQ); AllFieldsSearch.and("broadcastUri", AllFieldsSearch.entity().getBroadcastUri(), Op.EQ); + AllFieldsSearch.and("secondaryip", AllFieldsSearch.entity().getSecondaryIp(), Op.EQ); + AllFieldsSearch.and("nicid", AllFieldsSearch.entity().getId(), Op.EQ); AllFieldsSearch.done(); - + IpSearch = createSearchBuilder(String.class); IpSearch.select(null, Func.DISTINCT, IpSearch.entity().getIp4Address()); IpSearch.and("network", IpSearch.entity().getNetworkId(), Op.EQ); @@ -202,4 +204,12 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { sc.setParameters("address", ip4Address); return findOneBy(sc); } + + @Override + public List listByVmIdAndNicId(Long vmId, Long nicId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("instance", vmId); + sc.setParameters("nicid", nicId); + return listBy(sc); + } } diff --git a/server/src/com/cloud/vm/dao/NicSecondaryIpDao.java b/server/src/com/cloud/vm/dao/NicSecondaryIpDao.java new file mode 100644 index 00000000000..da96df43e83 --- /dev/null +++ b/server/src/com/cloud/vm/dao/NicSecondaryIpDao.java @@ -0,0 +1,53 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.vm.dao; + +import java.util.List; +import com.cloud.utils.db.GenericDao; + +public interface NicSecondaryIpDao extends GenericDao { + List listByVmId(long instanceId); + + List listSecondaryIpAddressInNetwork(long networkConfigId); + List listByNetworkId(long networkId); + + NicSecondaryIpVO findByInstanceIdAndNetworkId(long networkId, long instanceId); + + // void removeNicsForInstance(long instanceId); + // void removeSecondaryIpForNic(long nicId); + + NicSecondaryIpVO findByIp4AddressAndNetworkId(String ip4Address, long networkId); + + /** + * @param networkId + * @param instanceId + * @return + */ + + List getSecondaryIpAddressesForVm(long vmId); + + List listByNicId(long nicId); + + List listByNicIdAndVmid(long nicId, long vmId); + + NicSecondaryIpVO findByIp4AddressAndNicId(String ip4Address, long nicId); + + NicSecondaryIpVO findByIp4AddressAndNetworkIdAndInstanceId(long networkId, + Long vmId, String vmIp); + + List getSecondaryIpAddressesForNic(long nicId); +} diff --git a/server/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java b/server/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java new file mode 100644 index 00000000000..3befaf70529 --- /dev/null +++ b/server/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java @@ -0,0 +1,138 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.vm.dao; + +import java.util.ArrayList; +import java.util.List; + +import javax.ejb.Local; + +import org.springframework.stereotype.Component; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Func; +import com.cloud.utils.db.SearchCriteria.Op; + +@Component +@Local(value=NicSecondaryIpDao.class) +public class NicSecondaryIpDaoImpl extends GenericDaoBase implements NicSecondaryIpDao { + private final SearchBuilder AllFieldsSearch; + private final GenericSearchBuilder IpSearch; + + protected NicSecondaryIpDaoImpl() { + super(); + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("instanceId", AllFieldsSearch.entity().getVmId(), Op.EQ); + AllFieldsSearch.and("network", AllFieldsSearch.entity().getNetworkId(), Op.EQ); + AllFieldsSearch.and("address", AllFieldsSearch.entity().getIp4Address(), Op.EQ); + AllFieldsSearch.and("nicId", AllFieldsSearch.entity().getNicId(), Op.EQ); + AllFieldsSearch.done(); + + IpSearch = createSearchBuilder(String.class); + IpSearch.select(null, Func.DISTINCT, IpSearch.entity().getIp4Address()); + IpSearch.and("network", IpSearch.entity().getNetworkId(), Op.EQ); + IpSearch.and("address", IpSearch.entity().getIp4Address(), Op.NNULL); + IpSearch.done(); + } + + @Override + public List listByVmId(long instanceId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("instanceId", instanceId); + return listBy(sc); + } + + @Override + public List listByNicId(long nicId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("nicId", nicId); + return listBy(sc); + } + + @Override + public List listSecondaryIpAddressInNetwork(long networkId) { + SearchCriteria sc = IpSearch.create(); + sc.setParameters("network", networkId); + return customSearch(sc, null); + } + + @Override + public List listByNetworkId(long networkId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("network", networkId); + return listBy(sc); + } + + @Override + public List listByNicIdAndVmid(long nicId, long vmId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("nicId", nicId); + sc.setParameters("instanceId", vmId); + return listBy(sc); + } + + @Override + public List getSecondaryIpAddressesForVm(long vmId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("instanceId", vmId); + return listBy(sc); + } + + @Override + public List getSecondaryIpAddressesForNic(long nicId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("nicId", nicId); + List results = search(sc, null); + List ips = new ArrayList(results.size()); + for (NicSecondaryIpVO result : results) { + ips.add(result.getIp4Address()); + } + return ips; + } + + @Override + public NicSecondaryIpVO findByInstanceIdAndNetworkId(long networkId, long instanceId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public NicSecondaryIpVO findByIp4AddressAndNetworkId(String ip4Address, long networkId) { + // TODO Auto-generated method stub + return null; + } + @Override + public NicSecondaryIpVO findByIp4AddressAndNicId(String ip4Address, long nicId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("address", ip4Address); + sc.setParameters("nicId", nicId); + return findOneBy(sc); + } + + @Override + public NicSecondaryIpVO findByIp4AddressAndNetworkIdAndInstanceId( + long networkId, Long vmId, String vmIp) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("network", networkId); + sc.setParameters("instanceId", vmId); + sc.setParameters("address", vmIp); + return findOneBy(sc); + } +} diff --git a/server/src/com/cloud/vm/dao/NicSecondaryIpVO.java b/server/src/com/cloud/vm/dao/NicSecondaryIpVO.java new file mode 100644 index 00000000000..770e188ad83 --- /dev/null +++ b/server/src/com/cloud/vm/dao/NicSecondaryIpVO.java @@ -0,0 +1,160 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.vm.dao; + +import java.util.Date; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import com.cloud.utils.db.GenericDao; +import com.cloud.vm.NicSecondaryIp; + +@Entity +@Table(name = "nic_secondary_ips") +public class NicSecondaryIpVO implements NicSecondaryIp { + + public NicSecondaryIpVO(Long nicId, String ipaddr, Long vmId, + Long accountId, Long domainId, Long networkId) { + this.nicId = nicId; + this.vmId = vmId; + this.ip4Address = ipaddr; + this.accountId = accountId; + this.domainId = domainId; + this.networkId = networkId; + } + + protected NicSecondaryIpVO() { + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + long id; + + @Column(name = "nicId") + long nicId; + + @Column(name="domain_id", updatable=false) + long domainId; + + @Column(name="account_id", updatable=false) + private Long accountId; + + @Column(name = "ip4_address") + String ip4Address; + + @Column(name = "ip6_address") + String ip6Address; + + @Column(name = "network_id") + long networkId; + + @Column(name = GenericDao.CREATED_COLUMN) + Date created; + + @Column(name = "uuid") + String uuid = UUID.randomUUID().toString(); + + @Column(name = "vmId") + Long vmId; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public long getNicId() { + return nicId; + } + + public void setNicId(long nicId) { + this.nicId = nicId; + } + + public long getDomainId() { + return domainId; + } + + public void setDomainId(Long domainId) { + this.domainId = domainId; + } + + public long getAccountId() { + return accountId; + } + + public void setAccountId(Long accountId) { + this.accountId = accountId; + } + + public String getIp4Address() { + return ip4Address; + } + + public void setIp4Address(String ip4Address) { + this.ip4Address = ip4Address; + } + + public String getIp6Address() { + return ip6Address; + } + + public void setIp6Address(String ip6Address) { + this.ip6Address = ip6Address; + } + + public long getNetworkId() { + return networkId; + } + + public void setNetworkId(long networkId) { + this.networkId = networkId; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public long getVmId() { + return vmId; + } + + public void setVmId(Long vmId) { + this.vmId = vmId; + } +} diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index 3568da57b71..80043102648 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -29,6 +29,7 @@ import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; import org.springframework.stereotype.Component; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; import com.cloud.dc.DataCenter; import com.cloud.dc.Vlan.VlanType; @@ -64,6 +65,7 @@ import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.ReservationContext; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; @@ -824,4 +826,49 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage // TODO Auto-generated method stub return null; } + + @Override + public boolean isSecondaryIpSetForNic(long nicId) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean releaseSecondaryIpFromNic(long ipAddressId) { + // TODO Auto-generated method stub + return false; + } + + @Override + public String allocateSecondaryGuestIP(Account account, long zoneId, + Long nicId, Long networkId, String ipaddress) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String allocateGuestIP(Account ipOwner, boolean isSystem, + long zoneId, Long networkId, String requestedIp) + throws InsufficientAddressCapacityException { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean removeVmSecondaryIps(long vmId) { + // TODO Auto-generated method stub + return false; + } + + @Override + public List listVmNics(Long vmId, Long nicId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List listNics(ListNicsCmd listNicsCmd) { + // TODO Auto-generated method stub + return null; + } } diff --git a/server/test/com/cloud/network/MockRulesManagerImpl.java b/server/test/com/cloud/network/MockRulesManagerImpl.java index ba3dd413cc3..e5a6894d76d 100644 --- a/server/test/com/cloud/network/MockRulesManagerImpl.java +++ b/server/test/com/cloud/network/MockRulesManagerImpl.java @@ -39,6 +39,7 @@ import com.cloud.uservm.UserVm; import com.cloud.utils.Pair; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.net.Ip; import com.cloud.vm.VirtualMachine; @Local(value = {RulesManager.class, RulesService.class}) @@ -53,14 +54,6 @@ public class MockRulesManagerImpl extends ManagerBase implements RulesManager, R return null; } - @Override - public PortForwardingRule createPortForwardingRule(PortForwardingRule rule, - Long vmId, boolean openFirewall) - throws NetworkRuleConflictException { - // TODO Auto-generated method stub - return null; - } - @Override public boolean revokePortForwardingRule(long ruleId, boolean apply) { // TODO Auto-generated method stub @@ -83,7 +76,7 @@ public class MockRulesManagerImpl extends ManagerBase implements RulesManager, R @Override public boolean enableStaticNat(long ipAddressId, long vmId, long networkId, - boolean isSystemVm) throws NetworkRuleConflictException, + boolean isSystemVm, String ipAddr) throws NetworkRuleConflictException, ResourceUnavailableException { // TODO Auto-generated method stub return false; @@ -310,4 +303,12 @@ public class MockRulesManagerImpl extends ManagerBase implements RulesManager, R return "MockRulesManagerImpl"; } + @Override + public PortForwardingRule createPortForwardingRule(PortForwardingRule rule, + Long vmId, Ip vmIp, boolean openFirewall) + throws NetworkRuleConflictException { + // TODO Auto-generated method stub + return null; + } + } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index 828a555a539..63ef8744be8 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -29,6 +29,7 @@ import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementors import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -80,6 +81,7 @@ import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.ReservationContext; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; @@ -1317,4 +1319,75 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage // TODO Auto-generated method stub return null; } + + + + + + @Override + public boolean isSecondaryIpSetForNic(long nicId) { + // TODO Auto-generated method stub + return false; + } + + @Override + public String allocateSecondaryGuestIP(Account account, long zoneId, + Long nicId, Long networkId, String ipaddress) { + // TODO Auto-generated method stub + return null; + } + + + + + + + + @Override + public boolean releaseSecondaryIpFromNic(long ipAddressId) { + // TODO Auto-generated method stub + return false; + } + + + + + + @Override + public String allocateGuestIP(Account ipOwner, boolean isSystem, + long zoneId, Long networkId, String requestedIp) + throws InsufficientAddressCapacityException { + // TODO Auto-generated method stub + return null; + } + + + + + + @Override + public boolean removeVmSecondaryIps(long vmId) { + // TODO Auto-generated method stub + return false; + } + + + + + + @Override + public List listVmNics(Long vmId, Long nicId) { + // TODO Auto-generated method stub + return null; + } + + + + + + @Override + public List listNics(ListNicsCmd listNicsCmd) { + // TODO Auto-generated method stub + return null; + } } diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 4349bd08fc8..6f68e120ac1 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -112,3 +112,24 @@ INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'UserV -- Re-enable foreign key checking, at the end of the upgrade path SET foreign_key_checks = 1; + + +CREATE TABLE nic_secondary_ips ( + `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, + `uuid` varchar(40), + `vmId` bigint unsigned COMMENT 'vm instance id', + `nicId` bigint unsigned NOT NULL, + `ip4_address` char(40) COMMENT 'ip4 address', + `ip6_address` char(40) COMMENT 'ip6 address', + `network_id` bigint unsigned NOT NULL COMMENT 'network configuration id', + `created` datetime NOT NULL COMMENT 'date created', + `account_id` bigint unsigned NOT NULL COMMENT 'owner. foreign key to account table', + `domain_id` bigint unsigned NOT NULL COMMENT 'the domain that the owner belongs to', + PRIMARY KEY (`id`), + CONSTRAINT `fk_nic_secondary_ip__vmId` FOREIGN KEY `fk_nic_secondary_ip__vmId`(`vmId`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_nic_secondary_ip__networks_id` FOREIGN KEY `fk_nic_secondary_ip__networks_id`(`network_id`) REFERENCES `networks`(`id`), + CONSTRAINT `uc_nic_secondary_ip__uuid` UNIQUE (`uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `cloud`.`nics` ADD COLUMN secondary_ip SMALLINT DEFAULT '0' COMMENT 'secondary ips configured for the nic'; +ALTER TABLE `cloud`.`user_ip_address` ADD COLUMN dnat_vmip VARCHAR(40); From fc64ee57a37d9861f10c40cfac45d195d4026ddd Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Mon, 4 Mar 2013 14:39:22 +0530 Subject: [PATCH 11/21] dvswitch UI minor enhancements --- ui/scripts/system.js | 17 +++++------------ ui/scripts/zoneWizard.js | 16 ++++++---------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/ui/scripts/system.js b/ui/scripts/system.js index d1bd9c5e10b..ac8fe3d8870 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -7598,7 +7598,6 @@ if(vSwitchEnabled) { items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); - items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); @@ -7609,10 +7608,8 @@ // items.push({id: "" , description:" " }); else{ - items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); - - + items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); } @@ -7662,21 +7659,17 @@ if(vSwitchEnabled){ - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); - + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); - } else{ - - items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); - items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); - - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); + items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); + items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); } diff --git a/ui/scripts/zoneWizard.js b/ui/scripts/zoneWizard.js index d8684fb8e28..47932664927 100755 --- a/ui/scripts/zoneWizard.js +++ b/ui/scripts/zoneWizard.js @@ -909,10 +909,8 @@ // items.push({id: " ", description: " "}); else{ + items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); - items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); - - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); } @@ -923,7 +921,7 @@ }, vSwitchPublicName:{ - label:'vSwitch Public Traffic Name', + label:'Public Traffic vSwitch Name', dependsOn:'overridepublictraffic', isHidden:true @@ -961,8 +959,7 @@ if(vSwitchEnabled) { - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); - + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); @@ -972,10 +969,9 @@ } else{ - items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); - - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); + items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); } args.response.success({data: items}); @@ -986,7 +982,7 @@ }, vSwitchGuestName:{ - label:'vSwitch Guest Traffic Name', + label:'Guest Traffic vSwitch Name', dependsOn:'overrideguesttraffic', isHidden:true From e0019eccd997d9b2b3ff9395bcd99f821f5121db Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Mon, 4 Mar 2013 14:47:55 +0530 Subject: [PATCH 12/21] CLOUDSTACK-658 - Adding Scalevm command and XS related changes --- api/src/com/cloud/event/EventTypes.java | 1 + api/src/com/cloud/vm/UserVmService.java | 16 +- api/src/com/cloud/vm/VirtualMachine.java | 11 +- .../api/command/user/vm/ScaleVMCmd.java | 109 +++++++ client/tomcatconf/commands.properties.in | 1 + core/src/com/cloud/vm/VMInstanceVO.java | 26 +- .../xen/resource/CitrixResourceBase.java | 172 +++++----- .../xen/resource/XenServer56FP1Resource.java | 11 +- .../xenserver/Add-To-VCPUs-Params-Live.sh | 33 ++ scripts/vm/hypervisor/xenserver/vmops | 13 + .../src/com/cloud/configuration/Config.java | 3 +- .../cloud/server/ManagementServerImpl.java | 1 + server/src/com/cloud/vm/ItWorkVO.java | 3 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 86 ++++- .../com/cloud/vm/VirtualMachineManager.java | 12 + .../cloud/vm/VirtualMachineManagerImpl.java | 307 ++++++++++++++++-- .../com/cloud/vm/MockUserVmManagerImpl.java | 17 +- .../vm/MockVirtualMachineManagerImpl.java | 15 + 18 files changed, 676 insertions(+), 161 deletions(-) create mode 100644 api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java create mode 100644 scripts/vm/hypervisor/xenserver/Add-To-VCPUs-Params-Live.sh diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 0087edca743..c8cc841ffaf 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -59,6 +59,7 @@ public class EventTypes { public static final String EVENT_VM_REBOOT = "VM.REBOOT"; public static final String EVENT_VM_UPDATE = "VM.UPDATE"; public static final String EVENT_VM_UPGRADE = "VM.UPGRADE"; + public static final String EVENT_VM_SCALE = "VM.SCALE"; public static final String EVENT_VM_RESETPASSWORD = "VM.RESETPASSWORD"; public static final String EVENT_VM_RESETSSHKEY = "VM.RESETSSHKEY"; public static final String EVENT_VM_MIGRATE = "VM.MIGRATE"; diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index ea89eda89d2..be039d27669 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -23,18 +23,7 @@ import javax.naming.InsufficientResourcesException; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; -import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; -import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; -import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; -import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; -import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; -import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; -import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; -import org.apache.cloudstack.api.command.user.vm.StartVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; +import org.apache.cloudstack.api.command.user.vm.*; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; @@ -401,4 +390,7 @@ public interface UserVmService { VirtualMachine vmStorageMigration(Long vmId, StoragePool destPool); UserVm restoreVM(RestoreVMCmd cmd); + + UserVm upgradeVirtualMachine(ScaleVMCmd scaleVMCmd) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException; + } diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index 4300dd548c1..c3bd4bfc870 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -41,6 +41,7 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I Destroyed(false, "VM is marked for destroy."), Expunging(true, "VM is being expunged."), Migrating(true, "VM is being migrated. host id holds to from host"), + Reconfiguring(true, "VM is being reconfigured to a new service offering"), Error(false, "VM is in error"), Unknown(false, "VM state is unknown."), Shutdowned(false, "VM is shutdowned from inside"); @@ -95,6 +96,9 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I s_fsm.addTransition(State.Running, VirtualMachine.Event.StopRequested, State.Stopping); s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportMigrated, State.Running); + s_fsm.addTransition(State.Running, VirtualMachine.Event.ReconfiguringRequested, State.Reconfiguring); + s_fsm.addTransition(State.Reconfiguring, VirtualMachine.Event.OperationSucceeded, State.Running); + s_fsm.addTransition(State.Reconfiguring, VirtualMachine.Event.OperationFailed, State.Running); s_fsm.addTransition(State.Migrating, VirtualMachine.Event.MigrationRequested, State.Migrating); s_fsm.addTransition(State.Migrating, VirtualMachine.Event.OperationSucceeded, State.Running); s_fsm.addTransition(State.Migrating, VirtualMachine.Event.OperationFailed, State.Running); @@ -176,7 +180,8 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I AgentReportShutdowned, AgentReportMigrated, RevertRequested, - SnapshotRequested + SnapshotRequested, + ReconfiguringRequested }; public enum Type { @@ -294,4 +299,8 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I public Map getDetails(); + public Boolean getSameHost(); + + public Long getNewSvcOfferingId(); + } diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java new file mode 100644 index 00000000000..b4cc1caa7ef --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java @@ -0,0 +1,109 @@ +package org.apache.cloudstack.api.command.user.vm; + +import com.cloud.exception.*; +import com.cloud.user.Account; +import com.cloud.user.UserContext; +import com.cloud.uservm.UserVm; +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.ServiceOfferingResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.log4j.Logger; + +// 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. +@APICommand(name = "scaleVirtualMachine", description="Scales the virtual machine to a new service offering.", responseObject=UserVmResponse.class) +public class ScaleVMCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(ScaleVMCmd.class.getName()); + private static final String s_name = "scalevirtualmachineresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @ACL + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=UserVmResponse.class, + required=true, description="The ID of the virtual machine") + private Long id; + + @ACL + @Parameter(name=ApiConstants.SERVICE_OFFERING_ID, type=CommandType.UUID, entityType=ServiceOfferingResponse.class, + required=true, description="the ID of the service offering for the virtual machine") + private Long serviceOfferingId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public Long getServiceOfferingId() { + return serviceOfferingId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public static String getResultObjectName() { + return "virtualmachine"; + } + + @Override + public long getEntityOwnerId() { + UserVm userVm = _entityMgr.findById(UserVm.class, getId()); + if (userVm != null) { + return userVm.getAccountId(); + } + + return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked + } + + @Override + public void execute(){ + UserContext.current().setEventDetails("Vm Id: "+getId()); + UserVm result = null; + try { + result = _userVmService.upgradeVirtualMachine(this); + } catch (ResourceUnavailableException ex) { + s_logger.warn("Exception: ", ex); + throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage()); + } catch (ConcurrentOperationException ex) { + s_logger.warn("Exception: ", ex); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); + } catch (ManagementServerException ex) { + s_logger.warn("Exception: ", ex); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); + } catch (VirtualMachineMigrationException ex) { + s_logger.warn("Exception: ", ex); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); + } + if (result != null){ + UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", result).get(0); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to upgrade vm"); + } + } +} \ No newline at end of file diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index bbb3d3078ec..5b387bdb0e3 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -66,6 +66,7 @@ listVirtualMachines=15 getVMPassword=15 restoreVirtualMachine=15 changeServiceForVirtualMachine=15 +scaleVirtualMachine=15 assignVirtualMachine=1 migrateVirtualMachine=1 recoverVirtualMachine=7 diff --git a/core/src/com/cloud/vm/VMInstanceVO.java b/core/src/com/cloud/vm/VMInstanceVO.java index 6149e43f8fa..fb48e0fade3 100644 --- a/core/src/com/cloud/vm/VMInstanceVO.java +++ b/core/src/com/cloud/vm/VMInstanceVO.java @@ -151,6 +151,12 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject details; + @Transient + Long newSvcOfferingId; + + @Transient + Boolean sameHost; + @Column(name="uuid") protected String uuid = UUID.randomUUID().toString(); ; @@ -480,4 +486,22 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject _maxWeight) { + cpuWeight = _maxWeight; + } + + if (vmSpec.getLimitCpuUse()) { + long utilization = 0; // max CPU cap, default is unlimited + utilization = ((long)speed * 100 * vmSpec.getCpus()) / _host.speed ; + vm.addToVCPUsParamsLive(conn, "cap", Long.toString(utilization)); + } + //vm.addToVCPUsParamsLive(conn, "weight", Integer.toString(cpuWeight)); + callHostPlugin(conn, "vmops", "add_to_VCPUs_params_live", "key", "weight", "value", Integer.toString(cpuWeight), "vmname", vmSpec.getName() ); + } + } + + public ScaleVmAnswer execute(ScaleVmCommand cmd) { + VirtualMachineTO vmSpec = cmd.getVirtualMachine(); + String vmName = vmSpec.getName(); + try { + Connection conn = getConnection(); + Set vms = VM.getByNameLabel(conn, vmName); + Host host = Host.getByUuid(conn, _host.uuid); + // stop vm which is running on this host or is in halted state + Iterator iter = vms.iterator(); + while ( iter.hasNext() ) { + VM vm = iter.next(); + VM.Record vmr = vm.getRecord(conn); + + if ((vmr.powerState == VmPowerState.HALTED) || (vmr.powerState == VmPowerState.RUNNING && !isRefNull(vmr.residentOn) && !vmr.residentOn.getUuid(conn).equals(_host.uuid))) { + iter.remove(); + } + } + + if (vms.size() == 0) { + s_logger.info("No running VM " + vmName +" exists on XenServer" + _host.uuid); + return new ScaleVmAnswer(cmd, false, "VM does not exist"); + } + + for (VM vm : vms) { + VM.Record vmr = vm.getRecord(conn); + try { + scaleVM(conn, vm, vmSpec, host); + + } catch (Exception e) { + String msg = "Catch exception " + e.getClass().getName() + " when scaling VM:" + vmName + " due to " + e.toString(); + s_logger.debug(msg); + return new ScaleVmAnswer(cmd, false, msg); + } + + } + String msg = "scaling VM " + vmName + " is successful on host " + host; + s_logger.debug(msg); + return new ScaleVmAnswer(cmd, true, msg); + + } catch (XenAPIException e) { + String msg = "Upgrade Vm " + vmName + " fail due to " + e.toString(); + s_logger.warn(msg, e); + return new ScaleVmAnswer(cmd, false, msg); + } catch (XmlRpcException e) { + String msg = "Upgrade Vm " + vmName + " fail due to " + e.getMessage(); + s_logger.warn(msg, e); + return new ScaleVmAnswer(cmd, false, msg); + } catch (Exception e) { + String msg = "Unable to upgrade " + vmName + " due to " + e.getMessage(); + s_logger.warn(msg, e); + return new ScaleVmAnswer(cmd, false, msg); + } + } private Answer execute(RevertToVMSnapshotCommand cmd) { String vmName = cmd.getVmName(); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java index 7040311d04e..d64e17337a1 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java @@ -138,9 +138,14 @@ public class XenServer56FP1Resource extends XenServer56Resource { record.actionsAfterShutdown = Types.OnNormalExit.DESTROY; record.memoryDynamicMax = vmSpec.getMaxRam(); record.memoryDynamicMin = vmSpec.getMinRam(); - record.memoryStaticMax = vmSpec.getMaxRam(); - record.memoryStaticMin = vmSpec.getMinRam(); - record.VCPUsMax = (long) vmSpec.getCpus(); + record.memoryStaticMax = 8589934592L; //128GB + record.memoryStaticMin = 134217728L; //128MB + if (guestOsTypeName.toLowerCase().contains("windows")) { + record.VCPUsMax = (long) vmSpec.getCpus(); + } else { + record.VCPUsMax = 32L; + } + record.VCPUsAtStartup = (long) vmSpec.getCpus(); record.consoles.clear(); diff --git a/scripts/vm/hypervisor/xenserver/Add-To-VCPUs-Params-Live.sh b/scripts/vm/hypervisor/xenserver/Add-To-VCPUs-Params-Live.sh new file mode 100644 index 00000000000..0fadcd85860 --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/Add-To-VCPUs-Params-Live.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# 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. + +set -x + +vmname=$1 +key=$2 +value=$3 +uuid=`xe vm-list name-label=$vmname | grep uuid | awk '{print $NF}'` +if [[ $key == "weight" ]] +then + xe vm-param-set VCPUs-params:weight=$value uuid=$uuid +fi +if [[ $key == "cap" ]] +then + xe vm-param-set VCPUs-params:cap=$value uuid=$uuid +fi + diff --git a/scripts/vm/hypervisor/xenserver/vmops b/scripts/vm/hypervisor/xenserver/vmops index db6f6d63ac9..92ed79a1d6e 100755 --- a/scripts/vm/hypervisor/xenserver/vmops +++ b/scripts/vm/hypervisor/xenserver/vmops @@ -42,6 +42,18 @@ def echo(fn): return res return wrapped +@echo +def add_to_VCPUs_params_live(session, args): + key = args['key'] + value = args['value'] + vmname = args['vmname'] + try: + cmd = ["bash", "/opt/xensource/bin/Add-To-VCPUs-Params-Live.sh", vmname, key, value] + txt = util.pread2(cmd) + except: + return 'false' + return 'true' + @echo def gethostvmstats(session, args): collect_host_stats = args['collectHostStats'] @@ -1470,6 +1482,7 @@ if __name__ == "__main__": "destroy_network_rules_for_vm":destroy_network_rules_for_vm, "default_network_rules_systemvm":default_network_rules_systemvm, "get_rule_logs_for_vms":get_rule_logs_for_vms, + "add_to_VCPUs_params_live":add_to_VCPUs_params_live, "setLinkLocalIP":setLinkLocalIP, "cleanup_rules":cleanup_rules, "bumpUpPriority":bumpUpPriority, diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 8a75a96845a..04ad640f47a 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -173,7 +173,8 @@ public enum Config { RouterTemplateId("Advanced", NetworkManager.class, Long.class, "router.template.id", "1", "Default ID for template.", null), RouterExtraPublicNics("Advanced", NetworkManager.class, Integer.class, "router.extra.public.nics", "2", "specify extra public nics used for virtual router(up to 5)", "0-5"), StartRetry("Advanced", AgentManager.class, Integer.class, "start.retry", "10", "Number of times to retry create and start commands", null), - StopRetryInterval("Advanced", HighAvailabilityManager.class, Integer.class, "stop.retry.interval", "600", "Time in seconds between retries to stop or destroy a vm" , null), + ScaleRetry("Advanced", AgentManager.class, Integer.class, "scale.retry", "2", "Number of times to retry scaling up the vm", null), + StopRetryInterval("Advanced", HighAvailabilityManager.class, Integer.class, "stop.retry.interval", "600", "Time in seconds between retries to stop or destroy a vm" , null), StorageCleanupInterval("Advanced", StorageManager.class, Integer.class, "storage.cleanup.interval", "86400", "The interval (in seconds) to wait before running the storage cleanup thread.", null), StorageCleanupEnabled("Advanced", StorageManager.class, Boolean.class, "storage.cleanup.enabled", "true", "Enables/disables the storage cleanup thread.", null), UpdateWait("Advanced", AgentManager.class, Integer.class, "update.wait", "600", "Time to wait (in seconds) before alerting on a updating agent", null), diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 95b2973a384..0e530797971 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -2110,6 +2110,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(DestroyVMCmd.class); cmdList.add(GetVMPasswordCmd.class); cmdList.add(ListVMsCmd.class); + cmdList.add(ScaleVMCmd.class); cmdList.add(RebootVMCmd.class); cmdList.add(RemoveNicFromVMCmd.class); cmdList.add(ResetVMPasswordCmd.class); diff --git a/server/src/com/cloud/vm/ItWorkVO.java b/server/src/com/cloud/vm/ItWorkVO.java index 6f534953381..d218880c923 100644 --- a/server/src/com/cloud/vm/ItWorkVO.java +++ b/server/src/com/cloud/vm/ItWorkVO.java @@ -41,7 +41,8 @@ public class ItWorkVO { Started, Release, Done, - Migrating + Migrating, + Reconfiguring } @Id diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index ca9c13fd1c4..3fb5d924d7c 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -32,22 +32,12 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.api.ApiDBUtils; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; -import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; -import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; -import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; -import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; -import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; -import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; -import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; -import org.apache.cloudstack.api.command.user.vm.StartVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; +import org.apache.cloudstack.api.command.user.vm.*; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity; @@ -397,6 +387,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use protected String _instance; protected String _zone; protected boolean _instanceNameFlag; + protected int _scaleRetry; @Inject ConfigurationDao _configDao; private int _createprivatetemplatefromvolumewait; @@ -1017,6 +1008,74 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use throw new CloudRuntimeException("something strange happened, new default network(" + newdefault.getId() + ") is not null, and is not equal to the network(" + nic.getNetworkId() + ") of the chosen nic"); } + @Override + @ActionEvent(eventType = EventTypes.EVENT_VM_SCALE, eventDescription = "scaling Vm") + public UserVm upgradeVirtualMachine(ScaleVMCmd cmd) throws InvalidParameterValueException { + Long vmId = cmd.getId(); + Long newSvcOffId = cmd.getServiceOfferingId(); + Account caller = UserContext.current().getCaller(); + + // Verify input parameters + VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId); + if(vmInstance.getHypervisorType() != HypervisorType.XenServer){ + throw new InvalidParameterValueException("This operation not permitted for this hypervisor of the vm"); + } + + _accountMgr.checkAccess(caller, null, true, vmInstance); + + // Check that the specified service offering ID is valid + _itMgr.checkIfCanUpgrade(vmInstance, newSvcOffId); + + //Check if its a scale up + ServiceOffering newServiceOffering = _configMgr.getServiceOffering(newSvcOffId); + ServiceOffering oldServiceOffering = _configMgr.getServiceOffering(vmInstance.getServiceOfferingId()); + if(newServiceOffering.getSpeed() <= oldServiceOffering.getSpeed() + && newServiceOffering.getRamSize() <= oldServiceOffering.getRamSize()){ + throw new InvalidParameterValueException("Only scaling up the vm is supported"); + } + + // Dynamically upgrade the running vms + if(vmInstance.getState().equals(State.Running)){ + boolean success = false; + int retry = _scaleRetry; + while (retry-- != 0) { // It's != so that it can match -1. + try{ + // #1 Check existing host has capacity + boolean existingHostHasCapacity = _capacityMgr.checkIfHostHasCapacity(vmInstance.getHostId(), newServiceOffering.getSpeed() - oldServiceOffering.getSpeed(), + (newServiceOffering.getRamSize() - oldServiceOffering.getRamSize()) * 1024L * 1024L, false, ApiDBUtils.getCpuOverprovisioningFactor(), 1f, false); + + // #2 migrate the vm + if (!existingHostHasCapacity){ + vmInstance = _itMgr.scale(vmInstance.getType(), vmInstance, newSvcOffId); + }else{ + vmInstance.setSameHost(existingHostHasCapacity); + } + + // #3 scale the vm now + vmInstance = _itMgr.reConfigureVm(vmInstance, newServiceOffering, existingHostHasCapacity); + success = true; + }catch(InsufficientCapacityException e ){ + + } catch (ResourceUnavailableException e) { + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + e.printStackTrace(); + } catch (VirtualMachineMigrationException e) { + e.printStackTrace(); + } catch (ManagementServerException e) { + e.printStackTrace(); + } + } + if (!success) + return null; + } + + //Update the DB. + _itMgr.upgradeVmDb(vmId, newSvcOffId); + + return _vmDao.findById(vmInstance.getId()); + } + @Override public HashMap getVirtualMachineStatistics(long hostId, String hostName, List vmIds) throws CloudRuntimeException { @@ -1210,6 +1269,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use new UserVmStateListener(_usageEventDao, _networkDao, _nicDao)); value = _configDao.getValue(Config.SetVmInternalNameUsingDisplayName.key()); + if(value == null) { _instanceNameFlag = false; } @@ -1218,6 +1278,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _instanceNameFlag = Boolean.parseBoolean(value); } + _scaleRetry = NumbersUtil.parseInt(configs.get(Config.ScaleRetry.key()), 2); + s_logger.info("User VM Manager is configured."); return true; diff --git a/server/src/com/cloud/vm/VirtualMachineManager.java b/server/src/com/cloud/vm/VirtualMachineManager.java index 7b34f7f0616..b81d5330896 100644 --- a/server/src/com/cloud/vm/VirtualMachineManager.java +++ b/server/src/com/cloud/vm/VirtualMachineManager.java @@ -186,4 +186,16 @@ public interface VirtualMachineManager extends Manager { */ VirtualMachineTO toVmTO(VirtualMachineProfile profile); + + VMInstanceVO reConfigureVm(VMInstanceVO vm, ServiceOffering newServiceOffering, boolean sameHost) + throws ResourceUnavailableException, ConcurrentOperationException; + + VMInstanceVO scale(VirtualMachine.Type vmType, VMInstanceVO vm, Long newSvcOfferingId) throws InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException, + VirtualMachineMigrationException, ManagementServerException; + + T migrateForScale(T vm, long srcHostId, DeployDestination dest, Long newSvcOfferingId) + throws ResourceUnavailableException, ConcurrentOperationException, + ManagementServerException, VirtualMachineMigrationException; + } diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index f8448c0ac8f..a29133f2308 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -38,33 +38,13 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import com.cloud.dc.*; +import com.cloud.agent.api.*; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager.OnError; import com.cloud.agent.Listener; -import com.cloud.agent.api.AgentControlAnswer; -import com.cloud.agent.api.AgentControlCommand; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.CheckVirtualMachineAnswer; -import com.cloud.agent.api.CheckVirtualMachineCommand; -import com.cloud.agent.api.ClusterSyncAnswer; -import com.cloud.agent.api.ClusterSyncCommand; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.MigrateAnswer; -import com.cloud.agent.api.MigrateCommand; -import com.cloud.agent.api.PingRoutingCommand; -import com.cloud.agent.api.PrepareForMigrationAnswer; -import com.cloud.agent.api.PrepareForMigrationCommand; -import com.cloud.agent.api.RebootAnswer; -import com.cloud.agent.api.RebootCommand; -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.StartupRoutingCommand.VmState; -import com.cloud.agent.api.StopAnswer; -import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.manager.Commands; @@ -2421,13 +2401,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac if (newServiceOffering == null) { throw new InvalidParameterValueException("Unable to find a service offering with id " + newServiceOfferingId); } - - // Check that the VM is stopped - if (!vmInstance.getState().equals(State.Stopped)) { + + // Check that the VM is stopped / running + if (!(vmInstance.getState().equals(State.Stopped) || vmInstance.getState().equals(State.Running) )) { s_logger.warn("Unable to upgrade virtual machine " + vmInstance.toString() + " in state " + vmInstance.getState()); - throw new InvalidParameterValueException("Unable to upgrade virtual machine " + vmInstance.toString() + " " + - "in state " + vmInstance.getState() - + "; make sure the virtual machine is stopped and not in an error state before upgrading."); + throw new InvalidParameterValueException("Unable to upgrade virtual machine " + vmInstance.toString() + " " + " in state " + vmInstance.getState() + + "; make sure the virtual machine is stopped/running"); } // Check if the service offering being upgraded to is what the VM is already running with @@ -2678,4 +2657,276 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac return true; } -} + @Override + public VMInstanceVO scale(VirtualMachine.Type vmType, VMInstanceVO vm, Long newSvcOfferingId) + throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, VirtualMachineMigrationException, ManagementServerException { + + VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); + + Long srcHostId = vm.getHostId(); + Long oldSvcOfferingId = vm.getServiceOfferingId(); + if (srcHostId == null) { + s_logger.debug("Unable to scale the vm because it doesn't have a host id: " + vm); + return vm; + } + Host host = _hostDao.findById(srcHostId); + DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), null, null, null); + ExcludeList excludes = new ExcludeList(); + excludes.addHost(vm.getHostId()); + vm.setServiceOfferingId(newSvcOfferingId); // Need to find the destination host based on new svc offering + + DeployDestination dest = null; + + for (DeploymentPlanner planner : _planners) { + if (planner.canHandle(profile, plan, excludes)) { + dest = planner.plan(profile, plan, excludes); + } else { + continue; + } + + if (dest != null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Planner " + planner + " found " + dest + " for scaling the vm to."); + } + break; + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Planner " + planner + " was unable to find anything."); + } + } + + if (dest == null) { + throw new InsufficientServerCapacityException("Unable to find a server to scale the vm to.", host.getClusterId()); + } + + excludes.addHost(dest.getHost().getId()); + VMInstanceVO vmInstance = null; + try { + vmInstance = migrateForScale(vm, srcHostId, dest, oldSvcOfferingId); + } catch (ResourceUnavailableException e) { + s_logger.debug("Unable to migrate to unavailable " + dest); + throw e; + } catch (ConcurrentOperationException e) { + s_logger.debug("Unable to migrate VM due to: " + e.getMessage()); + throw e; + } catch (ManagementServerException e) { + s_logger.debug("Unable to migrate VM: " + e.getMessage()); + throw e; + } catch (VirtualMachineMigrationException e) { + s_logger.debug("Got VirtualMachineMigrationException, Unable to migrate: " + e.getMessage()); + if (vm.getState() == State.Starting) { + s_logger.debug("VM seems to be still Starting, we should retry migration later"); + throw e; + } else { + s_logger.debug("Unable to migrate VM, VM is not in Running or even Starting state, current state: " + vm.getState().toString()); + } + } + if (vmInstance != null) { + return vmInstance; + }else{ + return null; + } + } + + @Override + public VMInstanceVO reConfigureVm(VMInstanceVO vm , ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException { + ScaleVmCommand reconfigureCmd = new ScaleVmCommand(vm.getInstanceName(), newServiceOffering.getCpu(), + newServiceOffering.getSpeed(), newServiceOffering.getRamSize(), newServiceOffering.getRamSize()); + + Long dstHostId = vm.getHostId(); + ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Reconfiguring, vm.getType(), vm.getId()); + work.setStep(Step.Prepare); + work.setResourceType(ItWorkVO.ResourceType.Host); + work.setResourceId(vm.getHostId()); + work = _workDao.persist(work); + boolean success = false; + try { + vm.setNewSvcOfferingId(newServiceOffering.getId()); // Capacity update should be delta (new - old) offering + changeState(vm, Event.ReconfiguringRequested, dstHostId, work, Step.Reconfiguring); + + Answer reconfigureAnswer = _agentMgr.send(vm.getHostId(), reconfigureCmd); + if (!reconfigureAnswer.getResult()) { + s_logger.error("Unable to reconfigure due to " + reconfigureAnswer.getDetails()); + return null; + } + + changeState(vm, VirtualMachine.Event.OperationSucceeded, dstHostId, work, Step.Done); + success = true; + } catch (OperationTimedoutException e) { + throw new AgentUnavailableException("Operation timed out on reconfiguring " + vm, dstHostId); + } catch (AgentUnavailableException e) { + throw e; + } catch (NoTransitionException e) { + s_logger.info("Unable to change the state : " + e.getMessage()); + throw new ConcurrentOperationException("Unable to change the state : " + e.getMessage()); + }finally{ + work.setStep(Step.Done); + _workDao.update(work.getId(), work); + if(!success){ + try { + stateTransitTo(vm, Event.OperationFailed, vm.getHostId()); + } catch (NoTransitionException e) { + s_logger.warn(e.getMessage()); + } + } + } + + return vm; + + } + + @Override + public T migrateForScale(T vm, long srcHostId, DeployDestination dest, Long oldSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, + VirtualMachineMigrationException { + s_logger.info("Migrating " + vm + " to " + dest); + + Long newSvcOfferingId = vm.getServiceOfferingId(); + long dstHostId = dest.getHost().getId(); + Host fromHost = _hostDao.findById(srcHostId); + if (fromHost == null) { + s_logger.info("Unable to find the host to migrate from: " + srcHostId); + throw new CloudRuntimeException("Unable to find the host to migrate from: " + srcHostId); + } + + if (fromHost.getClusterId().longValue() != dest.getCluster().getId()) { + s_logger.info("Source and destination host are not in same cluster, unable to migrate to host: " + dest.getHost().getId()); + throw new CloudRuntimeException("Source and destination host are not in same cluster, unable to migrate to host: " + dest.getHost().getId()); + } + + VirtualMachineGuru vmGuru = getVmGuru(vm); + + long vmId = vm.getId(); + vm = vmGuru.findById(vmId); + if (vm == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Unable to find the vm " + vm); + } + throw new ManagementServerException("Unable to find a virtual machine with id " + vmId); + } + + if (vm.getState() != State.Running) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("VM is not Running, unable to migrate the vm " + vm); + } + throw new VirtualMachineMigrationException("VM is not Running, unable to migrate the vm currently " + vm + " , current state: " + vm.getState().toString()); + } + + short alertType = AlertManager.ALERT_TYPE_USERVM_MIGRATE; + if (VirtualMachine.Type.DomainRouter.equals(vm.getType())) { + alertType = AlertManager.ALERT_TYPE_DOMAIN_ROUTER_MIGRATE; + } else if (VirtualMachine.Type.ConsoleProxy.equals(vm.getType())) { + alertType = AlertManager.ALERT_TYPE_CONSOLE_PROXY_MIGRATE; + } + + VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); + _networkMgr.prepareNicForMigration(profile, dest); + this.volumeMgr.prepareForMigration(profile, dest); + + VirtualMachineTO to = toVmTO(profile); + PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(to); + + ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Migrating, vm.getType(), vm.getId()); + work.setStep(Step.Prepare); + work.setResourceType(ItWorkVO.ResourceType.Host); + work.setResourceId(dstHostId); + work = _workDao.persist(work); + + PrepareForMigrationAnswer pfma = null; + try { + pfma = (PrepareForMigrationAnswer) _agentMgr.send(dstHostId, pfmc); + if (!pfma.getResult()) { + String msg = "Unable to prepare for migration due to " + pfma.getDetails(); + pfma = null; + throw new AgentUnavailableException(msg, dstHostId); + } + } catch (OperationTimedoutException e1) { + throw new AgentUnavailableException("Operation timed out", dstHostId); + } finally { + if (pfma == null) { + work.setStep(Step.Done); + _workDao.update(work.getId(), work); + } + } + + vm.setLastHostId(srcHostId); + try { + if (vm == null || vm.getHostId() == null || vm.getHostId() != srcHostId || !changeState(vm, Event.MigrationRequested, dstHostId, work, Step.Migrating)) { + s_logger.info("Migration cancelled because state has changed: " + vm); + throw new ConcurrentOperationException("Migration cancelled because state has changed: " + vm); + } + } catch (NoTransitionException e1) { + s_logger.info("Migration cancelled because " + e1.getMessage()); + throw new ConcurrentOperationException("Migration cancelled because " + e1.getMessage()); + } + + boolean migrated = false; + try { + boolean isWindows = _guestOsCategoryDao.findById(_guestOsDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows"); + MigrateCommand mc = new MigrateCommand(vm.getInstanceName(), dest.getHost().getPrivateIpAddress(), isWindows); + mc.setHostGuid(dest.getHost().getGuid()); + + try { + MigrateAnswer ma = (MigrateAnswer) _agentMgr.send(vm.getLastHostId(), mc); + if (!ma.getResult()) { + s_logger.error("Unable to migrate due to " + ma.getDetails()); + return null; + } + } catch (OperationTimedoutException e) { + if (e.isActive()) { + s_logger.warn("Active migration command so scheduling a restart for " + vm); + _haMgr.scheduleRestart(vm, true); + } + throw new AgentUnavailableException("Operation timed out on migrating " + vm, dstHostId); + } + + try { + vm.setServiceOfferingId(oldSvcOfferingId); // release capacity for the old service offering only + if (!changeState(vm, VirtualMachine.Event.OperationSucceeded, dstHostId, work, Step.Started)) { + throw new ConcurrentOperationException("Unable to change the state for " + vm); + } + } catch (NoTransitionException e1) { + throw new ConcurrentOperationException("Unable to change state due to " + e1.getMessage()); + } + + try { + if (!checkVmOnHost(vm, dstHostId)) { + s_logger.error("Unable to complete migration for " + vm); + try { + _agentMgr.send(srcHostId, new Commands(cleanup(vm.getInstanceName())), null); + } catch (AgentUnavailableException e) { + s_logger.error("AgentUnavailableException while cleanup on source host: " + srcHostId); + } + cleanup(vmGuru, new VirtualMachineProfileImpl(vm), work, Event.AgentReportStopped, true, _accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); + return null; + } + } catch (OperationTimedoutException e) { + } + + migrated = true; + return vm; + } finally { + if (!migrated) { + s_logger.info("Migration was unsuccessful. Cleaning up: " + vm); + + _alertMgr.sendAlert(alertType, fromHost.getDataCenterId(), fromHost.getPodId(), "Unable to migrate vm " + vm.getInstanceName() + " from host " + fromHost.getName() + " in zone " + + dest.getDataCenter().getName() + " and pod " + dest.getPod().getName(), "Migrate Command failed. Please check logs."); + try { + _agentMgr.send(dstHostId, new Commands(cleanup(vm.getInstanceName())), null); + } catch (AgentUnavailableException ae) { + s_logger.info("Looks like the destination Host is unavailable for cleanup"); + } + + try { + stateTransitTo(vm, Event.OperationFailed, srcHostId); + } catch (NoTransitionException e) { + s_logger.warn(e.getMessage()); + } + } + + work.setStep(Step.Done); + _workDao.update(work.getId(), work); + } + } + + + } diff --git a/server/test/com/cloud/vm/MockUserVmManagerImpl.java b/server/test/com/cloud/vm/MockUserVmManagerImpl.java index 09825a8eeb6..dd8dd83df58 100644 --- a/server/test/com/cloud/vm/MockUserVmManagerImpl.java +++ b/server/test/com/cloud/vm/MockUserVmManagerImpl.java @@ -25,18 +25,7 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; -import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; -import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; -import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; -import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; -import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; -import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; -import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; -import org.apache.cloudstack.api.command.user.vm.StartVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; +import org.apache.cloudstack.api.command.user.vm.*; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; import org.springframework.stereotype.Component; @@ -391,6 +380,10 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, return null; } + @Override + public UserVm upgradeVirtualMachine(ScaleVMCmd scaleVMCmd) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } @Override diff --git a/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java b/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java index 612c70d02c8..b8f548bb993 100755 --- a/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java +++ b/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java @@ -265,6 +265,21 @@ public class MockVirtualMachineManagerImpl extends ManagerBase implements Virtua return null; } + @Override + public VMInstanceVO reConfigureVm(VMInstanceVO vm, ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public VMInstanceVO scale(Type vmType, VMInstanceVO vm, Long newSvcOfferingId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, VirtualMachineMigrationException, ManagementServerException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public T migrateForScale(T vm, long srcHostId, DeployDestination dest, Long newSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + /* (non-Javadoc) * @see com.cloud.vm.VirtualMachineManager#addVmToNetwork(com.cloud.vm.VirtualMachine, com.cloud.network.Network, com.cloud.vm.NicProfile) */ From 8366a15659f44539aea0e12a8e5e485c14be0d80 Mon Sep 17 00:00:00 2001 From: Sateesh Chodapuneedi Date: Mon, 4 Mar 2013 16:25:24 +0530 Subject: [PATCH 13/21] Fixing mapping of virtual switch types. --- .../com/cloud/hypervisor/vmware/mo/VirtualSwitchType.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualSwitchType.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualSwitchType.java index bcfc64b6174..d67128f723e 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualSwitchType.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualSwitchType.java @@ -29,14 +29,12 @@ public enum VirtualSwitchType { public final static String nexusDistributedVirtualSwitch = "nexusdvs"; public static VirtualSwitchType getType(String vSwitchType) { - if (vSwitchType == null) { + if (vSwitchType == null || vSwitchType.equalsIgnoreCase(vmwareStandardVirtualSwitch)) { return VirtualSwitchType.StandardVirtualSwitch; - } else if (vSwitchType.equalsIgnoreCase(vmwareStandardVirtualSwitch)) { - return VirtualSwitchType.VMwareDistributedVirtualSwitch; } else if (vSwitchType.equalsIgnoreCase(vmwareDistributedVirtualSwitch)) { - return VirtualSwitchType.NexusDistributedVirtualSwitch; + return VirtualSwitchType.VMwareDistributedVirtualSwitch; } else if (vSwitchType.equalsIgnoreCase(nexusDistributedVirtualSwitch)) { - return VirtualSwitchType.StandardVirtualSwitch; + return VirtualSwitchType.NexusDistributedVirtualSwitch; } return VirtualSwitchType.None; } From fd335b4b7b57cf2b707e970b948a6f3c08a207ba Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Mon, 4 Mar 2013 16:37:31 +0530 Subject: [PATCH 14/21] CLOUDSTACK-1493:IP Reservation UI tooltip enhancement for detail view: Widget modification done to support this enhancement --- ui/scripts/docs.js | 19 +++++++++++++++++++ ui/scripts/ui/widgets/detailView.js | 8 +++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/ui/scripts/docs.js b/ui/scripts/docs.js index 0ccedc5ddb1..3356ecb866e 100755 --- a/ui/scripts/docs.js +++ b/ui/scripts/docs.js @@ -15,6 +15,25 @@ // specific language governing permissions and limitations // under the License. cloudStack.docs = { + + //IP Reservation tooltips + helpIPReservationCidr: { + desc:'Edit CIDR when you want to configure IP Reservation in isolated guest Network', + externalLink:'' + + }, + + helpIPReservationNetworkCidr:{ + desc:'The CIDR of the entire network when IP reservation is configured', + externalLink:' ' + + }, + + helpReservedIPRange:{ + desc:'The IP Range which is not used by CloudStack to allocate to Guest VMs.Can be used for Non Cloudstack purposes.', + externalLink:'' + }, + // Add account helpAccountUsername: { desc: 'Any desired login ID. Must be unique in the current domain. The same username can exist in other domains, including sub-domains.', diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js index f0cc8fd60b2..db7f5240e20 100644 --- a/ui/scripts/ui/widgets/detailView.js +++ b/ui/scripts/ui/widgets/detailView.js @@ -338,6 +338,8 @@ $detailView.find('.tagger').find('input[type=text]').val(''); + $('div.container div.panel div.detail-group .details .main-groups').find('.cidr').toolTip({ docID:'helpIPReservationCidr' , mode:'hover' , tooltip:'.tooltip-box' }); + var convertInputs = function($inputs) { // Save and turn back into labels $inputs.each(function() { @@ -489,7 +491,11 @@ return true; }); - + + $('div.container div.panel div.detail-group .details .main-groups').find('.reservediprange').toolTip({ docID:'helpReservedIPRange' , mode:'hover' , tooltip:'.tooltip-box' }); + $('div.container div.panel div.detail-group .details .main-groups').find('.networkcidr').toolTip({ docID:'helpIPReservationNetworkCidr' , mode:'hover' , tooltip:'.tooltip-box' }); + + $detailView.find('td.value span').each(function() { var name = $(this).closest('tr').data('detail-view-field'); var $value = $(this); From 43c7126c0788d704b4a478e5a41e5787bb7be926 Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Mon, 4 Mar 2013 17:25:03 +0530 Subject: [PATCH 15/21] CLOUDSTACK-1495:lDAP:UI:change the UI field name bind username --- ui/scripts/globalSettings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/scripts/globalSettings.js b/ui/scripts/globalSettings.js index 0f573d8d196..912dde7d86b 100644 --- a/ui/scripts/globalSettings.js +++ b/ui/scripts/globalSettings.js @@ -134,7 +134,7 @@ title: 'Configure LDAP', fields:{ - name:{label: 'Bind Username' , validation: {required:true} }, + name:{label: 'Bind DN' , validation: {required:true} }, password: {label: 'Bind Password', validation: {required: true },isPassword:true }, hostname: {label:'Hostname' , validation:{required:true}}, queryfilter: {label:'Query Filter' , validation: {required:true}}, From b12aebefeedd7f1fed442ad742e446817b0d05dd Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Mon, 4 Mar 2013 23:32:52 +0530 Subject: [PATCH 16/21] Revert "CLOUDSTACK-658 - Adding Scalevm command and XS related changes" This reverts commit e0019eccd997d9b2b3ff9395bcd99f821f5121db. --- api/src/com/cloud/event/EventTypes.java | 1 - api/src/com/cloud/vm/UserVmService.java | 16 +- api/src/com/cloud/vm/VirtualMachine.java | 11 +- .../api/command/user/vm/ScaleVMCmd.java | 109 ------- client/tomcatconf/commands.properties.in | 1 - core/src/com/cloud/vm/VMInstanceVO.java | 26 +- .../xen/resource/CitrixResourceBase.java | 172 +++++----- .../xen/resource/XenServer56FP1Resource.java | 11 +- .../xenserver/Add-To-VCPUs-Params-Live.sh | 33 -- scripts/vm/hypervisor/xenserver/vmops | 13 - .../src/com/cloud/configuration/Config.java | 3 +- .../cloud/server/ManagementServerImpl.java | 1 - server/src/com/cloud/vm/ItWorkVO.java | 3 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 86 +---- .../com/cloud/vm/VirtualMachineManager.java | 12 - .../cloud/vm/VirtualMachineManagerImpl.java | 307 ++---------------- .../com/cloud/vm/MockUserVmManagerImpl.java | 17 +- .../vm/MockVirtualMachineManagerImpl.java | 15 - 18 files changed, 161 insertions(+), 676 deletions(-) delete mode 100644 api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java delete mode 100644 scripts/vm/hypervisor/xenserver/Add-To-VCPUs-Params-Live.sh diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index c8cc841ffaf..0087edca743 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -59,7 +59,6 @@ public class EventTypes { public static final String EVENT_VM_REBOOT = "VM.REBOOT"; public static final String EVENT_VM_UPDATE = "VM.UPDATE"; public static final String EVENT_VM_UPGRADE = "VM.UPGRADE"; - public static final String EVENT_VM_SCALE = "VM.SCALE"; public static final String EVENT_VM_RESETPASSWORD = "VM.RESETPASSWORD"; public static final String EVENT_VM_RESETSSHKEY = "VM.RESETSSHKEY"; public static final String EVENT_VM_MIGRATE = "VM.MIGRATE"; diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index be039d27669..ea89eda89d2 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -23,7 +23,18 @@ import javax.naming.InsufficientResourcesException; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.vm.*; +import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; +import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; +import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; +import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; +import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; +import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; +import org.apache.cloudstack.api.command.user.vm.StartVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; @@ -390,7 +401,4 @@ public interface UserVmService { VirtualMachine vmStorageMigration(Long vmId, StoragePool destPool); UserVm restoreVM(RestoreVMCmd cmd); - - UserVm upgradeVirtualMachine(ScaleVMCmd scaleVMCmd) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException; - } diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index c3bd4bfc870..4300dd548c1 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -41,7 +41,6 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I Destroyed(false, "VM is marked for destroy."), Expunging(true, "VM is being expunged."), Migrating(true, "VM is being migrated. host id holds to from host"), - Reconfiguring(true, "VM is being reconfigured to a new service offering"), Error(false, "VM is in error"), Unknown(false, "VM state is unknown."), Shutdowned(false, "VM is shutdowned from inside"); @@ -96,9 +95,6 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I s_fsm.addTransition(State.Running, VirtualMachine.Event.StopRequested, State.Stopping); s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportMigrated, State.Running); - s_fsm.addTransition(State.Running, VirtualMachine.Event.ReconfiguringRequested, State.Reconfiguring); - s_fsm.addTransition(State.Reconfiguring, VirtualMachine.Event.OperationSucceeded, State.Running); - s_fsm.addTransition(State.Reconfiguring, VirtualMachine.Event.OperationFailed, State.Running); s_fsm.addTransition(State.Migrating, VirtualMachine.Event.MigrationRequested, State.Migrating); s_fsm.addTransition(State.Migrating, VirtualMachine.Event.OperationSucceeded, State.Running); s_fsm.addTransition(State.Migrating, VirtualMachine.Event.OperationFailed, State.Running); @@ -180,8 +176,7 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I AgentReportShutdowned, AgentReportMigrated, RevertRequested, - SnapshotRequested, - ReconfiguringRequested + SnapshotRequested }; public enum Type { @@ -299,8 +294,4 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I public Map getDetails(); - public Boolean getSameHost(); - - public Long getNewSvcOfferingId(); - } diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java deleted file mode 100644 index b4cc1caa7ef..00000000000 --- a/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.apache.cloudstack.api.command.user.vm; - -import com.cloud.exception.*; -import com.cloud.user.Account; -import com.cloud.user.UserContext; -import com.cloud.uservm.UserVm; -import org.apache.cloudstack.api.*; -import org.apache.cloudstack.api.response.ServiceOfferingResponse; -import org.apache.cloudstack.api.response.UserVmResponse; -import org.apache.log4j.Logger; - -// 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. -@APICommand(name = "scaleVirtualMachine", description="Scales the virtual machine to a new service offering.", responseObject=UserVmResponse.class) -public class ScaleVMCmd extends BaseCmd { - public static final Logger s_logger = Logger.getLogger(ScaleVMCmd.class.getName()); - private static final String s_name = "scalevirtualmachineresponse"; - - ///////////////////////////////////////////////////// - //////////////// API parameters ///////////////////// - ///////////////////////////////////////////////////// - - @ACL - @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=UserVmResponse.class, - required=true, description="The ID of the virtual machine") - private Long id; - - @ACL - @Parameter(name=ApiConstants.SERVICE_OFFERING_ID, type=CommandType.UUID, entityType=ServiceOfferingResponse.class, - required=true, description="the ID of the service offering for the virtual machine") - private Long serviceOfferingId; - - ///////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// - - public Long getId() { - return id; - } - - public Long getServiceOfferingId() { - return serviceOfferingId; - } - - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// - - @Override - public String getCommandName() { - return s_name; - } - - public static String getResultObjectName() { - return "virtualmachine"; - } - - @Override - public long getEntityOwnerId() { - UserVm userVm = _entityMgr.findById(UserVm.class, getId()); - if (userVm != null) { - return userVm.getAccountId(); - } - - return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked - } - - @Override - public void execute(){ - UserContext.current().setEventDetails("Vm Id: "+getId()); - UserVm result = null; - try { - result = _userVmService.upgradeVirtualMachine(this); - } catch (ResourceUnavailableException ex) { - s_logger.warn("Exception: ", ex); - throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage()); - } catch (ConcurrentOperationException ex) { - s_logger.warn("Exception: ", ex); - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); - } catch (ManagementServerException ex) { - s_logger.warn("Exception: ", ex); - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); - } catch (VirtualMachineMigrationException ex) { - s_logger.warn("Exception: ", ex); - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); - } - if (result != null){ - UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", result).get(0); - response.setResponseName(getCommandName()); - this.setResponseObject(response); - } else { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to upgrade vm"); - } - } -} \ No newline at end of file diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 5b387bdb0e3..bbb3d3078ec 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -66,7 +66,6 @@ listVirtualMachines=15 getVMPassword=15 restoreVirtualMachine=15 changeServiceForVirtualMachine=15 -scaleVirtualMachine=15 assignVirtualMachine=1 migrateVirtualMachine=1 recoverVirtualMachine=7 diff --git a/core/src/com/cloud/vm/VMInstanceVO.java b/core/src/com/cloud/vm/VMInstanceVO.java index fb48e0fade3..6149e43f8fa 100644 --- a/core/src/com/cloud/vm/VMInstanceVO.java +++ b/core/src/com/cloud/vm/VMInstanceVO.java @@ -151,12 +151,6 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject details; - @Transient - Long newSvcOfferingId; - - @Transient - Boolean sameHost; - @Column(name="uuid") protected String uuid = UUID.randomUUID().toString(); ; @@ -486,22 +480,4 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject _maxWeight) { - cpuWeight = _maxWeight; - } - - if (vmSpec.getLimitCpuUse()) { - long utilization = 0; // max CPU cap, default is unlimited - utilization = ((long)speed * 100 * vmSpec.getCpus()) / _host.speed ; - vm.addToVCPUsParamsLive(conn, "cap", Long.toString(utilization)); - } - //vm.addToVCPUsParamsLive(conn, "weight", Integer.toString(cpuWeight)); - callHostPlugin(conn, "vmops", "add_to_VCPUs_params_live", "key", "weight", "value", Integer.toString(cpuWeight), "vmname", vmSpec.getName() ); - } - } - - public ScaleVmAnswer execute(ScaleVmCommand cmd) { - VirtualMachineTO vmSpec = cmd.getVirtualMachine(); - String vmName = vmSpec.getName(); - try { - Connection conn = getConnection(); - Set vms = VM.getByNameLabel(conn, vmName); - Host host = Host.getByUuid(conn, _host.uuid); - // stop vm which is running on this host or is in halted state - Iterator iter = vms.iterator(); - while ( iter.hasNext() ) { - VM vm = iter.next(); - VM.Record vmr = vm.getRecord(conn); - - if ((vmr.powerState == VmPowerState.HALTED) || (vmr.powerState == VmPowerState.RUNNING && !isRefNull(vmr.residentOn) && !vmr.residentOn.getUuid(conn).equals(_host.uuid))) { - iter.remove(); - } - } - - if (vms.size() == 0) { - s_logger.info("No running VM " + vmName +" exists on XenServer" + _host.uuid); - return new ScaleVmAnswer(cmd, false, "VM does not exist"); - } - - for (VM vm : vms) { - VM.Record vmr = vm.getRecord(conn); - try { - scaleVM(conn, vm, vmSpec, host); - - } catch (Exception e) { - String msg = "Catch exception " + e.getClass().getName() + " when scaling VM:" + vmName + " due to " + e.toString(); - s_logger.debug(msg); - return new ScaleVmAnswer(cmd, false, msg); - } - - } - String msg = "scaling VM " + vmName + " is successful on host " + host; - s_logger.debug(msg); - return new ScaleVmAnswer(cmd, true, msg); - - } catch (XenAPIException e) { - String msg = "Upgrade Vm " + vmName + " fail due to " + e.toString(); - s_logger.warn(msg, e); - return new ScaleVmAnswer(cmd, false, msg); - } catch (XmlRpcException e) { - String msg = "Upgrade Vm " + vmName + " fail due to " + e.getMessage(); - s_logger.warn(msg, e); - return new ScaleVmAnswer(cmd, false, msg); - } catch (Exception e) { - String msg = "Unable to upgrade " + vmName + " due to " + e.getMessage(); - s_logger.warn(msg, e); - return new ScaleVmAnswer(cmd, false, msg); - } - } private Answer execute(RevertToVMSnapshotCommand cmd) { String vmName = cmd.getVmName(); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java index d64e17337a1..7040311d04e 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java @@ -138,14 +138,9 @@ public class XenServer56FP1Resource extends XenServer56Resource { record.actionsAfterShutdown = Types.OnNormalExit.DESTROY; record.memoryDynamicMax = vmSpec.getMaxRam(); record.memoryDynamicMin = vmSpec.getMinRam(); - record.memoryStaticMax = 8589934592L; //128GB - record.memoryStaticMin = 134217728L; //128MB - if (guestOsTypeName.toLowerCase().contains("windows")) { - record.VCPUsMax = (long) vmSpec.getCpus(); - } else { - record.VCPUsMax = 32L; - } - + record.memoryStaticMax = vmSpec.getMaxRam(); + record.memoryStaticMin = vmSpec.getMinRam(); + record.VCPUsMax = (long) vmSpec.getCpus(); record.VCPUsAtStartup = (long) vmSpec.getCpus(); record.consoles.clear(); diff --git a/scripts/vm/hypervisor/xenserver/Add-To-VCPUs-Params-Live.sh b/scripts/vm/hypervisor/xenserver/Add-To-VCPUs-Params-Live.sh deleted file mode 100644 index 0fadcd85860..00000000000 --- a/scripts/vm/hypervisor/xenserver/Add-To-VCPUs-Params-Live.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh -# 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. - -set -x - -vmname=$1 -key=$2 -value=$3 -uuid=`xe vm-list name-label=$vmname | grep uuid | awk '{print $NF}'` -if [[ $key == "weight" ]] -then - xe vm-param-set VCPUs-params:weight=$value uuid=$uuid -fi -if [[ $key == "cap" ]] -then - xe vm-param-set VCPUs-params:cap=$value uuid=$uuid -fi - diff --git a/scripts/vm/hypervisor/xenserver/vmops b/scripts/vm/hypervisor/xenserver/vmops index 92ed79a1d6e..db6f6d63ac9 100755 --- a/scripts/vm/hypervisor/xenserver/vmops +++ b/scripts/vm/hypervisor/xenserver/vmops @@ -42,18 +42,6 @@ def echo(fn): return res return wrapped -@echo -def add_to_VCPUs_params_live(session, args): - key = args['key'] - value = args['value'] - vmname = args['vmname'] - try: - cmd = ["bash", "/opt/xensource/bin/Add-To-VCPUs-Params-Live.sh", vmname, key, value] - txt = util.pread2(cmd) - except: - return 'false' - return 'true' - @echo def gethostvmstats(session, args): collect_host_stats = args['collectHostStats'] @@ -1482,7 +1470,6 @@ if __name__ == "__main__": "destroy_network_rules_for_vm":destroy_network_rules_for_vm, "default_network_rules_systemvm":default_network_rules_systemvm, "get_rule_logs_for_vms":get_rule_logs_for_vms, - "add_to_VCPUs_params_live":add_to_VCPUs_params_live, "setLinkLocalIP":setLinkLocalIP, "cleanup_rules":cleanup_rules, "bumpUpPriority":bumpUpPriority, diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 04ad640f47a..8a75a96845a 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -173,8 +173,7 @@ public enum Config { RouterTemplateId("Advanced", NetworkManager.class, Long.class, "router.template.id", "1", "Default ID for template.", null), RouterExtraPublicNics("Advanced", NetworkManager.class, Integer.class, "router.extra.public.nics", "2", "specify extra public nics used for virtual router(up to 5)", "0-5"), StartRetry("Advanced", AgentManager.class, Integer.class, "start.retry", "10", "Number of times to retry create and start commands", null), - ScaleRetry("Advanced", AgentManager.class, Integer.class, "scale.retry", "2", "Number of times to retry scaling up the vm", null), - StopRetryInterval("Advanced", HighAvailabilityManager.class, Integer.class, "stop.retry.interval", "600", "Time in seconds between retries to stop or destroy a vm" , null), + StopRetryInterval("Advanced", HighAvailabilityManager.class, Integer.class, "stop.retry.interval", "600", "Time in seconds between retries to stop or destroy a vm" , null), StorageCleanupInterval("Advanced", StorageManager.class, Integer.class, "storage.cleanup.interval", "86400", "The interval (in seconds) to wait before running the storage cleanup thread.", null), StorageCleanupEnabled("Advanced", StorageManager.class, Boolean.class, "storage.cleanup.enabled", "true", "Enables/disables the storage cleanup thread.", null), UpdateWait("Advanced", AgentManager.class, Integer.class, "update.wait", "600", "Time to wait (in seconds) before alerting on a updating agent", null), diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 0e530797971..95b2973a384 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -2110,7 +2110,6 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(DestroyVMCmd.class); cmdList.add(GetVMPasswordCmd.class); cmdList.add(ListVMsCmd.class); - cmdList.add(ScaleVMCmd.class); cmdList.add(RebootVMCmd.class); cmdList.add(RemoveNicFromVMCmd.class); cmdList.add(ResetVMPasswordCmd.class); diff --git a/server/src/com/cloud/vm/ItWorkVO.java b/server/src/com/cloud/vm/ItWorkVO.java index d218880c923..6f534953381 100644 --- a/server/src/com/cloud/vm/ItWorkVO.java +++ b/server/src/com/cloud/vm/ItWorkVO.java @@ -41,8 +41,7 @@ public class ItWorkVO { Started, Release, Done, - Migrating, - Reconfiguring + Migrating } @Id diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 3fb5d924d7c..ca9c13fd1c4 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -32,12 +32,22 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.api.ApiDBUtils; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.vm.*; +import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; +import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; +import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; +import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; +import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; +import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; +import org.apache.cloudstack.api.command.user.vm.StartVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity; @@ -387,7 +397,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use protected String _instance; protected String _zone; protected boolean _instanceNameFlag; - protected int _scaleRetry; @Inject ConfigurationDao _configDao; private int _createprivatetemplatefromvolumewait; @@ -1008,74 +1017,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use throw new CloudRuntimeException("something strange happened, new default network(" + newdefault.getId() + ") is not null, and is not equal to the network(" + nic.getNetworkId() + ") of the chosen nic"); } - @Override - @ActionEvent(eventType = EventTypes.EVENT_VM_SCALE, eventDescription = "scaling Vm") - public UserVm upgradeVirtualMachine(ScaleVMCmd cmd) throws InvalidParameterValueException { - Long vmId = cmd.getId(); - Long newSvcOffId = cmd.getServiceOfferingId(); - Account caller = UserContext.current().getCaller(); - - // Verify input parameters - VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId); - if(vmInstance.getHypervisorType() != HypervisorType.XenServer){ - throw new InvalidParameterValueException("This operation not permitted for this hypervisor of the vm"); - } - - _accountMgr.checkAccess(caller, null, true, vmInstance); - - // Check that the specified service offering ID is valid - _itMgr.checkIfCanUpgrade(vmInstance, newSvcOffId); - - //Check if its a scale up - ServiceOffering newServiceOffering = _configMgr.getServiceOffering(newSvcOffId); - ServiceOffering oldServiceOffering = _configMgr.getServiceOffering(vmInstance.getServiceOfferingId()); - if(newServiceOffering.getSpeed() <= oldServiceOffering.getSpeed() - && newServiceOffering.getRamSize() <= oldServiceOffering.getRamSize()){ - throw new InvalidParameterValueException("Only scaling up the vm is supported"); - } - - // Dynamically upgrade the running vms - if(vmInstance.getState().equals(State.Running)){ - boolean success = false; - int retry = _scaleRetry; - while (retry-- != 0) { // It's != so that it can match -1. - try{ - // #1 Check existing host has capacity - boolean existingHostHasCapacity = _capacityMgr.checkIfHostHasCapacity(vmInstance.getHostId(), newServiceOffering.getSpeed() - oldServiceOffering.getSpeed(), - (newServiceOffering.getRamSize() - oldServiceOffering.getRamSize()) * 1024L * 1024L, false, ApiDBUtils.getCpuOverprovisioningFactor(), 1f, false); - - // #2 migrate the vm - if (!existingHostHasCapacity){ - vmInstance = _itMgr.scale(vmInstance.getType(), vmInstance, newSvcOffId); - }else{ - vmInstance.setSameHost(existingHostHasCapacity); - } - - // #3 scale the vm now - vmInstance = _itMgr.reConfigureVm(vmInstance, newServiceOffering, existingHostHasCapacity); - success = true; - }catch(InsufficientCapacityException e ){ - - } catch (ResourceUnavailableException e) { - e.printStackTrace(); - } catch (ConcurrentOperationException e) { - e.printStackTrace(); - } catch (VirtualMachineMigrationException e) { - e.printStackTrace(); - } catch (ManagementServerException e) { - e.printStackTrace(); - } - } - if (!success) - return null; - } - - //Update the DB. - _itMgr.upgradeVmDb(vmId, newSvcOffId); - - return _vmDao.findById(vmInstance.getId()); - } - @Override public HashMap getVirtualMachineStatistics(long hostId, String hostName, List vmIds) throws CloudRuntimeException { @@ -1269,7 +1210,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use new UserVmStateListener(_usageEventDao, _networkDao, _nicDao)); value = _configDao.getValue(Config.SetVmInternalNameUsingDisplayName.key()); - if(value == null) { _instanceNameFlag = false; } @@ -1278,8 +1218,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _instanceNameFlag = Boolean.parseBoolean(value); } - _scaleRetry = NumbersUtil.parseInt(configs.get(Config.ScaleRetry.key()), 2); - s_logger.info("User VM Manager is configured."); return true; diff --git a/server/src/com/cloud/vm/VirtualMachineManager.java b/server/src/com/cloud/vm/VirtualMachineManager.java index b81d5330896..7b34f7f0616 100644 --- a/server/src/com/cloud/vm/VirtualMachineManager.java +++ b/server/src/com/cloud/vm/VirtualMachineManager.java @@ -186,16 +186,4 @@ public interface VirtualMachineManager extends Manager { */ VirtualMachineTO toVmTO(VirtualMachineProfile profile); - - VMInstanceVO reConfigureVm(VMInstanceVO vm, ServiceOffering newServiceOffering, boolean sameHost) - throws ResourceUnavailableException, ConcurrentOperationException; - - VMInstanceVO scale(VirtualMachine.Type vmType, VMInstanceVO vm, Long newSvcOfferingId) throws InsufficientCapacityException, - ConcurrentOperationException, ResourceUnavailableException, - VirtualMachineMigrationException, ManagementServerException; - - T migrateForScale(T vm, long srcHostId, DeployDestination dest, Long newSvcOfferingId) - throws ResourceUnavailableException, ConcurrentOperationException, - ManagementServerException, VirtualMachineMigrationException; - } diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index a29133f2308..f8448c0ac8f 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -38,13 +38,33 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import com.cloud.dc.*; -import com.cloud.agent.api.*; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager.OnError; import com.cloud.agent.Listener; +import com.cloud.agent.api.AgentControlAnswer; +import com.cloud.agent.api.AgentControlCommand; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.CheckVirtualMachineAnswer; +import com.cloud.agent.api.CheckVirtualMachineCommand; +import com.cloud.agent.api.ClusterSyncAnswer; +import com.cloud.agent.api.ClusterSyncCommand; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.MigrateAnswer; +import com.cloud.agent.api.MigrateCommand; +import com.cloud.agent.api.PingRoutingCommand; +import com.cloud.agent.api.PrepareForMigrationAnswer; +import com.cloud.agent.api.PrepareForMigrationCommand; +import com.cloud.agent.api.RebootAnswer; +import com.cloud.agent.api.RebootCommand; +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.StartupRoutingCommand.VmState; +import com.cloud.agent.api.StopAnswer; +import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.manager.Commands; @@ -2401,12 +2421,13 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac if (newServiceOffering == null) { throw new InvalidParameterValueException("Unable to find a service offering with id " + newServiceOfferingId); } - - // Check that the VM is stopped / running - if (!(vmInstance.getState().equals(State.Stopped) || vmInstance.getState().equals(State.Running) )) { + + // Check that the VM is stopped + if (!vmInstance.getState().equals(State.Stopped)) { s_logger.warn("Unable to upgrade virtual machine " + vmInstance.toString() + " in state " + vmInstance.getState()); - throw new InvalidParameterValueException("Unable to upgrade virtual machine " + vmInstance.toString() + " " + " in state " + vmInstance.getState() - + "; make sure the virtual machine is stopped/running"); + throw new InvalidParameterValueException("Unable to upgrade virtual machine " + vmInstance.toString() + " " + + "in state " + vmInstance.getState() + + "; make sure the virtual machine is stopped and not in an error state before upgrading."); } // Check if the service offering being upgraded to is what the VM is already running with @@ -2657,276 +2678,4 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac return true; } - @Override - public VMInstanceVO scale(VirtualMachine.Type vmType, VMInstanceVO vm, Long newSvcOfferingId) - throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, VirtualMachineMigrationException, ManagementServerException { - - VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); - - Long srcHostId = vm.getHostId(); - Long oldSvcOfferingId = vm.getServiceOfferingId(); - if (srcHostId == null) { - s_logger.debug("Unable to scale the vm because it doesn't have a host id: " + vm); - return vm; - } - Host host = _hostDao.findById(srcHostId); - DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), null, null, null); - ExcludeList excludes = new ExcludeList(); - excludes.addHost(vm.getHostId()); - vm.setServiceOfferingId(newSvcOfferingId); // Need to find the destination host based on new svc offering - - DeployDestination dest = null; - - for (DeploymentPlanner planner : _planners) { - if (planner.canHandle(profile, plan, excludes)) { - dest = planner.plan(profile, plan, excludes); - } else { - continue; - } - - if (dest != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Planner " + planner + " found " + dest + " for scaling the vm to."); - } - break; - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("Planner " + planner + " was unable to find anything."); - } - } - - if (dest == null) { - throw new InsufficientServerCapacityException("Unable to find a server to scale the vm to.", host.getClusterId()); - } - - excludes.addHost(dest.getHost().getId()); - VMInstanceVO vmInstance = null; - try { - vmInstance = migrateForScale(vm, srcHostId, dest, oldSvcOfferingId); - } catch (ResourceUnavailableException e) { - s_logger.debug("Unable to migrate to unavailable " + dest); - throw e; - } catch (ConcurrentOperationException e) { - s_logger.debug("Unable to migrate VM due to: " + e.getMessage()); - throw e; - } catch (ManagementServerException e) { - s_logger.debug("Unable to migrate VM: " + e.getMessage()); - throw e; - } catch (VirtualMachineMigrationException e) { - s_logger.debug("Got VirtualMachineMigrationException, Unable to migrate: " + e.getMessage()); - if (vm.getState() == State.Starting) { - s_logger.debug("VM seems to be still Starting, we should retry migration later"); - throw e; - } else { - s_logger.debug("Unable to migrate VM, VM is not in Running or even Starting state, current state: " + vm.getState().toString()); - } - } - if (vmInstance != null) { - return vmInstance; - }else{ - return null; - } - } - - @Override - public VMInstanceVO reConfigureVm(VMInstanceVO vm , ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException { - ScaleVmCommand reconfigureCmd = new ScaleVmCommand(vm.getInstanceName(), newServiceOffering.getCpu(), - newServiceOffering.getSpeed(), newServiceOffering.getRamSize(), newServiceOffering.getRamSize()); - - Long dstHostId = vm.getHostId(); - ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Reconfiguring, vm.getType(), vm.getId()); - work.setStep(Step.Prepare); - work.setResourceType(ItWorkVO.ResourceType.Host); - work.setResourceId(vm.getHostId()); - work = _workDao.persist(work); - boolean success = false; - try { - vm.setNewSvcOfferingId(newServiceOffering.getId()); // Capacity update should be delta (new - old) offering - changeState(vm, Event.ReconfiguringRequested, dstHostId, work, Step.Reconfiguring); - - Answer reconfigureAnswer = _agentMgr.send(vm.getHostId(), reconfigureCmd); - if (!reconfigureAnswer.getResult()) { - s_logger.error("Unable to reconfigure due to " + reconfigureAnswer.getDetails()); - return null; - } - - changeState(vm, VirtualMachine.Event.OperationSucceeded, dstHostId, work, Step.Done); - success = true; - } catch (OperationTimedoutException e) { - throw new AgentUnavailableException("Operation timed out on reconfiguring " + vm, dstHostId); - } catch (AgentUnavailableException e) { - throw e; - } catch (NoTransitionException e) { - s_logger.info("Unable to change the state : " + e.getMessage()); - throw new ConcurrentOperationException("Unable to change the state : " + e.getMessage()); - }finally{ - work.setStep(Step.Done); - _workDao.update(work.getId(), work); - if(!success){ - try { - stateTransitTo(vm, Event.OperationFailed, vm.getHostId()); - } catch (NoTransitionException e) { - s_logger.warn(e.getMessage()); - } - } - } - - return vm; - - } - - @Override - public T migrateForScale(T vm, long srcHostId, DeployDestination dest, Long oldSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, - VirtualMachineMigrationException { - s_logger.info("Migrating " + vm + " to " + dest); - - Long newSvcOfferingId = vm.getServiceOfferingId(); - long dstHostId = dest.getHost().getId(); - Host fromHost = _hostDao.findById(srcHostId); - if (fromHost == null) { - s_logger.info("Unable to find the host to migrate from: " + srcHostId); - throw new CloudRuntimeException("Unable to find the host to migrate from: " + srcHostId); - } - - if (fromHost.getClusterId().longValue() != dest.getCluster().getId()) { - s_logger.info("Source and destination host are not in same cluster, unable to migrate to host: " + dest.getHost().getId()); - throw new CloudRuntimeException("Source and destination host are not in same cluster, unable to migrate to host: " + dest.getHost().getId()); - } - - VirtualMachineGuru vmGuru = getVmGuru(vm); - - long vmId = vm.getId(); - vm = vmGuru.findById(vmId); - if (vm == null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Unable to find the vm " + vm); - } - throw new ManagementServerException("Unable to find a virtual machine with id " + vmId); - } - - if (vm.getState() != State.Running) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("VM is not Running, unable to migrate the vm " + vm); - } - throw new VirtualMachineMigrationException("VM is not Running, unable to migrate the vm currently " + vm + " , current state: " + vm.getState().toString()); - } - - short alertType = AlertManager.ALERT_TYPE_USERVM_MIGRATE; - if (VirtualMachine.Type.DomainRouter.equals(vm.getType())) { - alertType = AlertManager.ALERT_TYPE_DOMAIN_ROUTER_MIGRATE; - } else if (VirtualMachine.Type.ConsoleProxy.equals(vm.getType())) { - alertType = AlertManager.ALERT_TYPE_CONSOLE_PROXY_MIGRATE; - } - - VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); - _networkMgr.prepareNicForMigration(profile, dest); - this.volumeMgr.prepareForMigration(profile, dest); - - VirtualMachineTO to = toVmTO(profile); - PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(to); - - ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Migrating, vm.getType(), vm.getId()); - work.setStep(Step.Prepare); - work.setResourceType(ItWorkVO.ResourceType.Host); - work.setResourceId(dstHostId); - work = _workDao.persist(work); - - PrepareForMigrationAnswer pfma = null; - try { - pfma = (PrepareForMigrationAnswer) _agentMgr.send(dstHostId, pfmc); - if (!pfma.getResult()) { - String msg = "Unable to prepare for migration due to " + pfma.getDetails(); - pfma = null; - throw new AgentUnavailableException(msg, dstHostId); - } - } catch (OperationTimedoutException e1) { - throw new AgentUnavailableException("Operation timed out", dstHostId); - } finally { - if (pfma == null) { - work.setStep(Step.Done); - _workDao.update(work.getId(), work); - } - } - - vm.setLastHostId(srcHostId); - try { - if (vm == null || vm.getHostId() == null || vm.getHostId() != srcHostId || !changeState(vm, Event.MigrationRequested, dstHostId, work, Step.Migrating)) { - s_logger.info("Migration cancelled because state has changed: " + vm); - throw new ConcurrentOperationException("Migration cancelled because state has changed: " + vm); - } - } catch (NoTransitionException e1) { - s_logger.info("Migration cancelled because " + e1.getMessage()); - throw new ConcurrentOperationException("Migration cancelled because " + e1.getMessage()); - } - - boolean migrated = false; - try { - boolean isWindows = _guestOsCategoryDao.findById(_guestOsDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows"); - MigrateCommand mc = new MigrateCommand(vm.getInstanceName(), dest.getHost().getPrivateIpAddress(), isWindows); - mc.setHostGuid(dest.getHost().getGuid()); - - try { - MigrateAnswer ma = (MigrateAnswer) _agentMgr.send(vm.getLastHostId(), mc); - if (!ma.getResult()) { - s_logger.error("Unable to migrate due to " + ma.getDetails()); - return null; - } - } catch (OperationTimedoutException e) { - if (e.isActive()) { - s_logger.warn("Active migration command so scheduling a restart for " + vm); - _haMgr.scheduleRestart(vm, true); - } - throw new AgentUnavailableException("Operation timed out on migrating " + vm, dstHostId); - } - - try { - vm.setServiceOfferingId(oldSvcOfferingId); // release capacity for the old service offering only - if (!changeState(vm, VirtualMachine.Event.OperationSucceeded, dstHostId, work, Step.Started)) { - throw new ConcurrentOperationException("Unable to change the state for " + vm); - } - } catch (NoTransitionException e1) { - throw new ConcurrentOperationException("Unable to change state due to " + e1.getMessage()); - } - - try { - if (!checkVmOnHost(vm, dstHostId)) { - s_logger.error("Unable to complete migration for " + vm); - try { - _agentMgr.send(srcHostId, new Commands(cleanup(vm.getInstanceName())), null); - } catch (AgentUnavailableException e) { - s_logger.error("AgentUnavailableException while cleanup on source host: " + srcHostId); - } - cleanup(vmGuru, new VirtualMachineProfileImpl(vm), work, Event.AgentReportStopped, true, _accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); - return null; - } - } catch (OperationTimedoutException e) { - } - - migrated = true; - return vm; - } finally { - if (!migrated) { - s_logger.info("Migration was unsuccessful. Cleaning up: " + vm); - - _alertMgr.sendAlert(alertType, fromHost.getDataCenterId(), fromHost.getPodId(), "Unable to migrate vm " + vm.getInstanceName() + " from host " + fromHost.getName() + " in zone " - + dest.getDataCenter().getName() + " and pod " + dest.getPod().getName(), "Migrate Command failed. Please check logs."); - try { - _agentMgr.send(dstHostId, new Commands(cleanup(vm.getInstanceName())), null); - } catch (AgentUnavailableException ae) { - s_logger.info("Looks like the destination Host is unavailable for cleanup"); - } - - try { - stateTransitTo(vm, Event.OperationFailed, srcHostId); - } catch (NoTransitionException e) { - s_logger.warn(e.getMessage()); - } - } - - work.setStep(Step.Done); - _workDao.update(work.getId(), work); - } - } - - - } +} diff --git a/server/test/com/cloud/vm/MockUserVmManagerImpl.java b/server/test/com/cloud/vm/MockUserVmManagerImpl.java index dd8dd83df58..09825a8eeb6 100644 --- a/server/test/com/cloud/vm/MockUserVmManagerImpl.java +++ b/server/test/com/cloud/vm/MockUserVmManagerImpl.java @@ -25,7 +25,18 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.vm.*; +import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; +import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; +import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; +import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; +import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; +import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; +import org.apache.cloudstack.api.command.user.vm.StartVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; import org.springframework.stereotype.Component; @@ -380,10 +391,6 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, return null; } - @Override - public UserVm upgradeVirtualMachine(ScaleVMCmd scaleVMCmd) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException { - return null; //To change body of implemented methods use File | Settings | File Templates. - } @Override diff --git a/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java b/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java index b8f548bb993..612c70d02c8 100755 --- a/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java +++ b/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java @@ -265,21 +265,6 @@ public class MockVirtualMachineManagerImpl extends ManagerBase implements Virtua return null; } - @Override - public VMInstanceVO reConfigureVm(VMInstanceVO vm, ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - - @Override - public VMInstanceVO scale(Type vmType, VMInstanceVO vm, Long newSvcOfferingId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, VirtualMachineMigrationException, ManagementServerException { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - - @Override - public T migrateForScale(T vm, long srcHostId, DeployDestination dest, Long newSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - /* (non-Javadoc) * @see com.cloud.vm.VirtualMachineManager#addVmToNetwork(com.cloud.vm.VirtualMachine, com.cloud.network.Network, com.cloud.vm.NicProfile) */ From ff099fa651e8476220332d7e1cc4b24746802cfe Mon Sep 17 00:00:00 2001 From: Dave Cahill Date: Fri, 22 Feb 2013 17:04:42 +0900 Subject: [PATCH 17/21] Adding support for multiple VIF drivers in KVM - Building map of {trafficType, vifDriver} at configure time - Use the relevant VIF driver for the given traffic type when call plug() - Inform all vif drivers when call unplug(), as we no longer know traffic type - Refactor VIF driver choosing code and add unit tests - Basic unit tests, just test default case - Also slight refactor of unit test code, and use jUnit 4 instead of 3, to match rest of codebase Signed-off-by: Hugo Trippaers --- .../resource/LibvirtComputingResource.java | 122 ++++++++-- .../kvm/resource/LibvirtVifDriverTest.java | 226 ++++++++++++++++++ 2 files changed, 325 insertions(+), 23 deletions(-) create mode 100644 plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVifDriverTest.java 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 805de408996..5a96c360616 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 @@ -41,6 +41,8 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.HashSet; import java.util.Properties; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -276,7 +278,11 @@ ServerResource { private String _mountPoint = "/mnt"; StorageLayer _storage; private KVMStoragePoolManager _storagePoolMgr; - private VifDriver _vifDriver; + + private VifDriver _defaultVifDriver; + private Map _trafficTypeVifDrivers; + protected static final String DEFAULT_OVS_VIF_DRIVER_CLASS_NAME = "com.cloud.hypervisor.kvm.resource.OvsVifDriver"; + protected static final String DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME = "com.cloud.hypervisor.kvm.resource.BridgeVifDriver"; private static final class KeyValueInterpreter extends OutputInterpreter { private final Map map = new HashMap(); @@ -775,24 +781,66 @@ ServerResource { params.put("libvirt.host.bridges", bridges); params.put("libvirt.host.pifs", _pifs); - // Load the vif driver - String vifDriverName = (String) params.get("libvirt.vif.driver"); - if (vifDriverName == null) { - if (_bridgeType == BridgeType.OPENVSWITCH) { - s_logger.info("No libvirt.vif.driver specififed. Defaults to OvsVifDriver."); - vifDriverName = "com.cloud.hypervisor.kvm.resource.OvsVifDriver"; - } else { - s_logger.info("No libvirt.vif.driver specififed. Defaults to BridgeVifDriver."); - vifDriverName = "com.cloud.hypervisor.kvm.resource.BridgeVifDriver"; - } - } - params.put("libvirt.computing.resource", this); + configureVifDrivers(params); + + return true; + } + + protected void configureVifDrivers(Map params) + throws ConfigurationException { + final String LIBVIRT_VIF_DRIVER = "libvirt.vif.driver"; + + _trafficTypeVifDrivers = new HashMap(); + + // Load the default vif driver + String defaultVifDriverName = (String) params.get(LIBVIRT_VIF_DRIVER); + if (defaultVifDriverName == null) { + if (_bridgeType == BridgeType.OPENVSWITCH) { + s_logger.info("No libvirt.vif.driver specified. Defaults to OvsVifDriver."); + defaultVifDriverName = DEFAULT_OVS_VIF_DRIVER_CLASS_NAME; + } else { + s_logger.info("No libvirt.vif.driver specified. Defaults to BridgeVifDriver."); + defaultVifDriverName = DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME; + } + } + _defaultVifDriver = getVifDriverClass(defaultVifDriverName, params); + + // Load any per-traffic-type vif drivers + for (Map.Entry entry : params.entrySet()) + { + String k = entry.getKey(); + String vifDriverPrefix = LIBVIRT_VIF_DRIVER + "."; + + if(k.startsWith(vifDriverPrefix)){ + // Get trafficType + String trafficTypeSuffix = k.substring(vifDriverPrefix.length()); + + // Does this suffix match a real traffic type? + TrafficType trafficType = TrafficType.getTrafficType(trafficTypeSuffix); + if(!trafficType.equals(TrafficType.None)){ + // Get vif driver class name + String vifDriverClassName = (String) entry.getValue(); + // if value is null, ignore + if(vifDriverClassName != null){ + // add traffic type to vif driver mapping to Map + _trafficTypeVifDrivers.put(trafficType, + getVifDriverClass(vifDriverClassName, params)); + } + } + } + } + } + + protected VifDriver getVifDriverClass(String vifDriverClassName, Map params) + throws ConfigurationException { + VifDriver vifDriver; + try { - Class clazz = Class.forName(vifDriverName); - _vifDriver = (VifDriver) clazz.newInstance(); - _vifDriver.configure(params); + Class clazz = Class.forName(vifDriverClassName); + vifDriver = (VifDriver) clazz.newInstance(); + vifDriver.configure(params); } catch (ClassNotFoundException e) { throw new ConfigurationException("Unable to find class for libvirt.vif.driver " + e); } catch (InstantiationException e) { @@ -800,8 +848,28 @@ ServerResource { } catch (Exception e) { throw new ConfigurationException("Failed to initialize libvirt.vif.driver " + e); } + return vifDriver; + } - return true; + protected VifDriver getVifDriver(TrafficType trafficType){ + VifDriver vifDriver = _trafficTypeVifDrivers.get(trafficType); + + if(vifDriver == null){ + vifDriver = _defaultVifDriver; + } + + return vifDriver; + } + + protected List getAllVifDrivers(){ + Set vifDrivers = new HashSet(); + + vifDrivers.add(_defaultVifDriver); + vifDrivers.addAll(_trafficTypeVifDrivers.values()); + + ArrayList vifDriverList = new ArrayList(vifDrivers); + + return vifDriverList; } private void getPifs() { @@ -1443,7 +1511,7 @@ ServerResource { } Domain vm = getDomain(conn, vmName); - vm.attachDevice(_vifDriver.plug(nicTO, "Other PV (32-bit)").toString()); + vm.attachDevice(getVifDriver(nicTO.getType()).plug(nicTO, "Other PV (32-bit)").toString()); } private PlugNicAnswer execute(PlugNicCommand cmd) { @@ -1462,7 +1530,7 @@ ServerResource { } nicnum++; } - vm.attachDevice(_vifDriver.plug(nic, "Other PV (32-bit)").toString()); + vm.attachDevice(getVifDriver(nic.getType()).plug(nic, "Other PV (32-bit)").toString()); return new PlugNicAnswer(cmd, true, "success"); } catch (Exception e) { String msg = " Plug Nic failed due to " + e.toString(); @@ -2560,7 +2628,11 @@ ServerResource { } else { destroy_network_rules_for_vm(conn, vmName); for (InterfaceDef iface : ifaces) { - _vifDriver.unplug(iface); + // We don't know which "traffic type" is associated with + // each interface at this point, so inform all vif drivers + for(VifDriver vifDriver : getAllVifDrivers()){ + vifDriver.unplug(iface); + } } cleanupVM(conn, vmName, getVnetId(VirtualMachineName.getVnet(vmName))); @@ -2580,7 +2652,7 @@ ServerResource { try { Connect conn = LibvirtConnection.getConnection(); for (NicTO nic : nics) { - _vifDriver.plug(nic, null); + getVifDriver(nic.getType()).plug(nic, null); } /* setup disks, e.g for iso */ @@ -2794,7 +2866,11 @@ ServerResource { } } for (InterfaceDef iface: ifaces) { - _vifDriver.unplug(iface); + // We don't know which "traffic type" is associated with + // each interface at this point, so inform all vif drivers + for(VifDriver vifDriver : getAllVifDrivers()){ + vifDriver.unplug(iface); + } } } @@ -3231,7 +3307,7 @@ ServerResource { private void createVif(LibvirtVMDef vm, NicTO nic) throws InternalErrorException, LibvirtException { vm.getDevices().addDevice( - _vifDriver.plug(nic, vm.getGuestOSType()).toString()); + getVifDriver(nic.getType()).plug(nic, vm.getGuestOSType()).toString()); } protected CheckSshAnswer execute(CheckSshCommand cmd) { diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVifDriverTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVifDriverTest.java new file mode 100644 index 00000000000..7d47e6e81de --- /dev/null +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVifDriverTest.java @@ -0,0 +1,226 @@ +/* + * 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.kvm.resource; + +import com.cloud.network.Networks.TrafficType; +import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource.BridgeType; + +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.HashMap; +import java.util.Map; +import javax.naming.ConfigurationException; + + +import static org.mockito.Mockito.*; + +public class LibvirtVifDriverTest { + private LibvirtComputingResource res; + + private Map assertions; + + final String LIBVIRT_VIF_DRIVER = "libvirt.vif.driver"; + final String FAKE_VIF_DRIVER_CLASS_NAME = "com.cloud.hypervisor.kvm.resource.FakeVifDriver"; + final String NONEXISTENT_VIF_DRIVER_CLASS_NAME = "com.cloud.hypervisor.kvm.resource.NonExistentVifDriver"; + + private VifDriver fakeVifDriver, bridgeVifDriver, ovsVifDriver; + + @Before + public void setUp() { + // Use a spy because we only want to override getVifDriverClass + LibvirtComputingResource resReal = new LibvirtComputingResource(); + res = spy(resReal); + + try{ + bridgeVifDriver = + (VifDriver) Class.forName(LibvirtComputingResource.DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME).newInstance(); + ovsVifDriver = + (VifDriver) Class.forName(LibvirtComputingResource.DEFAULT_OVS_VIF_DRIVER_CLASS_NAME).newInstance(); + + // Instantiating bridge vif driver again as the fake vif driver + // is good enough, as this is a separate instance + fakeVifDriver = + (VifDriver) Class.forName(LibvirtComputingResource.DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME).newInstance(); + + doReturn(bridgeVifDriver).when(res) + .getVifDriverClass(eq(LibvirtComputingResource.DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME), anyMap()); + doReturn(ovsVifDriver).when(res) + .getVifDriverClass(eq(LibvirtComputingResource.DEFAULT_OVS_VIF_DRIVER_CLASS_NAME), anyMap()); + doReturn(fakeVifDriver).when(res) + .getVifDriverClass(eq(FAKE_VIF_DRIVER_CLASS_NAME), anyMap()); + + } catch (final ConfigurationException ex){ + fail("Unexpected ConfigurationException while configuring VIF drivers: " + ex.getMessage()); + } catch (final Exception ex){ + fail("Unexpected Exception while configuring VIF drivers"); + } + + assertions = new HashMap(); + } + + + // Helper function + // Configure LibvirtComputingResource using params + private void configure (Map params) + throws ConfigurationException{ + res.configureVifDrivers(params); + } + + // Helper function + private void checkAssertions(){ + // Check the defined assertions + for (Map.Entry assertion : assertions.entrySet()){ + assertEquals(res.getVifDriver(assertion.getKey()), + assertion.getValue()); + } + } + + // Helper when all answers should be the same + private void checkAllSame(VifDriver vifDriver) + throws ConfigurationException { + + for(TrafficType trafficType : TrafficType.values()){ + assertions.put(trafficType, vifDriver); + } + + checkAssertions(); + } + + @Test + public void testDefaults() + throws ConfigurationException { + // If no special vif driver settings, all traffic types should + // map to the default vif driver for the bridge type + Map params = new HashMap(); + + res._bridgeType = BridgeType.NATIVE; + configure(params); + checkAllSame(bridgeVifDriver); + + res._bridgeType = BridgeType.OPENVSWITCH; + configure(params); + checkAllSame(ovsVifDriver); + } + + @Test + public void testDefaultsWhenExplicitlySet() + throws ConfigurationException { + + Map params = new HashMap(); + + // Switch res' bridge type for test purposes + params.put(LIBVIRT_VIF_DRIVER, LibvirtComputingResource.DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.NATIVE; + configure(params); + checkAllSame(bridgeVifDriver); + + params.clear(); + params.put(LIBVIRT_VIF_DRIVER, LibvirtComputingResource.DEFAULT_OVS_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.OPENVSWITCH; + configure(params); + checkAllSame(ovsVifDriver); + } + + @Test + public void testWhenExplicitlySetDifferentDefault() + throws ConfigurationException { + + // Tests when explicitly set vif driver to OVS when using regular bridges and vice versa + Map params = new HashMap(); + + // Switch res' bridge type for test purposes + params.put(LIBVIRT_VIF_DRIVER, LibvirtComputingResource.DEFAULT_OVS_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.NATIVE; + configure(params); + checkAllSame(ovsVifDriver); + + params.clear(); + params.put(LIBVIRT_VIF_DRIVER, LibvirtComputingResource.DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.OPENVSWITCH; + configure(params); + checkAllSame(bridgeVifDriver); + } + + @Test + public void testOverrideSomeTrafficTypes() + throws ConfigurationException { + + Map params = new HashMap(); + params.put(LIBVIRT_VIF_DRIVER + "." + "Public", FAKE_VIF_DRIVER_CLASS_NAME); + params.put(LIBVIRT_VIF_DRIVER + "." + "Guest", + LibvirtComputingResource.DEFAULT_OVS_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.NATIVE; + configure(params); + + // Initially, set all traffic types to use default + for(TrafficType trafficType : TrafficType.values()){ + assertions.put(trafficType, bridgeVifDriver); + } + + assertions.put(TrafficType.Public, fakeVifDriver); + assertions.put(TrafficType.Guest, ovsVifDriver); + + checkAssertions(); + } + + @Test + public void testBadTrafficType() + throws ConfigurationException { + Map params = new HashMap(); + params.put(LIBVIRT_VIF_DRIVER + "." + "NonExistentTrafficType", FAKE_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.NATIVE; + configure(params); + + // Set all traffic types to use default, because bad traffic type should be ignored + for(TrafficType trafficType : TrafficType.values()){ + assertions.put(trafficType, bridgeVifDriver); + } + + checkAssertions(); + } + + @Test + public void testEmptyTrafficType() + throws ConfigurationException { + Map params = new HashMap(); + params.put(LIBVIRT_VIF_DRIVER + ".", FAKE_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.NATIVE; + configure(params); + + // Set all traffic types to use default, because bad traffic type should be ignored + for(TrafficType trafficType : TrafficType.values()){ + assertions.put(trafficType, bridgeVifDriver); + } + + checkAssertions(); + } + + @Test(expected=ConfigurationException.class) + public void testBadVifDriverClassName() + throws ConfigurationException { + Map params = new HashMap(); + params.put(LIBVIRT_VIF_DRIVER + "." + "Public", NONEXISTENT_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.NATIVE; + configure(params); + } +} From d922f6fd4b41d939ee00c55638d8c5e8b56c8b77 Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Sat, 2 Mar 2013 21:04:54 +0100 Subject: [PATCH 18/21] CLOUDSTACK-1304 Set permissions using the chmod ant task --- client/pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/pom.xml b/client/pom.xml index e82660b8704..cda6ab8b4e7 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -271,6 +271,10 @@ + + + + From 8ae800193379f3494d56baf3c5d26c6a10624c25 Mon Sep 17 00:00:00 2001 From: Edison Su Date: Mon, 4 Mar 2013 14:11:09 -0800 Subject: [PATCH 19/21] CLOUDSTACK-1498: even we put the db encryption check at the wrong place, but seems it breaks other people's task, so add it back --- utils/src/com/cloud/utils/db/Transaction.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/src/com/cloud/utils/db/Transaction.java b/utils/src/com/cloud/utils/db/Transaction.java index c15104455c0..9113aca4b25 100755 --- a/utils/src/com/cloud/utils/db/Transaction.java +++ b/utils/src/com/cloud/utils/db/Transaction.java @@ -97,8 +97,8 @@ public class Transaction { /* FIXME: We need a better solution for this * Initialize encryption if we need it for db.properties */ - /*EncryptionSecretKeyChecker enc = new EncryptionSecretKeyChecker(); - enc.check(); */ + EncryptionSecretKeyChecker enc = new EncryptionSecretKeyChecker(); + enc.check(); } private final LinkedList _stack; From 48aa035a71aab534f6c736017c6faed8cedcd23e Mon Sep 17 00:00:00 2001 From: Min Chen Date: Mon, 4 Mar 2013 13:43:49 -0800 Subject: [PATCH 20/21] CLOUDSTACK-1449: listAccounts and listProjectAccounts API lists all the users not account-specific users for each account returned. --- .../com/cloud/api/query/dao/UserAccountJoinDaoImpl.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/server/src/com/cloud/api/query/dao/UserAccountJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/UserAccountJoinDaoImpl.java index 1bb3981cd72..7072324080d 100644 --- a/server/src/com/cloud/api/query/dao/UserAccountJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/UserAccountJoinDaoImpl.java @@ -22,22 +22,17 @@ import javax.ejb.Local; import org.apache.log4j.Logger; -import com.cloud.api.ApiDBUtils; -import com.cloud.api.ApiResponseHelper; -import com.cloud.api.query.vo.InstanceGroupJoinVO; + import com.cloud.api.query.vo.UserAccountJoinVO; -import org.apache.cloudstack.api.response.InstanceGroupResponse; import org.apache.cloudstack.api.response.UserResponse; import org.springframework.stereotype.Component; -import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.user.UserAccount; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.vm.InstanceGroup; @Component @@ -58,7 +53,7 @@ public class UserAccountJoinDaoImpl extends GenericDaoBase Date: Mon, 4 Mar 2013 16:15:16 -0800 Subject: [PATCH 21/21] CLOUDSTACK-1502 Fixed the api-doc build component caused by new API commands: addIpToNic removeIpFromNic listNics 1) Removed trailing whitespaces from commands.properties file for the commands above 2) Created a new category "Nic" in gen_toc.py for the new commands --- client/tomcatconf/commands.properties.in | 6 +++--- tools/apidoc/gen_toc.py | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index bbb3d3078ec..dd0c3f894fd 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -327,9 +327,9 @@ removeNicFromVirtualMachine=15 updateDefaultNicForVirtualMachine=15 #### -addIpToNic=15; -removeIpFromNic=15; -listNics=15; +addIpToNic=15 +removeIpFromNic=15 +listNics=15 #### SSH key pair commands registerSSHKeyPair=15 diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index 2fd855d75ad..6292c536a9d 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -132,6 +132,9 @@ known_categories = { 'Condition': 'AutoScale', 'Api': 'API Discovery', 'Region': 'Region', + 'addIpToNic': 'Nic', + 'removeIpFromNic': 'Nic', + 'listNics':'Nic', }