From af28ded904045734d83cac4c4fe711e5e1315a5b Mon Sep 17 00:00:00 2001 From: Priti Sarap Date: Fri, 7 Aug 2015 17:57:54 +0530 Subject: [PATCH 001/203] CLOUDSTACK-8717: Failed to start instance after restoring the running instance --- .../testpaths/testpath_restore_vm.py | 201 ++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 test/integration/testpaths/testpath_restore_vm.py diff --git a/test/integration/testpaths/testpath_restore_vm.py b/test/integration/testpaths/testpath_restore_vm.py new file mode 100644 index 0000000000..7fd1610dcc --- /dev/null +++ b/test/integration/testpaths/testpath_restore_vm.py @@ -0,0 +1,201 @@ +# 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. + +""" +Test restore running VM on VMWare with one cluster having 2 Primary Storage +""" + + +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.lib.utils import cleanup_resources +from marvin.lib.base import (Account, + ServiceOffering, + VirtualMachine, + StoragePool + ) +from marvin.lib.common import (get_domain, + get_zone, + get_template, + list_volumes, + list_virtual_machines + ) + +from marvin.codes import CLUSTERTAG1, ROOT +import time + + +class TestRestoreVM(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + testClient = super(TestRestoreVM, cls).getClsTestClient() + cls.apiclient = testClient.getApiClient() + cls.testdata = testClient.getParsedTestDataConfig() + cls.hypervisor = cls.testClient.getHypervisorInfo() + + # Get Zone, Domain and templates + cls.domain = get_domain(cls.apiclient) + cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) + + cls.template = get_template( + cls.apiclient, + cls.zone.id, + cls.testdata["ostype"]) + + cls._cleanup = [] + + try: + cls.skiptest = False + if cls.hypervisor.lower() not in ["vmware"]: + cls.skiptest = True + return + + # Create an account + cls.account = Account.create( + cls.apiclient, + cls.testdata["account"], + domainid=cls.domain.id + ) + cls._cleanup.append(cls.account) + # Create user api client of the account + cls.userapiclient = testClient.getUserApiClient( + UserName=cls.account.name, + DomainName=cls.account.domain + ) + # Create Service offering + cls.service_offering_cwps = ServiceOffering.create( + cls.apiclient, + cls.testdata["service_offering"], + tags=CLUSTERTAG1 + ) + cls._cleanup.append(cls.service_offering_cwps) + except Exception as e: + cls.tearDownClass() + raise e + return + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.apiclient, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + def setUp(self): + + self.cleanup = [] + if self.skiptest: + self.skipTest("This test is to be checked on VMWare only \ + Hence, skip for %s" % self.hypervisor) + + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + + def tearDown(self): + try: + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["advanced", "basic"], required_hardware="true") + def test_01_recover_VM(self): + """ Test Restore VM on VMWare + 1. Deploy a VM without datadisk + 2. Restore the VM + 3. Verify that VM comes up in Running state + """ + try: + self.pools = StoragePool.list( + self.apiclient, + zoneid=self.zone.id, + scope="CLUSTER") + + if len(self.pools) < 2: + self.skipTest("There must be at atleast two cluster wide\ + storage pools available in the setup") + + except Exception as e: + self.skipTest(e) + + # Adding tags to Storage Pools + cluster_no = 1 + self.debug("Storage Pools: %s" % self.pools) + for storagePool in self.pools: + if storagePool.scope == "CLUSTER": + StoragePool.update( + self.apiclient, + id=storagePool.id, + tags=[CLUSTERTAG1[:-1] + repr(cluster_no)]) + cluster_no += 1 + + self.vm = VirtualMachine.create( + self.apiclient, + self.testdata["small"], + accountid=self.account.name, + templateid=self.template.id, + domainid=self.account.domainid, + serviceofferingid=self.service_offering_cwps.id, + zoneid=self.zone.id, + ) + # Step 2 + + volumes_root_list = list_volumes( + self.apiclient, + virtualmachineid=self.vm.id, + type=ROOT, + listall=True + ) + + root_volume = volumes_root_list[0] + + # Restore VM till its ROOT disk is recreated on onother Primary Storage + while True: + self.vm.restore(self.apiclient) + volumes_root_list = list_volumes( + self.apiclient, + virtualmachineid=self.vm.id, + type=ROOT, + listall=True + ) + + root_volume = volumes_root_list[0] + + if root_volume.storage != self.pools[0].name: + break + + # Step 3 + vm_list = list_virtual_machines( + self.apiclient, + id=self.vm.id) + + state = vm_list[0].state + i = 0 + while(state != "Running"): + vm_list = list_virtual_machines( + self.apiclient, + id=self.vm.id) + + time.sleep(10) + i = i + 1 + state = vm_list[0].state + if i >= 10: + self.fail("Restore VM Failed") + break + + return From 4bbf151eb7d39d0ab535a3a7c45d95af71cbd689 Mon Sep 17 00:00:00 2001 From: Priti Sarap Date: Wed, 12 Aug 2015 12:50:56 +0530 Subject: [PATCH 002/203] CLOUDSTACK-8717: Failed to start instance after restoring the running instance -Modified code to add tag to aonly one cluster wide SP -Added validateList function -Added code to clear tags in tearDown class --- .../testpaths/testpath_restore_vm.py | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/test/integration/testpaths/testpath_restore_vm.py b/test/integration/testpaths/testpath_restore_vm.py index 7fd1610dcc..d73499ad21 100644 --- a/test/integration/testpaths/testpath_restore_vm.py +++ b/test/integration/testpaths/testpath_restore_vm.py @@ -22,7 +22,7 @@ from nose.plugins.attrib import attr from marvin.cloudstackTestCase import cloudstackTestCase -from marvin.lib.utils import cleanup_resources +from marvin.lib.utils import cleanup_resources, validateList from marvin.lib.base import (Account, ServiceOffering, VirtualMachine, @@ -35,7 +35,7 @@ list_virtual_machines ) -from marvin.codes import CLUSTERTAG1, ROOT +from marvin.codes import CLUSTERTAG1, ROOT, PASS import time @@ -108,6 +108,12 @@ def setUp(self): def tearDown(self): try: + if self.pools: + StoragePool.update( + self.apiclient, + id=self.pools[0].id, + tags="") + cleanup_resources(self.apiclient, self.cleanup) except Exception as e: raise Exception("Warning: Exception during cleanup : %s" % e) @@ -126,6 +132,14 @@ def test_01_recover_VM(self): zoneid=self.zone.id, scope="CLUSTER") + status = validateList(self.pools) + + # Step 3 + self.assertEqual( + status[0], + PASS, + "Check: Failed to list cluster wide storage pools") + if len(self.pools) < 2: self.skipTest("There must be at atleast two cluster wide\ storage pools available in the setup") @@ -135,14 +149,10 @@ def test_01_recover_VM(self): # Adding tags to Storage Pools cluster_no = 1 - self.debug("Storage Pools: %s" % self.pools) - for storagePool in self.pools: - if storagePool.scope == "CLUSTER": - StoragePool.update( - self.apiclient, - id=storagePool.id, - tags=[CLUSTERTAG1[:-1] + repr(cluster_no)]) - cluster_no += 1 + StoragePool.update( + self.apiclient, + id=self.pools[0].id, + tags=[CLUSTERTAG1[:-1] + repr(cluster_no)]) self.vm = VirtualMachine.create( self.apiclient, From c3777632c5817cc1e635ee59eb18d6cb4f210e29 Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Tue, 15 Sep 2015 16:22:06 +0530 Subject: [PATCH 003/203] CLOUDSTACK-8858: listVolumes API fails for a particular domain with NPE. Summary: listVolumes API fails when volume associated vm instance has NULL or invalid state. Fix the code to guard this situation since this should not block volume listing. --- .../cloud/api/query/dao/VolumeJoinDaoImpl.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java index 68a578fd21..7540d247a4 100644 --- a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java @@ -83,14 +83,18 @@ public VolumeResponse newVolumeResponse(ResponseView view, VolumeJoinVO volume) volResponse.setZoneId(volume.getDataCenterUuid()); volResponse.setZoneName(volume.getDataCenterName()); - volResponse.setVolumeType(volume.getVolumeType().toString()); + if (volume.getVolumeType() != null) { + volResponse.setVolumeType(volume.getVolumeType().toString()); + } volResponse.setDeviceId(volume.getDeviceId()); long instanceId = volume.getVmId(); if (instanceId > 0 && volume.getState() != Volume.State.Destroy) { volResponse.setVirtualMachineId(volume.getVmUuid()); volResponse.setVirtualMachineName(volume.getVmName()); - volResponse.setVirtualMachineState(volume.getVmState().toString()); + if (volume.getVmState() != null) { + volResponse.setVirtualMachineState(volume.getVmState().toString()); + } if (volume.getVmDisplayName() != null) { volResponse.setVirtualMachineDisplayName(volume.getVmDisplayName()); } else { @@ -98,7 +102,9 @@ public VolumeResponse newVolumeResponse(ResponseView view, VolumeJoinVO volume) } } - volResponse.setProvisioningType(volume.getProvisioningType().toString()); + if (volume.getProvisioningType() != null) { + volResponse.setProvisioningType(volume.getProvisioningType().toString()); + } // Show the virtual size of the volume volResponse.setSize(volume.getSize()); @@ -107,7 +113,9 @@ public VolumeResponse newVolumeResponse(ResponseView view, VolumeJoinVO volume) volResponse.setMaxIops(volume.getMaxIops()); volResponse.setCreated(volume.getCreated()); - volResponse.setState(volume.getState().toString()); + if (volume.getState() != null) { + volResponse.setState(volume.getState().toString()); + } if (volume.getState() == Volume.State.UploadOp) { // com.cloud.storage.VolumeHostVO volumeHostRef = // ApiDBUtils.findVolumeHostRef(volume.getId(), From 7d83ca9e0aea4744474f62a3a3ccee4b5fa8090d Mon Sep 17 00:00:00 2001 From: subhash yedugundla Date: Tue, 15 Sep 2015 19:25:41 +0530 Subject: [PATCH 004/203] CLOUDSTACK-8850: revertSnapshot command does not work Updating the documentation before the api is actually supported --- .../cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java index b8fbb02ad2..7f40c578f5 100644 --- a/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java @@ -36,7 +36,7 @@ import com.cloud.storage.Snapshot; import com.cloud.user.Account; -@APICommand(name = "revertSnapshot", description = "revert a volume snapshot.", responseObject = SnapshotResponse.class, entityType = {Snapshot.class}, +@APICommand(name = "revertSnapshot", description = "This is supposed to revert a volume snapshot. This command is not supported in this release", responseObject = SnapshotResponse.class, entityType = {Snapshot.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class RevertSnapshotCmd extends BaseAsyncCmd { public static final Logger s_logger = Logger.getLogger(RevertSnapshotCmd.class.getName()); From f2d4820773cf62b430889b39d67336cbd61ec378 Mon Sep 17 00:00:00 2001 From: subhash yedugundla Date: Wed, 16 Sep 2015 09:45:10 +0530 Subject: [PATCH 005/203] Updating the Description as only supported with KVM --- .../cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java index 7f40c578f5..4708aff6ff 100644 --- a/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java @@ -36,7 +36,7 @@ import com.cloud.storage.Snapshot; import com.cloud.user.Account; -@APICommand(name = "revertSnapshot", description = "This is supposed to revert a volume snapshot. This command is not supported in this release", responseObject = SnapshotResponse.class, entityType = {Snapshot.class}, +@APICommand(name = "revertSnapshot", description = "This is supposed to revert a volume snapshot. This command is only supported with KVM so far", responseObject = SnapshotResponse.class, entityType = {Snapshot.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class RevertSnapshotCmd extends BaseAsyncCmd { public static final Logger s_logger = Logger.getLogger(RevertSnapshotCmd.class.getName()); From e13352928940792df255995aa1e9069322906978 Mon Sep 17 00:00:00 2001 From: Priti Sarap Date: Tue, 22 Sep 2015 13:11:44 +0530 Subject: [PATCH 006/203] CLOUDSTACK-8895: Verify if storage can be selected when attaching uploaded data volume to VM --- .../testpaths/testpath_attach_disk_zwps.py | 188 +++++++++++++++++- 1 file changed, 187 insertions(+), 1 deletion(-) diff --git a/test/integration/testpaths/testpath_attach_disk_zwps.py b/test/integration/testpaths/testpath_attach_disk_zwps.py index d386438310..1f1e0735ea 100644 --- a/test/integration/testpaths/testpath_attach_disk_zwps.py +++ b/test/integration/testpaths/testpath_attach_disk_zwps.py @@ -34,7 +34,8 @@ ) from marvin.codes import (PASS, - ZONETAG1) + ZONETAG1, + CLUSTERTAG1) class TestAttachDataDisk(cloudstackTestCase): @@ -207,3 +208,188 @@ def test_01_attach_datadisk_to_vm_on_zwps(self): "Check: Data if Disk is attached to VM") return + + +class TestAttachDataDiskOnCWPS(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + testClient = super(TestAttachDataDiskOnCWPS, cls).getClsTestClient() + cls.apiclient = testClient.getApiClient() + cls.testdata = testClient.getParsedTestDataConfig() + cls.hypervisor = cls.testClient.getHypervisorInfo() + + # Get Zone, Domain and templates + cls.domain = get_domain(cls.apiclient) + cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) + cls._cleanup = [] + cls.template = get_template( + cls.apiclient, + cls.zone.id, + cls.testdata["ostype"]) + cls.skiptest = False + + try: + cls.pools = StoragePool.list( + cls.apiclient, + zoneid=cls.zone.id, + scope="CLUSTER") + except Exception as e: + cls.skiptest = True + return + try: + + # Create an account + cls.account = Account.create( + cls.apiclient, + cls.testdata["account"], + domainid=cls.domain.id + ) + cls._cleanup.append(cls.account) + + # Create user api client of the account + cls.userapiclient = testClient.getUserApiClient( + UserName=cls.account.name, + DomainName=cls.account.domain + ) + # Create Service offering + cls.service_offering = ServiceOffering.create( + cls.apiclient, + cls.testdata["service_offering"], + ) + cls._cleanup.append(cls.service_offering) + + # Create Disk offering + cls.disk_offering = DiskOffering.create( + cls.apiclient, + cls.testdata["disk_offering"], + custom=True, + tags=CLUSTERTAG1, + ) + + cls._cleanup.append(cls.disk_offering) + + except Exception as e: + cls.tearDownClass() + raise e + return + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.apiclient, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + try: + for storagePool in self.pools: + StoragePool.update(self.apiclient, id=storagePool.id, tags="") + + if hasattr(self, "data_volume_created"): + data_volumes_list = Volume.list( + self.userapiclient, + id=self.data_volume_created.id, + virtualmachineid=self.vm.id + ) + if data_volumes_list: + self.vm.detach_volume( + self.userapiclient, + data_volumes_list[0] + ) + + status = validateList(data_volumes_list) + self.assertEqual( + status[0], + PASS, + "DATA Volume List Validation Failed") + + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["basic", "advanced"], required_hardware="true") + def test_01_attach_datadisk_to_vm_on_zwps(self): + """ Attach Data Disk on CWPS To VM + 1. Check if zwps storage pool exists. + 2. Adding tag to zone wide primary storage + 3. Launch a VM + 4. Attach data disk to vm. + 5. Verify disk is attached and in correct storage pool. + """ + + # Step 1 + if len(list(self.pools)) < 1: + self.skipTest("There must be at least one zone wide \ + storage pools available in the setup") + + # Step 2 + # Adding tags to Storage Pools + StoragePool.update( + self.apiclient, + id=self.pools[0].id, + tags=[CLUSTERTAG1]) + + # Launch VM + self.vm = VirtualMachine.create( + self.apiclient, + self.testdata["small"], + templateid=self.template.id, + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering_zone1.id, + zoneid=self.zone.id + ) + + self.testdata["volume"]["zoneid"] = self.zone.id + self.testdata["volume"]["customdisksize"] = 1 + self.data_volume_created = Volume.create_custom_disk( + self.userapiclient, + self.testdata["volume"], + account=self.account.name, + domainid=self.account.domainid, + diskofferingid=self.disk_offering.id, + ) + + self.cleanup.append(self.data_volume_created) + + # Step 4 + self.vm.attach_volume( + self.userapiclient, + self.data_volume_created + ) + + data_volumes_list = Volume.list( + self.userapiclient, + virtualmachineid=self.vm.id, + type="DATA", + listall=True + ) + + self.debug("list volumes using vm id %s" % dir(data_volumes_list[0])) + + data_volumes_list = Volume.list(self.apiclient, + id=self.data_volume_created.id, + listall=True) + data_volume = data_volumes_list[0] + status = validateList(data_volume) + # Step 5 + self.assertEqual( + status[0], + PASS, + "Check: volume list is valid") + + self.assertEqual( + data_volume.state, + "Ready", + "Check: Data volume is attached to VM") + + if data_volume.storage != self.pools[0].name: + self.fail("check if volume is created in correct storage pool") + return From 775ebc6ece557cc86ff11a8580a44d4d7cd17b9a Mon Sep 17 00:00:00 2001 From: Priti Sarap Date: Wed, 12 Aug 2015 17:28:04 +0530 Subject: [PATCH 007/203] CLOUDSTACK-8728: Testcase to Verify if VRs IP changes if it is destroyed and re created in Basic Zone -Merging the testcase in exsiting testcase by adding support for basic zone -Merging two commits into single commit --- test/integration/smoke/test_routers.py | 53 +++++++++++++++++++------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/test/integration/smoke/test_routers.py b/test/integration/smoke/test_routers.py index 4478c7b8a8..c6aa4960db 100644 --- a/test/integration/smoke/test_routers.py +++ b/test/integration/smoke/test_routers.py @@ -313,7 +313,14 @@ def test_02_router_internal_adv(self): self.debug("Haproxy process status: %s" % res) return - @attr(tags=["advanced", "advancedns", "smoke", "dvs"], required_hardware="false") + @attr( + tags=[ + "advanced", + "basic", + "advancedns", + "smoke", + "dvs"], + required_hardware="false") def test_03_restart_network_cleanup(self): """Test restart network """ @@ -323,20 +330,30 @@ def test_03_restart_network_cleanup(self): # 2. New router should have the same public IP # Find router associated with user account - list_router_response = list_routers( - self.apiclient, - account=self.account.name, - domainid=self.account.domainid - ) + if self.zone.networktype.lower() == "basic": + list_router_response = list_routers( + self.apiclient, + listall="true" + ) + else: + list_router_response = list_routers( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid + ) self.assertEqual( isinstance(list_router_response, list), True, "Check list response returns a valid list" ) + router = list_router_response[0] # Store old values before restart - old_publicip = router.publicip + if self.zone.networktype.lower == "basic": + old_publicip = router.guestipaddress + else: + old_publicip = router.publicip timeout = 10 # Network should be in Implemented or Setup stage before restart @@ -371,11 +388,17 @@ def test_03_restart_network_cleanup(self): self.apiclient.restartNetwork(cmd) # Get router details after restart - list_router_response = list_routers( - self.apiclient, - account=self.account.name, - domainid=self.account.domainid - ) + if self.zone.networktype.lower() == "basic": + list_router_response = list_routers( + self.apiclient, + listall="true" + ) + else: + list_router_response = list_routers( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid + ) self.assertEqual( isinstance(list_router_response, list), True, @@ -383,8 +406,12 @@ def test_03_restart_network_cleanup(self): ) router = list_router_response[0] + if self.zone.networktype.lower() == "basic": + new_publicip = router.guestipaddress + else: + new_publicip = router.publicip self.assertEqual( - router.publicip, + new_publicip, old_publicip, "Public IP of the router should remain same after network restart" ) From 95355960746fbe1bdc649a483bff250b115ee7e7 Mon Sep 17 00:00:00 2001 From: shweta agarwal Date: Fri, 30 Oct 2015 16:54:16 +0530 Subject: [PATCH 008/203] automation of cores feature test path corrected some entires in test data --- test/integration/component/test_coreos.py | 291 ++++++++++++++++++++++ tools/marvin/marvin/config/test_data.py | 13 + tools/marvin/marvin/lib/base.py | 8 +- 3 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 test/integration/component/test_coreos.py diff --git a/test/integration/component/test_coreos.py b/test/integration/component/test_coreos.py new file mode 100644 index 0000000000..ad1c1ab6b7 --- /dev/null +++ b/test/integration/component/test_coreos.py @@ -0,0 +1,291 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" P1 tests for coreos template and vm +""" + +from marvin.lib.base import ( + VirtualMachine, + ServiceOffering, + Account, + SSHKeyPair, + Host, Template) +from marvin.lib.common import ( + get_zone, + get_template, + list_routers) +from marvin.lib.utils import ( + cleanup_resources, + get_hypervisor_type, + get_process_status) +from marvin.cloudstackTestCase import cloudstackTestCase +# Import System modules +import tempfile +import time +import os +import base64 +from nose.plugins.attrib import attr +from marvin.sshClient import SshClient + + +class TestDeployVmWithCoreosTemplate(cloudstackTestCase): + """Tests for deploying VM using coreos template + """ + + @classmethod + def setUpClass(cls): + cls._cleanup = [] + cls.testClient = super( + TestDeployVmWithCoreosTemplate, + cls).getClsTestClient() + cls.api_client = cls.testClient.getApiClient() + cls.services = cls.testClient.getParsedTestDataConfig() + cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) + cls.service_offering = ServiceOffering.create( + cls.api_client, services=cls.services["service_offerings"]["medium"]) + cls.account = Account.create( + cls.api_client, services=cls.services["account"]) + cls.cleanup = [cls.account] + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls.services["coreos"][ + "hypervisor"] = cls.testClient.getHypervisorInfo() + cls.userdata = '#cloud-config\n\ncoreos:\n units:\n - name: docker.service\n command: start\n ' \ + '- name: web.service\n command: start\n content: |\n [Unit]\n ' \ + 'After=docker.service\n Requires=docker.service\n Description=Starts web server ' \ + 'container\n [Service]\n TimeoutStartSec=0\n ' \ + 'ExecStartPre=/usr/bin/docker pull httpd:2.4\n ' \ + 'ExecStart=/usr/bin/docker run -d -p 8000:80 httpd:2.4' + cls.services["virtual_machine"]["userdata"] = cls.userdata + + cls.keypair = SSHKeyPair.create( + cls.api_client, + name="coreos", + account=cls.account.name, + domainid=cls.account.domainid + ) + cls.debug("Created a new keypair with name: %s" % cls.keypair.name) + + cls.debug("Writing the private key to local file") + cls.keyPairFilePath = tempfile.gettempdir() + os.sep + cls.keypair.name + # Clenaup at end of execution + cls.cleanup.append(cls.keyPairFilePath) + + cls.debug("File path: %s" % cls.keyPairFilePath) + + f = open(cls.keyPairFilePath, "w+") + f.write(cls.keypair.privatekey) + f.close() + os.system("chmod 400 " + cls.keyPairFilePath) + cls.mgtSvrDetails = cls.config.__dict__["mgtSvr"][0].__dict__ + return + + def setUp(self): + self.api_client = self.testClient.getApiClient() + return + + def tearDown(self): + # Clean up, terminate the created volumes + cleanup_resources(self.api_client, self.cleanup) + return + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["advanced"], required_hardware="true") + def test1_coreos_VM_creation(self): + + self.hypervisor = str(get_hypervisor_type(self.api_client)).lower() + self.services["virtual_machine"][ + "hypervisor"] = self.hypervisor.upper() + if self.hypervisor == "vmware": + self.services["coreos"][ + "url"] = self.services["coreos"]["urlvmware"] + self.services["coreos"]["format"] = "OVA" + elif self.hypervisor == "xenserver": + self.services["coreos"][ + "url"] = self.services["coreos"]["urlxen"] + self.services["coreos"]["format"] = "VHD" + elif self.hypervisor == "kvm": + self.services["coreos"][ + "url"] = self.services["coreos"]["urlkvm"] + self.services["coreos"]["format"] = "QCOW2" + elif self.hypervisor == "hyperv": + self.services["coreos"][ + "url"] = self.services["coreos"]["urlxen"] + self.services["coreos"]["format"] = "VHD" + + template_created = Template.register( + self.api_client, + self.services["coreos"], + self.zone.id, + account=self.account.name, + domainid=self.account.domainid) + self.assertIsNotNone(template_created, "Template creation failed") + # Wait for template to download + template_created.download(self.api_client) + self.cleanup.append(template_created) + # Wait for template status to be changed across + time.sleep(self.services["sleep"]) + + self.debug("Deploying instance in the account: %s" % self.account.name) + + virtual_machine = VirtualMachine.create( + self.api_client, + self.services["virtual_machine"], + templateid=template_created.id, + accountid=self.account.name, + domainid=self.account.domainid, + zoneid=self.zone.id, + serviceofferingid=self.service_offering.id, + keypair=self.keypair.name, + hypervisor=self.hypervisor, + mode=self.zone.networktype, + method="POST" + + ) + + self.debug("Check if the VM is properly deployed or not?") + vms = VirtualMachine.list( + self.api_client, + id=virtual_machine.id, + listall=True + ) + self.assertEqual( + isinstance(vms, list), + True, + "List VMs should return the valid list" + ) + vm = vms[0] + self.assertEqual( + vm.state, + "Running", + "VM state should be running after deployment" + ) + virtual_machine.stop(self.api_client) + virtual_machine.update( + self.api_client, + userdata=base64.b64encode( + self.userdata)) + virtual_machine.start(self.api_client) + self.assertEqual( + vm.state, + "Running", + "VM state should be running" + ) + # Wait for docker service to start + time.sleep(300) + + # Should be able to SSH VM + try: + + self.debug("SSH into VM: %s" % virtual_machine.ssh_ip) + cmd = "docker ps" + ssh = SshClient(virtual_machine.ssh_ip, 22, "core", + "", keyPairFiles=self.keyPairFilePath) + result = ssh.execute(cmd) + + except Exception as e: + self.fail( + "SSH Access failed for %s: %s" % + (virtual_machine.ssh_ip, e) + ) + + res = str(result) + self.assertEqual( + res.__contains__("httpd"), + True, + "docker web service not started in coreos vm ") + + if self.zone.networktype == "Basic": + list_router_response = list_routers( + self.api_client, + listall="true" + ) + else: + list_router_response = list_routers( + self.api_Client, + account=self.account.name, + domainid=self.account.domainid + ) + + self.assertEqual( + isinstance(list_router_response, list), + True, + "Check list response returns a valid list" + ) + router = list_router_response[0] + hosts = Host.list(self.api_client, id=router.hostid) + self.assertEqual( + isinstance(hosts, list), + True, + "Check list host returns a valid list" + ) + host = hosts[0] + self.debug("Router ID: %s, state: %s" % (router.id, router.state)) + + self.assertEqual( + router.state, + 'Running', + "Check list router response for router state" + ) + cmd = "cat /var/www/html/userdata/" + virtual_machine.ipaddress + "/user-data" + + if self.hypervisor.lower() in ('vmware', 'hyperv'): + + try: + result = get_process_status( + self.api_client.connection.mgtSvr, + 22, + self.api_client.connection.user, + self.api_client.connection.passwd, + router.linklocalip, + cmd, + hypervisor=self.hypervisor + ) + + except KeyError: + self.skipTest( + "Marvin configuration has no host credentials to check USERDATA") + + else: + try: + result = get_process_status( + host.ipaddress, + 22, + self.services["configurableData"]["host"]["username"], + self.services["configurableData"]["host"]["password"], + router.linklocalip, cmd + ) + except KeyError: + self.skipTest( + "Marvin configuration has no host credentials to check router user data") + res = str(result) + self.assertEqual( + res.__contains__("name: docker.service"), + True, + "Userdata Not applied Check the failures") + + return diff --git a/tools/marvin/marvin/config/test_data.py b/tools/marvin/marvin/config/test_data.py index b7d2781e19..0a7c4d218b 100644 --- a/tools/marvin/marvin/config/test_data.py +++ b/tools/marvin/marvin/config/test_data.py @@ -784,6 +784,19 @@ "format": "OVA", "ispublic": "true" }, + "coreos": { + "displaytext": "coreos", + "name": "coreos", + "passwordenabled": False, + "ostype": "Coreos", + "urlvmware":"http://dl.openvm.eu/cloudstack/coreos/x86_64/" \ + "coreos_production_cloudstack_image-vmware.vmdk.bz2", + "urlxen":"http://dl.openvm.eu/cloudstack/coreos/x86_64/" + "coreos_production_cloudstack_image-xen.vhd.bz2", + "urlkvm": "http://dl.openvm.eu/cloudstack/coreos/x86_64/" \ + "coreos_production_cloudstack_image-kvm.qcow2.bz2", + "urlhyperv":"http://dl.openvm.eu/cloudstack/coreos/x86_64/coreos_production_cloudstack_image-hyperv.vhd.zip" + }, "template_2": { "displaytext": "Public Template", "name": "Public template", diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index fc49fd2dad..4695559ac6 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -551,7 +551,7 @@ def restore(self, apiclient, templateid=None): def get_ssh_client( self, ipaddress=None, reconnect=False, port=None, - keyPairFileLocation=None, retries=20): + keyPairFileLocation=None,username=None,password=None, retries=20): """Get SSH object of VM""" # If NAT Rules are not created while VM deployment in Advanced mode @@ -564,6 +564,12 @@ def get_ssh_client( if keyPairFileLocation is not None: self.password = None + if username is not None: + self.username=username + + if password is not None: + self.password=password + if reconnect: self.ssh_client = is_server_ssh_ready( self.ssh_ip, From 64ef4fa958878ceedfc8009804898f439cdeaf0f Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 6 Nov 2015 14:28:14 +0100 Subject: [PATCH 009/203] CLOUDSTACK-5822: keep user-added sshkeys in authorized_keys --- setup/bindir/cloud-set-guest-sshkey.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/bindir/cloud-set-guest-sshkey.in b/setup/bindir/cloud-set-guest-sshkey.in index 0472a7c006..03d57f5366 100755 --- a/setup/bindir/cloud-set-guest-sshkey.in +++ b/setup/bindir/cloud-set-guest-sshkey.in @@ -81,8 +81,8 @@ if [ ! -e $authorized ]; then chmod 600 $authorized fi -cat $authorized|grep -v "$publickey"|tee $authorized > /dev/null -echo "$publickey" >> $authorized +sed -i "/ cloudstack@apache.org$/d" $authorized +echo "$publickey cloudstack@apache.org" >> $authorized which restorecon && restorecon -R -v $sshdir From 635f7c272e7889cfaaa0af812d9b80d9a90f72a2 Mon Sep 17 00:00:00 2001 From: sadhu suresh Date: Mon, 9 Nov 2015 16:19:14 +0530 Subject: [PATCH 010/203] CLOUDSTACK-8731-checking usage event for delete volume --- .../component/test_persistent_networks.py | 114 +++++++++++++++++- 1 file changed, 112 insertions(+), 2 deletions(-) diff --git a/test/integration/component/test_persistent_networks.py b/test/integration/component/test_persistent_networks.py index ae18424511..f8beed019e 100644 --- a/test/integration/component/test_persistent_networks.py +++ b/test/integration/component/test_persistent_networks.py @@ -17,7 +17,7 @@ """ Tests for Persistent Networks without running VMs feature""" from marvin.lib.utils import (cleanup_resources, validateList, - get_hypervisor_type) + get_hypervisor_type, get_process_status) from marvin.lib.base import (Account, VPC, VirtualMachine, @@ -40,7 +40,7 @@ get_template, verifyNetworkState, add_netscaler, - wait_for_cleanup) + wait_for_cleanup,list_routers,list_hosts) from nose.plugins.attrib import attr from marvin.codes import PASS, FAIL, FAILED from marvin.sshClient import SshClient @@ -1459,6 +1459,116 @@ def test_delete_account(self): return + @attr(tags=["advanced"], required_hardware="true") + def test_volume_delete_event_errorState(self): + """ + @summary: Test volume delete event generation in error state condition + @Steps: + Step1: Create a network using network created in Step1 + Step2: Verifying that network creation is successful + Step3: Login to Virtual router and add iptable rule to block insertion of vm rules + Step6: deploy a vm using network created in step2 + Step7: check the Vm status for failure + Step8: destroy and expunge the vm + Step9: list the generated events for volume delete event. + """ + + # Listing all the networks available + + account = Account.create( + self.api_client, + self.services["account"], + domainid=self.domain.id) + network = Network.create( + self.apiclient, + self.services["isolated_network"], + networkofferingid=self.isolated_persistent_network_offering.id, + accountid=self.account.name, + domainid=self.domain.id, + zoneid=self.zone.id) + response = verifyNetworkState( + self.apiclient, + network.id, + "implemented") + exceptionOccured = response[0] + isNetworkInDesiredState = response[1] + exceptionMessage = response[2] + + if (exceptionOccured or (not isNetworkInDesiredState)): + self.fail(exceptionMessage) + self.assertIsNotNone( + network.vlan, + "vlan must not be null for persistent network") + try: + list_router_response = list_routers( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid + ) + + self.assertEqual(validateList(list_router_response)[0], PASS, "Check list response returns a valid list") + router = list_router_response[0] + + self.debug("Router ID: %s, state: %s" % (router.id, router.state)) + + self.assertEqual( + router.state, + 'Running', + "Check list router response for router state" + ) + self.hypervisor = self.testClient.getHypervisorInfo() + if self.hypervisor.lower() in ('vmware', 'hyperv'): + result = get_process_status( + self.apiclient.connection.mgtSvr, + 22, + self.apiclient.connection.user, + self.apiclient.connection.passwd, + router.linklocalip, + "iptables -I INPUT 1 -j DROP", + hypervisor=self.hypervisor + ) + else: + try: + hosts = list_hosts( + self.apiclient, + zoneid=router.zoneid, + type='Routing', + state='Up', + id=router.hostid + ) + self.assertEqual(validateList(hosts)[0],PASS,"Check list host returns a valid list") + host = hosts[0] + result = get_process_status( + host.ipaddress,22, self.services["acl"]["host"]["username"],self.services["acl"]["host"]["password"], router.linklocalip, + "iptables -I INPUT 1 -j DROP" + ) + except Exception as e: + raise Exception("Exception raised in accessing/running the command on hosts : %s " % e) + except Exception as e: + raise Exception("Exception raised in getting hostcredentials: %s " % e) + + with self.assertRaises(Exception) as context: + virtual_machine = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + networkids=[ + network.id], + serviceofferingid=self.service_offering.id, + accountid=self.account.name, + domainid=self.domain.id) + #self.assertTrue('This is broken' in context.exception) + try: + account.delete(self.api_client) + except Exception as e: + self.cleanup.append(account) + qresultset = self.dbclient.execute( + "select id from usage_event where type = '%s' ORDER BY id DESC LIMIT 1;" % + str("VOLUME.DELETE")) + self.assertNotEqual( + len(qresultset), + 0, + "Check DB Query result set") + return @ddt class TestAssignVirtualMachine(cloudstackTestCase): From a8e60499fe7a895f03d875e27105e017fcc2e615 Mon Sep 17 00:00:00 2001 From: Priti Sarap Date: Tue, 17 Nov 2015 17:25:23 +0530 Subject: [PATCH 011/203] CLOUDSTACK-9066: Update testpath to delete account after deleting VMs of that account --- test/integration/testpaths/testpath_snapshot_hadrning.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/integration/testpaths/testpath_snapshot_hadrning.py b/test/integration/testpaths/testpath_snapshot_hadrning.py index 0b72a6aaf3..cb31f0f2fc 100755 --- a/test/integration/testpaths/testpath_snapshot_hadrning.py +++ b/test/integration/testpaths/testpath_snapshot_hadrning.py @@ -262,7 +262,6 @@ def setUpClass(cls): cls.testdata["account"], domainid=cls.domain.id ) - cls._cleanup.append(cls.account) # Create user api client of the account cls.userapiclient = testClient.getUserApiClient( @@ -327,6 +326,8 @@ def setUpClass(cls): mode=cls.zone.networktype ) cls._cleanup.append(cls.vm_ha) + + cls._cleanup.append(cls.account) cls.root_volume_ha = list_volumes( cls.userapiclient, virtualmachineid=cls.vm_ha.id, From 14c95b1871399d1988ff2fce50dab02e268bc765 Mon Sep 17 00:00:00 2001 From: Anshul Gangwar Date: Wed, 17 Jun 2015 10:55:07 +0530 Subject: [PATCH 012/203] CLOUDSTACK-9088: Update the description for migrateVirtualMachineWithVolume api. --- .../admin/vm/MigrateVirtualMachineWithVolumeCmd.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java index f1d3fe975f..32000c6364 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java @@ -75,7 +75,12 @@ public class MigrateVirtualMachineWithVolumeCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.MIGRATE_TO, type = CommandType.MAP, required = false, - description = "Map of pool to which each volume should be migrated (volume/pool pair)") + description = "Storage to pool mapping. This parameter specifies the mapping between a volume and a pool where you want to migrate that volume. Format of this " + + "parameter: migrateto[volume-index].volume=&migrateto[volume-index].pool=Where, [volume-index] indicates the index to identify the volume that you " + + "want to migrate, volume= indicates the UUID of the volume that you want to migrate, and pool= indicates the UUID of the pool where you want to " + + "migrate the volume. Example: migrateto[0].volume=<71f43cd6-69b0-4d3b-9fbc-67f50963d60b>&migrateto[0].pool=&" + + "migrateto[1].volume=<88de0173-55c0-4c1c-a269-83d0279eeedf>&migrateto[1].pool=<95d6e97c-6766-4d67-9a30-c449c15011d1>&migrateto[2].volume=" + + "<1b331390-59f2-4796-9993-bf11c6e76225>&migrateto[2].pool=<41fdb564-9d3b-447d-88ed-7628f7640cbc>") private Map migrateVolumeTo; ///////////////////////////////////////////////////// From 358115de151ababd45d31a743f71edadc8cfafae Mon Sep 17 00:00:00 2001 From: Priti Sarap Date: Fri, 27 Nov 2015 12:51:50 +0530 Subject: [PATCH 013/203] CLOUDSTACK-9091: Update testpath for parameter issues --- test/integration/testpaths/testpath_volume_snapshot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/testpaths/testpath_volume_snapshot.py b/test/integration/testpaths/testpath_volume_snapshot.py index 87c5fe4805..c0e609a289 100644 --- a/test/integration/testpaths/testpath_volume_snapshot.py +++ b/test/integration/testpaths/testpath_volume_snapshot.py @@ -805,13 +805,13 @@ def test_01_volume_snapshot(self): event_list_validation_result[2]) self.debug("Events list contains event SNAPSHOT.CREATE") + self.testdata["volume"]["zoneid"] = self.zone.id volumeFromSnap = Volume.create_from_snapshot( self.apiclient, data_vol_snap.id, self.testdata["volume"], account=self.account.name, domainid=self.account.domainid, - zoneid=self.zone.id ) self.assertTrue( @@ -926,13 +926,13 @@ def test_01_volume_snapshot(self): "Check resource id in list resources call" ) + self.testdata["volume"]["zoneid"] = self.zone.id volumeFromSnap_2 = Volume.create_from_snapshot( self.apiclient, data_vol_snap_2.id, self.testdata["volume"], account=self.account.name, domainid=self.account.domainid, - zoneid=self.zone.id ) self.vm_2.attach_volume( From 4a9487e581c2df35063edfc6ce8299a794fe0c8e Mon Sep 17 00:00:00 2001 From: weingartner Date: Sat, 28 Nov 2015 12:09:54 -0200 Subject: [PATCH 014/203] Changed return of methods from DataMotionStrategy, Void to void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The main changes are: • Changing methods “Void” to “void”. • Removal of the method “Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback)” that was never used. We noticed that methods form that class are using the return type Void with capital V. This way that method has to return a null value at the end. --- .../api/storage/DataMotionStrategy.java | 7 +-- .../motion/AncientDataMotionStrategy.java | 28 +++--------- .../StorageSystemDataMotionStrategy.java | 33 +++++--------- .../test/MockStorageMotionStrategy.java | 45 +------------------ .../motion/HypervStorageMotionStrategy.java | 16 ++----- .../motion/SimulatorDataMotionStrategy.java | 12 +---- .../motion/VmwareStorageMotionStrategy.java | 19 ++------ .../XenServerStorageMotionStrategy.java | 19 ++------ 8 files changed, 33 insertions(+), 146 deletions(-) diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java index b5601e9693..5d552c4013 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java @@ -30,10 +30,7 @@ public interface DataMotionStrategy { StrategyPriority canHandle(Map volumeMap, Host srcHost, Host destHost); - Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback); - - Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback); - - Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback); + void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback); + void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback); } diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java index 24ecff57e9..3124666db1 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java @@ -23,9 +23,6 @@ import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; @@ -41,7 +38,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.StorageAction; import org.apache.cloudstack.engine.subsystem.api.storage.StorageCacheManager; import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; -import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; @@ -49,6 +45,8 @@ import org.apache.cloudstack.storage.RemoteHostEndPoint; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.agent.api.Answer; import com.cloud.agent.api.storage.MigrateVolumeAnswer; @@ -61,9 +59,9 @@ import com.cloud.configuration.Config; import com.cloud.host.Host; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePool; import com.cloud.storage.VolumeVO; -import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.DB; @@ -99,22 +97,14 @@ protected boolean needCacheStorage(DataObject srcData, DataObject destData) { DataStoreTO srcStoreTO = srcTO.getDataStore(); if (srcStoreTO instanceof NfsTO || srcStoreTO.getRole() == DataStoreRole.ImageCache) { - //|| - // (srcStoreTO instanceof PrimaryDataStoreTO && ((PrimaryDataStoreTO)srcStoreTO).getPoolType() == StoragePoolType.NetworkFilesystem)) { return false; } - DataTO destTO = destData.getTO(); DataStoreTO destStoreTO = destTO.getDataStore(); if (destStoreTO instanceof NfsTO || destStoreTO.getRole() == DataStoreRole.ImageCache) { return false; } - - if (srcData.getType() == DataObjectType.TEMPLATE) { - TemplateInfo template = (TemplateInfo)srcData; - } - if (s_logger.isDebugEnabled()) { s_logger.debug("needCacheStorage true, dest at " + destTO.getPath() + " dest role " + destStoreTO.getRole().toString() + srcTO.getPath() + " src role " + srcStoreTO.getRole().toString()); @@ -429,7 +419,7 @@ protected Answer migrateVolumeToPool(DataObject srcData, DataObject destData) { // Note: destHost is currently only used if the copyObject method is invoked @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { Answer answer = null; String errMsg = null; try { @@ -465,12 +455,6 @@ public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, As CopyCommandResult result = new CopyCommandResult(null, answer); result.setResult(errMsg); callback.complete(result); - return null; - } - - @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { - return copyAsync(srcData, destData, null, callback); } @DB @@ -569,11 +553,9 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) { } @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { CopyCommandResult result = new CopyCommandResult(null, null); result.setResult("Unsupported operation requested for copying data."); callback.complete(result); - - return null; } } diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java index 3c9334df73..cdcab754e9 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java @@ -24,30 +24,29 @@ import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.CopyCmdAnswer; +import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.agent.api.to.DiskTO; @@ -64,8 +63,8 @@ import com.cloud.storage.DataStoreRole; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.SnapshotVO; -import com.cloud.storage.VolumeVO; import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.SnapshotDetailsDao; @@ -127,7 +126,7 @@ public StrategyPriority canHandle(Map volumeMap, Host src } @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { if (srcData instanceof SnapshotInfo) { SnapshotInfo snapshotInfo = (SnapshotInfo)srcData; @@ -137,23 +136,22 @@ public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, As if (canHandleSrc && destData instanceof TemplateInfo && (destData.getDataStore().getRole() == DataStoreRole.Image || destData.getDataStore().getRole() == DataStoreRole.ImageCache)) { - return handleCreateTemplateFromSnapshot(snapshotInfo, (TemplateInfo)destData, callback); + handleCreateTemplateFromSnapshot(snapshotInfo, (TemplateInfo)destData, callback); + return; } if (destData instanceof VolumeInfo) { VolumeInfo volumeInfo = (VolumeInfo)destData; - boolean canHandleDest = canHandle(destData.getDataStore()); if (canHandleSrc && canHandleDest) { - return handleCreateVolumeFromSnapshotBothOnStorageSystem(snapshotInfo, volumeInfo, callback); + handleCreateVolumeFromSnapshotBothOnStorageSystem(snapshotInfo, volumeInfo, callback); + return; } - if (canHandleSrc) { throw new UnsupportedOperationException("This operation is not supported (DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " + "not supported by destination storage plug-in)."); } - if (canHandleDest) { throw new UnsupportedOperationException("This operation is not supported (DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " + "not supported by source storage plug-in)."); @@ -413,18 +411,9 @@ public HostVO getHost(long dataStoreId) { } @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { - return copyAsync(srcData, destData, null, callback); - } - - @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { CopyCommandResult result = new CopyCommandResult(null, null); - result.setResult("Unsupported operation requested for copying data."); - callback.complete(result); - - return null; } } diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java index accfeb5318..757d96caba 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java @@ -19,25 +19,17 @@ package org.apache.cloudstack.storage.test; import java.util.Map; -import java.util.UUID; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.storage.command.CopyCmdAnswer; -import org.apache.cloudstack.storage.to.SnapshotObjectTO; -import org.apache.cloudstack.storage.to.TemplateObjectTO; -import com.cloud.agent.api.to.DataObjectType; -import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.host.Host; -import com.cloud.storage.Storage; public class MockStorageMotionStrategy implements DataMotionStrategy { @@ -58,46 +50,13 @@ public StrategyPriority canHandle(Map volumeMap, Host src } @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { throw new UnsupportedOperationException(); } @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { - CopyCmdAnswer answer = null; - DataTO data = null; - if (!success) { - CopyCommandResult result = new CopyCommandResult(null, null); - result.setResult("Failed"); - callback.complete(result); - } - if (destData.getType() == DataObjectType.SNAPSHOT) { - SnapshotInfo srcSnapshot = (SnapshotInfo)srcData; - - SnapshotObjectTO newSnapshot = new SnapshotObjectTO(); - newSnapshot.setPath(UUID.randomUUID().toString()); - if (srcSnapshot.getParent() != null) { - newSnapshot.setParentSnapshotPath(srcSnapshot.getParent().getPath()); - } - data = newSnapshot; - } else if (destData.getType() == DataObjectType.TEMPLATE) { - TemplateObjectTO newTemplate = new TemplateObjectTO(); - newTemplate.setPath(UUID.randomUUID().toString()); - newTemplate.setFormat(Storage.ImageFormat.QCOW2); - newTemplate.setSize(10L); - newTemplate.setPhysicalSize(10L); - data = newTemplate; - } - answer = new CopyCmdAnswer(data); - CopyCommandResult result = new CopyCommandResult("something", answer); - callback.complete(result); - return null; - } - - @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { CopyCommandResult result = new CopyCommandResult("something", null); callback.complete(result); - return null; } } diff --git a/plugins/hypervisors/hyperv/src/org/apache/cloudstack/storage/motion/HypervStorageMotionStrategy.java b/plugins/hypervisors/hyperv/src/org/apache/cloudstack/storage/motion/HypervStorageMotionStrategy.java index 8a1c414fb4..19c655b8f2 100644 --- a/plugins/hypervisors/hyperv/src/org/apache/cloudstack/storage/motion/HypervStorageMotionStrategy.java +++ b/plugins/hypervisors/hyperv/src/org/apache/cloudstack/storage/motion/HypervStorageMotionStrategy.java @@ -48,9 +48,9 @@ import com.cloud.exception.OperationTimedoutException; import com.cloud.host.Host; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePool; import com.cloud.storage.VolumeVO; -import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; @@ -82,21 +82,12 @@ public StrategyPriority canHandle(Map volumeMap, Host src } @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { throw new UnsupportedOperationException(); } @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { - CopyCommandResult result = new CopyCommandResult(null, null); - result.setResult("Unsupported operation requested for copying data."); - callback.complete(result); - - return null; - } - - @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { Answer answer = null; String errMsg = null; @@ -115,7 +106,6 @@ public Void copyAsync(Map volumeMap, VirtualMachineTO vmT CopyCommandResult result = new CopyCommandResult(null, answer); result.setResult(errMsg); callback.complete(result); - return null; } private Answer migrateVmWithVolumes(VMInstanceVO vm, VirtualMachineTO to, Host srcHost, diff --git a/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/motion/SimulatorDataMotionStrategy.java b/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/motion/SimulatorDataMotionStrategy.java index 40909629c7..5e72babf08 100644 --- a/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/motion/SimulatorDataMotionStrategy.java +++ b/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/motion/SimulatorDataMotionStrategy.java @@ -43,21 +43,13 @@ public StrategyPriority canHandle(Map volumeMap, Host src } @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { throw new UnsupportedOperationException(); } @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { CopyCommandResult result = new CopyCommandResult("something", null); callback.complete(result); - return null; - } - - @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { - CopyCommandResult result = new CopyCommandResult("something", null); - callback.complete(result); - return null; } } diff --git a/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java b/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java index 4b77aab617..23b32a3d25 100644 --- a/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java +++ b/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java @@ -25,9 +25,6 @@ import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; @@ -38,6 +35,8 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; @@ -87,21 +86,12 @@ public StrategyPriority canHandle(Map volumeMap, Host src } @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { throw new UnsupportedOperationException(); } @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { - CopyCommandResult result = new CopyCommandResult(null, null); - result.setResult("Unsupported operation requested for copying data."); - callback.complete(result); - - return null; - } - - @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { Answer answer = null; String errMsg = null; try { @@ -123,7 +113,6 @@ public Void copyAsync(Map volumeMap, VirtualMachineTO vmT CopyCommandResult result = new CopyCommandResult(null, answer); result.setResult(errMsg); callback.complete(result); - return null; } private Answer migrateVmWithVolumesAcrossCluster(VMInstanceVO vm, VirtualMachineTO to, Host srcHost, Host destHost, Map volumeToPool) diff --git a/plugins/hypervisors/xenserver/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java b/plugins/hypervisors/xenserver/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java index c8367dd3ac..6f5e38bfcd 100644 --- a/plugins/hypervisors/xenserver/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java +++ b/plugins/hypervisors/xenserver/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java @@ -24,9 +24,6 @@ import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; @@ -37,6 +34,8 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; @@ -91,21 +90,12 @@ public StrategyPriority canHandle(Map volumeMap, Host src } @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { throw new UnsupportedOperationException(); } @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { - CopyCommandResult result = new CopyCommandResult(null, null); - result.setResult("Unsupported operation requested for copying data."); - callback.complete(result); - - return null; - } - - @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { Answer answer = null; String errMsg = null; try { @@ -127,7 +117,6 @@ public Void copyAsync(Map volumeMap, VirtualMachineTO vmT CopyCommandResult result = new CopyCommandResult(null, answer); result.setResult(errMsg); callback.complete(result); - return null; } private Answer migrateVmWithVolumesAcrossCluster(VMInstanceVO vm, VirtualMachineTO to, Host srcHost, Host destHost, Map volumeToPool) From 6ea2b482f75435cd166229404e71ee490ad67f7f Mon Sep 17 00:00:00 2001 From: weingartner Date: Fri, 4 Dec 2015 10:36:16 -0200 Subject: [PATCH 015/203] Add Javadoc to AgentBasedStandaloneConsoleProxyManager --- ...entBasedStandaloneConsoleProxyManager.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java b/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java index b473f7e7f3..70afd8ab1d 100644 --- a/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java +++ b/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java @@ -18,7 +18,6 @@ import java.util.List; - import org.apache.log4j.Logger; import com.cloud.host.Host; @@ -26,6 +25,10 @@ import com.cloud.info.ConsoleProxyInfo; import com.cloud.vm.UserVmVO; +/** + * This class is intended to replace the use of console proxy VMs managed by the Apache CloudStack (ACS) + * to non ACS console proxy services. The documentation that describe its use and requirements can be found in QuickCloud. + */ public class AgentBasedStandaloneConsoleProxyManager extends AgentBasedConsoleProxyManager { private static final Logger s_logger = Logger.getLogger(AgentBasedStandaloneConsoleProxyManager.class); @@ -58,26 +61,30 @@ public ConsoleProxyInfo assignProxy(long dataCenterId, long userVmId) { } } if (allocatedHost == null) { - if (s_logger.isDebugEnabled()) + if (s_logger.isDebugEnabled()) { s_logger.debug("Failed to find a console proxy at host: " + host.getName() + " and in the pod: " + host.getPodId() + " to user vm " + userVmId); + } return null; } - if (s_logger.isDebugEnabled()) - s_logger.debug("Assign standalone console proxy running at " + allocatedHost.getName() + " to user vm " + userVmId + " with public IP " + - allocatedHost.getPublicIpAddress()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Assign standalone console proxy running at " + allocatedHost.getName() + " to user vm " + userVmId + " with public IP " + + allocatedHost.getPublicIpAddress()); + } // only private IP, public IP, host id have meaningful values, rest of all are place-holder values String publicIp = allocatedHost.getPublicIpAddress(); if (publicIp == null) { - if (s_logger.isDebugEnabled()) - s_logger.debug("Host " + allocatedHost.getName() + "/" + allocatedHost.getPrivateIpAddress() + - " does not have public interface, we will return its private IP for cosole proxy."); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Host " + allocatedHost.getName() + "/" + allocatedHost.getPrivateIpAddress() + + " does not have public interface, we will return its private IP for cosole proxy."); + } publicIp = allocatedHost.getPrivateIpAddress(); } int urlPort = _consoleProxyUrlPort; - if (allocatedHost.getProxyPort() != null && allocatedHost.getProxyPort().intValue() > 0) + if (allocatedHost.getProxyPort() != null && allocatedHost.getProxyPort().intValue() > 0) { urlPort = allocatedHost.getProxyPort().intValue(); + } return new ConsoleProxyInfo(_sslEnabled, publicIp, _consoleProxyPort, urlPort, _consoleProxyUrlDomain); } else { From 1cf44dee3a94dcac765aff9b2827e20cd05f971f Mon Sep 17 00:00:00 2001 From: Priti Sarap Date: Tue, 8 Dec 2015 16:29:13 +0530 Subject: [PATCH 016/203] CLOUDSTACK-9121: Adding VmSnapshot validation in testpath_revert_snap.py --- test/integration/testpaths/testpath_revert_snap.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/integration/testpaths/testpath_revert_snap.py b/test/integration/testpaths/testpath_revert_snap.py index 8026f34391..5934400912 100644 --- a/test/integration/testpaths/testpath_revert_snap.py +++ b/test/integration/testpaths/testpath_revert_snap.py @@ -150,7 +150,12 @@ def test_01_check_revert_snapshot(self): vm_snap = VmSnapshot.create(self.apiclient, vm.id) - volume_list_validation = validateList(vm_snap) + self.assertEqual( + vm_snap.state, + "Ready", + "Check the snapshot of vm is ready!" + ) + #Step 3 with self.assertRaises(Exception): From 5b3ffeb6cd087c6b4406eae3a8c3ec782cdb80d0 Mon Sep 17 00:00:00 2001 From: Koushik Das Date: Wed, 9 Dec 2015 15:19:10 +0530 Subject: [PATCH 017/203] CLOUDSTACK-9130: Make RebootCommand similar to start/stop/migrate agent commands w.r.t. "execute in sequence" flag RebootCommand now behaves in the same way as start/stop/migrate agent commands w.r.t. to sequential/parallel execution. --- core/src/com/cloud/agent/api/RebootCommand.java | 14 +++++--------- .../com/cloud/agent/api/RebootRouterCommand.java | 2 +- core/src/com/cloud/agent/api/StopCommand.java | 16 ++++++---------- .../src/com/cloud/vm/VirtualMachineManager.java | 7 ++++--- .../com/cloud/vm/VirtualMachineManagerImpl.java | 10 +++++----- .../cloud/vm/VirtualMachineManagerImplTest.java | 9 +++++++++ .../LibvirtRebootRouterCommandWrapper.java | 2 +- .../resource/LibvirtComputingResourceTest.java | 8 ++++---- .../resources/Ovm3HypervisorResourceTest.java | 2 +- .../CitrixRebootRouterCommandWrapper.java | 2 +- .../xenbase/CitrixRequestWrapperTest.java | 2 +- .../consoleproxy/ConsoleProxyManagerImpl.java | 2 +- .../SecondaryStorageManagerImpl.java | 2 +- 13 files changed, 40 insertions(+), 38 deletions(-) diff --git a/core/src/com/cloud/agent/api/RebootCommand.java b/core/src/com/cloud/agent/api/RebootCommand.java index d8f1ce9569..eecf7f635d 100644 --- a/core/src/com/cloud/agent/api/RebootCommand.java +++ b/core/src/com/cloud/agent/api/RebootCommand.java @@ -19,29 +19,25 @@ package com.cloud.agent.api; -import com.cloud.vm.VirtualMachine; - public class RebootCommand extends Command { String vmName; + protected boolean executeInSequence = false; protected RebootCommand() { } - public RebootCommand(VirtualMachine vm) { - vmName = vm.getInstanceName(); - } - - public RebootCommand(String vmName) { + public RebootCommand(String vmName, boolean executeInSequence) { this.vmName = vmName; + this.executeInSequence = executeInSequence; } public String getVmName() { - return vmName; + return this.vmName; } @Override public boolean executeInSequence() { - return true; + return this.executeInSequence; } } diff --git a/core/src/com/cloud/agent/api/RebootRouterCommand.java b/core/src/com/cloud/agent/api/RebootRouterCommand.java index 149ac5d7b3..6d6c0a9038 100644 --- a/core/src/com/cloud/agent/api/RebootRouterCommand.java +++ b/core/src/com/cloud/agent/api/RebootRouterCommand.java @@ -27,7 +27,7 @@ protected RebootRouterCommand() { } public RebootRouterCommand(String vmName, String privateIp) { - super(vmName); + super(vmName, true); this.privateIp = privateIp; } diff --git a/core/src/com/cloud/agent/api/StopCommand.java b/core/src/com/cloud/agent/api/StopCommand.java index c4948cd631..b723d746cc 100644 --- a/core/src/com/cloud/agent/api/StopCommand.java +++ b/core/src/com/cloud/agent/api/StopCommand.java @@ -26,7 +26,6 @@ public class StopCommand extends RebootCommand { private boolean isProxy = false; private String urlPort = null; private String publicConsoleProxyIpAddress = null; - boolean executeInSequence = false; private GPUDeviceTO gpuDevice; boolean checkBeforeCleanup = false; @@ -34,33 +33,30 @@ protected StopCommand() { } public StopCommand(VirtualMachine vm, boolean isProxy, String urlPort, String publicConsoleProxyIpAddress, boolean executeInSequence, boolean checkBeforeCleanup) { - super(vm); + super(vm.getInstanceName(), executeInSequence); this.isProxy = isProxy; this.urlPort = urlPort; this.publicConsoleProxyIpAddress = publicConsoleProxyIpAddress; - this.executeInSequence = executeInSequence; this.checkBeforeCleanup = checkBeforeCleanup; } public StopCommand(VirtualMachine vm, boolean executeInSequence, boolean checkBeforeCleanup) { - super(vm); - this.executeInSequence = executeInSequence; + super(vm.getInstanceName(), executeInSequence); this.checkBeforeCleanup = checkBeforeCleanup; } public StopCommand(String vmName, boolean executeInSequence, boolean checkBeforeCleanup) { - super(vmName); - this.executeInSequence = executeInSequence; + super(vmName, executeInSequence); this.checkBeforeCleanup = checkBeforeCleanup; } @Override public boolean executeInSequence() { - //VR stop doesn't go through queue - if (vmName != null && vmName.startsWith("r-")) { + // VR stop doesn't go through queue + if (this.vmName != null && this.vmName.startsWith("r-")) { return false; } - return executeInSequence; + return this.executeInSequence; } public boolean isProxy() { diff --git a/engine/api/src/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/com/cloud/vm/VirtualMachineManager.java index 8b22656422..d68f3485b0 100644 --- a/engine/api/src/com/cloud/vm/VirtualMachineManager.java +++ b/engine/api/src/com/cloud/vm/VirtualMachineManager.java @@ -49,11 +49,10 @@ public interface VirtualMachineManager extends Manager { static final ConfigKey ExecuteInSequence = new ConfigKey("Advanced", Boolean.class, "execute.in.sequence.hypervisor.commands", "false", - "If set to true, StartCommand, StopCommand, CopyCommand, MigrateCommand will be synchronized on the agent side." - + " If set to false, these commands become asynchronous. Default value is false.", false); + "If set to true, start, stop, reboot, copy and migrate commands will be serialized on the agent side. If set to false the commands are executed in parallel. Default value is false.", false); static final ConfigKey VmConfigDriveLabel = new ConfigKey("Hidden", String.class, "vm.configdrive.label", "config", - "The default lable name for the config drive", false); + "The default label name for the config drive", false); public interface Topics { public static final String VM_POWER_STATE = "vm.powerstate"; @@ -199,4 +198,6 @@ void findHostAndMigrate(String vmUuid, Long newSvcOfferingId, DeploymentPlanner. ConcurrentOperationException, ResourceUnavailableException; void migrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long newSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException; + + boolean getExecuteInSequence(HypervisorType hypervisorType); } diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java index 5c5838951f..7a7aedaedf 100644 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -1240,11 +1240,11 @@ public void stop(final String vmUuid) throws ResourceUnavailableException { } } - - protected boolean getExecuteInSequence(final HypervisorType hypervisorType) { - if (HypervisorType.KVM == hypervisorType || HypervisorType.LXC == hypervisorType || HypervisorType.XenServer == hypervisorType) { + @Override + public boolean getExecuteInSequence(final HypervisorType hypervisorType) { + if (HypervisorType.KVM == hypervisorType || HypervisorType.XenServer == hypervisorType || HypervisorType.Hyperv == hypervisorType || HypervisorType.LXC == hypervisorType) { return false; - } else if(HypervisorType.VMware == hypervisorType) { + } else if (HypervisorType.VMware == hypervisorType) { final Boolean fullClone = HypervisorGuru.VmwareFullClone.value(); return fullClone; } else { @@ -2584,7 +2584,7 @@ private void orchestrateReboot(final String vmUuid, final Map Date: Mon, 14 Dec 2015 12:10:48 +0530 Subject: [PATCH 018/203] CLOUDSTACK-9161: fix the quota marvin test 1. Create a dummy user, as existing user may already have stale quota data 2. fix the tests to use the dummy user 3. a boundary condition was revealed and fixed for a new user where quota service has never run and created bootstrap entries Quota Marvin: If the quota plugin is not enabled skip tests Quota Service: Enable quota plugin in zone setup configuration Quota: Moving test_quota.py the test to test/integration/plugins In most automated environment this test case will not run as it requires a mangement server restart to enable the plugin. Due to this requirement moving it to plugin folder. This condition is already documented in the test case. --- .../cloudstack/quota/QuotaManagerImpl.java | 4 +- .../cloudstack/quota/vo/QuotaBalanceVO.java | 10 ++- .../response/QuotaResponseBuilderImpl.java | 2 +- .../{smoke => plugins}/test_quota.py | 85 ++++++++++++++++--- tools/marvin/marvin/config/setup.cfg | 4 + 5 files changed, 89 insertions(+), 16 deletions(-) rename test/integration/{smoke => plugins}/test_quota.py (69%) diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java index b039e26a9b..ac14718fd4 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java @@ -220,7 +220,9 @@ public void processQuotaBalanceForAccount(final AccountVO account, final List Date: Wed, 16 Dec 2015 17:53:03 +0530 Subject: [PATCH 019/203] CLOUDSTACK-9180: Optimize concurrent VM deployment operation on same network Check if VR needs to be allocated for a given network and only acquire lock if required --- .../RouterDeploymentDefinition.java | 49 +++++++++++++------ .../RouterDeploymentDefinitionTest.java | 36 ++++++++++++-- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java b/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java index 2d04a7e633..19f80b94a4 100644 --- a/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java +++ b/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java @@ -193,28 +193,45 @@ protected void generateDeploymentPlan() { } public List deployVirtualRouter() throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { - findOrDeployVirtualRouter(); - return nwHelper.startRouters(this); } + private boolean isRouterDeployed() throws ResourceUnavailableException { + boolean isDeployed = true; + checkPreconditions(); + final List destinations = findDestinations(); + for (final DeployDestination destination : destinations) { + dest = destination; + generateDeploymentPlan(); + planDeploymentRouters(); + if (getNumberOfRoutersToDeploy() > 0 && prepareDeployment()) { + isDeployed = false; + break; + } + } + return isDeployed; + } + @DB protected void findOrDeployVirtualRouter() throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { - try { - lock(); - checkPreconditions(); - - // dest has pod=null, for Basic Zone findOrDeployVRs for all Pods - final List destinations = findDestinations(); - - for (final DeployDestination destination : destinations) { - dest = destination; - generateDeploymentPlan(); - executeDeployment(); + if (!isRouterDeployed()) { + try { + lock(); + // reset router list that got populated during isRouterDeployed() + routers.clear(); + checkPreconditions(); + + // dest has pod=null, for Basic Zone findOrDeployVRs for all Pods + final List destinations = findDestinations(); + for (final DeployDestination destination : destinations) { + dest = destination; + generateDeploymentPlan(); + executeDeployment(); + } + } finally { + unlock(); } - } finally { - unlock(); } } @@ -378,7 +395,7 @@ protected void findVirtualProvider() { final PhysicalNetworkServiceProvider provider = physicalProviderDao.findByServiceProvider(physicalNetworkId, type.toString()); if (provider == null) { - throw new CloudRuntimeException(String.format("Cannot find service provider %s in physical network %s", type.toString(), physicalNetworkId)); + throw new CloudRuntimeException(String.format("Cannot find service provider %s in physical network %s", type.toString(), physicalNetworkId)); } vrProvider = vrProviderDao.findByNspIdAndType(provider.getId(), type); diff --git a/server/test/org/cloud/network/router/deployment/RouterDeploymentDefinitionTest.java b/server/test/org/cloud/network/router/deployment/RouterDeploymentDefinitionTest.java index 1570a2e15a..eff16c16b8 100644 --- a/server/test/org/cloud/network/router/deployment/RouterDeploymentDefinitionTest.java +++ b/server/test/org/cloud/network/router/deployment/RouterDeploymentDefinitionTest.java @@ -513,9 +513,9 @@ public void testDeployVirtualRouter() throws ConcurrentOperationException, } finally { // Assert verify(deploymentUT, times(1)).lock(); - verify(deploymentUT, times(1)).checkPreconditions(); - verify(deploymentUT, times(1)).findDestinations(); - verify(deploymentUT, times(2)).generateDeploymentPlan(); + verify(deploymentUT, times(2)).checkPreconditions(); + verify(deploymentUT, times(2)).findDestinations(); + verify(deploymentUT, times(3)).generateDeploymentPlan(); verify(deploymentUT, times(2)).executeDeployment(); //verify(deploymentUT, times(2)).planDeploymentRouters(); verify(deploymentUT, times(1)).unlock(); @@ -524,6 +524,36 @@ public void testDeployVirtualRouter() throws ConcurrentOperationException, fail(); } + @Test + public void testDeployVirtualRouterSkip() throws ConcurrentOperationException, + InsufficientCapacityException, ResourceUnavailableException { + + // Prepare + final List mockDestinations = new ArrayList<>(); + mockDestinations.add(mock(DeployDestination.class)); + mockDestinations.add(mock(DeployDestination.class)); + + final RouterDeploymentDefinition deploymentUT = spy(deployment); + doNothing().when(deploymentUT).checkPreconditions(); + doReturn(mockDestinations).when(deploymentUT).findDestinations(); + doNothing().when(deploymentUT).planDeploymentRouters(); + doNothing().when(deploymentUT).generateDeploymentPlan(); + doReturn(0).when(deploymentUT).getNumberOfRoutersToDeploy(); + + // Execute + try { + deploymentUT.findOrDeployVirtualRouter(); + } finally { + // Assert + verify(deploymentUT, times(0)).lock(); // lock shouldn't be acquired when VR already present + verify(deploymentUT, times(1)).checkPreconditions(); + verify(deploymentUT, times(1)).findDestinations(); + verify(deploymentUT, times(2)).generateDeploymentPlan(); + verify(deploymentUT, times(0)).executeDeployment(); // no need to deploy VR as already present + verify(deploymentUT, times(0)).unlock(); // same as lock + } + } + @Test public void testGetNumberOfRoutersToDeploy() { // Prepare From 2d5f6a7911585a8075996e106f97b7f3b89067f8 Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Thu, 17 Dec 2015 10:59:31 +0530 Subject: [PATCH 020/203] CLOUDSTACK-9185: [VMware DRS] VM sync failed with exception due to out-of-band changes Summary: The target "ClusteredVirtualMachineManagerImpl.HandlePowerStateReport" invoked during the VM power state sync is not found as HandlePowerStateReport was not implemented in ClusteredVirtualMachineManagerImpl and was private in VirtualMachineManagerImpl, which was resulting in InvocationTargetException. Changed HandlePowerStateReport() in VirtualMachineManagerImpl to protected. --- .../src/com/cloud/vm/VirtualMachineManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java index 5c5838951f..1ed02496ac 100644 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -3685,7 +3685,7 @@ public void setStoragePoolAllocators(final List storagePoo // @MessageHandler(topic = Topics.VM_POWER_STATE) - private void HandlePowerStateReport(final String subject, final String senderAddress, final Object args) { + protected void HandlePowerStateReport(final String subject, final String senderAddress, final Object args) { assert args != null; final Long vmId = (Long)args; From 983dee7f20bdcfb27cab20a46905ed58a558cb73 Mon Sep 17 00:00:00 2001 From: Abhinandan Prateek Date: Thu, 17 Dec 2015 10:32:33 +0530 Subject: [PATCH 021/203] CLOUDSTACK-9174: A deleted account results in NPE When an account is deleted from cloudstack for which quota is still being calculated and if the quota reaches minimum threshold then quota service will try to alert the user. This results in NPE and is fixed by excluding such accounts from alerting and other quota related mechanisms. Quota service: Fix check for admin account --- .../quota/QuotaAlertManagerImpl.java | 1 + .../cloudstack/quota/QuotaManagerImpl.java | 7 ++++--- .../cloudstack/quota/QuotaStatementImpl.java | 18 ++++++++++-------- .../api/command/QuotaSummaryCmd.java | 2 +- .../api/response/QuotaResponseBuilderImpl.java | 6 +++++- ui/plugins/quota/quota.js | 7 ------- 6 files changed, 21 insertions(+), 20 deletions(-) diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java index a57e0c27db..a25ed04282 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java @@ -153,6 +153,7 @@ public void checkAndSendQuotaAlertEmails() { BigDecimal thresholdBalance = quotaAccount.getQuotaMinBalance(); if (accountBalance != null) { AccountVO account = _accountDao.findById(quotaAccount.getId()); + if (account == null) continue; // the account is removed if (s_logger.isDebugEnabled()) { s_logger.debug("checkAndSendQuotaAlertEmails: Check id=" + account.getId() + " bal=" + accountBalance + ", alertDate=" + alertDate + ", lockable=" + lockable); } diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java index b039e26a9b..f4012b134c 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java @@ -358,10 +358,11 @@ public List updateQuotaRunningVMUsage(UsageVO usageRecord, final B BigDecimal rawusage; // get service offering details ServiceOfferingVO serviceoffering = _serviceOfferingDao.findServiceOffering(usageRecord.getVmInstanceId(), usageRecord.getOfferingId()); + if (serviceoffering == null) return quotalist; rawusage = new BigDecimal(usageRecord.getRawUsage()); QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.CPU_NUMBER, usageRecord.getEndDate()); - if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) { + if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0 && serviceoffering.getCpu() != null) { BigDecimal cpu = new BigDecimal(serviceoffering.getCpu()); onehourcostpercpu = tariff.getCurrencyValue().multiply(aggregationRatio); cpuquotausgage = rawusage.multiply(onehourcostpercpu).multiply(cpu); @@ -371,7 +372,7 @@ public List updateQuotaRunningVMUsage(UsageVO usageRecord, final B quotalist.add(quota_usage); } tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.CPU_CLOCK_RATE, usageRecord.getEndDate()); - if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) { + if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0 && serviceoffering.getSpeed() != null) { BigDecimal speed = new BigDecimal(serviceoffering.getSpeed() / 100.00); onehourcostper100mhz = tariff.getCurrencyValue().multiply(aggregationRatio); speedquotausage = rawusage.multiply(onehourcostper100mhz).multiply(speed); @@ -381,7 +382,7 @@ public List updateQuotaRunningVMUsage(UsageVO usageRecord, final B quotalist.add(quota_usage); } tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.MEMORY, usageRecord.getEndDate()); - if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) { + if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0 && serviceoffering.getRamSize() != null) { BigDecimal memory = new BigDecimal(serviceoffering.getRamSize()); onehourcostper1mb = tariff.getCurrencyValue().multiply(aggregationRatio); memoryquotausage = rawusage.multiply(onehourcostper1mb).multiply(memory); diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java index 682b2ef036..dde3069721 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java @@ -122,15 +122,17 @@ public void sendStatement() { Date lastStatementDate = quotaAccount.getLastStatementDate(); if (interval != null) { AccountVO account = _accountDao.findById(quotaAccount.getId()); - if (lastStatementDate == null || getDifferenceDays(lastStatementDate, new Date()) >= s_LAST_STATEMENT_SENT_DAYS + 1) { - BigDecimal quotaUsage = _quotaUsage.findTotalQuotaUsage(account.getAccountId(), account.getDomainId(), null, interval[0].getTime(), interval[1].getTime()); - s_logger.info("For account=" + quotaAccount.getId() + ", quota used = " + quotaUsage); - // send statement - deferredQuotaEmailList.add(new DeferredQuotaEmail(account, quotaAccount, quotaUsage, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_STATEMENT)); - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("For " + quotaAccount.getId() + " the statement has been sent recently"); + if (account != null) { + if (lastStatementDate == null || getDifferenceDays(lastStatementDate, new Date()) >= s_LAST_STATEMENT_SENT_DAYS + 1) { + BigDecimal quotaUsage = _quotaUsage.findTotalQuotaUsage(account.getAccountId(), account.getDomainId(), null, interval[0].getTime(), interval[1].getTime()); + s_logger.info("For account=" + quotaAccount.getId() + ", quota used = " + quotaUsage); + // send statement + deferredQuotaEmailList.add(new DeferredQuotaEmail(account, quotaAccount, quotaUsage, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_STATEMENT)); + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("For " + quotaAccount.getId() + " the statement has been sent recently"); + } } } } else if (lastStatementDate != null) { diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaSummaryCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaSummaryCmd.java index b4f2001f95..88466e08c6 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaSummaryCmd.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaSummaryCmd.java @@ -59,7 +59,7 @@ public QuotaSummaryCmd() { public void execute() { Account caller = CallContext.current().getCallingAccount(); List responses; - if (caller.getAccountId() <= 2) { //non root admin or system + if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN) { //admin account if (getAccountName() != null && getDomainId() != null) responses = _responseBuilder.createQuotaSummaryResponse(caller.getAccountName(), caller.getDomainId()); else diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java index 1b6f400f40..59c53ecb5d 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java @@ -138,6 +138,7 @@ public List createQuotaSummaryResponse(Boolean listAll) { } else { for (final QuotaAccountVO quotaAccount : _quotaAccountDao.listAllQuotaAccount()) { AccountVO account = _accountDao.findById(quotaAccount.getId()); + if (account == null) continue; QuotaSummaryResponse qr = getQuotaSummaryResponse(account); result.add(qr); } @@ -167,7 +168,7 @@ private QuotaSummaryResponse getQuotaSummaryResponse(final Account account) { qr.setObjectName("summary"); return qr; } else { - throw new InvalidParameterValueException("Quota summary response for an account requires a valid account."); + return new QuotaSummaryResponse(); } } @@ -396,6 +397,9 @@ public QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Doubl QuotaCreditsVO result = _quotaCreditsDao.saveCredits(credits); final AccountVO account = _accountDao.findById(accountId); + if (account == null) { + throw new InvalidParameterValueException("Account does not exist with account id " + accountId); + } final boolean lockAccountEnforcement = "true".equalsIgnoreCase(QuotaConfig.QuotaEnableEnforcement.value()); final BigDecimal currentAccountBalance = _quotaBalanceDao.lastQuotaBalance(accountId, domainId, startOfNextDay(new Date(despositedOn.getTime()))); if (s_logger.isDebugEnabled()) { diff --git a/ui/plugins/quota/quota.js b/ui/plugins/quota/quota.js index 94a8730b5e..d9f61b2371 100644 --- a/ui/plugins/quota/quota.js +++ b/ui/plugins/quota/quota.js @@ -329,13 +329,6 @@ }); }, detailView: { - viewAll: [{ - path: 'quota.quotastatement', - label: 'label.quota.statement.quota' - },{ - path: 'quota.balancestatement', - label: 'label.quota.statement.balance' - }], actions: { add: { label: 'label.quota.add.credits', From 5d3adb3a2da6aea6fba8f563548de14cdcca7625 Mon Sep 17 00:00:00 2001 From: pedro-martins Date: Sat, 19 Dec 2015 15:54:26 -0200 Subject: [PATCH 022/203] Removed unused variables from class NetworkStateListener --- .../cloud/network/NetworkStateListener.java | 21 ++++++------------- .../orchestration/NetworkOrchestrator.java | 2 +- .../cloud/network/IpAddressManagerImpl.java | 2 +- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/engine/components-api/src/com/cloud/network/NetworkStateListener.java b/engine/components-api/src/com/cloud/network/NetworkStateListener.java index 0ed1d9ea7f..ef8dddc1f2 100644 --- a/engine/components-api/src/com/cloud/network/NetworkStateListener.java +++ b/engine/components-api/src/com/cloud/network/NetworkStateListener.java @@ -24,38 +24,29 @@ import javax.inject.Inject; -import com.cloud.utils.fsm.StateMachine2; -import org.apache.log4j.Logger; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; - import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.events.EventBus; import org.apache.cloudstack.framework.events.EventBusException; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import com.cloud.event.EventCategory; -import com.cloud.event.dao.UsageEventDao; import com.cloud.network.Network.Event; import com.cloud.network.Network.State; -import com.cloud.network.dao.NetworkDao; import com.cloud.utils.component.ComponentContext; import com.cloud.utils.fsm.StateListener; +import com.cloud.utils.fsm.StateMachine2; public class NetworkStateListener implements StateListener { @Inject - protected UsageEventDao _usageEventDao; - @Inject - protected NetworkDao _networkDao; - @Inject - protected ConfigurationDao _configDao; + private ConfigurationDao _configDao; - protected static EventBus s_eventBus = null; + private static EventBus s_eventBus = null; private static final Logger s_logger = Logger.getLogger(NetworkStateListener.class); - public NetworkStateListener(UsageEventDao usageEventDao, NetworkDao networkDao, ConfigurationDao configDao) { - _usageEventDao = usageEventDao; - _networkDao = networkDao; + public NetworkStateListener(ConfigurationDao configDao) { _configDao = configDao; } diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index d99c9efa49..0bfd94749e 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -575,7 +575,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) { _agentMgr.registerForHostEvents(this, true, false, true); - Network.State.getStateMachine().registerListener(new NetworkStateListener(_usageEventDao, _networksDao, _configDao)); + Network.State.getStateMachine().registerListener(new NetworkStateListener(_configDao)); s_logger.info("Network Manager is configured."); diff --git a/server/src/com/cloud/network/IpAddressManagerImpl.java b/server/src/com/cloud/network/IpAddressManagerImpl.java index d4da5fae24..e65adb60f7 100644 --- a/server/src/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/com/cloud/network/IpAddressManagerImpl.java @@ -401,7 +401,7 @@ public boolean configure(String name, Map params) { AssignIpAddressFromPodVlanSearch.join("vlan", podVlanSearch, podVlanSearch.entity().getId(), AssignIpAddressFromPodVlanSearch.entity().getVlanId(), JoinType.INNER); AssignIpAddressFromPodVlanSearch.done(); - Network.State.getStateMachine().registerListener(new NetworkStateListener(_usageEventDao, _networksDao, _configDao)); + Network.State.getStateMachine().registerListener(new NetworkStateListener(_configDao)); s_logger.info("Network Manager is configured."); From 935113fbd3f1f370604a652b5d19d69e5fe56b9b Mon Sep 17 00:00:00 2001 From: cirstofolini Date: Sat, 19 Dec 2015 16:42:52 -0200 Subject: [PATCH 023/203] Removed unnecessary code from getGuestOsType in CitrixResourceBase --- .../resource/CitrixResourceBase.java | 10 +++--- .../xenserver/resource/XcpOssResource.java | 16 ---------- .../resource/CitrixResourceBaseTest.java | 31 +++++++++++++++++++ .../resource/XcpOssResourceTest.java | 17 ++++++++++ .../resource/XcpServerResourceTest.java | 17 ++++++++++ .../resource/XenServer56FP1ResourceTest.java | 17 ++++++++++ .../resource/XenServer56ResourceTest.java | 17 ++++++++++ .../resource/XenServer56SP2ResourceTest.java | 17 ++++++++++ .../resource/XenServer600ResourceTest.java | 17 ++++++++++ .../resource/XenServer625ResourceTest.java | 17 ++++++++++ .../resource/XenServer650ResourceTest.java | 17 ++++++++++ 11 files changed, 171 insertions(+), 22 deletions(-) diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index 7c8bca7f1b..155c84bbad 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -44,7 +44,6 @@ import java.util.UUID; import java.util.concurrent.TimeoutException; -import javax.ejb.Local; import javax.naming.ConfigurationException; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -164,7 +163,6 @@ * before you do any changes in this code here. * */ -@Local(value = ServerResource.class) public abstract class CitrixResourceBase implements ServerResource, HypervisorResource, VirtualRouterDeployer { public enum SRType { @@ -1232,7 +1230,7 @@ public VIF createVif(final Connection conn, final String vmName, final VM vm, fi } public VM createVmFromTemplate(final Connection conn, final VirtualMachineTO vmSpec, final Host host) throws XenAPIException, XmlRpcException { - final String guestOsTypeName = getGuestOsType(vmSpec.getOs(), vmSpec.getPlatformEmulator(), vmSpec.getBootloader() == BootloaderType.CD); + final String guestOsTypeName = getGuestOsType(vmSpec.getPlatformEmulator()); final Set templates = VM.getByNameLabel(conn, guestOsTypeName); if (templates == null || templates.isEmpty()) { throw new CloudRuntimeException("Cannot find template " + guestOsTypeName + " on XenServer host"); @@ -1337,7 +1335,7 @@ public VM createVmFromTemplate(final Connection conn, final VirtualMachineTO vmS final TemplateObjectTO iso = (TemplateObjectTO) disk.getData(); final String osType = iso.getGuestOsType(); if (osType != null) { - final String isoGuestOsName = getGuestOsType(osType, vmSpec.getPlatformEmulator(), vmSpec.getBootloader() == BootloaderType.CD); + final String isoGuestOsName = getGuestOsType(vmSpec.getPlatformEmulator()); if (!isoGuestOsName.equals(guestOsTypeName)) { vmSpec.setBootloader(BootloaderType.PyGrub); } @@ -2019,8 +2017,8 @@ public HashMap> getGPUGroupDetails(final return null; } - protected String getGuestOsType(final String stdType, String platformEmulator, final boolean bootFromCD) { - if (platformEmulator == null) { + protected String getGuestOsType(String platformEmulator) { + if (org.apache.commons.lang.StringUtils.isBlank(platformEmulator)) { s_logger.debug("no guest OS type, start it as HVM guest"); platformEmulator = "Other install media"; } diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XcpOssResource.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XcpOssResource.java index 44fad93514..ea7fe6ff34 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XcpOssResource.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XcpOssResource.java @@ -17,16 +17,12 @@ package com.cloud.hypervisor.xenserver.resource; -import javax.ejb.Local; - import org.apache.xmlrpc.XmlRpcException; -import com.cloud.resource.ServerResource; import com.xensource.xenapi.Connection; import com.xensource.xenapi.Types.XenAPIException; import com.xensource.xenapi.VM; -@Local(value = ServerResource.class) public class XcpOssResource extends CitrixResourceBase { private static final long mem_32m = 33554432L; @@ -36,18 +32,6 @@ protected String getPatchFilePath() { return "scripts/vm/hypervisor/xenserver/xcposs/patch"; } - @Override - protected String getGuestOsType(final String stdType, - final String platformEmulator, final boolean bootFromCD) { - if (stdType.equalsIgnoreCase("Debian GNU/Linux 6(64-bit)")) { - return "Debian Squeeze 6.0 (64-bit)"; - } else if (stdType.equalsIgnoreCase("CentOS 5.6 (64-bit)")) { - return "CentOS 5 (64-bit)"; - } else { - return super.getGuestOsType(stdType, platformEmulator, bootFromCD); - } - } - @Override protected void setMemory(final Connection conn, final VM vm, long minMemsize, final long maxMemsize) throws XmlRpcException, XenAPIException { vm.setMemoryLimits(conn, mem_32m, maxMemsize, minMemsize, maxMemsize); diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java index 353b10683e..81853d4554 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java @@ -49,4 +49,35 @@ public void testGetPathFilesListReturned(CitrixResourceBase citrixResourceBase) String receivedPath = files.get(0).getAbsolutePath(); Assert.assertEquals(receivedPath, pathExpected); } + + public void testGetGuestOsTypeNull(CitrixResourceBase citrixResourceBase) { + String platformEmulator = null; + + String expected = "Other install media"; + String guestOsType = citrixResourceBase.getGuestOsType(platformEmulator); + Assert.assertEquals(expected, guestOsType); + } + + public void testGetGuestOsTypeEmpty(CitrixResourceBase citrixResourceBase) { + String platformEmulator = ""; + + String expected = "Other install media"; + String guestOsType = citrixResourceBase.getGuestOsType(platformEmulator); + Assert.assertEquals(expected, guestOsType); + } + + public void testGetGuestOsTypeBlank(CitrixResourceBase citrixResourceBase) { + String platformEmulator = " "; + + String expected = "Other install media"; + String guestOsType = citrixResourceBase.getGuestOsType(platformEmulator); + Assert.assertEquals(expected, guestOsType); + } + + public void testGetGuestOsTypeOther(CitrixResourceBase citrixResourceBase) { + String platformEmulator = "My Own Linux Distribution Y.M (64-bit)"; + + String guestOsType = citrixResourceBase.getGuestOsType(platformEmulator); + Assert.assertEquals(platformEmulator, guestOsType); + } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java index b0c900c7f6..cd4db0f6d0 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java @@ -47,4 +47,21 @@ public void testGetFiles(){ public void testGetFilesListReturned(){ testGetPathFilesListReturned(xcpOssResource); } + + @Test + public void testGetOsTypeNull() { + testGetGuestOsTypeNull(xcpOssResource); + } + @Test + public void testGetOsTypeEmpty() { + testGetGuestOsTypeEmpty(xcpOssResource); + } + @Test + public void testGetOsTypeBlank() { + testGetGuestOsTypeBlank(xcpOssResource); + } + @Test + public void testGetOsTypeOther() { + testGetGuestOsTypeOther(xcpOssResource); + } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java index ba3d91de2a..95ba8f6785 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java @@ -48,4 +48,21 @@ public void testGetFilesExeption(){ public void testGetFilesListReturned(){ testGetPathFilesListReturned(xcpServerResource); } + + @Test + public void testGetOsTypeNull() { + testGetGuestOsTypeNull(xcpServerResource); + } + @Test + public void testGetOsTypeEmpty() { + testGetGuestOsTypeEmpty(xcpServerResource); + } + @Test + public void testGetOsTypeBlank() { + testGetGuestOsTypeBlank(xcpServerResource); + } + @Test + public void testGetOsTypeOther() { + testGetGuestOsTypeOther(xcpServerResource); + } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java index def51cf0d5..bba3b6ad04 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java @@ -45,4 +45,21 @@ public void testGetFiles(){ public void testGetFilesListReturned(){ testGetPathFilesListReturned(xenServer56FP1Resource); } + + @Test + public void testGetOsTypeNull() { + testGetGuestOsTypeNull(xenServer56FP1Resource); + } + @Test + public void testGetOsTypeEmpty() { + testGetGuestOsTypeEmpty(xenServer56FP1Resource); + } + @Test + public void testGetOsTypeBlank() { + testGetGuestOsTypeBlank(xenServer56FP1Resource); + } + @Test + public void testGetOsTypeOther() { + testGetGuestOsTypeOther(xenServer56FP1Resource); + } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java index 960dd7f049..4a6ff0bea5 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java @@ -46,4 +46,21 @@ public void testGetFiles(){ public void testGetFilesListReturned(){ testGetPathFilesListReturned(xenServer56Resource); } + + @Test + public void testGetOsTypeNull() { + testGetGuestOsTypeNull(xenServer56Resource); + } + @Test + public void testGetOsTypeEmpty() { + testGetGuestOsTypeEmpty(xenServer56Resource); + } + @Test + public void testGetOsTypeBlank() { + testGetGuestOsTypeBlank(xenServer56Resource); + } + @Test + public void testGetOsTypeOther() { + testGetGuestOsTypeOther(xenServer56Resource); + } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java index 300f95d6dd..defbe9be9d 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java @@ -45,4 +45,21 @@ public void testGetFiles(){ public void testGetFilesListReturned(){ testGetPathFilesListReturned(xenServer56SP2Resource); } + + @Test + public void testGetOsTypeNull() { + testGetGuestOsTypeNull(xenServer56SP2Resource); + } + @Test + public void testGetOsTypeEmpty() { + testGetGuestOsTypeEmpty(xenServer56SP2Resource); + } + @Test + public void testGetOsTypeBlank() { + testGetGuestOsTypeBlank(xenServer56SP2Resource); + } + @Test + public void testGetOsTypeOther() { + testGetGuestOsTypeOther(xenServer56SP2Resource); + } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java index 34deeb81f8..899f0a7339 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java @@ -45,4 +45,21 @@ public void testGetFiles(){ public void testGetFilesListReturned(){ testGetPathFilesListReturned(xenServer600Resource); } + + @Test + public void testGetOsTypeNull() { + testGetGuestOsTypeNull(xenServer600Resource); + } + @Test + public void testGetOsTypeEmpty() { + testGetGuestOsTypeEmpty(xenServer600Resource); + } + @Test + public void testGetOsTypeBlank() { + testGetGuestOsTypeBlank(xenServer600Resource); + } + @Test + public void testGetOsTypeOther() { + testGetGuestOsTypeOther(xenServer600Resource); + } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java index 640ca060a8..4c6a6ecf62 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java @@ -45,4 +45,21 @@ public void testGetFiles(){ public void testGetFilesListReturned(){ testGetPathFilesListReturned(xenServer625Resource); } + + @Test + public void testGetOsTypeNull() { + testGetGuestOsTypeNull(xenServer625Resource); + } + @Test + public void testGetOsTypeEmpty() { + testGetGuestOsTypeEmpty(xenServer625Resource); + } + @Test + public void testGetOsTypeBlank() { + testGetGuestOsTypeBlank(xenServer625Resource); + } + @Test + public void testGetOsTypeOther() { + testGetGuestOsTypeOther(xenServer625Resource); + } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java index 148b22def3..a062c0c99d 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java @@ -46,4 +46,21 @@ public void testGetFiles(){ public void testGetFilesListReturned(){ testGetPathFilesListReturned(xenServer650Resource); } + + @Test + public void testGetOsTypeNull() { + testGetGuestOsTypeNull(xenServer650Resource); + } + @Test + public void testGetOsTypeEmpty() { + testGetGuestOsTypeEmpty(xenServer650Resource); + } + @Test + public void testGetOsTypeBlank() { + testGetGuestOsTypeBlank(xenServer650Resource); + } + @Test + public void testGetOsTypeOther() { + testGetGuestOsTypeOther(xenServer650Resource); + } } From e985db90573accb2abb391c75223d111cb17a664 Mon Sep 17 00:00:00 2001 From: Anshul Gangwar Date: Fri, 8 May 2015 15:59:54 +0530 Subject: [PATCH 024/203] CLOUDSTACK-9194: Making the console popup window resizable in IE to make sure the focus is not lost. --- ui/scripts/ui/widgets/detailView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js index ddd7265774..2ce72a2578 100644 --- a/ui/scripts/ui/widgets/detailView.js +++ b/ui/scripts/ui/widgets/detailView.js @@ -301,7 +301,7 @@ }), // Window options - 'menubar=0,resizable=0,' + 'width=' + externalLinkAction.width + ',' + 'height=' + externalLinkAction.height + 'menubar=0,resizable=1,' + 'width=' + externalLinkAction.width + ',' + 'height=' + externalLinkAction.height ); } else { notification.desc = messages.notification(messageArgs); From cbbec6f8e26b8a25a87aa0e841ad86cf6a8fe957 Mon Sep 17 00:00:00 2001 From: Anshul Gangwar Date: Thu, 18 Jun 2015 15:49:29 +0530 Subject: [PATCH 025/203] CLOUDSTACK-9196: Fixing null pointer exception when vm meta data is synced on upgraded setup. --- .../src/com/cloud/vm/VirtualMachineManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java index 5c5838951f..300475af88 100644 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -2641,7 +2641,7 @@ public void syncVMMetaData(final Map vmMetadatum) { if(!found) { VMInstanceVO vm = _vmDao.findVMByInstanceName(name); - if(vm.getType() == VirtualMachine.Type.User) { + if(vm != null && vm.getType() == VirtualMachine.Type.User) { updateVmMetaData(vm.getId(), platform); } } From 149f6c05147a07abe845b53ed4d9bc159b68b0ff Mon Sep 17 00:00:00 2001 From: Anshul Gangwar Date: Wed, 23 Dec 2015 12:12:44 +0530 Subject: [PATCH 026/203] CLOUDSTACK-9199: Fixed deployVirtualMachine API does not throw an error when cpunumber is specified for static compute offering --- .../cloudstack/api/command/user/vm/DeployVMCmd.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index 82c281dad4..cfd2627585 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -553,6 +553,14 @@ public void create() throws ResourceAllocationException { throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId); } + if(!serviceOffering.isDynamic()) { + for(String detail: getDetails().keySet()) { + if(detail.equalsIgnoreCase("cpuNumber") || detail.equalsIgnoreCase("cpuSpeed") || detail.equalsIgnoreCase("memory")) { + throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering"); + } + } + } + VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId); // Make sure a valid template ID was specified if (template == null) { From ffce2d601eecab625376fd54f23d7741b9a64e7e Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Sat, 26 Dec 2015 09:00:31 +0100 Subject: [PATCH 027/203] remove autogenerated pydev files --- .gitignore | 2 ++ plugins/hypervisors/kvm/.pydevproject | 25 ------------------------ scripts/.pydevproject | 28 --------------------------- 3 files changed, 2 insertions(+), 53 deletions(-) delete mode 100644 plugins/hypervisors/kvm/.pydevproject delete mode 100644 scripts/.pydevproject diff --git a/.gitignore b/.gitignore index 58eafaf68d..48aa29b69e 100644 --- a/.gitignore +++ b/.gitignore @@ -96,3 +96,5 @@ tools/appliance/box/ .pydevproject systemvm/.pydevproject test/.pydevprojec +plugins/hypervisors/kvm/.pydevproject +scripts/.pydevproject diff --git a/plugins/hypervisors/kvm/.pydevproject b/plugins/hypervisors/kvm/.pydevproject deleted file mode 100644 index d4a984a390..0000000000 --- a/plugins/hypervisors/kvm/.pydevproject +++ /dev/null @@ -1,25 +0,0 @@ - - - - - -Default -python 2.7 - diff --git a/scripts/.pydevproject b/scripts/.pydevproject deleted file mode 100644 index 43efe469ed..0000000000 --- a/scripts/.pydevproject +++ /dev/null @@ -1,28 +0,0 @@ - - - - - -Default -python 2.6 - -/scripts - - From 1ead444cca7c11181899627698b7a0779812c76c Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Fri, 25 Dec 2015 13:51:50 +0100 Subject: [PATCH 028/203] security rules test --- .../agent/api/SecurityGroupRulesCmd.java | 2 + .../agent/api/SecurityGroupRulesCmdTest.java | 101 ++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 core/test/com/cloud/agent/api/SecurityGroupRulesCmdTest.java diff --git a/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java b/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java index b9bdef5646..098d82c834 100644 --- a/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java +++ b/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java @@ -32,6 +32,8 @@ import com.cloud.utils.net.NetUtils; public class SecurityGroupRulesCmd extends Command { + static final String EGRESS_RULE = "E:"; + static final String INGRESS_RULE = "I:"; private static Logger s_logger = Logger.getLogger(SecurityGroupRulesCmd.class); public static class IpPortAndProto { diff --git a/core/test/com/cloud/agent/api/SecurityGroupRulesCmdTest.java b/core/test/com/cloud/agent/api/SecurityGroupRulesCmdTest.java new file mode 100644 index 0000000000..2b094c5a40 --- /dev/null +++ b/core/test/com/cloud/agent/api/SecurityGroupRulesCmdTest.java @@ -0,0 +1,101 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.agent.api; + +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.Vector; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +import com.cloud.agent.api.SecurityGroupRulesCmd.IpPortAndProto; + +/** + * @author daan + * + */ +@RunWith(MockitoJUnitRunner.class) +public class SecurityGroupRulesCmdTest { + private SecurityGroupRulesCmd securityGroupRulesCmd; + + /** + * @throws java.lang.Exception + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + String guestIp = "10.10.10.10"; + String guestMac = "aa:aa:aa:aa:aa:aa"; + String vmName = "vm"; + Long vmId = 1L; + String signature = "sig"; + Long seqNum = 0L; + String proto = "abc"; + int startPort = 1; + int endPort = 2; + String[] allowedCidrs = new String[] {"1.2.3.4/5","6.7.8.9/0"}; + IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{new IpPortAndProto(proto, startPort, endPort, allowedCidrs)}; + IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{new IpPortAndProto(proto, startPort, endPort, allowedCidrs)}; + List secIps = new Vector(); + securityGroupRulesCmd = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps); + } + + /** + * Test method for {@link com.cloud.agent.api.SecurityGroupRulesCmd#stringifyRules()}. + */ + @Test + public void testStringifyRules() throws Exception { + String a = securityGroupRulesCmd.stringifyRules(); +// do verification on a + assertTrue(a.contains(SecurityGroupRulesCmd.EGRESS_RULE)); + } + + /** + * Test method for {@link com.cloud.agent.api.SecurityGroupRulesCmd#stringifyCompressedRules()}. + */ + @Test + public void testStringifyCompressedRules() throws Exception { + String a = securityGroupRulesCmd.stringifyCompressedRules(); +// do verification on a + assertTrue(a.contains(SecurityGroupRulesCmd.EGRESS_RULE)); + } + + /** + * Test method for {@link com.cloud.agent.api.SecurityGroupRulesCmd#compressStringifiedRules()}. + */ + @Test + public void testCompressStringifiedRules() throws Exception { + String compressed = "eJzztEpMSrYytDKyMtQz0jPWM9E31THTM9ez0LPUN9Dxc40IUXAlrAQAPdoP3Q=="; + String a = securityGroupRulesCmd.compressStringifiedRules(); + assertTrue(compressed.equals(a)); + } + +} From d1c1bde01bda6e2aa01fd1fa5226b4067ff517ce Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Fri, 25 Dec 2015 13:04:11 +0100 Subject: [PATCH 029/203] code cleanup --- .../agent/api/SecurityGroupRulesCmd.java | 94 +++++-------------- 1 file changed, 26 insertions(+), 68 deletions(-) diff --git a/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java b/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java index 098d82c834..fbc3835d43 100644 --- a/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java +++ b/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java @@ -47,7 +47,7 @@ public IpPortAndProto() { } public IpPortAndProto(String proto, int startPort, int endPort, String[] allowedCidrs) { - super(); + this(); this.proto = proto; this.startPort = startPort; this.endPort = endPort; @@ -93,7 +93,7 @@ public SecurityGroupRulesCmd() { public SecurityGroupRulesCmd(String guestIp, String guestMac, String vmName, Long vmId, String signature, Long seqNum, IpPortAndProto[] ingressRuleSet, IpPortAndProto[] egressRuleSet) { - super(); + this(); this.guestIp = guestIp; this.vmName = vmName; this.ingressRuleSet = ingressRuleSet; @@ -110,19 +110,7 @@ public SecurityGroupRulesCmd(String guestIp, String guestMac, String vmName, Lon public SecurityGroupRulesCmd(String guestIp, String guestMac, String vmName, Long vmId, String signature, Long seqNum, IpPortAndProto[] ingressRuleSet, IpPortAndProto[] egressRuleSet, List secIps) { - super(); - this.guestIp = guestIp; - this.vmName = vmName; - this.ingressRuleSet = ingressRuleSet; - this.egressRuleSet = egressRuleSet; - this.guestMac = guestMac; - this.signature = signature; - this.seqNum = seqNum; - this.vmId = vmId; - if (signature == null) { - String stringified = stringifyRules(); - this.signature = DigestUtils.md5Hex(stringified); - } + this(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet); this.secIps = secIps; } @@ -159,27 +147,6 @@ public String getVmName() { return vmName; } - public String stringifyRules() { - StringBuilder ruleBuilder = new StringBuilder(); - for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : getIngressRuleSet()) { - ruleBuilder.append("I:").append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); - for (String cidr : ipPandP.getAllowedCidrs()) { - ruleBuilder.append(cidr).append(","); - } - ruleBuilder.append("NEXT"); - ruleBuilder.append(" "); - } - for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : getEgressRuleSet()) { - ruleBuilder.append("E:").append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); - for (String cidr : ipPandP.getAllowedCidrs()) { - ruleBuilder.append(cidr).append(","); - } - ruleBuilder.append("NEXT"); - ruleBuilder.append(" "); - } - return ruleBuilder.toString(); - } - //convert cidrs in the form "a.b.c.d/e" to "hexvalue of 32bit ip/e" private String compressCidr(String cidr) { String[] toks = cidr.split("/"); @@ -200,27 +167,35 @@ public String getSecIpsString() { return sb.toString(); } + public String stringifyRules() { + StringBuilder ruleBuilder = new StringBuilder(); + stringifyRulesFor(getIngressRuleSet(), INGRESS_RULE, false, ruleBuilder); + stringifyRulesFor(getEgressRuleSet(), EGRESS_RULE, false, ruleBuilder); + return ruleBuilder.toString(); + } + public String stringifyCompressedRules() { StringBuilder ruleBuilder = new StringBuilder(); - for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : getIngressRuleSet()) { - ruleBuilder.append("I:").append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); - for (String cidr : ipPandP.getAllowedCidrs()) { - //convert cidrs in the form "a.b.c.d/e" to "hexvalue of 32bit ip/e" - ruleBuilder.append(compressCidr(cidr)).append(","); - } - ruleBuilder.append("NEXT"); - ruleBuilder.append(" "); - } - for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : getEgressRuleSet()) { - ruleBuilder.append("E:").append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); + stringifyRulesFor(getEgressRuleSet(), INGRESS_RULE, true, ruleBuilder); + stringifyRulesFor(getEgressRuleSet(), EGRESS_RULE, true, ruleBuilder); + return ruleBuilder.toString(); + } + + /** + * @param ipPandPs + * @param gression + * @param compress + * @param ruleBuilder + */ + void stringifyRulesFor(SecurityGroupRulesCmd.IpPortAndProto[] ipPandPs, String gression, boolean compress, StringBuilder ruleBuilder) { + for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : ipPandPs) { + ruleBuilder.append(gression).append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); for (String cidr : ipPandP.getAllowedCidrs()) { - //convert cidrs in the form "a.b.c.d/e" to "hexvalue of 32bit ip/e" - ruleBuilder.append(compressCidr(cidr)).append(","); + ruleBuilder.append(compress?compressCidr(cidr):cidr).append(","); } ruleBuilder.append("NEXT"); ruleBuilder.append(" "); } - return ruleBuilder.toString(); } /* @@ -228,24 +203,7 @@ public String stringifyCompressedRules() { * to scale beyond 8k cidrs. */ public String compressStringifiedRules() { - StringBuilder ruleBuilder = new StringBuilder(); - for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : getIngressRuleSet()) { - ruleBuilder.append("I:").append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); - for (String cidr : ipPandP.getAllowedCidrs()) { - ruleBuilder.append(cidr).append(","); - } - ruleBuilder.append("NEXT"); - ruleBuilder.append(" "); - } - for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : getEgressRuleSet()) { - ruleBuilder.append("E:").append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); - for (String cidr : ipPandP.getAllowedCidrs()) { - ruleBuilder.append(cidr).append(","); - } - ruleBuilder.append("NEXT"); - ruleBuilder.append(" "); - } - String stringified = ruleBuilder.toString(); + String stringified = stringifyRules(); ByteArrayOutputStream out = new ByteArrayOutputStream(); try { //Note : not using GZipOutputStream since that is for files From d39182f9d432ff477b7021ce805980c35ba39408 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Fri, 25 Dec 2015 16:47:14 +0100 Subject: [PATCH 030/203] deal with PMD warnings --- .../agent/api/SecurityGroupRulesCmd.java | 168 +++---- .../SecurityGroupHttpClient.java | 410 +++++++++--------- ...bvirtSecurityGroupRulesCommandWrapper.java | 2 +- .../LibvirtComputingResourceTest.java | 22 +- .../cloud/ovm/hypervisor/OvmResourceBase.java | 4 +- .../agent/manager/MockVmManagerImpl.java | 2 +- ...itrixSecurityGroupRulesCommandWrapper.java | 2 +- .../xenbase/CitrixRequestWrapperTest.java | 14 +- .../security/SecurityGroupManagerImpl2.java | 4 +- 9 files changed, 329 insertions(+), 299 deletions(-) diff --git a/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java b/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java index fbc3835d43..a7f44251dd 100644 --- a/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java +++ b/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java @@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.zip.DeflaterOutputStream; @@ -32,34 +33,47 @@ import com.cloud.utils.net.NetUtils; public class SecurityGroupRulesCmd extends Command { - static final String EGRESS_RULE = "E:"; - static final String INGRESS_RULE = "I:"; - private static Logger s_logger = Logger.getLogger(SecurityGroupRulesCmd.class); + private static final char RULE_TARGET_SEPARATOR = ','; + private static final char RULE_COMMAND_SEPARATOR = ':'; + protected static final String EGRESS_RULE = "E:"; + protected static final String INGRESS_RULE = "I:"; + private static final Logger LOGGER = Logger.getLogger(SecurityGroupRulesCmd.class); + + private final String guestIp; + private final String vmName; + private final String guestMac; + private final String signature; + private final Long seqNum; + private final Long vmId; + private Long msId; + private List ingressRuleSet; + private List egressRuleSet; + private final List secIps; public static class IpPortAndProto { - private String proto; - private int startPort; - private int endPort; + private final String proto; + private final int startPort; + private final int endPort; @LogLevel(Log4jLevel.Trace) - private String[] allowedCidrs; + private List allowedCidrs; - public IpPortAndProto() { - } - - public IpPortAndProto(String proto, int startPort, int endPort, String[] allowedCidrs) { - this(); + public IpPortAndProto(final String proto, final int startPort, final int endPort, final String... allowedCidrs) { + super(); this.proto = proto; this.startPort = startPort; this.endPort = endPort; - this.allowedCidrs = allowedCidrs; + setAllowedCidrs(allowedCidrs); } - public String[] getAllowedCidrs() { + public List getAllowedCidrs() { return allowedCidrs; } - public void setAllowedCidrs(String[] allowedCidrs) { - this.allowedCidrs = allowedCidrs; + public void setAllowedCidrs(final String... allowedCidrs) { + this.allowedCidrs = new ArrayList(); + for (final String allowedCidr : allowedCidrs) { + this.allowedCidrs.add(allowedCidr); + } } public String getProto() { @@ -76,41 +90,29 @@ public int getEndPort() { } - String guestIp; - String vmName; - String guestMac; - String signature; - Long seqNum; - Long vmId; - Long msId; - IpPortAndProto[] ingressRuleSet; - IpPortAndProto[] egressRuleSet; - private List secIps; - - public SecurityGroupRulesCmd() { - super(); - } - - public SecurityGroupRulesCmd(String guestIp, String guestMac, String vmName, Long vmId, String signature, Long seqNum, IpPortAndProto[] ingressRuleSet, - IpPortAndProto[] egressRuleSet) { - this(); + public SecurityGroupRulesCmd( + final String guestIp, + final String guestMac, + final String vmName, + final Long vmId, + final String signature, + final Long seqNum, + final IpPortAndProto[] ingressRuleSet, + final IpPortAndProto[] egressRuleSet, + final List secIps) { this.guestIp = guestIp; this.vmName = vmName; - this.ingressRuleSet = ingressRuleSet; - this.egressRuleSet = egressRuleSet; + setIngressRuleSet(ingressRuleSet); + this.setEgressRuleSet(egressRuleSet); this.guestMac = guestMac; - this.signature = signature; this.seqNum = seqNum; this.vmId = vmId; if (signature == null) { - String stringified = stringifyRules(); + final String stringified = stringifyRules(); this.signature = DigestUtils.md5Hex(stringified); + } else { + this.signature = signature; } - } - - public SecurityGroupRulesCmd(String guestIp, String guestMac, String vmName, Long vmId, String signature, Long seqNum, IpPortAndProto[] ingressRuleSet, - IpPortAndProto[] egressRuleSet, List secIps) { - this(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet); this.secIps = secIps; } @@ -119,20 +121,26 @@ public boolean executeInSequence() { return true; } - public IpPortAndProto[] getIngressRuleSet() { + public List getIngressRuleSet() { return ingressRuleSet; } - public void setIngressRuleSet(IpPortAndProto[] ingressRuleSet) { - this.ingressRuleSet = ingressRuleSet; + public void setIngressRuleSet(final IpPortAndProto... ingressRuleSet) { + this.ingressRuleSet = new ArrayList(); + for(final IpPortAndProto rule: ingressRuleSet) { + this.ingressRuleSet.add(rule); + } } - public IpPortAndProto[] getEgressRuleSet() { + public List getEgressRuleSet() { return egressRuleSet; } - public void setEgressRuleSet(IpPortAndProto[] egressRuleSet) { - this.egressRuleSet = egressRuleSet; + public void setEgressRuleSet(final IpPortAndProto... egressRuleSet) { + this.egressRuleSet = new ArrayList(); + for(final IpPortAndProto rule: egressRuleSet) { + this.egressRuleSet.add(rule); + } } public String getGuestIp() { @@ -148,35 +156,35 @@ public String getVmName() { } //convert cidrs in the form "a.b.c.d/e" to "hexvalue of 32bit ip/e" - private String compressCidr(String cidr) { - String[] toks = cidr.split("/"); - long ipnum = NetUtils.ip2Long(toks[0]); + private String compressCidr(final String cidr) { + final String[] toks = cidr.split("/"); + final long ipnum = NetUtils.ip2Long(toks[0]); return Long.toHexString(ipnum) + "/" + toks[1]; } public String getSecIpsString() { - StringBuilder sb = new StringBuilder(); - List ips = getSecIps(); + final StringBuilder sb = new StringBuilder(); + final List ips = getSecIps(); if (ips == null) { - return "0:"; + sb.append("0:"); } else { - for (String ip : ips) { - sb.append(ip).append(":"); + for (final String ip : ips) { + sb.append(ip).append(RULE_COMMAND_SEPARATOR); } } return sb.toString(); } public String stringifyRules() { - StringBuilder ruleBuilder = new StringBuilder(); + final StringBuilder ruleBuilder = new StringBuilder(); stringifyRulesFor(getIngressRuleSet(), INGRESS_RULE, false, ruleBuilder); stringifyRulesFor(getEgressRuleSet(), EGRESS_RULE, false, ruleBuilder); return ruleBuilder.toString(); } public String stringifyCompressedRules() { - StringBuilder ruleBuilder = new StringBuilder(); - stringifyRulesFor(getEgressRuleSet(), INGRESS_RULE, true, ruleBuilder); + final StringBuilder ruleBuilder = new StringBuilder(); + stringifyRulesFor(getIngressRuleSet(), INGRESS_RULE, true, ruleBuilder); stringifyRulesFor(getEgressRuleSet(), EGRESS_RULE, true, ruleBuilder); return ruleBuilder.toString(); } @@ -187,14 +195,17 @@ public String stringifyCompressedRules() { * @param compress * @param ruleBuilder */ - void stringifyRulesFor(SecurityGroupRulesCmd.IpPortAndProto[] ipPandPs, String gression, boolean compress, StringBuilder ruleBuilder) { - for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : ipPandPs) { - ruleBuilder.append(gression).append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); - for (String cidr : ipPandP.getAllowedCidrs()) { - ruleBuilder.append(compress?compressCidr(cidr):cidr).append(","); + private void stringifyRulesFor( + final List ipPandPs, + final String gression, + final boolean compress, + final StringBuilder ruleBuilder) { + for (final IpPortAndProto ipPandP : ipPandPs) { + ruleBuilder.append(gression).append(ipPandP.getProto()).append(RULE_COMMAND_SEPARATOR).append(ipPandP.getStartPort()).append(RULE_COMMAND_SEPARATOR).append(ipPandP.getEndPort()).append(RULE_COMMAND_SEPARATOR); + for (final String cidr : ipPandP.getAllowedCidrs()) { + ruleBuilder.append(compress?compressCidr(cidr):cidr).append(RULE_TARGET_SEPARATOR); } - ruleBuilder.append("NEXT"); - ruleBuilder.append(" "); + ruleBuilder.append("NEXT "); } } @@ -203,19 +214,20 @@ void stringifyRulesFor(SecurityGroupRulesCmd.IpPortAndProto[] ipPandPs, String g * to scale beyond 8k cidrs. */ public String compressStringifiedRules() { - String stringified = stringifyRules(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); + final String stringified = stringifyRules(); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + String encodedResult = null; try { //Note : not using GZipOutputStream since that is for files //GZipOutputStream gives a different header, although the compression is the same - DeflaterOutputStream dzip = new DeflaterOutputStream(out); + final DeflaterOutputStream dzip = new DeflaterOutputStream(out); dzip.write(stringified.getBytes()); dzip.close(); + encodedResult = Base64.encodeBase64String(out.toByteArray()); } catch (IOException e) { - s_logger.warn("Exception while compressing security group rules"); - return null; + LOGGER.warn("Exception while compressing security group rules"); } - return Base64.encodeBase64String(out.toByteArray()); + return encodedResult; } public String getSignature() { @@ -237,16 +249,16 @@ public Long getVmId() { public int getTotalNumCidrs() { //useful for logging int count = 0; - for (IpPortAndProto i : ingressRuleSet) { - count += i.allowedCidrs.length; + for (final IpPortAndProto i : ingressRuleSet) { + count += i.allowedCidrs.size(); } - for (IpPortAndProto i : egressRuleSet) { - count += i.allowedCidrs.length; + for (final IpPortAndProto i : egressRuleSet) { + count += i.allowedCidrs.size(); } return count; } - public void setMsId(long msId) { + public void setMsId(final long msId) { this.msId = msId; } diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java index b9e4858895..b100929da9 100644 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java @@ -1,205 +1,205 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// -// Automatically generated by addcopyright.py at 01/29/2013 -// Apache License, Version 2.0 (the "License"); you may not use this -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// -// Automatically generated by addcopyright.py at 04/03/2012 - -package com.cloud.baremetal.networkservice; - -import com.cloud.agent.api.SecurityGroupRuleAnswer; -import com.cloud.agent.api.SecurityGroupRulesCmd; -import com.cloud.agent.api.SecurityGroupRulesCmd.IpPortAndProto; -import com.cloud.baremetal.networkservice.schema.SecurityGroupRule; -import com.cloud.baremetal.networkservice.schema.SecurityGroupVmRuleSet; -import com.cloud.utils.Pair; -import com.cloud.utils.exception.CloudRuntimeException; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.StringRequestEntity; -import org.apache.log4j.Logger; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; -import java.io.StringWriter; -import java.net.SocketTimeoutException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.TimeUnit; - -public class SecurityGroupHttpClient { - private static final Logger logger = Logger.getLogger(SecurityGroupHttpClient.class); - private static final String ARG_NAME = "args"; - private static final String COMMAND = "command"; - private JAXBContext context; - private int port; - private static HttpClient httpClient; - static { - MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager(); - httpClient = new HttpClient(connman); - httpClient.setConnectionTimeout(5000); - } - - private enum OpConstant { - setRules, echo, - } - - public SecurityGroupHttpClient() { - try { - context = JAXBContext.newInstance(SecurityGroupRule.class, SecurityGroupVmRuleSet.class); - port = 9988; - } catch (Exception e) { - throw new CloudRuntimeException( - "Unable to create JAXBContext for security group", e); - } - } - - private List generateRules(IpPortAndProto[] ipps) { - List rules = new ArrayList( - ipps.length); - for (SecurityGroupRulesCmd.IpPortAndProto ipp : ipps) { - SecurityGroupRule r = new SecurityGroupRule(); - r.setProtocol(ipp.getProto()); - r.setStartPort(ipp.getStartPort()); - r.setEndPort(ipp.getEndPort()); - for (String cidr : ipp.getAllowedCidrs()) { - r.getIp().add(cidr); - } - rules.add(r); - } - return rules; - } - - public HashMap> sync(String vmName, Long vmId, String agentIp) { - HashMap> states = new HashMap>(); - PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort())); - try { - post.addRequestHeader("command", "sync"); - if (httpClient.executeMethod(post) != 200) { - logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString())); - } else { - String res = post.getResponseBodyAsString(); - // res = ';'.join([vmName, vmId, seqno]) - String[] rulelogs = res.split(","); - if (rulelogs.length != 6) { - logger.debug(String.format("host[%s] returns invalid security group sync document[%s], reset rules", agentIp, res)); - states.put(vmName, new Pair(vmId, -1L)); - return states; - } - Pair p = new Pair(Long.valueOf(rulelogs[1]), Long.valueOf(rulelogs[5])); - states.put(rulelogs[0], p); - return states; - } - } catch (SocketTimeoutException se) { - logger.warn(String.format("unable to sync security group rules on host[%s], %s", agentIp, se.getMessage())); - } catch (Exception e) { - logger.warn(String.format("unable to sync security group rules on host[%s]", agentIp), e); - } finally { - if (post != null) { - post.releaseConnection(); - } - } - return states; - } - - - public boolean echo(String agentIp, long l, long m) { - boolean ret = false; - int count = 1; - while (true) { - try { - Thread.sleep(m); - count++; - } catch (InterruptedException e1) { - logger.warn("", e1); - break; - } - PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort())); - try { - post.addRequestHeader("command", "echo"); - if (httpClient.executeMethod(post) != 200) { - logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString())); - } else { - ret = true; - } - break; - } catch (Exception e) { - if (count*m >= l) { - logger.debug(String.format("ping security group agent on vm[%s] timeout after %s minutes, starting vm failed, count=%s", agentIp, TimeUnit.MILLISECONDS.toSeconds(l), count)); - break; - } else { - logger.debug(String.format("Having pinged security group agent on vm[%s] %s times, continue to wait...", agentIp, count)); - } - } finally { - if (post != null) { - post.releaseConnection(); - } - } - } - return ret; - } - - public SecurityGroupRuleAnswer call(String agentIp, SecurityGroupRulesCmd cmd) { - PostMethod post = new PostMethod(String.format( - "http://%s:%s", agentIp, getPort())); - try { - SecurityGroupVmRuleSet rset = new SecurityGroupVmRuleSet(); - rset.getEgressRules().addAll(generateRules(cmd.getEgressRuleSet())); - rset.getIngressRules().addAll( - generateRules(cmd.getIngressRuleSet())); - rset.setVmName(cmd.getVmName()); - rset.setVmIp(cmd.getGuestIp()); - rset.setVmMac(cmd.getGuestMac()); - rset.setVmId(cmd.getVmId()); - rset.setSignature(cmd.getSignature()); - rset.setSequenceNumber(cmd.getSeqNum()); - Marshaller marshaller = context.createMarshaller(); - StringWriter writer = new StringWriter(); - marshaller.marshal(rset, writer); - String xmlContents = writer.toString(); - logger.debug(xmlContents); - - post.addRequestHeader("command", "set_rules"); - StringRequestEntity entity = new StringRequestEntity(xmlContents); - post.setRequestEntity(entity); - if (httpClient.executeMethod(post) != 200) { - return new SecurityGroupRuleAnswer(cmd, false, - post.getResponseBodyAsString()); - } else { - return new SecurityGroupRuleAnswer(cmd); - } - } catch (Exception e) { - return new SecurityGroupRuleAnswer(cmd, false, e.getMessage()); - } finally { - if (post != null) { - post.releaseConnection(); - } - } - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } -} +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// Automatically generated by addcopyright.py at 01/29/2013 +// Apache License, Version 2.0 (the "License"); you may not use this +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// Automatically generated by addcopyright.py at 04/03/2012 + +package com.cloud.baremetal.networkservice; + +import com.cloud.agent.api.SecurityGroupRuleAnswer; +import com.cloud.agent.api.SecurityGroupRulesCmd; +import com.cloud.agent.api.SecurityGroupRulesCmd.IpPortAndProto; +import com.cloud.baremetal.networkservice.schema.SecurityGroupRule; +import com.cloud.baremetal.networkservice.schema.SecurityGroupVmRuleSet; +import com.cloud.utils.Pair; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.StringRequestEntity; +import org.apache.log4j.Logger; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; +import java.io.StringWriter; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class SecurityGroupHttpClient { + private static final Logger logger = Logger.getLogger(SecurityGroupHttpClient.class); + private static final String ARG_NAME = "args"; + private static final String COMMAND = "command"; + private JAXBContext context; + private int port; + private static HttpClient httpClient; + static { + MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager(); + httpClient = new HttpClient(connman); + httpClient.setConnectionTimeout(5000); + } + + private enum OpConstant { + setRules, echo, + } + + public SecurityGroupHttpClient() { + try { + context = JAXBContext.newInstance(SecurityGroupRule.class, SecurityGroupVmRuleSet.class); + port = 9988; + } catch (Exception e) { + throw new CloudRuntimeException( + "Unable to create JAXBContext for security group", e); + } + } + + private List generateRules(final List ipps) { + List rules = new ArrayList( + ipps.size()); + for (SecurityGroupRulesCmd.IpPortAndProto ipp : ipps) { + SecurityGroupRule r = new SecurityGroupRule(); + r.setProtocol(ipp.getProto()); + r.setStartPort(ipp.getStartPort()); + r.setEndPort(ipp.getEndPort()); + for (String cidr : ipp.getAllowedCidrs()) { + r.getIp().add(cidr); + } + rules.add(r); + } + return rules; + } + + public HashMap> sync(String vmName, Long vmId, String agentIp) { + HashMap> states = new HashMap>(); + PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort())); + try { + post.addRequestHeader("command", "sync"); + if (httpClient.executeMethod(post) != 200) { + logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString())); + } else { + String res = post.getResponseBodyAsString(); + // res = ';'.join([vmName, vmId, seqno]) + String[] rulelogs = res.split(","); + if (rulelogs.length != 6) { + logger.debug(String.format("host[%s] returns invalid security group sync document[%s], reset rules", agentIp, res)); + states.put(vmName, new Pair(vmId, -1L)); + return states; + } + Pair p = new Pair(Long.valueOf(rulelogs[1]), Long.valueOf(rulelogs[5])); + states.put(rulelogs[0], p); + return states; + } + } catch (SocketTimeoutException se) { + logger.warn(String.format("unable to sync security group rules on host[%s], %s", agentIp, se.getMessage())); + } catch (Exception e) { + logger.warn(String.format("unable to sync security group rules on host[%s]", agentIp), e); + } finally { + if (post != null) { + post.releaseConnection(); + } + } + return states; + } + + + public boolean echo(String agentIp, long l, long m) { + boolean ret = false; + int count = 1; + while (true) { + try { + Thread.sleep(m); + count++; + } catch (InterruptedException e1) { + logger.warn("", e1); + break; + } + PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort())); + try { + post.addRequestHeader("command", "echo"); + if (httpClient.executeMethod(post) != 200) { + logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString())); + } else { + ret = true; + } + break; + } catch (Exception e) { + if (count*m >= l) { + logger.debug(String.format("ping security group agent on vm[%s] timeout after %s minutes, starting vm failed, count=%s", agentIp, TimeUnit.MILLISECONDS.toSeconds(l), count)); + break; + } else { + logger.debug(String.format("Having pinged security group agent on vm[%s] %s times, continue to wait...", agentIp, count)); + } + } finally { + if (post != null) { + post.releaseConnection(); + } + } + } + return ret; + } + + public SecurityGroupRuleAnswer call(String agentIp, SecurityGroupRulesCmd cmd) { + PostMethod post = new PostMethod(String.format( + "http://%s:%s", agentIp, getPort())); + try { + SecurityGroupVmRuleSet rset = new SecurityGroupVmRuleSet(); + rset.getEgressRules().addAll(generateRules(cmd.getEgressRuleSet())); + rset.getIngressRules().addAll( + generateRules(cmd.getIngressRuleSet())); + rset.setVmName(cmd.getVmName()); + rset.setVmIp(cmd.getGuestIp()); + rset.setVmMac(cmd.getGuestMac()); + rset.setVmId(cmd.getVmId()); + rset.setSignature(cmd.getSignature()); + rset.setSequenceNumber(cmd.getSeqNum()); + Marshaller marshaller = context.createMarshaller(); + StringWriter writer = new StringWriter(); + marshaller.marshal(rset, writer); + String xmlContents = writer.toString(); + logger.debug(xmlContents); + + post.addRequestHeader("command", "set_rules"); + StringRequestEntity entity = new StringRequestEntity(xmlContents); + post.setRequestEntity(entity); + if (httpClient.executeMethod(post) != 200) { + return new SecurityGroupRuleAnswer(cmd, false, + post.getResponseBodyAsString()); + } else { + return new SecurityGroupRuleAnswer(cmd); + } + } catch (Exception e) { + return new SecurityGroupRuleAnswer(cmd, false, e.getMessage()); + } finally { + if (post != null) { + post.releaseConnection(); + } + } + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } +} diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtSecurityGroupRulesCommandWrapper.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtSecurityGroupRulesCommandWrapper.java index f1a2e02dea..ef9fd896dd 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtSecurityGroupRulesCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtSecurityGroupRulesCommandWrapper.java @@ -62,7 +62,7 @@ public Answer execute(final SecurityGroupRulesCmd command, final LibvirtComputin return new SecurityGroupRuleAnswer(command, false, "programming network rules failed"); } else { s_logger.debug("Programmed network rules for vm " + command.getVmName() + " guestIp=" + command.getGuestIp() + ",ingress numrules=" - + command.getIngressRuleSet().length + ",egress numrules=" + command.getEgressRuleSet().length); + + command.getIngressRuleSet().size() + ",egress numrules=" + command.getEgressRuleSet().size()); return new SecurityGroupRuleAnswer(command); } } diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 04a27f3d8c..66efdf29ec 100644 --- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -39,6 +39,7 @@ import java.util.List; import java.util.Random; import java.util.UUID; +import java.util.Vector; import javax.naming.ConfigurationException; import javax.xml.parsers.DocumentBuilderFactory; @@ -2893,8 +2894,11 @@ public void testSecurityGroupRulesCmdFalse() { final Long seqNum = 1l; final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; + final List secIps = new Vector(); + final List cidrs = new Vector(); + cidrs.add("0.0.0.0/0"); - final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet); + final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps); final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class); final Connect conn = Mockito.mock(Connect.class); @@ -2914,12 +2918,12 @@ public void testSecurityGroupRulesCmdFalse() { when(ingressRuleSet[0].getProto()).thenReturn("tcp"); when(ingressRuleSet[0].getStartPort()).thenReturn(22); when(ingressRuleSet[0].getEndPort()).thenReturn(22); - when(ingressRuleSet[0].getAllowedCidrs()).thenReturn(new String[]{"0.0.0.0/0"}); + when(ingressRuleSet[0].getAllowedCidrs()).thenReturn(cidrs); when(egressRuleSet[0].getProto()).thenReturn("tcp"); when(egressRuleSet[0].getStartPort()).thenReturn(22); when(egressRuleSet[0].getEndPort()).thenReturn(22); - when(egressRuleSet[0].getAllowedCidrs()).thenReturn(new String[]{"0.0.0.0/0"}); + when(egressRuleSet[0].getAllowedCidrs()).thenReturn(cidrs); final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance(); assertNotNull(wrapper); @@ -2945,8 +2949,11 @@ public void testSecurityGroupRulesCmdTrue() { final Long seqNum = 1l; final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; + final List secIps = new Vector(); + final List cidrs = new Vector(); + cidrs.add("0.0.0.0/0"); - final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet); + final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps); final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class); final Connect conn = Mockito.mock(Connect.class); @@ -2972,12 +2979,12 @@ public void testSecurityGroupRulesCmdTrue() { when(ingressRuleSet[0].getProto()).thenReturn("tcp"); when(ingressRuleSet[0].getStartPort()).thenReturn(22); when(ingressRuleSet[0].getEndPort()).thenReturn(22); - when(ingressRuleSet[0].getAllowedCidrs()).thenReturn(new String[]{"0.0.0.0/0"}); + when(ingressRuleSet[0].getAllowedCidrs()).thenReturn(cidrs); when(egressRuleSet[0].getProto()).thenReturn("tcp"); when(egressRuleSet[0].getStartPort()).thenReturn(22); when(egressRuleSet[0].getEndPort()).thenReturn(22); - when(egressRuleSet[0].getAllowedCidrs()).thenReturn(new String[]{"0.0.0.0/0"}); + when(egressRuleSet[0].getAllowedCidrs()).thenReturn(cidrs); when(libvirtComputingResource.addNetworkRules(command.getVmName(), Long.toString(command.getVmId()), command.getGuestIp(), command.getSignature(), Long.toString(command.getSeqNum()), command.getGuestMac(), command.stringifyRules(), vif, brname, command.getSecIpsString())).thenReturn(true); @@ -3007,8 +3014,9 @@ public void testSecurityGroupRulesCmdException() { final Long seqNum = 1l; final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; + final List secIps = new Vector(); - final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet); + final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps); final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class); final Connect conn = Mockito.mock(Connect.class); diff --git a/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java b/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java index 0541b7e61a..648bf7fc39 100644 --- a/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java +++ b/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java @@ -940,8 +940,8 @@ private Answer execute(SecurityGroupRulesCmd cmd) { s_logger.warn("Failed to program network rules for vm " + cmd.getVmName()); return new SecurityGroupRuleAnswer(cmd, false, "programming network rules failed"); } else { - s_logger.info("Programmed network rules for vm " + cmd.getVmName() + " guestIp=" + cmd.getGuestIp() + ":ingress num rules=" + cmd.getIngressRuleSet().length + - ":egress num rules=" + cmd.getEgressRuleSet().length); + s_logger.info("Programmed network rules for vm " + cmd.getVmName() + " guestIp=" + cmd.getGuestIp() + ":ingress num rules=" + cmd.getIngressRuleSet().size() + + ":egress num rules=" + cmd.getEgressRuleSet().size()); return new SecurityGroupRuleAnswer(cmd); } } diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java index 6602e1f1ad..5efcd3b57e 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java @@ -626,7 +626,7 @@ private boolean logSecurityGroupAction(final SecurityGroupRulesCmd cmd, final Te reason = ", seqno_new"; } s_logger.info("Programmed network rules for vm " + cmd.getVmName() + " seqno=" + cmd.getSeqNum() + " signature=" + cmd.getSignature() + " guestIp=" + - cmd.getGuestIp() + ", numIngressRules=" + cmd.getIngressRuleSet().length + ", numEgressRules=" + cmd.getEgressRuleSet().length + " total cidrs=" + + cmd.getGuestIp() + ", numIngressRules=" + cmd.getIngressRuleSet().size() + ", numEgressRules=" + cmd.getEgressRuleSet().size() + " total cidrs=" + cmd.getTotalNumCidrs() + action + reason); return updateSeqnoAndSig; } diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixSecurityGroupRulesCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixSecurityGroupRulesCommandWrapper.java index 0f8e6b5ba8..b189ba076f 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixSecurityGroupRulesCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixSecurityGroupRulesCommandWrapper.java @@ -56,7 +56,7 @@ public Answer execute(final SecurityGroupRulesCmd command, final CitrixResourceB return new SecurityGroupRuleAnswer(command, false, "programming network rules failed"); } else { s_logger.info("Programmed network rules for vm " + command.getVmName() + " guestIp=" + command.getGuestIp() + ", ingress numrules=" - + command.getIngressRuleSet().length + ", egress numrules=" + command.getEgressRuleSet().length); + + command.getIngressRuleSet().size() + ", egress numrules=" + command.getEgressRuleSet().size()); return new SecurityGroupRuleAnswer(command); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java index ca58f35533..0e512fb940 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java @@ -33,6 +33,7 @@ import java.util.Hashtable; import java.util.List; import java.util.Map; +import java.util.Vector; import org.apache.cloudstack.storage.command.AttachAnswer; import org.apache.cloudstack.storage.command.AttachCommand; @@ -101,6 +102,7 @@ import com.cloud.agent.api.UpdateHostPasswordCommand; import com.cloud.agent.api.UpgradeSnapshotCommand; import com.cloud.agent.api.VMSnapshotTO; +import com.cloud.agent.api.SecurityGroupRulesCmd.IpPortAndProto; import com.cloud.agent.api.check.CheckSshCommand; import com.cloud.agent.api.proxy.CheckConsoleProxyLoadCommand; import com.cloud.agent.api.proxy.WatchConsoleProxyLoadCommand; @@ -740,7 +742,17 @@ public void testSecurityGroupRulesCommand() { final Connection conn = Mockito.mock(Connection.class); final XsHost xsHost = Mockito.mock(XsHost.class); - final SecurityGroupRulesCmd sshCommand = new SecurityGroupRulesCmd(); + final String guestIp = "127.0.0.1"; + final String guestMac = "00:00:00:00"; + final String vmName = "Test"; + final Long vmId = 1l; + final String signature = "signature"; + final Long seqNum = 1l; + final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; + final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; + final List secIps = new Vector(); + + final SecurityGroupRulesCmd sshCommand = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); diff --git a/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java b/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java index 64204fe9a7..64bbb75faa 100644 --- a/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java +++ b/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java @@ -182,8 +182,6 @@ public void sendRulesetUpdates(SecurityGroupWork work) { List nicSecIps = null; if (nic != null) { if (nic.getSecondaryIp()) { - //get secondary ips of the vm - long networkId = nic.getNetworkId(); nicSecIps = _nicSecIpDao.getSecondaryIpAddressesForNic(nic.getId()); } } @@ -193,7 +191,7 @@ public void sendRulesetUpdates(SecurityGroupWork work) { cmd.setMsId(_serverId); if (s_logger.isDebugEnabled()) { s_logger.debug("SecurityGroupManager v2: sending ruleset update for vm " + vm.getInstanceName() + ":ingress num rules=" + - cmd.getIngressRuleSet().length + ":egress num rules=" + cmd.getEgressRuleSet().length + " num cidrs=" + cmd.getTotalNumCidrs() + " sig=" + + cmd.getIngressRuleSet().size() + ":egress num rules=" + cmd.getEgressRuleSet().size() + " num cidrs=" + cmd.getTotalNumCidrs() + " sig=" + cmd.getSignature()); } Commands cmds = new Commands(cmd); From 28ca93369d1aa19e6397f5c6dbc97ba19d042519 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Sun, 27 Dec 2015 12:34:58 +0100 Subject: [PATCH 031/203] trailing commas in javascripts removed --- ui/plugins/plugins.js | 4 ++-- ui/plugins/quota/quota.js | 47 +++++++++++++++++++-------------------- ui/scripts/accounts.js | 4 ++-- ui/scripts/cloudStack.js | 2 +- ui/scripts/instances.js | 2 +- ui/scripts/metrics.js | 20 ++++++++--------- ui/scripts/system.js | 4 ++-- 7 files changed, 41 insertions(+), 42 deletions(-) diff --git a/ui/plugins/plugins.js b/ui/plugins/plugins.js index b629e3095b..21da7a07f4 100644 --- a/ui/plugins/plugins.js +++ b/ui/plugins/plugins.js @@ -16,7 +16,7 @@ // under the License. (function($, cloudStack) { cloudStack.plugins = [ - 'quota', - //'testPlugin' + //'testPlugin', + 'quota' ]; }(jQuery, cloudStack)); diff --git a/ui/plugins/quota/quota.js b/ui/plugins/quota/quota.js index 94a8730b5e..5514bd4ebe 100644 --- a/ui/plugins/quota/quota.js +++ b/ui/plugins/quota/quota.js @@ -79,9 +79,9 @@ indicator: { 'enabled': 'on', 'disabled': 'off', - 'locked': 'off', + 'locked': 'off' } - }, + } }, dataProvider: function(args) { var data = { @@ -171,7 +171,7 @@ label: 'label.quota.enforcequota', isBoolean: true, isChecked: false - }, + } } }, @@ -196,7 +196,7 @@ }); $(window).trigger('cloudStack.fullRefresh'); } - }, + } }, tabs: { details: { @@ -207,10 +207,10 @@ } }, { startdate: { - label: 'label.quota.date', + label: 'label.quota.date' }, startquota: { - label: 'label.quota.value', + label: 'label.quota.value' } }], dataProvider: function(args) { @@ -235,8 +235,7 @@ } }); } - }, - + } } } } @@ -277,9 +276,9 @@ indicator: { 'enabled': 'on', 'disabled': 'off', - 'locked': 'off', + 'locked': 'off' } - }, + } }, dataProvider: function(args) { var data = { @@ -369,7 +368,7 @@ label: 'label.quota.enforcequota', isBoolean: true, isChecked: false - }, + } } }, @@ -394,7 +393,7 @@ }); $(window).trigger('cloudStack.fullRefresh'); } - }, + } }, tabs: { details: { @@ -405,10 +404,10 @@ } }, { startdate: { - label: 'label.quota.date', + label: 'label.quota.date' }, startquota: { - label: 'label.quota.value', + label: 'label.quota.value' } }], dataProvider: function(args) { @@ -433,7 +432,7 @@ } }); } - }, + } } } } @@ -668,7 +667,7 @@ action: function(args) { if (isAdmin()) { var data = { - usagetype: args.data.jsonObj.usageType, + usagetype: args.data.jsonObj.usageType }; var tariffVal = args.data.tariffValue.split(' '); if (tariffVal.length==2){ @@ -697,7 +696,7 @@ validation: { required: true } - }, + } } }, after: function(argsLocal) { @@ -769,7 +768,7 @@ input.datepicker({ defaultDate: new Date(), changeMonth: true, - dateFormat: "yy-mm-dd", + dateFormat: "yy-mm-dd" }); input.parent().attr('title', _l('label.quota.effectivedate')); }, @@ -800,7 +799,7 @@ label: 'label.usage.unit' }, tariffValue: { - label: 'label.quota.tariff.value', + label: 'label.quota.tariff.value' }, description: { label: 'label.quota.description', @@ -832,7 +831,7 @@ input.datepicker({ defaultDate: new Date(), changeMonth: true, - dateFormat: "yy-mm-dd", + dateFormat: "yy-mm-dd" }); input.parent().attr('title', _l('label.quota.effectivedate')); }, @@ -854,7 +853,7 @@ disableInfiniteScrolling: true, fields: { templatetype: { - label: 'label.quota.email.template', + label: 'label.quota.email.template' }, templatesubject: { label: 'label.quota.email.subject', @@ -867,7 +866,7 @@ last_updated: { label: 'label.quota.email.lastupdated', truncate: true - }, + } }, dataProvider: function(args) { var data = {}; @@ -941,8 +940,8 @@ textArea: true }, last_updated: { - label: 'label.quota.email.lastupdated', - }, + label: 'label.quota.email.lastupdated' + } }], dataProvider: function(args) { diff --git a/ui/scripts/accounts.js b/ui/scripts/accounts.js index db0ab3fc34..0058b69024 100644 --- a/ui/scripts/accounts.js +++ b/ui/scripts/accounts.js @@ -1337,7 +1337,7 @@ $.ajax({ url: createURL('listSamlAuthorization'), data: { - userid: context.users[0].id, + userid: context.users[0].id }, success: function(json) { var authorization = json.listsamlauthorizationsresponse.samlauthorization[0]; @@ -1881,7 +1881,7 @@ if (!args.context.projects) { $.extend(data, { domainid: args.context.sshkeypairs[0].domainid, - account: args.context.sshkeypairs[0].account, + account: args.context.sshkeypairs[0].account }); } $.ajax({ diff --git a/ui/scripts/cloudStack.js b/ui/scripts/cloudStack.js index 63b6dbf60f..3f6b6b50ec 100644 --- a/ui/scripts/cloudStack.js +++ b/ui/scripts/cloudStack.js @@ -181,7 +181,7 @@ } }, error: function(xhr) { // ignore any errors, fallback to the default - }, + } }); diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index a367f46beb..19db257029 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -310,7 +310,7 @@ return 'label.metrics'; } } - }, + } }, dataProvider: function(args) { diff --git a/ui/scripts/metrics.js b/ui/scripts/metrics.js index 609022a81a..7fca043f72 100644 --- a/ui/scripts/metrics.js +++ b/ui/scripts/metrics.js @@ -23,7 +23,7 @@ name: { label: 'metrics' } - }, + } } }; @@ -546,7 +546,7 @@ 'Error': 'off', 'Connecting': 'transition', 'Rebalancing': 'transition', - 'Alert': 'warning', + 'Alert': 'warning' }, compact: true }, @@ -558,7 +558,7 @@ collapsible: true, columns: { cores: { - label: 'label.metrics.num.cpu.cores', + label: 'label.metrics.num.cpu.cores' }, cputotal: { label: 'label.metrics.cpu.total' @@ -768,7 +768,7 @@ 'Stopping': 'transition', 'Starting': 'transition', 'Migrating': 'transition', - 'Shutdowned': 'warning', + 'Shutdowned': 'warning' }, compact: true }, @@ -783,13 +783,13 @@ collapsible: true, columns: { cores: { - label: 'label.metrics.num.cpu.cores', + label: 'label.metrics.num.cpu.cores' }, cputotal: { label: 'label.metrics.cpu.total' }, cpuused: { - label: 'label.metrics.cpu.used.avg', + label: 'label.metrics.cpu.used.avg' } } }, @@ -912,7 +912,7 @@ 'Expunging': 'off', 'Migrating': 'warning', 'UploadOp': 'transition', - 'Snapshotting': 'warning', + 'Snapshotting': 'warning' }, compact: true }, @@ -927,7 +927,7 @@ }, storagepool: { label: 'label.metrics.storagepool' - }, + } }, dataProvider: function(args) { var data = {listAll: true}; @@ -990,7 +990,7 @@ 'ErrorInMaintenance': 'off', 'PrepareForMaintenance': 'transition', 'CancelMaintenance': 'warning', - 'Maintenance': 'warning', + 'Maintenance': 'warning' }, compact: true }, @@ -999,7 +999,7 @@ }, type: { label: 'label.metrics.disk.storagetype' - }, + } } }, disk: { diff --git a/ui/scripts/system.js b/ui/scripts/system.js index af69359637..cea6366218 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -870,7 +870,7 @@ var data = { id: args.context.multiRule[0].id, zoneid: args.context.multiRule[0].zoneid, - domainid: args.data.domainid, + domainid: args.data.domainid }; if (args.data.account) { $.extend(data, { @@ -7869,7 +7869,7 @@ return 'label.metrics'; } } - }, + } }, detailView: { From 656ae109377e7d4400d16f05cbb4096e20a8c05b Mon Sep 17 00:00:00 2001 From: nvazquez Date: Tue, 5 Jan 2016 10:45:01 -0800 Subject: [PATCH 032/203] CLOUDSTACK-9211: Support passing vRAM size to support 3D GPU on Vmware --- .../vmware/resource/VmwareResource.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index fdbc244997..7248b08b37 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -94,6 +94,7 @@ import com.vmware.vim25.VirtualMachineRelocateSpec; import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator; import com.vmware.vim25.VirtualMachineRuntimeInfo; +import com.vmware.vim25.VirtualMachineVideoCard; import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; @@ -1895,6 +1896,9 @@ protected StartAnswer execute(StartCommand cmd) { postDiskConfigBeforeStart(vmMo, vmSpec, sortedDisks, ideControllerKey, scsiControllerKey, iqnToPath, hyperHost, context); + //Sets video card memory to the one provided in detail svga.vramSize (if provided), 64MB was always set before + postVideoCardMemoryConfigBeforeStart(vmMo, vmSpec); + // // Power-on VM // @@ -1943,6 +1947,44 @@ protected StartAnswer execute(StartCommand cmd) { } } + private void postVideoCardMemoryConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec) { + String paramVRamSize = "svga.vramSize"; + if (vmSpec.getDetails().containsKey(paramVRamSize)){ + String value = vmSpec.getDetails().get(paramVRamSize); + try { + long svgaVmramSize = Long.parseLong(value); + for (VirtualDevice device : vmMo.getAllDeviceList()){ + if (device instanceof VirtualMachineVideoCard){ + VirtualMachineVideoCard videoCard = (VirtualMachineVideoCard) device; + if (videoCard.getVideoRamSizeInKB().longValue() != svgaVmramSize){ + s_logger.info("Video card memory was set " + videoCard.getVideoRamSizeInKB().longValue() + "kb instead of " + svgaVmramSize + "kb"); + videoCard.setVideoRamSizeInKB(svgaVmramSize); + videoCard.setUseAutoDetect(false); + + VirtualDeviceConfigSpec arrayVideoCardConfigSpecs = new VirtualDeviceConfigSpec(); + arrayVideoCardConfigSpecs.setDevice(videoCard); + arrayVideoCardConfigSpecs.setOperation(VirtualDeviceConfigSpecOperation.EDIT); + + VirtualMachineConfigSpec changeVideoCardSpecs = new VirtualMachineConfigSpec(); + changeVideoCardSpecs.getDeviceChange().add(arrayVideoCardConfigSpecs); + + boolean res = vmMo.configureVm(changeVideoCardSpecs); + if (res) { + s_logger.info("Video card memory successfully updated to " + svgaVmramSize + "kb"); + } + } + } + } + } + catch (NumberFormatException e){ + s_logger.error("Unexpected value, cannot parse " + value + " to long due to: " + e.getMessage()); + } + catch (Exception e){ + s_logger.error("Error while reconfiguring vm due to: " + e.getMessage()); + } + } + } + private void tearDownVm(VirtualMachineMO vmMo) throws Exception{ if(vmMo == null) return; From 88327b99f755f4d8710515cd3b5169d3becd9b5b Mon Sep 17 00:00:00 2001 From: sanjeevn Date: Mon, 4 Jan 2016 18:14:24 +0530 Subject: [PATCH 033/203] Test to verify CS-45057 Bug-Id: CS-45057 Reviewed-by: Self --- test/integration/component/test_vpc.py | 30 +++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/test/integration/component/test_vpc.py b/test/integration/component/test_vpc.py index f81f53f5d2..0cde535f85 100644 --- a/test/integration/component/test_vpc.py +++ b/test/integration/component/test_vpc.py @@ -36,7 +36,8 @@ NetworkACL, NATRule, Zone, - StaticNATRule) + StaticNATRule, + VpnCustomerGateway) from marvin.lib.common import (get_domain, get_zone, get_template, @@ -182,6 +183,13 @@ def __init__(self): "domain": { "name": "TestDomain" }, + "vpn_customer_gw": { + "ipsecpsk": "s2svpn", + "ikepolicy": "3des-md5", + "ikelifetime": "86400", + "esppolicy": "3des-md5", + "esplifetime": "3600", + }, "ostype": 'CentOS 5.3 (64-bit)', # Cent OS 5.3 (64 bit) "sleep": 60, @@ -2490,3 +2498,23 @@ def test_21_deploy_vm_with_gateway_ip(self): "Failed to create VM with first ip address in the CIDR as the vm ip" ) return + + @attr(tags=["advanced", "intervlan"], required_hardware="false") + def test_22_vpn_customer_gw_with_hostname(self): + """ + Test to create vpn customer gateway with hostname + instead of gateway ip address + """ + try: + vpnGw = VpnCustomerGateway.create( + self.apiclient, + self.services["vpn_customer_gw"], + name="test_vpn_customer_gw", + gateway="GwWithHostName", + cidrlist="10.1.0.0/16" + ) + self.cleanup.append(vpnGw) + except Exception as e: + self.fail("Creating vpn customer gateway with hostname\ + Failed with error :%s" % e) + return From 4497c6064aad5603ccd5c09e651294a2a4e6b542 Mon Sep 17 00:00:00 2001 From: sanjeevn Date: Thu, 7 Jan 2016 14:34:05 +0530 Subject: [PATCH 034/203] Added few validation steps after adding vpncustomer gateway with hostname Changes are as per review comments in PR#1308 --- test/integration/component/test_vpc.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test/integration/component/test_vpc.py b/test/integration/component/test_vpc.py index 0cde535f85..5f7ea98b5f 100644 --- a/test/integration/component/test_vpc.py +++ b/test/integration/component/test_vpc.py @@ -22,7 +22,7 @@ from marvin.cloudstackTestCase import cloudstackTestCase from marvin.cloudstackException import CloudstackAPIException from marvin.cloudstackAPI import updateZone -from marvin.lib.utils import cleanup_resources +from marvin.lib.utils import cleanup_resources, validateList from marvin.lib.base import (Account, VPC, VpcOffering, @@ -42,6 +42,7 @@ get_zone, get_template, list_configurations) +from marvin.codes import PASS import time @@ -2517,4 +2518,18 @@ def test_22_vpn_customer_gw_with_hostname(self): except Exception as e: self.fail("Creating vpn customer gateway with hostname\ Failed with error :%s" % e) + vpn_cgw_res = VpnCustomerGateway.list( + self.apiclient, + id=vpnGw.id + ) + self.assertEqual( + validateList(vpn_cgw_res)[0], + PASS, + "Invalid response for list vpncustomer gateways" + ) + self.assertEqual( + vpnGw.gateway, + vpn_cgw_res[0].gateway, + "Mismatch in vpn customer gateway names" + ) return From 448b43faeae58c923fe52c5540d604db03d70b15 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Thu, 14 Jan 2016 17:26:36 -0200 Subject: [PATCH 035/203] CLOUDSTACK-9211: Add javadoc and refactor method --- .../vmware/resource/VmwareResource.java | 88 +++++++++++-------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 7248b08b37..6796c47a62 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1896,9 +1896,8 @@ protected StartAnswer execute(StartCommand cmd) { postDiskConfigBeforeStart(vmMo, vmSpec, sortedDisks, ideControllerKey, scsiControllerKey, iqnToPath, hyperHost, context); - //Sets video card memory to the one provided in detail svga.vramSize (if provided), 64MB was always set before postVideoCardMemoryConfigBeforeStart(vmMo, vmSpec); - + // // Power-on VM // @@ -1947,42 +1946,57 @@ protected StartAnswer execute(StartCommand cmd) { } } + /** + * Sets video card memory to the one provided in detail svga.vramSize (if provided). + * 64MB was always set before. + * Size must be in KB. + * @param vmMo virtual machine mo + * @param vmSpec virtual machine specs + */ private void postVideoCardMemoryConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec) { - String paramVRamSize = "svga.vramSize"; - if (vmSpec.getDetails().containsKey(paramVRamSize)){ - String value = vmSpec.getDetails().get(paramVRamSize); - try { - long svgaVmramSize = Long.parseLong(value); - for (VirtualDevice device : vmMo.getAllDeviceList()){ - if (device instanceof VirtualMachineVideoCard){ - VirtualMachineVideoCard videoCard = (VirtualMachineVideoCard) device; - if (videoCard.getVideoRamSizeInKB().longValue() != svgaVmramSize){ - s_logger.info("Video card memory was set " + videoCard.getVideoRamSizeInKB().longValue() + "kb instead of " + svgaVmramSize + "kb"); - videoCard.setVideoRamSizeInKB(svgaVmramSize); - videoCard.setUseAutoDetect(false); - - VirtualDeviceConfigSpec arrayVideoCardConfigSpecs = new VirtualDeviceConfigSpec(); - arrayVideoCardConfigSpecs.setDevice(videoCard); - arrayVideoCardConfigSpecs.setOperation(VirtualDeviceConfigSpecOperation.EDIT); - - VirtualMachineConfigSpec changeVideoCardSpecs = new VirtualMachineConfigSpec(); - changeVideoCardSpecs.getDeviceChange().add(arrayVideoCardConfigSpecs); - - boolean res = vmMo.configureVm(changeVideoCardSpecs); - if (res) { - s_logger.info("Video card memory successfully updated to " + svgaVmramSize + "kb"); - } - } - } - } - } - catch (NumberFormatException e){ - s_logger.error("Unexpected value, cannot parse " + value + " to long due to: " + e.getMessage()); - } - catch (Exception e){ - s_logger.error("Error while reconfiguring vm due to: " + e.getMessage()); - } - } + String paramVRamSize = "svga.vramSize"; + if (vmSpec.getDetails().containsKey(paramVRamSize)){ + String value = vmSpec.getDetails().get(paramVRamSize); + try { + long svgaVmramSize = Long.parseLong(value); + for (VirtualDevice device : vmMo.getAllDeviceList()){ + if (device instanceof VirtualMachineVideoCard){ + VirtualMachineVideoCard videoCard = (VirtualMachineVideoCard) device; + if (videoCard.getVideoRamSizeInKB().longValue() != svgaVmramSize){ + s_logger.info("Video card memory was set " + videoCard.getVideoRamSizeInKB().longValue() + "kb instead of " + svgaVmramSize + "kb"); + boolean res = vmMo.configureVm(configSpecVideoCardNewVRamSize(videoCard, svgaVmramSize)); + if (res) { + s_logger.info("Video card memory successfully updated to " + svgaVmramSize + "kb"); + } + } + } + } + } + catch (NumberFormatException e){ + s_logger.error("Unexpected value, cannot parse " + value + " to long due to: " + e.getMessage()); + } + catch (Exception e){ + s_logger.error("Error while reconfiguring vm due to: " + e.getMessage()); + } + } + } + + /** + * Returns a VirtualMachineConfigSpec to edit its svga vram size + * @param videoCard video card device to edit providing the svga vram size + * @param svgaVmramSize new svga vram size + */ + private VirtualMachineConfigSpec configSpecVideoCardNewVRamSize(VirtualMachineVideoCard videoCard, long svgaVmramSize){ + videoCard.setVideoRamSizeInKB(svgaVmramSize); + videoCard.setUseAutoDetect(false); + + VirtualDeviceConfigSpec arrayVideoCardConfigSpecs = new VirtualDeviceConfigSpec(); + arrayVideoCardConfigSpecs.setDevice(videoCard); + arrayVideoCardConfigSpecs.setOperation(VirtualDeviceConfigSpecOperation.EDIT); + + VirtualMachineConfigSpec changeVideoCardSpecs = new VirtualMachineConfigSpec(); + changeVideoCardSpecs.getDeviceChange().add(arrayVideoCardConfigSpecs); + return changeVideoCardSpecs; } private void tearDownVm(VirtualMachineMO vmMo) throws Exception{ From b9b5967d6bbe7fd351dbc80499672e2c2edb1105 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Sun, 17 Jan 2016 16:24:54 +0100 Subject: [PATCH 036/203] SecurityGroupRulesCmd code cleanup review comments handled --- .../agent/api/SecurityGroupRulesCmd.java | 48 ++++++++++--------- .../agent/api/SecurityGroupRulesCmdTest.java | 42 +++++++--------- 2 files changed, 42 insertions(+), 48 deletions(-) diff --git a/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java b/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java index a7f44251dd..09f9266669 100644 --- a/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java +++ b/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java @@ -33,6 +33,7 @@ import com.cloud.utils.net.NetUtils; public class SecurityGroupRulesCmd extends Command { + private static final String CIDR_LENGTH_SEPARATOR = "/"; private static final char RULE_TARGET_SEPARATOR = ','; private static final char RULE_COMMAND_SEPARATOR = ':'; protected static final String EGRESS_RULE = "E:"; @@ -155,11 +156,10 @@ public String getVmName() { return vmName; } - //convert cidrs in the form "a.b.c.d/e" to "hexvalue of 32bit ip/e" - private String compressCidr(final String cidr) { - final String[] toks = cidr.split("/"); + private String compressCidrToHexRepresentation(final String cidr) { + final String[] toks = cidr.split(CIDR_LENGTH_SEPARATOR); final long ipnum = NetUtils.ip2Long(toks[0]); - return Long.toHexString(ipnum) + "/" + toks[1]; + return Long.toHexString(ipnum) + CIDR_LENGTH_SEPARATOR + toks[1]; } public String getSecIpsString() { @@ -189,42 +189,41 @@ public String stringifyCompressedRules() { return ruleBuilder.toString(); } - /** - * @param ipPandPs - * @param gression - * @param compress - * @param ruleBuilder - */ - private void stringifyRulesFor( - final List ipPandPs, - final String gression, - final boolean compress, - final StringBuilder ruleBuilder) { - for (final IpPortAndProto ipPandP : ipPandPs) { - ruleBuilder.append(gression).append(ipPandP.getProto()).append(RULE_COMMAND_SEPARATOR).append(ipPandP.getStartPort()).append(RULE_COMMAND_SEPARATOR).append(ipPandP.getEndPort()).append(RULE_COMMAND_SEPARATOR); + private void stringifyRulesFor(final List ipPortAndProtocols, final String inOrEgress, final boolean compressed, final StringBuilder ruleBuilder) { + for (final IpPortAndProto ipPandP : ipPortAndProtocols) { + ruleBuilder.append(inOrEgress).append(ipPandP.getProto()).append(RULE_COMMAND_SEPARATOR).append(ipPandP.getStartPort()).append(RULE_COMMAND_SEPARATOR) + .append(ipPandP.getEndPort()).append(RULE_COMMAND_SEPARATOR); for (final String cidr : ipPandP.getAllowedCidrs()) { - ruleBuilder.append(compress?compressCidr(cidr):cidr).append(RULE_TARGET_SEPARATOR); + ruleBuilder.append(represent(cidr, compressed)).append(RULE_TARGET_SEPARATOR); } ruleBuilder.append("NEXT "); } } - /* + private String represent(final String cidr, final boolean compressed) { + if (compressed) { + return compressCidrToHexRepresentation(cidr); + } else { + return cidr; + } + } + + /** * Compress the security group rules using zlib compression to allow the call to the hypervisor * to scale beyond 8k cidrs. + * Note : not using {@see GZipOutputStream} since that is for files, using {@see DeflaterOutputStream} instead. + * {@see GZipOutputStream} gives a different header, although the compression is the same */ public String compressStringifiedRules() { final String stringified = stringifyRules(); final ByteArrayOutputStream out = new ByteArrayOutputStream(); String encodedResult = null; try { - //Note : not using GZipOutputStream since that is for files - //GZipOutputStream gives a different header, although the compression is the same final DeflaterOutputStream dzip = new DeflaterOutputStream(out); dzip.write(stringified.getBytes()); dzip.close(); encodedResult = Base64.encodeBase64String(out.toByteArray()); - } catch (IOException e) { + } catch (final IOException e) { LOGGER.warn("Exception while compressing security group rules"); } return encodedResult; @@ -246,8 +245,11 @@ public Long getVmId() { return vmId; } + /** + * used for logging + * @return the number of Cidrs in the in and egress rule sets for this security group rules command. + */ public int getTotalNumCidrs() { - //useful for logging int count = 0; for (final IpPortAndProto i : ingressRuleSet) { count += i.allowedCidrs.size(); diff --git a/core/test/com/cloud/agent/api/SecurityGroupRulesCmdTest.java b/core/test/com/cloud/agent/api/SecurityGroupRulesCmdTest.java index 2b094c5a40..37b15ebb72 100644 --- a/core/test/com/cloud/agent/api/SecurityGroupRulesCmdTest.java +++ b/core/test/com/cloud/agent/api/SecurityGroupRulesCmdTest.java @@ -25,7 +25,6 @@ import java.util.Vector; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner; @@ -40,31 +39,24 @@ public class SecurityGroupRulesCmdTest { private SecurityGroupRulesCmd securityGroupRulesCmd; - /** - * @throws java.lang.Exception - */ - @BeforeClass - public static void setUpBeforeClass() throws Exception { - } - /** * @throws java.lang.Exception */ @Before public void setUp() throws Exception { - String guestIp = "10.10.10.10"; - String guestMac = "aa:aa:aa:aa:aa:aa"; - String vmName = "vm"; - Long vmId = 1L; - String signature = "sig"; - Long seqNum = 0L; - String proto = "abc"; - int startPort = 1; - int endPort = 2; - String[] allowedCidrs = new String[] {"1.2.3.4/5","6.7.8.9/0"}; - IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{new IpPortAndProto(proto, startPort, endPort, allowedCidrs)}; - IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{new IpPortAndProto(proto, startPort, endPort, allowedCidrs)}; - List secIps = new Vector(); + final String guestIp = "10.10.10.10"; + final String guestMac = "aa:aa:aa:aa:aa:aa"; + final String vmName = "vm"; + final Long vmId = 1L; + final String signature = "sig"; + final Long seqNum = 0L; + final String proto = "abc"; + final int startPort = 1; + final int endPort = 2; + final String[] allowedCidrs = new String[] {"1.2.3.4/5","6.7.8.9/0"}; + final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{new IpPortAndProto(proto, startPort, endPort, allowedCidrs)}; + final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{new IpPortAndProto(proto, startPort, endPort, allowedCidrs)}; + final List secIps = new Vector(); securityGroupRulesCmd = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps); } @@ -73,7 +65,7 @@ public void setUp() throws Exception { */ @Test public void testStringifyRules() throws Exception { - String a = securityGroupRulesCmd.stringifyRules(); + final String a = securityGroupRulesCmd.stringifyRules(); // do verification on a assertTrue(a.contains(SecurityGroupRulesCmd.EGRESS_RULE)); } @@ -83,7 +75,7 @@ public void testStringifyRules() throws Exception { */ @Test public void testStringifyCompressedRules() throws Exception { - String a = securityGroupRulesCmd.stringifyCompressedRules(); + final String a = securityGroupRulesCmd.stringifyCompressedRules(); // do verification on a assertTrue(a.contains(SecurityGroupRulesCmd.EGRESS_RULE)); } @@ -93,8 +85,8 @@ public void testStringifyCompressedRules() throws Exception { */ @Test public void testCompressStringifiedRules() throws Exception { - String compressed = "eJzztEpMSrYytDKyMtQz0jPWM9E31THTM9ez0LPUN9Dxc40IUXAlrAQAPdoP3Q=="; - String a = securityGroupRulesCmd.compressStringifiedRules(); + final String compressed = "eJzztEpMSrYytDKyMtQz0jPWM9E31THTM9ez0LPUN9Dxc40IUXAlrAQAPdoP3Q=="; + final String a = securityGroupRulesCmd.compressStringifiedRules(); assertTrue(compressed.equals(a)); } From 1304406fd188722dd884c49f545828e7c1546667 Mon Sep 17 00:00:00 2001 From: Abhinandan Prateek Date: Wed, 23 Dec 2015 10:12:11 +0530 Subject: [PATCH 037/203] Quota: findbug fixes Findbug fixes for cloud-framework-quota and cloud-plugin-database-quota. --- .../cloudstack/quota/QuotaStatementImpl.java | 2 +- .../quota/vo/ServiceOfferingVO.java | 89 +++++-------------- .../response/QuotaResponseBuilderImpl.java | 4 +- .../QuotaResponseBuilderImplTest.java | 2 +- 4 files changed, 25 insertions(+), 72 deletions(-) diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java index 682b2ef036..0f957be5d7 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java @@ -85,7 +85,7 @@ public boolean configure(String name, Map params) throws Configu mergeConfigs(configs, params); } String period_str = configs.get(QuotaConfig.QuotaStatementPeriod.key()); - int period = period_str == null ? 1 : Integer.valueOf(period_str); + int period = period_str == null ? 1 : Integer.parseInt(period_str); STATEMENT_PERIODS _period = STATEMENT_PERIODS.values()[period]; return true; diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java index 2d11edda77..795a178238 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java @@ -16,6 +16,7 @@ //under the License. package org.apache.cloudstack.quota.vo; +import java.util.HashMap; import java.util.Map; import javax.persistence.Column; @@ -74,14 +75,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering @Column(name = "deployment_planner") private String deploymentPlanner = null; - // This is a delayed load value. If the value is null, - // then this field has not been loaded yet. - // Call service offering dao to load it. @Transient - Map details; + Map details = new HashMap(); - // This flag is required to tell if the offering is dynamic once the cpu, memory and speed are set. - // In some cases cpu, memory and speed are set to non-null values even if the offering is dynamic. @Transient boolean isDynamic; @@ -90,7 +86,7 @@ protected ServiceOfferingVO() { } public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, String displayText, - ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, boolean defaultUse) { + ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, boolean defaultUse) { super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true); this.cpu = cpu; this.ramSize = ramSize; @@ -105,7 +101,8 @@ public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer spee } public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse, - boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, Long domainId) { + boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, + VirtualMachine.Type vmType, Long domainId) { super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true, domainId); this.cpu = cpu; this.ramSize = ramSize; @@ -118,68 +115,26 @@ public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer spee this.vmType = vmType == null ? null : vmType.toString().toLowerCase(); } - public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, - boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, - VirtualMachine.Type vmType, Long domainId, String hostTag) { - this(name, - cpu, - ramSize, - speed, - rateMbps, - multicastRateMbps, - offerHA, - limitResourceUse, - volatileVm, - displayText, - provisioningType, - useLocalStorage, - recreatable, - tags, - systemUse, - vmType, - domainId); + public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitResourceUse, + boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, + VirtualMachine.Type vmType, Long domainId, String hostTag) { + this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, displayText, provisioningType, useLocalStorage, recreatable, tags, + systemUse, vmType, domainId); this.hostTag = hostTag; } - public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, - boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, - VirtualMachine.Type vmType, Long domainId, String hostTag, String deploymentPlanner) { - this(name, - cpu, - ramSize, - speed, - rateMbps, - multicastRateMbps, - offerHA, - limitResourceUse, - volatileVm, - displayText, - provisioningType, - useLocalStorage, - recreatable, - tags, - systemUse, - vmType, - domainId, - hostTag); + public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitResourceUse, + boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, + VirtualMachine.Type vmType, Long domainId, String hostTag, String deploymentPlanner) { + this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, displayText, provisioningType, useLocalStorage, recreatable, tags, + systemUse, vmType, domainId, hostTag); this.deploymentPlanner = deploymentPlanner; } public ServiceOfferingVO(ServiceOfferingVO offering) { - super(offering.getId(), - offering.getName(), - offering.getDisplayText(), - offering.getProvisioningType(), - false, - offering.getTags(), - offering.isRecreatable(), - offering.getUseLocalStorage(), - offering.getSystemUse(), - true, - offering.isCustomizedIops()== null ? false:offering.isCustomizedIops(), - offering.getDomainId(), - offering.getMinIops(), - offering.getMaxIops()); + super(offering.getId(), offering.getName(), offering.getDisplayText(), offering.getProvisioningType(), false, offering.getTags(), offering.isRecreatable(), + offering.getUseLocalStorage(), offering.getSystemUse(), true, offering.isCustomizedIops() == null ? false : offering.isCustomizedIops(), offering.getDomainId(), + offering.getMinIops(), offering.getMaxIops()); cpu = offering.getCpu(); ramSize = offering.getRamSize(); speed = offering.getSpeed(); @@ -310,14 +265,10 @@ public Map getDetails() { } public String getDetail(String name) { - assert (details != null) : "Did you forget to load the details?"; - - return details != null ? details.get(name) : null; + return details.get(name); } - public void setDetail(String name, String value) { - assert (details != null) : "Did you forget to load the details?"; - + public void addDetail(String name, String value) { details.put(name, value); } diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java index 1b6f400f40..746c7c3293 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java @@ -174,10 +174,12 @@ private QuotaSummaryResponse getQuotaSummaryResponse(final Account account) { @Override public QuotaBalanceResponse createQuotaBalanceResponse(List quotaBalance, Date startDate, Date endDate) { if (quotaBalance == null || quotaBalance.isEmpty()) { - new InvalidParameterValueException("The request period does not contain balance entries."); + throw new InvalidParameterValueException("The request period does not contain balance entries."); } Collections.sort(quotaBalance, new Comparator() { public int compare(QuotaBalanceVO o1, QuotaBalanceVO o2) { + o1 = o1 == null ? new QuotaBalanceVO() : o1; + o2 = o2 == null ? new QuotaBalanceVO() : o2; return o2.getUpdatedOn().compareTo(o1.getUpdatedOn()); // desc } }); diff --git a/plugins/database/quota/test/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java b/plugins/database/quota/test/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java index 73ead4a71b..c113e55164 100644 --- a/plugins/database/quota/test/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java +++ b/plugins/database/quota/test/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java @@ -118,7 +118,7 @@ private QuotaTariffVO makeTariffTestData() { tariffVO.setUsageType(QuotaTypes.IP_ADDRESS); tariffVO.setUsageName("ip address"); tariffVO.setUsageUnit("IP-Month"); - tariffVO.setCurrencyValue(new BigDecimal(100.19)); + tariffVO.setCurrencyValue(BigDecimal.valueOf(100.19)); tariffVO.setEffectiveOn(new Date()); tariffVO.setUsageDiscriminator(""); return tariffVO; From 4fcebfc813628cdd87a2b96736b889da203dfe84 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Mon, 18 Jan 2016 12:09:11 -0200 Subject: [PATCH 038/203] CLOUDSTACK-9211: Refactor vm vram size setter method --- .../vmware/resource/VmwareResource.java | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 6796c47a62..bdaf8cfa4b 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1959,18 +1959,7 @@ private void postVideoCardMemoryConfigBeforeStart(VirtualMachineMO vmMo, Virtual String value = vmSpec.getDetails().get(paramVRamSize); try { long svgaVmramSize = Long.parseLong(value); - for (VirtualDevice device : vmMo.getAllDeviceList()){ - if (device instanceof VirtualMachineVideoCard){ - VirtualMachineVideoCard videoCard = (VirtualMachineVideoCard) device; - if (videoCard.getVideoRamSizeInKB().longValue() != svgaVmramSize){ - s_logger.info("Video card memory was set " + videoCard.getVideoRamSizeInKB().longValue() + "kb instead of " + svgaVmramSize + "kb"); - boolean res = vmMo.configureVm(configSpecVideoCardNewVRamSize(videoCard, svgaVmramSize)); - if (res) { - s_logger.info("Video card memory successfully updated to " + svgaVmramSize + "kb"); - } - } - } - } + setNewVRamSizeVmVideoCard(vmMo, svgaVmramSize); } catch (NumberFormatException e){ s_logger.error("Unexpected value, cannot parse " + value + " to long due to: " + e.getMessage()); @@ -1981,10 +1970,41 @@ private void postVideoCardMemoryConfigBeforeStart(VirtualMachineMO vmMo, Virtual } } + /** + * Search for vm video card iterating through vm device list + * @param vmMo virtual machine mo + * @param svgaVmramSize new svga vram size (in KB) + */ + private void setNewVRamSizeVmVideoCard(VirtualMachineMO vmMo, long svgaVmramSize) throws Exception { + for (VirtualDevice device : vmMo.getAllDeviceList()){ + if (device instanceof VirtualMachineVideoCard){ + VirtualMachineVideoCard videoCard = (VirtualMachineVideoCard) device; + modifyVmVideoCardVRamSize(videoCard, vmMo, svgaVmramSize); + } + } + } + + /** + * Modifies vm vram size if it was set to a different size to the one provided in svga.vramSize (user_vm_details or template_vm_details) + * @param videoCard vm's video card device + * @param vmMo virtual machine mo + * @param svgaVmramSize new svga vram size (in KB) + */ + private void modifyVmVideoCardVRamSize(VirtualMachineVideoCard videoCard, VirtualMachineMO vmMo, long svgaVmramSize) throws Exception { + if (videoCard.getVideoRamSizeInKB().longValue() != svgaVmramSize){ + s_logger.info("Video card memory was set " + videoCard.getVideoRamSizeInKB().longValue() + "kb instead of " + svgaVmramSize + "kb"); + VirtualMachineConfigSpec newSizeSpecs = configSpecVideoCardNewVRamSize(videoCard, svgaVmramSize); + boolean res = vmMo.configureVm(newSizeSpecs); + if (res) { + s_logger.info("Video card memory successfully updated to " + svgaVmramSize + "kb"); + } + } + } + /** * Returns a VirtualMachineConfigSpec to edit its svga vram size * @param videoCard video card device to edit providing the svga vram size - * @param svgaVmramSize new svga vram size + * @param svgaVmramSize new svga vram size (in KB) */ private VirtualMachineConfigSpec configSpecVideoCardNewVRamSize(VirtualMachineVideoCard videoCard, long svgaVmramSize){ videoCard.setVideoRamSizeInKB(svgaVmramSize); From d53dd0a671e635edcefcae332e1b7d428ac7600b Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Wed, 20 Jan 2016 13:22:34 +0100 Subject: [PATCH 039/203] UI: improve filter dropdown width --- ui/css/cloudstack3.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index a04ff7cad1..7e2c201944 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -3491,7 +3491,7 @@ div.toolbar div.section-switcher div.section-select label { /*Breadcrumbs*/ div.toolbar div.filters { margin: 5px 0px 0 12px; - width: 168px; + width: 200px; float: left; } From b73c053abd59617b1faca18ad21ed26c5dc78e9f Mon Sep 17 00:00:00 2001 From: nvazquez Date: Wed, 20 Jan 2016 12:09:30 -0800 Subject: [PATCH 040/203] CLOUDSTACK-9211: Unit test for 3dgpu support --- .../vmware/resource/VmwareResource.java | 2 +- .../vmware/resource/VmwareResourceTest.java | 29 ++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index bdaf8cfa4b..d6322ab3af 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1953,7 +1953,7 @@ protected StartAnswer execute(StartCommand cmd) { * @param vmMo virtual machine mo * @param vmSpec virtual machine specs */ - private void postVideoCardMemoryConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec) { + protected void postVideoCardMemoryConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec) { String paramVRamSize = "svga.vramSize"; if (vmSpec.getDetails().containsKey(paramVRamSize)){ String value = vmSpec.getDetails().get(paramVRamSize); diff --git a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java index 2e3d41c048..f554da9b39 100644 --- a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java +++ b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java @@ -19,6 +19,12 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.any; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import org.junit.Before; import org.junit.Test; @@ -26,8 +32,9 @@ import org.mockito.MockitoAnnotations; import org.mockito.Spy; +import com.vmware.vim25.VirtualDevice; import com.vmware.vim25.VirtualMachineConfigSpec; - +import com.vmware.vim25.VirtualMachineVideoCard; import com.cloud.agent.api.Command; import com.cloud.agent.api.ScaleVmAnswer; import com.cloud.agent.api.ScaleVmCommand; @@ -64,6 +71,10 @@ public VmwareHypervisorHost getHyperHost(VmwareContext context, Command cmd) { VirtualMachineMO vmMo; @Mock VirtualMachineConfigSpec vmConfigSpec; + @Mock + VirtualMachineMO vmMo3dgpu; + @Mock + VirtualMachineTO vmSpec3dgpu; @Before public void setup() { @@ -90,4 +101,20 @@ public void testScaleVMF1() throws Exception { verify(_resource).execute(cmd); } + @Test + public void testStartVm3dgpuEnabled() throws Exception{ + Map specDetails = new HashMap(); + specDetails.put("svga.vramSize", "131072"); + when(vmSpec3dgpu.getDetails()).thenReturn(specDetails); + + VirtualMachineVideoCard videoCard = mock(VirtualMachineVideoCard.class); + when(videoCard.getVideoRamSizeInKB()).thenReturn(65536l); + when(vmMo3dgpu.getAllDeviceList()).thenReturn(Arrays.asList((VirtualDevice) videoCard)); + + when(vmMo3dgpu.configureVm(any(VirtualMachineConfigSpec.class))).thenReturn(true); + + _resource.postVideoCardMemoryConfigBeforeStart(vmMo3dgpu, vmSpec3dgpu); + verify(vmMo3dgpu).configureVm(any(VirtualMachineConfigSpec.class)); + } + } From ef3dfbbd3485bd33c02b19bf9bfe8d5940330737 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 25 Jan 2016 15:32:29 +0100 Subject: [PATCH 041/203] Fix issue in scale VM to dynamic service offering This reverts commit 9c4162ac7f451fc3e2155418dcfff224c8c08a4a and 16baa1289b7de383e98d0070717b3f1873fa2db3 Before change: exception when change compute offering (to dynamic service offering) on UI After change: succeed --- .../api/command/user/vm/ScaleVMCmd.java | 21 +++++++++++++++++-- .../api/command/user/vm/UpgradeVMCmd.java | 16 +++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java index e4c2f7d633..661100b533 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java @@ -16,6 +16,9 @@ // under the License. package org.apache.cloudstack.api.command.user.vm; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -78,8 +81,22 @@ public Long getServiceOfferingId() { return serviceOfferingId; } + //instead of reading a map directly we are using collections. + //it is because details.values() cannot be cast to a map. + //it gives a exception public Map getDetails() { - return details; + Map customparameterMap = new HashMap(); + if (details != null && details.size() != 0) { + Collection parameterCollection = details.values(); + Iterator iter = parameterCollection.iterator(); + while (iter.hasNext()) { + HashMap value = (HashMap)iter.next(); + for (String key : value.keySet()) { + customparameterMap.put(key, value.get(key)); + } + } + } + return customparameterMap; } ///////////////////////////////////////////////////// @@ -142,4 +159,4 @@ public void execute() { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to scale vm"); } } -} +} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/UpgradeVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/UpgradeVMCmd.java index bc9c1c8596..b10555556b 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/UpgradeVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/UpgradeVMCmd.java @@ -16,6 +16,9 @@ // under the License. package org.apache.cloudstack.api.command.user.vm; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import org.apache.log4j.Logger; @@ -77,7 +80,18 @@ public Long getServiceOfferingId() { } public Map getDetails() { - return details; + Map customparameterMap = new HashMap(); + if (details != null && details.size() != 0) { + Collection parameterCollection = details.values(); + Iterator iter = parameterCollection.iterator(); + while (iter.hasNext()) { + HashMap value = (HashMap)iter.next(); + for (String key : value.keySet()) { + customparameterMap.put(key, value.get(key)); + } + } + } + return customparameterMap; } ///////////////////////////////////////////////////// From 43ab98d8230f977ac58f6e0c25c359563b879352 Mon Sep 17 00:00:00 2001 From: Remi Bergsma Date: Tue, 26 Jan 2016 15:11:03 +0100 Subject: [PATCH 042/203] Updating pom.xml version numbers for release 4.9.0-SNAPSHOT Signed-off-by: Remi Bergsma --- agent/pom.xml | 2 +- api/pom.xml | 2 +- client/pom.xml | 2 +- core/pom.xml | 2 +- debian/changelog | 6 +++--- developer/pom.xml | 2 +- engine/api/pom.xml | 2 +- engine/components-api/pom.xml | 2 +- engine/network/pom.xml | 2 +- engine/orchestration/pom.xml | 2 +- engine/pom.xml | 2 +- engine/schema/pom.xml | 2 +- engine/service/pom.xml | 2 +- engine/storage/cache/pom.xml | 2 +- engine/storage/datamotion/pom.xml | 2 +- engine/storage/image/pom.xml | 2 +- engine/storage/integration-test/pom.xml | 2 +- engine/storage/pom.xml | 2 +- engine/storage/snapshot/pom.xml | 2 +- engine/storage/volume/pom.xml | 2 +- framework/cluster/pom.xml | 2 +- framework/config/pom.xml | 2 +- framework/db/pom.xml | 2 +- framework/events/pom.xml | 2 +- framework/ipc/pom.xml | 2 +- framework/jobs/pom.xml | 2 +- framework/managed-context/pom.xml | 2 +- framework/pom.xml | 2 +- framework/quota/pom.xml | 2 +- framework/rest/pom.xml | 2 +- framework/security/pom.xml | 2 +- framework/spring/lifecycle/pom.xml | 2 +- framework/spring/module/pom.xml | 2 +- maven-standard/pom.xml | 2 +- plugins/acl/static-role-based/pom.xml | 2 +- .../affinity-group-processors/explicit-dedication/pom.xml | 2 +- .../affinity-group-processors/host-anti-affinity/pom.xml | 2 +- plugins/alert-handlers/snmp-alerts/pom.xml | 2 +- plugins/alert-handlers/syslog-alerts/pom.xml | 2 +- plugins/api/discovery/pom.xml | 2 +- plugins/api/rate-limit/pom.xml | 2 +- plugins/api/solidfire-intg-test/pom.xml | 2 +- plugins/database/mysql-ha/pom.xml | 2 +- plugins/database/quota/pom.xml | 2 +- plugins/dedicated-resources/pom.xml | 2 +- plugins/deployment-planners/implicit-dedication/pom.xml | 2 +- plugins/deployment-planners/user-concentrated-pod/pom.xml | 2 +- plugins/deployment-planners/user-dispersing/pom.xml | 2 +- plugins/event-bus/inmemory/pom.xml | 2 +- plugins/event-bus/kafka/pom.xml | 2 +- plugins/event-bus/rabbitmq/pom.xml | 2 +- plugins/file-systems/netapp/pom.xml | 2 +- plugins/ha-planners/skip-heurestics/pom.xml | 2 +- plugins/host-allocators/random/pom.xml | 2 +- plugins/hypervisors/baremetal/pom.xml | 2 +- plugins/hypervisors/hyperv/pom.xml | 2 +- plugins/hypervisors/kvm/pom.xml | 2 +- plugins/hypervisors/ovm/pom.xml | 2 +- plugins/hypervisors/ovm3/pom.xml | 2 +- plugins/hypervisors/simulator/pom.xml | 2 +- plugins/hypervisors/ucs/pom.xml | 2 +- plugins/hypervisors/vmware/pom.xml | 2 +- plugins/hypervisors/xenserver/pom.xml | 2 +- plugins/network-elements/bigswitch/pom.xml | 2 +- plugins/network-elements/brocade-vcs/pom.xml | 2 +- plugins/network-elements/cisco-vnmc/pom.xml | 2 +- plugins/network-elements/dns-notifier/pom.xml | 2 +- plugins/network-elements/elastic-loadbalancer/pom.xml | 2 +- plugins/network-elements/f5/pom.xml | 2 +- plugins/network-elements/globodns/pom.xml | 2 +- plugins/network-elements/internal-loadbalancer/pom.xml | 2 +- plugins/network-elements/juniper-contrail/pom.xml | 2 +- plugins/network-elements/juniper-srx/pom.xml | 2 +- plugins/network-elements/midonet/pom.xml | 2 +- plugins/network-elements/netscaler/pom.xml | 2 +- plugins/network-elements/nicira-nvp/pom.xml | 4 ++-- plugins/network-elements/nuage-vsp/pom.xml | 2 +- plugins/network-elements/opendaylight/pom.xml | 2 +- plugins/network-elements/ovs/pom.xml | 2 +- plugins/network-elements/palo-alto/pom.xml | 2 +- plugins/network-elements/stratosphere-ssp/pom.xml | 2 +- plugins/network-elements/vxlan/pom.xml | 2 +- plugins/pom.xml | 2 +- plugins/storage-allocators/random/pom.xml | 2 +- plugins/storage/image/default/pom.xml | 2 +- plugins/storage/image/s3/pom.xml | 2 +- plugins/storage/image/sample/pom.xml | 2 +- plugins/storage/image/swift/pom.xml | 2 +- plugins/storage/volume/cloudbyte/pom.xml | 2 +- plugins/storage/volume/default/pom.xml | 2 +- plugins/storage/volume/nexenta/pom.xml | 2 +- plugins/storage/volume/sample/pom.xml | 2 +- plugins/storage/volume/solidfire/pom.xml | 2 +- plugins/user-authenticators/ldap/pom.xml | 2 +- plugins/user-authenticators/md5/pom.xml | 2 +- plugins/user-authenticators/pbkdf2/pom.xml | 2 +- plugins/user-authenticators/plain-text/pom.xml | 2 +- plugins/user-authenticators/saml2/pom.xml | 2 +- plugins/user-authenticators/sha256salted/pom.xml | 2 +- pom.xml | 2 +- quickcloud/pom.xml | 2 +- server/pom.xml | 2 +- services/console-proxy-rdp/rdpconsole/pom.xml | 2 +- services/console-proxy/plugin/pom.xml | 2 +- services/console-proxy/pom.xml | 2 +- services/console-proxy/server/pom.xml | 2 +- services/iam/plugin/pom.xml | 2 +- services/iam/server/pom.xml | 2 +- services/pom.xml | 2 +- services/secondary-storage/controller/pom.xml | 2 +- services/secondary-storage/pom.xml | 2 +- services/secondary-storage/server/pom.xml | 2 +- systemvm/pom.xml | 2 +- test/pom.xml | 2 +- tools/apidoc/pom.xml | 2 +- tools/checkstyle/pom.xml | 2 +- tools/devcloud-kvm/pom.xml | 2 +- tools/devcloud/pom.xml | 2 +- tools/devcloud4/pom.xml | 2 +- tools/marvin/pom.xml | 2 +- tools/marvin/setup.py | 2 +- tools/pom.xml | 2 +- tools/wix-cloudstack-maven-plugin/pom.xml | 2 +- usage/pom.xml | 2 +- utils/pom.xml | 2 +- vmware-base/pom.xml | 2 +- 126 files changed, 129 insertions(+), 129 deletions(-) diff --git a/agent/pom.xml b/agent/pom.xml index 96bfd4d9a5..9ff0c5e23c 100644 --- a/agent/pom.xml +++ b/agent/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/api/pom.xml b/api/pom.xml index 160629c219..6b9c98f9c1 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/client/pom.xml b/client/pom.xml index d329c7f08a..5cafd832d2 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/core/pom.xml b/core/pom.xml index 9c74333144..60dc02ff57 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -25,7 +25,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/debian/changelog b/debian/changelog index 2c1a2344ef..04ae4f7537 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,14 +1,14 @@ -cloudstack (4.8.1-SNAPSHOT) unstable; urgency=low +cloudstack (4.9.0-SNAPSHOT) unstable; urgency=low [ Remi Bergsma ] - * Update the version to 4.8.1-SNAPSHOT + * Update the version to 4.9.0.snapshot -- the Apache CloudStack project Wed, 20 Jan 2016 23:43:35 +0100 cloudstack (4.8.0-SNAPSHOT) unstable; urgency=low [ Remi Bergsma ] - * Update the version to 4.8.1.snapshot + * Update the version to 4.8.0.snapshot -- the Apache CloudStack project Sun, 21 Dec 2015 22:11:55 +0100 diff --git a/developer/pom.xml b/developer/pom.xml index bdd330a26b..b7d70004b0 100644 --- a/developer/pom.xml +++ b/developer/pom.xml @@ -18,7 +18,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/engine/api/pom.xml b/engine/api/pom.xml index 71003da0eb..01a6051a34 100644 --- a/engine/api/pom.xml +++ b/engine/api/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/engine/components-api/pom.xml b/engine/components-api/pom.xml index 6947aefc27..7ea56d66dc 100644 --- a/engine/components-api/pom.xml +++ b/engine/components-api/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/engine/network/pom.xml b/engine/network/pom.xml index fca11c6350..a41ed26275 100644 --- a/engine/network/pom.xml +++ b/engine/network/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/engine/orchestration/pom.xml b/engine/orchestration/pom.xml index 099fdc4f35..ee3bb34200 100755 --- a/engine/orchestration/pom.xml +++ b/engine/orchestration/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/engine/pom.xml b/engine/pom.xml index 6895f25f66..c3c0b28e76 100644 --- a/engine/pom.xml +++ b/engine/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/engine/schema/pom.xml b/engine/schema/pom.xml index f7b1fb4075..4d0b90d6de 100644 --- a/engine/schema/pom.xml +++ b/engine/schema/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/engine/service/pom.xml b/engine/service/pom.xml index bbdded98fd..38b6035e87 100644 --- a/engine/service/pom.xml +++ b/engine/service/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT cloud-engine-service war diff --git a/engine/storage/cache/pom.xml b/engine/storage/cache/pom.xml index 5290ee3a53..976a2e75a8 100644 --- a/engine/storage/cache/pom.xml +++ b/engine/storage/cache/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/datamotion/pom.xml b/engine/storage/datamotion/pom.xml index a816531af7..3324270198 100644 --- a/engine/storage/datamotion/pom.xml +++ b/engine/storage/datamotion/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/image/pom.xml b/engine/storage/image/pom.xml index 6617d42622..779f1399ab 100644 --- a/engine/storage/image/pom.xml +++ b/engine/storage/image/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/integration-test/pom.xml b/engine/storage/integration-test/pom.xml index 50990aa2e8..d648129574 100644 --- a/engine/storage/integration-test/pom.xml +++ b/engine/storage/integration-test/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/pom.xml b/engine/storage/pom.xml index 1cfd140a6c..cf9a8ea973 100644 --- a/engine/storage/pom.xml +++ b/engine/storage/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/engine/storage/snapshot/pom.xml b/engine/storage/snapshot/pom.xml index c3c216e666..97ca7f21e3 100644 --- a/engine/storage/snapshot/pom.xml +++ b/engine/storage/snapshot/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/volume/pom.xml b/engine/storage/volume/pom.xml index 41058374e7..e790df12dd 100644 --- a/engine/storage/volume/pom.xml +++ b/engine/storage/volume/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/framework/cluster/pom.xml b/framework/cluster/pom.xml index 68142ac7ee..d14e5c455d 100644 --- a/framework/cluster/pom.xml +++ b/framework/cluster/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/config/pom.xml b/framework/config/pom.xml index d9d9c6cfc2..349e9f29d3 100644 --- a/framework/config/pom.xml +++ b/framework/config/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/db/pom.xml b/framework/db/pom.xml index f311ecea57..71b9af36b4 100644 --- a/framework/db/pom.xml +++ b/framework/db/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/events/pom.xml b/framework/events/pom.xml index d8a69cf572..a633a779fc 100644 --- a/framework/events/pom.xml +++ b/framework/events/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/ipc/pom.xml b/framework/ipc/pom.xml index dee2edf589..0341ff7dea 100644 --- a/framework/ipc/pom.xml +++ b/framework/ipc/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/jobs/pom.xml b/framework/jobs/pom.xml index dd3cce4814..ff17f48358 100644 --- a/framework/jobs/pom.xml +++ b/framework/jobs/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/managed-context/pom.xml b/framework/managed-context/pom.xml index 72572348fc..e2058fe03f 100644 --- a/framework/managed-context/pom.xml +++ b/framework/managed-context/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-maven-standard - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../maven-standard/pom.xml diff --git a/framework/pom.xml b/framework/pom.xml index 7b58cdd098..a60841c750 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT install diff --git a/framework/quota/pom.xml b/framework/quota/pom.xml index 1687892576..82d43cdd4d 100644 --- a/framework/quota/pom.xml +++ b/framework/quota/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/rest/pom.xml b/framework/rest/pom.xml index 545a651e78..830b7ec94d 100644 --- a/framework/rest/pom.xml +++ b/framework/rest/pom.xml @@ -22,7 +22,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml cloud-framework-rest diff --git a/framework/security/pom.xml b/framework/security/pom.xml index 6649e9946f..cfe04de079 100644 --- a/framework/security/pom.xml +++ b/framework/security/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/spring/lifecycle/pom.xml b/framework/spring/lifecycle/pom.xml index 15b3367fd1..93160c472c 100644 --- a/framework/spring/lifecycle/pom.xml +++ b/framework/spring/lifecycle/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-maven-standard - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../maven-standard/pom.xml diff --git a/framework/spring/module/pom.xml b/framework/spring/module/pom.xml index 17e89f8d60..6f89f53530 100644 --- a/framework/spring/module/pom.xml +++ b/framework/spring/module/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-maven-standard - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../maven-standard/pom.xml diff --git a/maven-standard/pom.xml b/maven-standard/pom.xml index dd8d83c25c..6f8530a0f5 100644 --- a/maven-standard/pom.xml +++ b/maven-standard/pom.xml @@ -25,7 +25,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/plugins/acl/static-role-based/pom.xml b/plugins/acl/static-role-based/pom.xml index 5171886ccf..62ba16696f 100644 --- a/plugins/acl/static-role-based/pom.xml +++ b/plugins/acl/static-role-based/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/affinity-group-processors/explicit-dedication/pom.xml b/plugins/affinity-group-processors/explicit-dedication/pom.xml index e8b13d0643..d4fc0f1a2c 100644 --- a/plugins/affinity-group-processors/explicit-dedication/pom.xml +++ b/plugins/affinity-group-processors/explicit-dedication/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/affinity-group-processors/host-anti-affinity/pom.xml b/plugins/affinity-group-processors/host-anti-affinity/pom.xml index 7f712a96f8..58e205d18b 100644 --- a/plugins/affinity-group-processors/host-anti-affinity/pom.xml +++ b/plugins/affinity-group-processors/host-anti-affinity/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/alert-handlers/snmp-alerts/pom.xml b/plugins/alert-handlers/snmp-alerts/pom.xml index 7b2727d78e..7cbca893fd 100644 --- a/plugins/alert-handlers/snmp-alerts/pom.xml +++ b/plugins/alert-handlers/snmp-alerts/pom.xml @@ -22,7 +22,7 @@ cloudstack-plugins org.apache.cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/plugins/alert-handlers/syslog-alerts/pom.xml b/plugins/alert-handlers/syslog-alerts/pom.xml index 8ad576627c..e4616acd07 100644 --- a/plugins/alert-handlers/syslog-alerts/pom.xml +++ b/plugins/alert-handlers/syslog-alerts/pom.xml @@ -22,7 +22,7 @@ cloudstack-plugins org.apache.cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/plugins/api/discovery/pom.xml b/plugins/api/discovery/pom.xml index 93e8b2d7b5..049061abfa 100644 --- a/plugins/api/discovery/pom.xml +++ b/plugins/api/discovery/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/api/rate-limit/pom.xml b/plugins/api/rate-limit/pom.xml index 0690489148..3e826c2b49 100644 --- a/plugins/api/rate-limit/pom.xml +++ b/plugins/api/rate-limit/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/api/solidfire-intg-test/pom.xml b/plugins/api/solidfire-intg-test/pom.xml index a991112098..a15d7b3e85 100644 --- a/plugins/api/solidfire-intg-test/pom.xml +++ b/plugins/api/solidfire-intg-test/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/database/mysql-ha/pom.xml b/plugins/database/mysql-ha/pom.xml index 9b89047dc1..c275743cef 100644 --- a/plugins/database/mysql-ha/pom.xml +++ b/plugins/database/mysql-ha/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/database/quota/pom.xml b/plugins/database/quota/pom.xml index 450eb67860..b429c0ddd9 100644 --- a/plugins/database/quota/pom.xml +++ b/plugins/database/quota/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/dedicated-resources/pom.xml b/plugins/dedicated-resources/pom.xml index 24a86913bb..040e936d49 100644 --- a/plugins/dedicated-resources/pom.xml +++ b/plugins/dedicated-resources/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/plugins/deployment-planners/implicit-dedication/pom.xml b/plugins/deployment-planners/implicit-dedication/pom.xml index 15b56bfa4f..f0f817ce9f 100644 --- a/plugins/deployment-planners/implicit-dedication/pom.xml +++ b/plugins/deployment-planners/implicit-dedication/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/deployment-planners/user-concentrated-pod/pom.xml b/plugins/deployment-planners/user-concentrated-pod/pom.xml index f22932b5e7..d27188dcc8 100644 --- a/plugins/deployment-planners/user-concentrated-pod/pom.xml +++ b/plugins/deployment-planners/user-concentrated-pod/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/deployment-planners/user-dispersing/pom.xml b/plugins/deployment-planners/user-dispersing/pom.xml index 20a63d902a..413993f24f 100644 --- a/plugins/deployment-planners/user-dispersing/pom.xml +++ b/plugins/deployment-planners/user-dispersing/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/event-bus/inmemory/pom.xml b/plugins/event-bus/inmemory/pom.xml index 50c842c6dc..efbf29086d 100644 --- a/plugins/event-bus/inmemory/pom.xml +++ b/plugins/event-bus/inmemory/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/event-bus/kafka/pom.xml b/plugins/event-bus/kafka/pom.xml index 4d380b9973..b6827a176b 100644 --- a/plugins/event-bus/kafka/pom.xml +++ b/plugins/event-bus/kafka/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/event-bus/rabbitmq/pom.xml b/plugins/event-bus/rabbitmq/pom.xml index e68d49a28a..bc8f78cab5 100644 --- a/plugins/event-bus/rabbitmq/pom.xml +++ b/plugins/event-bus/rabbitmq/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/file-systems/netapp/pom.xml b/plugins/file-systems/netapp/pom.xml index 205eddc795..2b2c7bd923 100644 --- a/plugins/file-systems/netapp/pom.xml +++ b/plugins/file-systems/netapp/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/ha-planners/skip-heurestics/pom.xml b/plugins/ha-planners/skip-heurestics/pom.xml index 140737ce87..1511f8da0d 100644 --- a/plugins/ha-planners/skip-heurestics/pom.xml +++ b/plugins/ha-planners/skip-heurestics/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/host-allocators/random/pom.xml b/plugins/host-allocators/random/pom.xml index 9d55949952..62284c229f 100644 --- a/plugins/host-allocators/random/pom.xml +++ b/plugins/host-allocators/random/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/baremetal/pom.xml b/plugins/hypervisors/baremetal/pom.xml index 109e418179..6e569cf680 100755 --- a/plugins/hypervisors/baremetal/pom.xml +++ b/plugins/hypervisors/baremetal/pom.xml @@ -21,7 +21,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml cloud-plugin-hypervisor-baremetal diff --git a/plugins/hypervisors/hyperv/pom.xml b/plugins/hypervisors/hyperv/pom.xml index f13301cc00..d88fd14188 100644 --- a/plugins/hypervisors/hyperv/pom.xml +++ b/plugins/hypervisors/hyperv/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/kvm/pom.xml b/plugins/hypervisors/kvm/pom.xml index 8275e253c0..f8100a50c0 100644 --- a/plugins/hypervisors/kvm/pom.xml +++ b/plugins/hypervisors/kvm/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/ovm/pom.xml b/plugins/hypervisors/ovm/pom.xml index 2ad537cc3d..e754e632a8 100644 --- a/plugins/hypervisors/ovm/pom.xml +++ b/plugins/hypervisors/ovm/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/ovm3/pom.xml b/plugins/hypervisors/ovm3/pom.xml index 1bc4ae3e4e..8da1430137 100644 --- a/plugins/hypervisors/ovm3/pom.xml +++ b/plugins/hypervisors/ovm3/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/simulator/pom.xml b/plugins/hypervisors/simulator/pom.xml index ebe8870591..dbebba0146 100644 --- a/plugins/hypervisors/simulator/pom.xml +++ b/plugins/hypervisors/simulator/pom.xml @@ -22,7 +22,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml cloud-plugin-hypervisor-simulator diff --git a/plugins/hypervisors/ucs/pom.xml b/plugins/hypervisors/ucs/pom.xml index ea1536747a..c8a14d19b0 100755 --- a/plugins/hypervisors/ucs/pom.xml +++ b/plugins/hypervisors/ucs/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml cloud-plugin-hypervisor-ucs diff --git a/plugins/hypervisors/vmware/pom.xml b/plugins/hypervisors/vmware/pom.xml index fd0f1709cf..455fb5819d 100644 --- a/plugins/hypervisors/vmware/pom.xml +++ b/plugins/hypervisors/vmware/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/xenserver/pom.xml b/plugins/hypervisors/xenserver/pom.xml index 6f86a5c0bc..d03ae541a5 100644 --- a/plugins/hypervisors/xenserver/pom.xml +++ b/plugins/hypervisors/xenserver/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/bigswitch/pom.xml b/plugins/network-elements/bigswitch/pom.xml index 699c85f4db..05603a61fd 100644 --- a/plugins/network-elements/bigswitch/pom.xml +++ b/plugins/network-elements/bigswitch/pom.xml @@ -25,7 +25,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/brocade-vcs/pom.xml b/plugins/network-elements/brocade-vcs/pom.xml index c4d28d8394..c0ed17c144 100644 --- a/plugins/network-elements/brocade-vcs/pom.xml +++ b/plugins/network-elements/brocade-vcs/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/cisco-vnmc/pom.xml b/plugins/network-elements/cisco-vnmc/pom.xml index 12a994e8ac..2c8bb7f719 100644 --- a/plugins/network-elements/cisco-vnmc/pom.xml +++ b/plugins/network-elements/cisco-vnmc/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/dns-notifier/pom.xml b/plugins/network-elements/dns-notifier/pom.xml index 0f58b883ed..7db075f0aa 100644 --- a/plugins/network-elements/dns-notifier/pom.xml +++ b/plugins/network-elements/dns-notifier/pom.xml @@ -22,7 +22,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml cloud-plugin-example-dns-notifier diff --git a/plugins/network-elements/elastic-loadbalancer/pom.xml b/plugins/network-elements/elastic-loadbalancer/pom.xml index ddb00d31ac..c52cc042de 100644 --- a/plugins/network-elements/elastic-loadbalancer/pom.xml +++ b/plugins/network-elements/elastic-loadbalancer/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/f5/pom.xml b/plugins/network-elements/f5/pom.xml index 571f529685..54533e7aa7 100644 --- a/plugins/network-elements/f5/pom.xml +++ b/plugins/network-elements/f5/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/globodns/pom.xml b/plugins/network-elements/globodns/pom.xml index 73d40d1ac3..9e177a53d6 100644 --- a/plugins/network-elements/globodns/pom.xml +++ b/plugins/network-elements/globodns/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/internal-loadbalancer/pom.xml b/plugins/network-elements/internal-loadbalancer/pom.xml index c9d7e7e06a..0eb1523254 100644 --- a/plugins/network-elements/internal-loadbalancer/pom.xml +++ b/plugins/network-elements/internal-loadbalancer/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/juniper-contrail/pom.xml b/plugins/network-elements/juniper-contrail/pom.xml index f493b423b8..cac4d593d5 100644 --- a/plugins/network-elements/juniper-contrail/pom.xml +++ b/plugins/network-elements/juniper-contrail/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/juniper-srx/pom.xml b/plugins/network-elements/juniper-srx/pom.xml index 9e2833b729..ba3ecd7a95 100644 --- a/plugins/network-elements/juniper-srx/pom.xml +++ b/plugins/network-elements/juniper-srx/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/midonet/pom.xml b/plugins/network-elements/midonet/pom.xml index b57a482655..00ca4aef7c 100644 --- a/plugins/network-elements/midonet/pom.xml +++ b/plugins/network-elements/midonet/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/netscaler/pom.xml b/plugins/network-elements/netscaler/pom.xml index 4bc747dfde..2475c41363 100644 --- a/plugins/network-elements/netscaler/pom.xml +++ b/plugins/network-elements/netscaler/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/nicira-nvp/pom.xml b/plugins/network-elements/nicira-nvp/pom.xml index e86fdf10ef..7ed0f235d6 100644 --- a/plugins/network-elements/nicira-nvp/pom.xml +++ b/plugins/network-elements/nicira-nvp/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml @@ -34,7 +34,7 @@ org.apache.cloudstack cloud-utils - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT test-jar test diff --git a/plugins/network-elements/nuage-vsp/pom.xml b/plugins/network-elements/nuage-vsp/pom.xml index b254cbccd3..402f9a3829 100644 --- a/plugins/network-elements/nuage-vsp/pom.xml +++ b/plugins/network-elements/nuage-vsp/pom.xml @@ -25,7 +25,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/opendaylight/pom.xml b/plugins/network-elements/opendaylight/pom.xml index 167375a2ca..a5f2a26781 100644 --- a/plugins/network-elements/opendaylight/pom.xml +++ b/plugins/network-elements/opendaylight/pom.xml @@ -25,7 +25,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/ovs/pom.xml b/plugins/network-elements/ovs/pom.xml index 26f9873268..4f5adf9d65 100644 --- a/plugins/network-elements/ovs/pom.xml +++ b/plugins/network-elements/ovs/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/palo-alto/pom.xml b/plugins/network-elements/palo-alto/pom.xml index 5719acfbe3..555ef7ab3f 100644 --- a/plugins/network-elements/palo-alto/pom.xml +++ b/plugins/network-elements/palo-alto/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/stratosphere-ssp/pom.xml b/plugins/network-elements/stratosphere-ssp/pom.xml index 6d57670d55..89e84db27b 100644 --- a/plugins/network-elements/stratosphere-ssp/pom.xml +++ b/plugins/network-elements/stratosphere-ssp/pom.xml @@ -25,7 +25,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/vxlan/pom.xml b/plugins/network-elements/vxlan/pom.xml index c31b72f792..46e5af03ed 100644 --- a/plugins/network-elements/vxlan/pom.xml +++ b/plugins/network-elements/vxlan/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/pom.xml b/plugins/pom.xml index 530245c546..bafe299da9 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/plugins/storage-allocators/random/pom.xml b/plugins/storage-allocators/random/pom.xml index 960aa1f0cd..87cd5b582c 100644 --- a/plugins/storage-allocators/random/pom.xml +++ b/plugins/storage-allocators/random/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/storage/image/default/pom.xml b/plugins/storage/image/default/pom.xml index 48a544ae38..b9c641cfd9 100644 --- a/plugins/storage/image/default/pom.xml +++ b/plugins/storage/image/default/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/image/s3/pom.xml b/plugins/storage/image/s3/pom.xml index d7f8d4f448..d7ee4372d0 100644 --- a/plugins/storage/image/s3/pom.xml +++ b/plugins/storage/image/s3/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/image/sample/pom.xml b/plugins/storage/image/sample/pom.xml index 961a36750d..c63929e79a 100644 --- a/plugins/storage/image/sample/pom.xml +++ b/plugins/storage/image/sample/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/image/swift/pom.xml b/plugins/storage/image/swift/pom.xml index 3365e7775d..a6c7dd1164 100644 --- a/plugins/storage/image/swift/pom.xml +++ b/plugins/storage/image/swift/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/volume/cloudbyte/pom.xml b/plugins/storage/volume/cloudbyte/pom.xml index a762cec109..2a4e02dd8e 100755 --- a/plugins/storage/volume/cloudbyte/pom.xml +++ b/plugins/storage/volume/cloudbyte/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/volume/default/pom.xml b/plugins/storage/volume/default/pom.xml index 17500d7cb6..1cba838939 100644 --- a/plugins/storage/volume/default/pom.xml +++ b/plugins/storage/volume/default/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/volume/nexenta/pom.xml b/plugins/storage/volume/nexenta/pom.xml index 04556c1b8a..e4d8ebe069 100644 --- a/plugins/storage/volume/nexenta/pom.xml +++ b/plugins/storage/volume/nexenta/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/volume/sample/pom.xml b/plugins/storage/volume/sample/pom.xml index c26d574142..d649df248d 100644 --- a/plugins/storage/volume/sample/pom.xml +++ b/plugins/storage/volume/sample/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/volume/solidfire/pom.xml b/plugins/storage/volume/solidfire/pom.xml index fb7ecdf74d..21b3636ddb 100644 --- a/plugins/storage/volume/solidfire/pom.xml +++ b/plugins/storage/volume/solidfire/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/user-authenticators/ldap/pom.xml b/plugins/user-authenticators/ldap/pom.xml index 95e7824acc..a2af718737 100644 --- a/plugins/user-authenticators/ldap/pom.xml +++ b/plugins/user-authenticators/ldap/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/user-authenticators/md5/pom.xml b/plugins/user-authenticators/md5/pom.xml index 29199a7de5..f436f90e32 100644 --- a/plugins/user-authenticators/md5/pom.xml +++ b/plugins/user-authenticators/md5/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/user-authenticators/pbkdf2/pom.xml b/plugins/user-authenticators/pbkdf2/pom.xml index 1f62293476..b26636bd7e 100644 --- a/plugins/user-authenticators/pbkdf2/pom.xml +++ b/plugins/user-authenticators/pbkdf2/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/user-authenticators/plain-text/pom.xml b/plugins/user-authenticators/plain-text/pom.xml index c64f6fce9d..3598cc168d 100644 --- a/plugins/user-authenticators/plain-text/pom.xml +++ b/plugins/user-authenticators/plain-text/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/user-authenticators/saml2/pom.xml b/plugins/user-authenticators/saml2/pom.xml index f7b6140c63..a978860461 100644 --- a/plugins/user-authenticators/saml2/pom.xml +++ b/plugins/user-authenticators/saml2/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/user-authenticators/sha256salted/pom.xml b/plugins/user-authenticators/sha256salted/pom.xml index 3713ab2ba5..fe5fa6f5ed 100644 --- a/plugins/user-authenticators/sha256salted/pom.xml +++ b/plugins/user-authenticators/sha256salted/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/pom.xml b/pom.xml index fb434072c8..c18c377cf2 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT pom Apache CloudStack Apache CloudStack is an IaaS (“Infrastructure as a Service”) cloud orchestration platform. diff --git a/quickcloud/pom.xml b/quickcloud/pom.xml index a1ec781c94..841a9c5185 100644 --- a/quickcloud/pom.xml +++ b/quickcloud/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-maven-standard - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../maven-standard/pom.xml diff --git a/server/pom.xml b/server/pom.xml index 0656541f08..b8e3598e3e 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/services/console-proxy-rdp/rdpconsole/pom.xml b/services/console-proxy-rdp/rdpconsole/pom.xml index a64b118630..ba311830af 100755 --- a/services/console-proxy-rdp/rdpconsole/pom.xml +++ b/services/console-proxy-rdp/rdpconsole/pom.xml @@ -27,7 +27,7 @@ org.apache.cloudstack cloudstack-services - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/services/console-proxy/plugin/pom.xml b/services/console-proxy/plugin/pom.xml index 14a3ffc3e2..dbaf85791c 100644 --- a/services/console-proxy/plugin/pom.xml +++ b/services/console-proxy/plugin/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-service-console-proxy - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/console-proxy/pom.xml b/services/console-proxy/pom.xml index 8dddaeab70..9d5feec386 100644 --- a/services/console-proxy/pom.xml +++ b/services/console-proxy/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-services - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/console-proxy/server/pom.xml b/services/console-proxy/server/pom.xml index 99d0f921b7..541d242013 100644 --- a/services/console-proxy/server/pom.xml +++ b/services/console-proxy/server/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-service-console-proxy - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/iam/plugin/pom.xml b/services/iam/plugin/pom.xml index c770ef2689..974d2166bf 100644 --- a/services/iam/plugin/pom.xml +++ b/services/iam/plugin/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-service-iam - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/iam/server/pom.xml b/services/iam/server/pom.xml index 71bafed62e..b2ad0a4f52 100644 --- a/services/iam/server/pom.xml +++ b/services/iam/server/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-service-iam - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/pom.xml b/services/pom.xml index c8812f75e2..f315b5e8b1 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/secondary-storage/controller/pom.xml b/services/secondary-storage/controller/pom.xml index f242663b31..bb8878010f 100644 --- a/services/secondary-storage/controller/pom.xml +++ b/services/secondary-storage/controller/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-service-secondary-storage - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/secondary-storage/pom.xml b/services/secondary-storage/pom.xml index 33b5860c11..bce61d66f1 100644 --- a/services/secondary-storage/pom.xml +++ b/services/secondary-storage/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-services - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/secondary-storage/server/pom.xml b/services/secondary-storage/server/pom.xml index 87a0381316..b6bfbf7df7 100644 --- a/services/secondary-storage/server/pom.xml +++ b/services/secondary-storage/server/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-service-secondary-storage - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/systemvm/pom.xml b/systemvm/pom.xml index f0cb0dae0e..c72b56df67 100644 --- a/systemvm/pom.xml +++ b/systemvm/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/test/pom.xml b/test/pom.xml index e582d3e876..3f1119f9cb 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/tools/apidoc/pom.xml b/tools/apidoc/pom.xml index fb84b7a572..75cb1650d1 100644 --- a/tools/apidoc/pom.xml +++ b/tools/apidoc/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloud-tools - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/tools/checkstyle/pom.xml b/tools/checkstyle/pom.xml index 1c2655fe9f..f4ee2b8e1f 100644 --- a/tools/checkstyle/pom.xml +++ b/tools/checkstyle/pom.xml @@ -24,7 +24,7 @@ Apache CloudStack Developer Tools - Checkstyle Configuration org.apache.cloudstack checkstyle - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/tools/devcloud-kvm/pom.xml b/tools/devcloud-kvm/pom.xml index ce01784211..a71968e95d 100644 --- a/tools/devcloud-kvm/pom.xml +++ b/tools/devcloud-kvm/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloud-tools - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/tools/devcloud/pom.xml b/tools/devcloud/pom.xml index 38750e5ae1..e8bcaebe60 100644 --- a/tools/devcloud/pom.xml +++ b/tools/devcloud/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloud-tools - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/tools/devcloud4/pom.xml b/tools/devcloud4/pom.xml index 586c195ae9..47493931ba 100644 --- a/tools/devcloud4/pom.xml +++ b/tools/devcloud4/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloud-tools - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml index e9c8c78347..391987be4b 100644 --- a/tools/marvin/pom.xml +++ b/tools/marvin/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-tools - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/tools/marvin/setup.py b/tools/marvin/setup.py index 43bc454424..81fefd829c 100644 --- a/tools/marvin/setup.py +++ b/tools/marvin/setup.py @@ -27,7 +27,7 @@ raise RuntimeError("python setuptools is required to build Marvin") -VERSION = "4.8.1-SNAPSHOT" +VERSION = "4.9.0-SNAPSHOT" setup(name="Marvin", version=VERSION, diff --git a/tools/pom.xml b/tools/pom.xml index 6c8577f424..02ad3185db 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -27,7 +27,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/tools/wix-cloudstack-maven-plugin/pom.xml b/tools/wix-cloudstack-maven-plugin/pom.xml index 6359537e22..deb4284b3d 100644 --- a/tools/wix-cloudstack-maven-plugin/pom.xml +++ b/tools/wix-cloudstack-maven-plugin/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/usage/pom.xml b/usage/pom.xml index 0e6f720ec9..ff10e819e4 100644 --- a/usage/pom.xml +++ b/usage/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/utils/pom.xml b/utils/pom.xml index 34ff4c3925..3a23a58774 100755 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/vmware-base/pom.xml b/vmware-base/pom.xml index 9df193a055..e18dc8ea14 100644 --- a/vmware-base/pom.xml +++ b/vmware-base/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT From e1ecfad32213147e991c23ce3e2a31ad5d9bb5cd Mon Sep 17 00:00:00 2001 From: Remi Bergsma Date: Tue, 26 Jan 2016 15:21:23 +0100 Subject: [PATCH 043/203] Implement upgrade path 4.8.1 -> 4.9.0 --- .../cloud/upgrade/DatabaseUpgradeChecker.java | 107 +++++++++--------- .../cloud/upgrade/dao/Upgrade481to490.java | 67 +++++++++++ setup/db/db/schema-481to490-cleanup.sql | 20 ++++ setup/db/db/schema-481to490.sql | 20 ++++ 4 files changed, 162 insertions(+), 52 deletions(-) create mode 100644 engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java create mode 100644 setup/db/db/schema-481to490-cleanup.sql create mode 100644 setup/db/db/schema-481to490.sql diff --git a/engine/schema/src/com/cloud/upgrade/DatabaseUpgradeChecker.java b/engine/schema/src/com/cloud/upgrade/DatabaseUpgradeChecker.java index d2b0066bc6..fc44c4f5e3 100644 --- a/engine/schema/src/com/cloud/upgrade/DatabaseUpgradeChecker.java +++ b/engine/schema/src/com/cloud/upgrade/DatabaseUpgradeChecker.java @@ -63,6 +63,7 @@ import com.cloud.upgrade.dao.Upgrade470to471; import com.cloud.upgrade.dao.Upgrade471to480; import com.cloud.upgrade.dao.Upgrade480to481; +import com.cloud.upgrade.dao.Upgrade481to490; import com.cloud.upgrade.dao.UpgradeSnapshot217to224; import com.cloud.upgrade.dao.UpgradeSnapshot223to224; import com.cloud.upgrade.dao.VersionDao; @@ -110,7 +111,7 @@ public DatabaseUpgradeChecker() { new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), - new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.1.8", new DbUpgrade[] {new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), @@ -118,7 +119,7 @@ public DatabaseUpgradeChecker() { new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.1.9", new DbUpgrade[] {new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), @@ -126,165 +127,167 @@ public DatabaseUpgradeChecker() { new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), - new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.1", new DbUpgrade[] {new Upgrade221to222(), new UpgradeSnapshot223to224(), new Upgrade222to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), - new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.2", new DbUpgrade[] {new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.3", new DbUpgrade[] {new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.4", new DbUpgrade[] {new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.5", new DbUpgrade[] {new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), - new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.6", new DbUpgrade[] {new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.7", new DbUpgrade[] {new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), - new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.8", new DbUpgrade[] {new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30() , new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.9", new DbUpgrade[] {new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.10", new DbUpgrade[] {new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), - new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.12", new DbUpgrade[] {new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), - new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.13", new DbUpgrade[] {new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.14", new DbUpgrade[] {new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), - new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("3.0.0", new DbUpgrade[] {new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), - new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("3.0.1", new DbUpgrade[] {new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("3.0.2", new DbUpgrade[] {new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), - new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.0.0", new DbUpgrade[] {new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.0.0", new DbUpgrade[] {new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.0.1", new DbUpgrade[] {new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.0.1", new DbUpgrade[] {new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.0.2", new DbUpgrade[] {new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.0.2", new DbUpgrade[] {new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.1.0", new DbUpgrade[] {new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.1.0", new DbUpgrade[] {new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.1.1", new DbUpgrade[] {new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.1.1", new DbUpgrade[] {new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.2.0", new DbUpgrade[] {new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.2.0", new DbUpgrade[] {new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.2.1", new DbUpgrade[] {new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.2.1", new DbUpgrade[] {new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.3.0", new DbUpgrade[] {new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.3.0", new DbUpgrade[] {new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.3.1", new DbUpgrade[] {new Upgrade431to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.3.1", new DbUpgrade[] {new Upgrade431to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.3.2", new DbUpgrade[] {new Upgrade432to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.3.2", new DbUpgrade[] {new Upgrade432to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.4.0", new DbUpgrade[] {new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.4.0", new DbUpgrade[] {new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.4.1", new DbUpgrade[] {new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481() }); + _upgradeMap.put("4.4.1", new DbUpgrade[] {new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490() }); - _upgradeMap.put("4.4.2", new DbUpgrade[] {new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.4.2", new DbUpgrade[] {new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.4.3", new DbUpgrade[] {new Upgrade443to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.4.3", new DbUpgrade[] {new Upgrade443to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.4.4", new DbUpgrade[] {new Upgrade444to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.4.4", new DbUpgrade[] {new Upgrade444to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.5.0", new DbUpgrade[] {new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.5.0", new DbUpgrade[] {new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.5.1", new DbUpgrade[] {new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.5.1", new DbUpgrade[] {new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.5.2", new DbUpgrade[] {new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.5.2", new DbUpgrade[] {new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.5.3", new DbUpgrade[] {new Upgrade453to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.5.3", new DbUpgrade[] {new Upgrade453to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.6.0", new DbUpgrade[] {new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.6.0", new DbUpgrade[] {new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.6.1", new DbUpgrade[] {new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.6.1", new DbUpgrade[] {new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.6.2", new DbUpgrade[] {new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.6.2", new DbUpgrade[] {new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.7.0", new DbUpgrade[] {new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.7.0", new DbUpgrade[] {new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.7.1", new DbUpgrade[] {new Upgrade471to480(),new Upgrade480to481()}); + _upgradeMap.put("4.7.1", new DbUpgrade[] {new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.7.2", new DbUpgrade[] {new Upgrade471to480(),new Upgrade480to481()}); + _upgradeMap.put("4.7.2", new DbUpgrade[] {new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.8.0", new DbUpgrade[] {new Upgrade480to481()}); + _upgradeMap.put("4.8.0", new DbUpgrade[] {new Upgrade480to481(), new Upgrade481to490()}); + + _upgradeMap.put("4.8.1", new DbUpgrade[] {new Upgrade481to490()}); //CP Upgrades _upgradeMap.put("3.0.3", new DbUpgrade[] {new Upgrade303to304(), new Upgrade304to305(), new Upgrade305to306(), new Upgrade306to307(), new Upgrade307to410(), - new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("3.0.4", new DbUpgrade[] {new Upgrade304to305(), new Upgrade305to306(), new Upgrade306to307(), new Upgrade307to410(), new Upgrade410to420(), - new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("3.0.5", new DbUpgrade[] {new Upgrade305to306(), new Upgrade306to307(), new Upgrade307to410(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("3.0.6", new DbUpgrade[] {new Upgrade306to307(), new Upgrade307to410(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), - new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("3.0.7", new DbUpgrade[] {new Upgrade307to410(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("3.0.7", new DbUpgrade[] {new Upgrade307to410(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.15", new DbUpgrade[] {new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to303(), new Upgrade303to304(), new Upgrade304to305(), new Upgrade305to306(), new Upgrade306to307(), new Upgrade307to410(), new Upgrade410to420(), - new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.16", new DbUpgrade[] {new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to303(), new Upgrade303to304(), new Upgrade304to305(), new Upgrade305to306(), new Upgrade306to307(), new Upgrade307to410(), new Upgrade410to420(), - new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); } protected void runScript(Connection conn, File file) { diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java new file mode 100644 index 0000000000..9e5213478e --- /dev/null +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java @@ -0,0 +1,67 @@ +// 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.upgrade.dao; + +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; +import org.apache.log4j.Logger; + +import java.io.File; +import java.sql.Connection; + +public class Upgrade481to490 implements DbUpgrade { + final static Logger s_logger = Logger.getLogger(Upgrade481to490.class); + + @Override + public String[] getUpgradableVersionRange() { + return new String[] {"4.8.1", "4.9.0"}; + } + + @Override + public String getUpgradedVersion() { + return "4.9.0"; + } + + @Override + public boolean supportsRollingUpgrade() { + return false; + } + + @Override + public File[] getPrepareScripts() { + String script = Script.findScript("", "db/schema-481to490.sql"); + if (script == null) { + throw new CloudRuntimeException("Unable to find db/schema-481to490.sql"); + } + return new File[] {new File(script)}; + } + + @Override + public void performDataMigration(Connection conn) { + } + + @Override + public File[] getCleanupScripts() { + String script = Script.findScript("", "db/schema-481to490-cleanup.sql"); + if (script == null) { + throw new CloudRuntimeException("Unable to find db/schema-481to490-cleanup.sql"); + } + + return new File[] {new File(script)}; + } +} diff --git a/setup/db/db/schema-481to490-cleanup.sql b/setup/db/db/schema-481to490-cleanup.sql new file mode 100644 index 0000000000..c74fa41533 --- /dev/null +++ b/setup/db/db/schema-481to490-cleanup.sql @@ -0,0 +1,20 @@ +-- 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. + +--; +-- Schema cleanup from 4.8.1 to 4.9.0; +--; diff --git a/setup/db/db/schema-481to490.sql b/setup/db/db/schema-481to490.sql new file mode 100644 index 0000000000..c80fa2aa0d --- /dev/null +++ b/setup/db/db/schema-481to490.sql @@ -0,0 +1,20 @@ +-- 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. + +--; +-- Schema upgrade from 4.8.1 to 4.9.0; +--; From 04ca7e57d5ad129664ec727b14b0456391ad87b2 Mon Sep 17 00:00:00 2001 From: Abhinandan Prateek Date: Mon, 18 Jan 2016 13:41:38 +0530 Subject: [PATCH 044/203] Quota: consolidated lockable account check to a method. Added unit tests to check lockablity of various accounts --- .../quota/QuotaAlertManagerImpl.java | 8 ++-- .../apache/cloudstack/quota/QuotaManager.java | 3 ++ .../cloudstack/quota/QuotaManagerImpl.java | 5 +++ .../quota/dao/QuotaBalanceDaoImpl.java | 2 +- .../quota/QuotaManagerImplTest.java | 38 +++++++++++++++++++ .../api/command/QuotaCreditsCmd.java | 4 +- .../api/response/QuotaResponseBuilder.java | 2 +- .../response/QuotaResponseBuilderImpl.java | 18 ++++----- .../cloudstack/quota/QuotaServiceImpl.java | 6 +-- .../api/command/QuotaCreditsCmdTest.java | 4 +- .../QuotaResponseBuilderImplTest.java | 2 +- 11 files changed, 69 insertions(+), 23 deletions(-) diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java index a57e0c27db..93cffc4393 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java @@ -27,7 +27,6 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.TransactionLegacy; -import com.cloud.utils.exception.CloudRuntimeException; import com.google.common.base.Strings; import com.sun.mail.smtp.SMTPMessage; import com.sun.mail.smtp.SMTPSSLTransport; @@ -83,6 +82,8 @@ public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertMana private ConfigurationDao _configDao; @Inject private QuotaUsageDao _quotaUsage; + @Inject + private QuotaManager _quotaManager; private EmailQuotaAlert _emailQuotaAlert; private boolean _lockAccountEnforcement = false; @@ -158,7 +159,7 @@ public void checkAndSendQuotaAlertEmails() { } if (accountBalance.compareTo(zeroBalance) < 0) { if (_lockAccountEnforcement && (lockable == 1)) { - if (account.getType() == Account.ACCOUNT_TYPE_NORMAL) { + if (_quotaManager.isLockable(account)) { s_logger.info("Locking account " + account.getAccountName() + " due to quota < 0."); lockAccount(account.getId()); } @@ -382,7 +383,8 @@ protected PasswordAuthentication getPasswordAuthentication() { public void sendQuotaAlert(List emails, String subject, String body) throws MessagingException, UnsupportedEncodingException { if (_smtpSession == null) { - throw new CloudRuntimeException("Unable to create smtp session."); + s_logger.error("Unable to create smtp session."); + return; } SMTPMessage msg = new SMTPMessage(_smtpSession); msg.setSender(new InternetAddress(_emailSender, _emailSender)); diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaManager.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaManager.java index 1cda3b22e4..7811bcbcca 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/QuotaManager.java +++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaManager.java @@ -16,10 +16,13 @@ //under the License. package org.apache.cloudstack.quota; +import com.cloud.user.AccountVO; import com.cloud.utils.component.Manager; public interface QuotaManager extends Manager { boolean calculateQuotaUsage(); + boolean isLockable(AccountVO account); + } diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java index ac14718fd4..74a59acdd1 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java @@ -463,4 +463,9 @@ public QuotaUsageVO updateQuotaNetwork(UsageVO usageRecord, final int transferTy return quota_usage; } + @Override + public boolean isLockable(AccountVO account) { + return (account.getType() == AccountVO.ACCOUNT_TYPE_NORMAL || account.getType() == AccountVO.ACCOUNT_TYPE_DOMAIN_ADMIN); + } + } diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java index aa650e165a..d8ce7acc97 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java @@ -156,7 +156,7 @@ public List doInTransaction(final TransactionStatus status) { // get records before startDate to find start balance for (QuotaBalanceVO entry : quotaUsageRecords) { if (s_logger.isDebugEnabled()) { - s_logger.debug("FindQuotaBalIance Entry=" + entry); + s_logger.debug("FindQuotaBalance Entry=" + entry); } if (entry.getCreditsId() > 0) { trimmedRecords.add(entry); diff --git a/framework/quota/test/org/apache/cloudstack/quota/QuotaManagerImplTest.java b/framework/quota/test/org/apache/cloudstack/quota/QuotaManagerImplTest.java index 792728f5e8..c9f6dcd5a3 100644 --- a/framework/quota/test/org/apache/cloudstack/quota/QuotaManagerImplTest.java +++ b/framework/quota/test/org/apache/cloudstack/quota/QuotaManagerImplTest.java @@ -197,4 +197,42 @@ public void testProcessQuotaBalanceForAccount() { Mockito.verify(quotaAcc, Mockito.times(1)).persistQuotaAccount(Mockito.any(QuotaAccountVO.class)); } + private AccountVO accountVO = new AccountVO(); + + @Test + public void testAdminLockableAccount() { + accountVO.setType(Account.ACCOUNT_TYPE_ADMIN); + assertFalse(quotaManager.isLockable(accountVO)); + } + + @Test + public void testNormalLockableAccount() { + accountVO.setType(Account.ACCOUNT_TYPE_NORMAL); + assertTrue(quotaManager.isLockable(accountVO)); + } + + @Test + public void tesDomainAdmingLockableAccount() { + accountVO.setType(Account.ACCOUNT_TYPE_DOMAIN_ADMIN); + assertTrue(quotaManager.isLockable(accountVO)); + } + + @Test + public void testReadOnlyAdminLockableAccount() { + accountVO.setType(Account.ACCOUNT_TYPE_READ_ONLY_ADMIN); + assertFalse(quotaManager.isLockable(accountVO)); + } + + @Test + public void testResourceDomainAdminLockableAccount() { + accountVO.setType(Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN); + assertFalse(quotaManager.isLockable(accountVO)); + } + + @Test + public void testProjectLockableAccount() { + accountVO.setType(Account.ACCOUNT_TYPE_PROJECT); + assertFalse(quotaManager.isLockable(accountVO)); + } + } diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.java index 125844548a..f12733d2ce 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.java @@ -123,7 +123,7 @@ public void execute() { if (getValue() == null) { throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Please send a valid non-empty quota value"); } - if (getQuotaEnforce() != null && getQuotaEnforce()) { + if (getQuotaEnforce() != null) { _quotaService.setLockAccount(accountId, getQuotaEnforce()); } if (getMinBalance() != null) { @@ -133,7 +133,7 @@ public void execute() { throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Please set a value for min balance"); } - final QuotaCreditsResponse response = _responseBuilder.addQuotaCredits(accountId, getDomainId(), getValue(), CallContext.current().getCallingUserId()); + final QuotaCreditsResponse response = _responseBuilder.addQuotaCredits(accountId, getDomainId(), getValue(), CallContext.current().getCallingUserId(), getQuotaEnforce()); response.setResponseName(getCommandName()); response.setObjectName("quotacredits"); setResponseObject(response); diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java index 6e7ab81118..0f276973ee 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java @@ -51,7 +51,7 @@ public interface QuotaResponseBuilder { List getQuotaBalance(QuotaBalanceCmd cmd); - QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy); + QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy, Boolean enforce); List listQuotaEmailTemplates(QuotaEmailTemplateListCmd cmd); diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java index ab66289448..e615bcde25 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java @@ -32,6 +32,7 @@ import org.apache.cloudstack.api.command.QuotaStatementCmd; import org.apache.cloudstack.api.command.QuotaTariffListCmd; import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd; +import org.apache.cloudstack.quota.QuotaManager; import org.apache.cloudstack.quota.QuotaService; import org.apache.cloudstack.quota.QuotaStatement; import org.apache.cloudstack.quota.constant.QuotaConfig; @@ -98,6 +99,8 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder { private AccountManager _accountMgr; @Inject private QuotaStatement _statement; + @Inject + private QuotaManager _quotaManager; @Override public QuotaTariffResponse createQuotaTariffResponse(QuotaTariffVO tariff) { @@ -384,11 +387,10 @@ public QuotaTariffVO updateQuotaTariffPlan(QuotaTariffUpdateCmd cmd) { } @Override - public QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy) { + public QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy, Boolean enforce) { Date despositedOn = _quotaService.computeAdjustedTime(new Date()); QuotaBalanceVO qb = _quotaBalanceDao.findLaterBalanceEntry(accountId, domainId, despositedOn); - if (qb != null) { throw new InvalidParameterValueException("Incorrect deposit date: " + despositedOn + " there are balance entries after this date"); } @@ -407,16 +409,12 @@ public QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Doubl _quotaService.saveQuotaAccount(account, currentAccountBalance, despositedOn); if (lockAccountEnforcement) { if (currentAccountBalance.compareTo(new BigDecimal(0)) >= 0) { - if (account.getType() == Account.ACCOUNT_TYPE_NORMAL) { - if (account.getState() == Account.State.locked) { - s_logger.info("UnLocking account " + account.getAccountName() + " , due to positive balance " + currentAccountBalance); - _accountMgr.enableAccount(account.getAccountName(), domainId, accountId); - } - } else { - s_logger.warn("Only normal accounts will get locked " + account.getAccountName() + " even if they have run out of quota " + currentAccountBalance); + if (account.getState() == Account.State.locked) { + s_logger.info("UnLocking account " + account.getAccountName() + " , due to positive balance " + currentAccountBalance); + _accountMgr.enableAccount(account.getAccountName(), domainId, accountId); } } else { // currentAccountBalance < 0 then lock the account - if (account.getState() == Account.State.enabled) { + if (_quotaManager.isLockable(account) && account.getState() == Account.State.enabled && enforce) { s_logger.info("Locking account " + account.getAccountName() + " , due to negative balance " + currentAccountBalance); _accountMgr.lockAccount(account.getAccountName(), domainId, accountId); } diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java index 0fd7101bf6..3efc0959e6 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java @@ -274,14 +274,14 @@ public Date computeAdjustedTime(final Date date) { } @Override - public void setLockAccount(Long accountId, Boolean state) { + public void setLockAccount(Long accountId, Boolean enforce) { QuotaAccountVO acc = _quotaAcc.findByIdQuotaAccount(accountId); if (acc == null) { acc = new QuotaAccountVO(accountId); - acc.setQuotaEnforce(state ? 1 : 0); + acc.setQuotaEnforce(enforce ? 1 : 0); _quotaAcc.persistQuotaAccount(acc); } else { - acc.setQuotaEnforce(state ? 1 : 0); + acc.setQuotaEnforce(enforce ? 1 : 0); _quotaAcc.updateQuotaAccount(accountId, acc); } } diff --git a/plugins/database/quota/test/org/apache/cloudstack/api/command/QuotaCreditsCmdTest.java b/plugins/database/quota/test/org/apache/cloudstack/api/command/QuotaCreditsCmdTest.java index f4d16b7b68..1f22508d81 100644 --- a/plugins/database/quota/test/org/apache/cloudstack/api/command/QuotaCreditsCmdTest.java +++ b/plugins/database/quota/test/org/apache/cloudstack/api/command/QuotaCreditsCmdTest.java @@ -65,7 +65,7 @@ public void testQuotaCreditsCmd() throws NoSuchFieldException, IllegalAccessExce AccountVO acc = new AccountVO(); acc.setId(2L); Mockito.when(accountService.getActiveAccountByName(Mockito.anyString(), Mockito.anyLong())).thenReturn(acc); - Mockito.when(responseBuilder.addQuotaCredits(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyDouble(), Mockito.anyLong())).thenReturn(new QuotaCreditsResponse()); + Mockito.when(responseBuilder.addQuotaCredits(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyDouble(), Mockito.anyLong(), Mockito.anyBoolean())).thenReturn(new QuotaCreditsResponse()); // No value provided test try { @@ -79,7 +79,7 @@ public void testQuotaCreditsCmd() throws NoSuchFieldException, IllegalAccessExce cmd.execute(); Mockito.verify(quotaService, Mockito.times(0)).setLockAccount(Mockito.anyLong(), Mockito.anyBoolean()); Mockito.verify(quotaService, Mockito.times(1)).setMinBalance(Mockito.anyLong(), Mockito.anyDouble()); - Mockito.verify(responseBuilder, Mockito.times(1)).addQuotaCredits(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyDouble(), Mockito.anyLong()); + Mockito.verify(responseBuilder, Mockito.times(1)).addQuotaCredits(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyDouble(), Mockito.anyLong(), Mockito.anyBoolean()); } diff --git a/plugins/database/quota/test/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java b/plugins/database/quota/test/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java index c113e55164..4a76052f69 100644 --- a/plugins/database/quota/test/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java +++ b/plugins/database/quota/test/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java @@ -150,7 +150,7 @@ public void testAddQuotaCredits() { account.setState(Account.State.locked); Mockito.when(accountDao.findById(Mockito.anyLong())).thenReturn(account); - QuotaCreditsResponse resp = quotaResponseBuilder.addQuotaCredits(accountId, domainId, amount, updatedBy); + QuotaCreditsResponse resp = quotaResponseBuilder.addQuotaCredits(accountId, domainId, amount, updatedBy, true); assertTrue(resp.getCredits().compareTo(credit.getCredit()) == 0); } From 14c837ab8329f98b3fe071dd69807dcae77f4f7c Mon Sep 17 00:00:00 2001 From: Remi Bergsma Date: Sat, 30 Jan 2016 16:50:46 +0100 Subject: [PATCH 045/203] CLOUDSTACK-8300: Set indexes on event table --- setup/db/db/schema-481to490.sql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup/db/db/schema-481to490.sql b/setup/db/db/schema-481to490.sql index c80fa2aa0d..0f27e45582 100644 --- a/setup/db/db/schema-481to490.sql +++ b/setup/db/db/schema-481to490.sql @@ -18,3 +18,6 @@ --; -- Schema upgrade from 4.8.1 to 4.9.0; --; + +ALTER TABLE `event` ADD INDEX `archived` (`archived`); +ALTER TABLE `event` ADD INDEX `state` (`state`); From 0bc1b2727ae80f60518d091410f7538a67161233 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Fri, 22 Jan 2016 16:39:47 -0200 Subject: [PATCH 046/203] CLOUDSTACK-9252: Add nfs version to commands --- .../cloud/agent/api/GetStorageStatsCommand.java | 14 ++++++++++++++ .../cloud/agent/api/SecStorageSetupCommand.java | 9 +++++++++ .../agent/api/storage/ListTemplateCommand.java | 10 ++++++++++ .../storage/image/TemplateServiceImpl.java | 16 +++++++++++++++- .../SecondaryStorageManagerImpl.java | 16 ++++++++++++++++ 5 files changed, 64 insertions(+), 1 deletion(-) diff --git a/core/src/com/cloud/agent/api/GetStorageStatsCommand.java b/core/src/com/cloud/agent/api/GetStorageStatsCommand.java index 23e8f9e3e5..84b5426451 100644 --- a/core/src/com/cloud/agent/api/GetStorageStatsCommand.java +++ b/core/src/com/cloud/agent/api/GetStorageStatsCommand.java @@ -30,6 +30,7 @@ public class GetStorageStatsCommand extends Command { private StoragePoolType pooltype; private String secUrl; private DataStoreTO store; + private String nfsVersion; public String getSecUrl() { return secUrl; @@ -54,6 +55,11 @@ public GetStorageStatsCommand(DataStoreTO store) { this.store = store; } + public GetStorageStatsCommand(DataStoreTO store, String nfsVersion) { + this.store = store; + this.nfsVersion = nfsVersion; + } + public GetStorageStatsCommand(String secUrl) { this.secUrl = secUrl; } @@ -81,6 +87,14 @@ public DataStoreTO getStore() { return this.store; } + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } + @Override public boolean executeInSequence() { return false; diff --git a/core/src/com/cloud/agent/api/SecStorageSetupCommand.java b/core/src/com/cloud/agent/api/SecStorageSetupCommand.java index 28e55c2f4e..316e4698dc 100644 --- a/core/src/com/cloud/agent/api/SecStorageSetupCommand.java +++ b/core/src/com/cloud/agent/api/SecStorageSetupCommand.java @@ -28,6 +28,7 @@ public class SecStorageSetupCommand extends Command { private String secUrl; private KeystoreManager.Certificates certs; private String postUploadKey; + private String nfsVersion; public SecStorageSetupCommand() { @@ -74,4 +75,12 @@ public String getPostUploadKey() { public void setPostUploadKey(String postUploadKey) { this.postUploadKey = postUploadKey; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java b/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java index 855095280d..bacc83aea5 100644 --- a/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java +++ b/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java @@ -23,6 +23,7 @@ public class ListTemplateCommand extends StorageCommand { private DataStoreTO store; + private String nfsVersion; //private String secUrl; @@ -34,6 +35,11 @@ public ListTemplateCommand(DataStoreTO store) { // this.secUrl = url; } + public ListTemplateCommand(DataStoreTO store, String nfsVersion) { + this.store = store; + this.nfsVersion = nfsVersion; + } + @Override public boolean executeInSequence() { return true; @@ -43,6 +49,10 @@ public DataStoreTO getDataStore() { return store; } + public String getNfsVersion() { + return nfsVersion; + } + // public String getSecUrl() { // return secUrl; // } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index 9ab3595371..cbfcb42668 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -56,6 +56,7 @@ import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.datastore.DataObjectManager; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; @@ -135,6 +136,8 @@ public class TemplateServiceImpl implements TemplateService { ConfigurationDao _configDao; @Inject StorageCacheManager _cacheMgr; + @Inject + ImageStoreDetailsDao _imageStoreDetailsDao; class TemplateOpContext extends AsyncRpcContext { final TemplateObject template; @@ -564,7 +567,7 @@ public void associateCrosszoneTemplatesToZone(long dcId) { } private Map listTemplate(DataStore ssStore) { - ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO()); + ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO(), getNfsVersion(ssStore.getId())); EndPoint ep = _epSelector.select(ssStore); Answer answer = null; if (ep == null) { @@ -586,6 +589,17 @@ private Map listTemplate(DataStore ssStore) { return null; } + private String getNfsVersion(long storeId) { + String nfsVersion = null; + if (_imageStoreDetailsDao.getDetails(storeId) != null){ + Map storeDetails = _imageStoreDetailsDao.getDetails(storeId); + if (storeDetails != null && storeDetails.containsKey("nfs.version")){ + nfsVersion = storeDetails.get("nfs.version"); + } + } + return nfsVersion; + } + protected Void createTemplateCallback(AsyncCallbackDispatcher callback, TemplateOpContext context) { TemplateObject template = context.getTemplate(); AsyncCompletionCallback parentCallback = context.getParentCallback(); diff --git a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java index 4891b71967..1ae5d5b304 100644 --- a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java @@ -39,6 +39,7 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.security.keystore.KeystoreManager; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; @@ -236,6 +237,8 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar @Inject ImageStoreDao _imageStoreDao; @Inject + ImageStoreDetailsDao _imageStoreDetailsDao; + @Inject TemplateDataStoreDao _tmplStoreDao; @Inject VolumeDataStoreDao _volumeStoreDao; @@ -310,6 +313,8 @@ public boolean generateSetupCommand(Long ssHostId) { setupCmd = new SecStorageSetupCommand(ssStore.getTO(), secUrl, certs); } + setupCmd.setNfsVersion(getNfsVersion(ssStore.getId())); + //template/volume file upload key String postUploadKey = _configDao.getValue(Config.SSVMPSK.key()); setupCmd.setPostUploadKey(postUploadKey); @@ -358,6 +363,17 @@ else if( cssHost.getType() == Host.Type.SecondaryStorage ) { return true; } + private String getNfsVersion(long storeId) { + String nfsVersion = null; + if (_imageStoreDetailsDao.getDetails(storeId) != null){ + Map storeDetails = _imageStoreDetailsDao.getDetails(storeId); + if (storeDetails != null && storeDetails.containsKey("nfs.version")){ + nfsVersion = storeDetails.get("nfs.version"); + } + } + return nfsVersion; + } + @Override public boolean generateVMSetupCommand(Long ssAHostId) { HostVO ssAHost = _hostDao.findById(ssAHostId); From e524f6557033f92da7cf9c099662630580b6a9e5 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Fri, 22 Jan 2016 16:41:23 -0200 Subject: [PATCH 047/203] CLOUDSTACK-9252: Support configurable nfs version --- .../cloud/resource/AgentStorageResource.java | 2 +- .../vmware/manager/VmwareManager.java | 4 +- .../vmware/manager/VmwareManagerImpl.java | 34 ++++++-- .../manager/VmwareStorageManagerImpl.java | 16 ++-- .../vmware/manager/VmwareStorageMount.java | 2 +- .../vmware/resource/VmwareResource.java | 18 +++-- ...VmwareSecondaryStorageResourceHandler.java | 4 +- .../resource/VmwareStorageProcessor.java | 14 ++-- .../VmwareStorageSubsystemCommandHandler.java | 6 +- .../vmware/VmwareDatacenterApiUnitTest.java | 6 ++ .../src/com/cloud/server/StatsCollector.java | 16 +++- .../LocalNfsSecondaryStorageResource.java | 8 +- .../LocalSecondaryStorageResource.java | 2 +- .../resource/NfsSecondaryStorageResource.java | 79 ++++++++++++------- .../resource/SecondaryStorageResource.java | 2 +- .../storage/template/DownloadManagerImpl.java | 2 +- .../NfsSecondaryStorageResourceTest.java | 2 +- 17 files changed, 144 insertions(+), 73 deletions(-) diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java index 751da9e3d2..9b1f091db7 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java @@ -109,7 +109,7 @@ public boolean configure(String name, Map params) throws Configu } @Override - public String getRootDir(String url) { + public String getRootDir(String url, String nfsVersion) { // TODO Auto-generated method stub return null; } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java index 72ee2184e3..65590500a0 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java @@ -36,7 +36,7 @@ public interface VmwareManager { String getSystemVMDefaultNicAdapterType(); - void prepareSecondaryStorageStore(String strStorageUrl); + void prepareSecondaryStorageStore(String strStorageUrl, Long storeId); void setupResourceStartupParams(Map params); @@ -48,7 +48,7 @@ public interface VmwareManager { String getManagementPortGroupName(); - String getSecondaryStorageStoreUrl(long dcId); + Pair getSecondaryStorageStoreUrlAndId(long dcId); File getSystemVMKeyFile(); 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 575801fa60..602a544485 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -46,6 +46,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.utils.identity.ManagementServerNode; import com.cloud.agent.AgentManager; @@ -167,6 +168,8 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw private ManagementServerHostPeerDao _mshostPeerDao; @Inject private ClusterManager _clusterMgr; + @Inject + private ImageStoreDetailsDao _imageDetailsStoreDao; private String _mountParent; private StorageLayer _storage; @@ -439,12 +442,14 @@ public List addHostToPodCluster(VmwareContext serviceCon } @Override - public String getSecondaryStorageStoreUrl(long dcId) { + public Pair getSecondaryStorageStoreUrlAndId(long dcId) { String secUrl = null; + Long secId = null; DataStore secStore = _dataStoreMgr.getImageStore(dcId); if (secStore != null) { secUrl = secStore.getUri(); + secId = secStore.getId(); } if (secUrl == null) { @@ -453,12 +458,13 @@ public String getSecondaryStorageStoreUrl(long dcId) { DataStore cacheStore = _dataStoreMgr.getImageCacheStore(dcId); if (cacheStore != null) { secUrl = cacheStore.getUri(); + secId = cacheStore.getId(); } else { s_logger.warn("No staging storage is found when non-NFS secondary storage is used"); } } - return secUrl; + return new Pair(secUrl, secId); } @Override @@ -546,8 +552,17 @@ public boolean needRecycle(String workerTag) { } @Override - public void prepareSecondaryStorageStore(String storageUrl) { - String mountPoint = getMountPoint(storageUrl); + public void prepareSecondaryStorageStore(String storageUrl, Long storeId) { + String nfsVersion = null; + if (storeId != null){ + Map details = _imageDetailsStoreDao.getDetails(storeId); + for (String detailKey : details.keySet()) { + if (detailKey.equals("nfs.version")){ + nfsVersion = details.get(detailKey); + } + } + } + String mountPoint = getMountPoint(storageUrl, nfsVersion); GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm"); try { @@ -655,7 +670,7 @@ public void run() { } @Override - public String getMountPoint(String storageUrl) { + public String getMountPoint(String storageUrl, String nfsVersion) { String mountPoint = null; synchronized (_storageMounts) { mountPoint = _storageMounts.get(storageUrl); @@ -670,7 +685,8 @@ public String getMountPoint(String storageUrl) { s_logger.error("Invalid storage URL format ", e); throw new CloudRuntimeException("Unable to create mount point due to invalid storage URL format " + storageUrl); } - mountPoint = mount(uri.getHost() + ":" + uri.getPath(), _mountParent); + + mountPoint = mount(uri.getHost() + ":" + uri.getPath(), _mountParent, nfsVersion); if (mountPoint == null) { s_logger.error("Unable to create mount point for " + storageUrl); return "/mnt/sec"; // throw new CloudRuntimeException("Unable to create mount point for " + storageUrl); @@ -745,7 +761,7 @@ private void shutdownCleanup() { } } - protected String mount(String path, String parent) { + protected String mount(String path, String parent, String nfsVersion) { String mountPoint = setupMountPoint(parent); if (mountPoint == null) { s_logger.warn("Unable to create a mount point"); @@ -756,6 +772,9 @@ protected String mount(String path, String parent) { String result = null; Script command = new Script(true, "mount", _timeout, s_logger); command.add("-t", "nfs"); + if (nfsVersion != null){ + command.add("-o", "vers=" + nfsVersion); + } // command.add("-o", "soft,timeo=133,retrans=2147483647,tcp,acdirmax=0,acdirmin=0"); if ("Mac OS X".equalsIgnoreCase(System.getProperty("os.name"))) { command.add("-o", "resvport"); @@ -1234,4 +1253,5 @@ public boolean hasNexusVSM(Long clusterId) { return true; } } + } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index 4109ff2345..f87fe6c4a8 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -156,7 +156,7 @@ public String createOvaForTemplate(TemplateObjectTO template) { String secStorageUrl = nfsStore.getUrl(); assert (secStorageUrl != null); String installPath = template.getPath(); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); String installFullPath = secondaryMountPoint + "/" + installPath; try { if (installFullPath.endsWith(".ova")) { @@ -194,7 +194,7 @@ public String createOvaForVolume(VolumeObjectTO volume) { String installPath = volume.getPath(); int index = installPath.lastIndexOf(File.separator); String volumeUuid = installPath.substring(index + 1); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); //The real volume path String volumePath = installPath + File.separator + volumeUuid + ".ova"; String installFullPath = secondaryMountPoint + "/" + installPath; @@ -547,7 +547,7 @@ private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: " + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage + ", templateName: " + templateName); - String secondaryMountPoint = _mountService.getMountPoint(secondaryStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secondaryStorageUrl, null); s_logger.info("Secondary storage mount point: " + secondaryMountPoint); String srcOVAFileName = secondaryMountPoint + "/" + templatePathAtSecondaryStorage + templateName + "." + ImageFormat.OVA.getFileExtension(); @@ -600,7 +600,7 @@ private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, private Ternary createTemplateFromVolume(VirtualMachineMO vmMo, long accountId, long templateId, String templateUniqueName, String secStorageUrl, String volumePath, String workerVmName) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId); String installFullPath = secondaryMountPoint + "/" + installPath; synchronized (installPath.intern()) { @@ -665,7 +665,7 @@ private Ternary createTemplateFromVolume(VirtualMachineMO vm private Ternary createTemplateFromSnapshot(long accountId, long templateId, String templateUniqueName, String secStorageUrl, long volumeId, String backedUpSnapshotUuid) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId); String installFullPath = secondaryMountPoint + "/" + installPath; String installFullOVAName = installFullPath + "/" + templateUniqueName + ".ova"; //Note: volss for tmpl @@ -856,7 +856,7 @@ private String createVolumeFromSnapshot(VmwareHypervisorHost hyperHost, Datastor private void restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, String secStorageUrl, String secStorageDir, String backupName) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); String srcOVAFileName = secondaryMountPoint + "/" + secStorageDir + "/" + backupName + "." + ImageFormat.OVA.getFileExtension(); String snapshotDir = ""; if (backupName.contains("/")) { @@ -924,7 +924,7 @@ private String backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, long acco private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath, String secStorageUrl, String secStorageDir, String exportName, String workerVmName) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); String exportPath = secondaryMountPoint + "/" + secStorageDir + "/" + exportName; synchronized (exportPath.intern()) { @@ -1446,7 +1446,7 @@ public RevertToVMSnapshotAnswer execute(VmwareHostService hostService, RevertToV } private String deleteVolumeDirOnSecondaryStorage(long volumeId, String secStorageUrl) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); String volumeMountRoot = secondaryMountPoint + "/" + getVolumeRelativeDirInSecStroage(volumeId); return deleteDir(volumeMountRoot); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java index dd07029766..54b52f6dff 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java @@ -17,5 +17,5 @@ package com.cloud.hypervisor.vmware.manager; public interface VmwareStorageMount { - String getMountPoint(String storageUrl); + String getMountPoint(String storageUrl, String nfsVersion); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index fdbc244997..56f929824c 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1636,12 +1636,14 @@ protected StartAnswer execute(StartCommand cmd) { // prepare systemvm patch ISO if (vmSpec.getType() != VirtualMachine.Type.User) { // attach ISO (for patching of system VM) - String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId)); + Pair secStoreUrlAndId = mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId)); + String secStoreUrl = secStoreUrlAndId.first(); + Long secStoreId = secStoreUrlAndId.second(); if (secStoreUrl == null) { String msg = "secondary storage for dc " + _dcId + " is not ready yet?"; throw new Exception(msg); } - mgr.prepareSecondaryStorageStore(secStoreUrl); + mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId); ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnHost(secStoreUrl); if (morSecDs == null) { @@ -3134,12 +3136,14 @@ protected Answer execute(PrepareForMigrationCommand cmd) { prepareNetworkFromNicInfo(new HostMO(getServiceContext(), _morHyperHost), nic, false, cmd.getVirtualMachine().getType()); } - String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId)); + Pair secStoreUrlAndId = mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId)); + String secStoreUrl = secStoreUrlAndId.first(); + Long secStoreId = secStoreUrlAndId.second(); if (secStoreUrl == null) { String msg = "secondary storage for dc " + _dcId + " is not ready yet?"; throw new Exception(msg); } - mgr.prepareSecondaryStorageStore(secStoreUrl); + mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId); ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnHost(secStoreUrl); if (morSecDs == null) { @@ -3350,12 +3354,14 @@ protected Answer execute(MigrateWithStorageCommand cmd) { } // Ensure secondary storage mounted on target host - String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId)); + Pair secStoreUrlAndId = mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId)); + String secStoreUrl = secStoreUrlAndId.first(); + Long secStoreId = secStoreUrlAndId.second(); if (secStoreUrl == null) { String msg = "secondary storage for dc " + _dcId + " is not ready yet?"; throw new Exception(msg); } - mgr.prepareSecondaryStorageStore(secStoreUrl); + mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId); ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnSpecificHost(secStoreUrl, tgtHyperHost); if (morSecDs == null) { String msg = "Failed to prepare secondary storage on host, secondary store url: " + secStoreUrl; diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java index 8a277991aa..c3f65cbc47 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java @@ -304,7 +304,7 @@ public String getWorkerName(VmwareContext context, Command cmd, int workerSequen } @Override - public String getMountPoint(String storageUrl) { - return _resource.getRootDir(storageUrl); + public String getMountPoint(String storageUrl, String nfsVersion) { + return _resource.getRootDir(storageUrl, nfsVersion); } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index fa2f369afa..35e775fbc7 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -160,7 +160,7 @@ private VirtualMachineMO copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: " + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage + ", templateName: " + templateName); - String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl, null); s_logger.info("Secondary storage mount point: " + secondaryMountPoint); String srcOVAFileName = @@ -539,7 +539,7 @@ private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyper } private String deleteVolumeDirOnSecondaryStorage(String volumeDir, String secStorageUrl) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, null); String volumeMountRoot = secondaryMountPoint + File.separator + volumeDir; return deleteDir(volumeMountRoot); @@ -722,7 +722,7 @@ private void postCreatePrivateTemplate(String installFullPath, long templateId, private Ternary createTemplateFromVolume(VirtualMachineMO vmMo, String installPath, long templateId, String templateUniqueName, String secStorageUrl, String volumePath, String workerVmName) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, null); String installFullPath = secondaryMountPoint + "/" + installPath; synchronized (installPath.intern()) { Script command = new Script(false, "mkdir", _timeout, s_logger); @@ -899,7 +899,7 @@ private Ternary createTemplateFromSnapshot(String installPat snapshotFolder = StringUtils.join(tokens, File.separator, 0, tokens.length - 1); } - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, null); String installFullPath = secondaryMountPoint + "/" + installPath; String installFullOVAName = installFullPath + "/" + templateUniqueName + ".ova"; //Note: volss for tmpl String snapshotRoot = secondaryMountPoint + "/" + snapshotFolder; @@ -1054,7 +1054,7 @@ public Answer createTemplateFromSnapshot(CopyCommand cmd) { private Pair exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath, String secStorageUrl, String secStorageDir, String exportName, String workerVmName) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, null); String exportPath = secondaryMountPoint + "/" + secStorageDir + "/" + exportName; synchronized (exportPath.intern()) { @@ -1186,7 +1186,7 @@ public Answer backupSnapshot(CopyCommand cmd) { // Get snapshot physical size long physicalSize = 0l; - String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl, null); String snapshotDir = destSnapshot.getPath() + "/" + snapshotBackupUuid; File[] files = new File(secondaryMountPoint + "/" + snapshotDir).listFiles(); if(files != null) { @@ -2146,7 +2146,7 @@ private List getManagedIqnsFromVirtualDisks(List virtualDis private Long restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, String secStorageUrl, String secStorageDir, String backupName, long wait) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, null); String srcOVAFileName = null; String srcOVFFileName = null; diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java index 431286248b..5beab056c5 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java @@ -82,7 +82,7 @@ protected Answer execute(CopyCommand cmd) { //need to take extra processing for vmware, such as packing to ova, before sending to S3 if (srcData.getObjectType() == DataObjectType.VOLUME) { NfsTO cacheStore = (NfsTO)srcDataStore; - String parentPath = storageResource.getRootDir(cacheStore.getUrl()); + String parentPath = storageResource.getRootDir(cacheStore.getUrl(), null); VolumeObjectTO vol = (VolumeObjectTO)srcData; String path = vol.getPath(); int index = path.lastIndexOf(File.separator); @@ -95,7 +95,7 @@ protected Answer execute(CopyCommand cmd) { } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT) { // pack ova first // sync snapshot from NFS cache to S3 in NFS migration to S3 case - String parentPath = storageResource.getRootDir(srcDataStore.getUrl()); + String parentPath = storageResource.getRootDir(srcDataStore.getUrl(), null); SnapshotObjectTO snap = (SnapshotObjectTO)srcData; String path = snap.getPath(); int index = path.lastIndexOf(File.separator); @@ -138,7 +138,7 @@ protected Answer execute(CopyCommand cmd) { return answer; } NfsTO cacheStore = (NfsTO)cmd.getCacheTO().getDataStore(); - String parentPath = storageResource.getRootDir(cacheStore.getUrl()); + String parentPath = storageResource.getRootDir(cacheStore.getUrl(), null); SnapshotObjectTO newSnapshot = (SnapshotObjectTO)answer.getNewData(); String path = newSnapshot.getPath(); int index = path.lastIndexOf(File.separator); diff --git a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java index 3b3dd47949..6b89e7bb9c 100644 --- a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java +++ b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java @@ -54,6 +54,7 @@ import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.test.utils.SpringUtils; import com.cloud.agent.AgentManager; @@ -431,6 +432,11 @@ public DataStoreManager dataStoreManager() { return Mockito.mock(DataStoreManager.class); } + @Bean + public ImageStoreDetailsDao imageStoreDetailsDao(){ + return Mockito.mock(ImageStoreDetailsDao.class); + } + public static class Library implements TypeFilter { @Override diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index ca86cfd080..c66ada8d3f 100644 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -44,6 +44,7 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.utils.graphite.GraphiteClient; @@ -198,6 +199,8 @@ public String toString() { private ServiceOfferingDao _serviceOfferingDao; @Inject private HostGpuGroupsDao _hostGpuGroupsDao; + @Inject + private ImageStoreDetailsDao _imageStoreDetailsDao; private ConcurrentHashMap _hostStats = new ConcurrentHashMap(); private final ConcurrentHashMap _VmStats = new ConcurrentHashMap(); @@ -715,7 +718,7 @@ protected void runInContext() { continue; } - GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO()); + GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO(), getNfsVersion(store.getId())); EndPoint ssAhost = _epSelector.select(store); if (ssAhost == null) { s_logger.debug("There is no secondary storage VM for secondary storage host " + store.getName()); @@ -762,6 +765,17 @@ protected void runInContext() { s_logger.error("Error trying to retrieve storage stats", t); } } + + private String getNfsVersion(long storeId) { + String nfsVersion = null; + if (_imageStoreDetailsDao.getDetails(storeId) != null){ + Map storeDetails = _imageStoreDetailsDao.getDetails(storeId); + if (storeDetails != null && storeDetails.containsKey("nfs.version")){ + nfsVersion = storeDetails.get("nfs.version"); + } + } + return nfsVersion; + } } class AutoScaleMonitor extends ManagedContextRunnable { diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java index 9393ee217a..6f189ef5f3 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java @@ -53,10 +53,10 @@ public Answer executeRequest(Command cmd) { } @Override - synchronized public String getRootDir(String secUrl) { + synchronized public String getRootDir(String secUrl, String nfsVersion) { try { URI uri = new URI(secUrl); - String dir = mountUri(uri); + String dir = mountUri(uri, nfsVersion); return _parent + "/" + dir; } catch (Exception e) { String msg = "GetRootDir for " + secUrl + " failed due to " + e.toString(); @@ -66,14 +66,14 @@ synchronized public String getRootDir(String secUrl) { } @Override - protected void mount(String localRootPath, String remoteDevice, URI uri) { + protected void mount(String localRootPath, String remoteDevice, URI uri, String nfsVersion) { ensureLocalRootPathExists(localRootPath, uri); if (mountExists(localRootPath, uri)) { return; } - attemptMount(localRootPath, remoteDevice, uri); + attemptMount(localRootPath, remoteDevice, uri, nfsVersion); // Change permissions for the mountpoint - seems to bypass authentication Script script = new Script(true, "chmod", _timeout, s_logger); diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java index bdfe7e837f..d953338c91 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java @@ -72,7 +72,7 @@ public void disconnected() { } @Override - public String getRootDir(String url) { + public String getRootDir(String url, String nfsVersion) { return getRootDir(); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index 768a177cdc..b71c96f113 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -44,6 +44,7 @@ import java.util.Map; import java.util.UUID; +import javax.inject.Inject; import javax.naming.ConfigurationException; import com.cloud.exception.InvalidParameterValueException; @@ -91,6 +92,9 @@ import org.apache.cloudstack.storage.command.DownloadProgressCommand; import org.apache.cloudstack.storage.command.UploadStatusAnswer; import org.apache.cloudstack.storage.command.UploadStatusAnswer.UploadStatus; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.command.UploadStatusCommand; import org.apache.cloudstack.storage.template.DownloadManager; import org.apache.cloudstack.storage.template.DownloadManagerImpl; @@ -212,6 +216,14 @@ public void setTimeout(int timeout) { private HashMap uploadEntityStateMap = new HashMap(); private String _ssvmPSK = null; + @Inject + ImageStoreDao dataStoreDao; + + @Inject + ImageStoreDetailsDao detailsStoreDao; + + public static final String IMAGE_STORE_PARAMETER_ID = "imageStoreId"; + public void setParentPath(String path) { _parent = path; } @@ -412,7 +424,7 @@ protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataT protected Answer copySnapshotToTemplateFromNfsToNfsXenserver(CopyCommand cmd, SnapshotObjectTO srcData, NfsTO srcDataStore, TemplateObjectTO destData, NfsTO destDataStore) { - String srcMountPoint = getRootDir(srcDataStore.getUrl()); + String srcMountPoint = getRootDir(srcDataStore.getUrl(), null); String snapshotPath = srcData.getPath(); int index = snapshotPath.lastIndexOf("/"); String snapshotName = snapshotPath.substring(index + 1); @@ -422,7 +434,7 @@ protected Answer copySnapshotToTemplateFromNfsToNfsXenserver(CopyCommand cmd, Sn snapshotPath = snapshotPath.substring(0, index); snapshotPath = srcMountPoint + File.separator + snapshotPath; - String destMountPoint = getRootDir(destDataStore.getUrl()); + String destMountPoint = getRootDir(destDataStore.getUrl(), null); String destPath = destMountPoint + File.separator + destData.getPath(); String errMsg = null; @@ -566,7 +578,7 @@ protected Answer copySnapshotToTemplateFromNfsToNfs(CopyCommand cmd, SnapshotObj } protected File getFile(String path, String nfsPath) { - String filePath = getRootDir(nfsPath) + File.separator + path; + String filePath = getRootDir(nfsPath, null) + File.separator + path; File f = new File(filePath); if (!f.exists()) { _storage.mkdirs(filePath); @@ -706,7 +718,7 @@ protected Long determineS3VolumeIdFromKey(String key) { } private String determineStorageTemplatePath(final String storagePath, String dataPath) { - return join(asList(getRootDir(storagePath), dataPath), File.separator); + return join(asList(getRootDir(storagePath, null), dataPath), File.separator); } protected File downloadFromUrlToNfs(String url, NfsTO nfs, String path, String name) { @@ -720,7 +732,7 @@ protected File downloadFromUrlToNfs(String url, NfsTO nfs, String path, String n throw new CloudRuntimeException("Failed to get url: " + url); } - String nfsMountPath = getRootDir(nfs.getUrl()); + String nfsMountPath = getRootDir(nfs.getUrl(), null); String filePath = nfsMountPath + File.separator + path; File directory = new File(filePath); @@ -1098,7 +1110,7 @@ public Answer execute(DeleteSnapshotsDirCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeSnapshotPath = cmd.getDirectory(); - String parent = getRootDir(nfs.getUrl()); + String parent = getRootDir(nfs.getUrl(), null); if (relativeSnapshotPath.startsWith(File.separator)) { relativeSnapshotPath = relativeSnapshotPath.substring(1); @@ -1176,7 +1188,7 @@ private Answer execute(ComputeChecksumCommand cmd) { return new Answer(cmd, false, "can't handle non nfs data store"); } NfsTO nfsStore = (NfsTO)store; - String parent = getRootDir(nfsStore.getUrl()); + String parent = getRootDir(nfsStore.getUrl(), null); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); @@ -1297,6 +1309,16 @@ private void configCerts(KeystoreManager.Certificates certs) { } } + private Long getImageStoreId(DataStoreTO dataStore){ + Long imgStoreId = null; + if (dataStore.getRole().equals(DataStoreRole.Image)){ + String uuid = dataStore.getUuid(); + ImageStoreVO imageStoreVO = dataStoreDao.findByUuid(uuid); + imgStoreId = imageStoreVO.getId(); + } + return imgStoreId; + } + private Answer execute(SecStorageSetupCommand cmd) { if (!_inSystemVM) { return new Answer(cmd, true, null); @@ -1310,7 +1332,8 @@ private Answer execute(SecStorageSetupCommand cmd) { String nfsHostIp = getUriHostIp(uri); addRouteToInternalIpOrCidr(_storageGateway, _storageIp, _storageNetmask, nfsHostIp); - String dir = mountUri(uri); + + String dir = mountUri(uri, cmd.getNfsVersion()); configCerts(cmd.getCerts()); @@ -1386,7 +1409,7 @@ protected Answer deleteSnapshot(final DeleteCommand cmd) { DataStoreTO dstore = obj.getDataStore(); if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; - String parent = getRootDir(nfs.getUrl()); + String parent = getRootDir(nfs.getUrl(), null); if (!parent.endsWith(File.separator)) { parent += File.separator; } @@ -1557,7 +1580,7 @@ private Answer execute(ListTemplateCommand cmd) { if (store instanceof NfsTO) { NfsTO nfs = (NfsTO)store; String secUrl = nfs.getUrl(); - String root = getRootDir(secUrl); + String root = getRootDir(secUrl, cmd.getNfsVersion()); Map templateInfos = _dlMgr.gatherTemplateInfo(root); return new ListTemplateAnswer(secUrl, templateInfos); } else if (store instanceof SwiftTO) { @@ -1579,7 +1602,7 @@ private Answer execute(ListVolumeCommand cmd) { } DataStoreTO store = cmd.getDataStore(); if (store instanceof NfsTO) { - String root = getRootDir(cmd.getSecUrl()); + String root = getRootDir(cmd.getSecUrl(), null); Map templateInfos = _dlMgr.gatherVolumeInfo(root); return new ListVolumeAnswer(cmd.getSecUrl(), templateInfos); } else if (store instanceof S3TO) { @@ -1714,7 +1737,7 @@ protected GetStorageStatsAnswer execute(final GetStorageStatsCommand cmd) { return new GetStorageStatsAnswer(cmd, infinity, 0L); } - String rootDir = getRootDir(((NfsTO)store).getUrl()); + String rootDir = getRootDir(((NfsTO)store).getUrl(), cmd.getNfsVersion()); final long usedSize = getUsedSize(rootDir); final long totalSize = getTotalSize(rootDir); if (usedSize == -1 || totalSize == -1) { @@ -1748,7 +1771,7 @@ protected Answer deleteTemplate(DeleteCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeTemplatePath = obj.getPath(); - String parent = getRootDir(nfs.getUrl()); + String parent = getRootDir(nfs.getUrl(), null); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); @@ -1852,7 +1875,7 @@ protected Answer deleteVolume(final DeleteCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeVolumePath = obj.getPath(); - String parent = getRootDir(nfs.getUrl()); + String parent = getRootDir(nfs.getUrl(), null); if (relativeVolumePath.startsWith(File.separator)) { relativeVolumePath = relativeVolumePath.substring(1); @@ -1954,13 +1977,13 @@ protected Answer deleteVolume(final DeleteCommand cmd) { } @Override - synchronized public String getRootDir(String secUrl) { + synchronized public String getRootDir(String secUrl, String nfsVersion) { if (!_inSystemVM) { return _parent; } try { URI uri = new URI(secUrl); - String dir = mountUri(uri); + String dir = mountUri(uri, nfsVersion); return _parent + "/" + dir; } catch (Exception e) { String msg = "GetRootDir for " + secUrl + " failed due to " + e.toString(); @@ -2291,10 +2314,11 @@ private String configureIpFirewall(List ipList, boolean isAppend) { * @param uri * crresponding to the remote device. Will throw for unsupported * scheme. + * @param imgStoreId * @return name of folder in _parent that device was mounted. * @throws UnknownHostException */ - protected String mountUri(URI uri) throws UnknownHostException { + protected String mountUri(URI uri, String nfsVersion) throws UnknownHostException { String uriHostIp = getUriHostIp(uri); String nfsPath = uriHostIp + ":" + uri.getPath(); @@ -2312,7 +2336,7 @@ protected String mountUri(URI uri) throws UnknownHostException { s_logger.debug("Mounting device with nfs-style path of " + remoteDevice); } - mount(localRootPath, remoteDevice, uri); + mount(localRootPath, remoteDevice, uri, nfsVersion); return dir; } @@ -2340,15 +2364,15 @@ protected void umount(String localRootPath, URI uri) { s_logger.debug("Successfully umounted " + localRootPath); } - protected void mount(String localRootPath, String remoteDevice, URI uri) { - s_logger.debug("mount " + uri.toString() + " on " + localRootPath); + protected void mount(String localRootPath, String remoteDevice, URI uri, String nfsVersion) { + s_logger.debug("mount " + uri.toString() + " on " + localRootPath + ((nfsVersion != null) ? " nfsVersion="+nfsVersion : "")); ensureLocalRootPathExists(localRootPath, uri); if (mountExists(localRootPath, uri)) { return; } - attemptMount(localRootPath, remoteDevice, uri); + attemptMount(localRootPath, remoteDevice, uri, nfsVersion); // XXX: Adding the check for creation of snapshots dir here. Might have // to move it somewhere more logical later. @@ -2356,9 +2380,10 @@ protected void mount(String localRootPath, String remoteDevice, URI uri) { checkForVolumesDir(localRootPath); } - protected void attemptMount(String localRootPath, String remoteDevice, URI uri) { + protected void attemptMount(String localRootPath, String remoteDevice, URI uri, String nfsVersion) { String result; - s_logger.debug("Make cmdline call to mount " + remoteDevice + " at " + localRootPath + " based on uri " + uri); + s_logger.debug("Make cmdline call to mount " + remoteDevice + " at " + localRootPath + " based on uri " + uri + + ((nfsVersion != null) ? " nfsVersion=" + nfsVersion : "")); Script command = new Script(!_inSystemVM, "mount", _timeout, s_logger); String scheme = uri.getScheme().toLowerCase(); @@ -2370,7 +2395,7 @@ protected void attemptMount(String localRootPath, String remoteDevice, URI uri) command.add("-o", "resvport"); } if (_inSystemVM) { - command.add("-o", "soft,timeo=133,retrans=2147483647,tcp,acdirmax=0,acdirmin=0"); + command.add("-o", "soft,timeo=133,retrans=2147483647,tcp,acdirmax=0,acdirmin=0" + ((nfsVersion != null) ? ",vers=" + nfsVersion : "")); } } else if (scheme.equals("cifs")) { String extraOpts = parseCifsMountOptions(uri); @@ -2647,7 +2672,7 @@ public UploadEntity createUploadEntity(String uuid, String metadata, long conten //relative path with out ssvm mount info. uploadEntity.setTemplatePath(absolutePath); String dataStoreUrl = cmd.getDataTo(); - String installPathPrefix = this.getRootDir(dataStoreUrl) + File.separator + absolutePath; + String installPathPrefix = this.getRootDir(dataStoreUrl, null) + File.separator + absolutePath; uploadEntity.setInstallPathPrefix(installPathPrefix); uploadEntity.setHvm(cmd.getRequiresHvm()); uploadEntity.setChksum(cmd.getChecksum()); @@ -2669,7 +2694,7 @@ public UploadEntity createUploadEntity(String uuid, String metadata, long conten } private synchronized void checkSecondaryStorageResourceLimit(TemplateOrVolumePostUploadCommand cmd, int contentLengthInGB) { - String rootDir = this.getRootDir(cmd.getDataTo()) + File.separator; + String rootDir = this.getRootDir(cmd.getDataTo(), null) + File.separator; long accountId = cmd.getAccountId(); long accountTemplateDirSize = 0; @@ -2716,7 +2741,7 @@ private String getSnapshotPathForAccount(long accountId) { private boolean isOneTimePostUrlUsed(TemplateOrVolumePostUploadCommand cmd) { String uuid = cmd.getEntityUUID(); - String uploadPath = this.getRootDir(cmd.getDataTo()) + File.separator + cmd.getAbsolutePath(); + String uploadPath = this.getRootDir(cmd.getDataTo(), null) + File.separator + cmd.getAbsolutePath(); return uploadEntityStateMap.containsKey(uuid) || new File(uploadPath).exists(); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java index 4d3f04819e..3c24b6c6de 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java @@ -23,6 +23,6 @@ */ public interface SecondaryStorageResource extends ServerResource { - String getRootDir(String cmd); + String getRootDir(String cmd, String nfsVersion); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java index 9cf37e5659..7829bf6625 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java @@ -708,7 +708,7 @@ public DownloadAnswer handleDownloadCommand(SecondaryStorageResource resource, D String installPathPrefix = cmd.getInstallPath(); // for NFS, we need to get mounted path if (dstore instanceof NfsTO) { - installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl()) + File.separator + installPathPrefix; + installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl(), null) + File.separator + installPathPrefix; } String user = null; String password = null; diff --git a/services/secondary-storage/server/test/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResourceTest.java b/services/secondary-storage/server/test/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResourceTest.java index 13ddb3531a..9da5c53a90 100644 --- a/services/secondary-storage/server/test/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResourceTest.java +++ b/services/secondary-storage/server/test/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResourceTest.java @@ -80,7 +80,7 @@ public void testMount() throws Exception { if (!sampleMount.isEmpty()) { s_logger.info("functional test, mount " + sampleMount); URI realMntUri = new URI(sampleMount); - String mntSubDir = resource.mountUri(realMntUri); + String mntSubDir = resource.mountUri(realMntUri, null); s_logger.info("functional test, umount " + mntSubDir); resource.umount(resource.getMountingRoot() + mntSubDir, realMntUri); } else { From 76dc2705b7873f52b35c07ae742190c3515f4245 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Thu, 28 Jan 2016 17:57:33 -0200 Subject: [PATCH 048/203] CLOUDSTACK-9252: Remove duplicates getNfsVersion, refactor --- .../agent/api/BackupSnapshotCommand.java | 9 +++ ...atePrivateTemplateFromSnapshotCommand.java | 9 +++ ...reatePrivateTemplateFromVolumeCommand.java | 9 +++ .../api/CreateVolumeFromSnapshotCommand.java | 10 +++ .../agent/api/storage/CopyVolumeCommand.java | 9 +++ .../PrimaryStorageDownloadCommand.java | 9 +++ .../TemplateOrVolumePostUploadCommand.java | 10 +++ .../storage/image/TemplateServiceImpl.java | 17 +---- .../MockLocalNfsSecondaryStorageResource.java | 2 +- .../vmware/manager/VmwareManagerImpl.java | 12 +--- .../manager/VmwareStorageManagerImpl.java | 65 ++++++++++--------- .../resource/VmwareStorageProcessor.java | 54 ++++++++------- .../VmwareStorageSubsystemCommandHandler.java | 9 +-- .../src/com/cloud/server/StatsCollector.java | 14 +--- .../cloud/storage/ImageStoreDetailsUtil.java | 59 +++++++++++++++++ .../SecondaryStorageManagerImpl.java | 18 +---- .../resource/NfsSecondaryStorageResource.java | 48 +++++++------- .../storage/template/DownloadManagerImpl.java | 3 +- 18 files changed, 231 insertions(+), 135 deletions(-) create mode 100755 server/src/com/cloud/storage/ImageStoreDetailsUtil.java diff --git a/core/src/com/cloud/agent/api/BackupSnapshotCommand.java b/core/src/com/cloud/agent/api/BackupSnapshotCommand.java index 2a46610117..d93c32f990 100644 --- a/core/src/com/cloud/agent/api/BackupSnapshotCommand.java +++ b/core/src/com/cloud/agent/api/BackupSnapshotCommand.java @@ -39,6 +39,7 @@ public class BackupSnapshotCommand extends SnapshotCommand { private S3TO s3; StorageFilerTO pool; private Long secHostId; + private String nfsVersion; protected BackupSnapshotCommand() { @@ -107,4 +108,12 @@ public Long getSnapshotId() { public Long getSecHostId() { return secHostId; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java index 7ac2ddedd2..5a09994ab7 100644 --- a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java +++ b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java @@ -28,6 +28,7 @@ public class CreatePrivateTemplateFromSnapshotCommand extends SnapshotCommand { private String origTemplateInstallPath; private Long newTemplateId; private String templateName; + private String nfsVersion; protected CreatePrivateTemplateFromSnapshotCommand() { @@ -72,4 +73,12 @@ public Long getNewTemplateId() { public String getTemplateName() { return templateName; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java index 3025147a30..b6cc6ac447 100644 --- a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java +++ b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java @@ -32,6 +32,7 @@ public class CreatePrivateTemplateFromVolumeCommand extends SnapshotCommand { StorageFilerTO _primaryPool; // For XenServer private String _secondaryStorageUrl; + private String nfsVersion; public CreatePrivateTemplateFromVolumeCommand() { } @@ -99,4 +100,12 @@ public Long getAccountId() { public void setTemplateId(long templateId) { _templateId = templateId; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java b/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java index fa9a4d5846..933be03606 100644 --- a/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java +++ b/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java @@ -26,6 +26,8 @@ */ public class CreateVolumeFromSnapshotCommand extends SnapshotCommand { + private String nfsVersion; + protected CreateVolumeFromSnapshotCommand() { } @@ -50,4 +52,12 @@ public CreateVolumeFromSnapshotCommand(StoragePool pool, String secondaryStorage super(pool, secondaryStoragePoolURL, backedUpSnapshotUuid, backedUpSnapshotName, dcId, accountId, volumeId); setWait(wait); } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java b/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java index 43c84ee2bc..7ab822c03b 100644 --- a/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java +++ b/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java @@ -32,6 +32,7 @@ public class CopyVolumeCommand extends Command { boolean toSecondaryStorage; String vmName; boolean executeInSequence = false; + String nfsVersion; public CopyVolumeCommand() { } @@ -75,4 +76,12 @@ public boolean toSecondaryStorage() { public String getVmName() { return vmName; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java b/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java index ce8ed217a5..9dae513b98 100644 --- a/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java +++ b/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java @@ -35,6 +35,7 @@ public class PrimaryStorageDownloadCommand extends AbstractDownloadCommand { String secondaryStorageUrl; String primaryStorageUrl; + String nfsVersion; protected PrimaryStorageDownloadCommand() { } @@ -87,4 +88,12 @@ public String getPrimaryStorageUrl() { public boolean executeInSequence() { return true; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java b/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java index 5d1e56bd77..bfcd9ae9b4 100644 --- a/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java +++ b/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java @@ -53,6 +53,8 @@ public class TemplateOrVolumePostUploadCommand { private long accountId; + private String nfsVersion; + public TemplateOrVolumePostUploadCommand(long entityId, String entityUUID, String absolutePath, String checksum, String type, String name, String imageFormat, String dataTo, String dataToRole) { this.entityId = entityId; @@ -196,4 +198,12 @@ public void setAccountId(long accountId) { public long getAccountId() { return accountId; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index cbfcb42668..2a6159e85f 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -56,7 +56,6 @@ import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.datastore.DataObjectManager; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; -import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; @@ -74,6 +73,7 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.StoragePool; @@ -136,8 +136,6 @@ public class TemplateServiceImpl implements TemplateService { ConfigurationDao _configDao; @Inject StorageCacheManager _cacheMgr; - @Inject - ImageStoreDetailsDao _imageStoreDetailsDao; class TemplateOpContext extends AsyncRpcContext { final TemplateObject template; @@ -567,7 +565,7 @@ public void associateCrosszoneTemplatesToZone(long dcId) { } private Map listTemplate(DataStore ssStore) { - ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO(), getNfsVersion(ssStore.getId())); + ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO(), ImageStoreDetailsUtil.getNfsVersion(ssStore.getId())); EndPoint ep = _epSelector.select(ssStore); Answer answer = null; if (ep == null) { @@ -589,17 +587,6 @@ private Map listTemplate(DataStore ssStore) { return null; } - private String getNfsVersion(long storeId) { - String nfsVersion = null; - if (_imageStoreDetailsDao.getDetails(storeId) != null){ - Map storeDetails = _imageStoreDetailsDao.getDetails(storeId); - if (storeDetails != null && storeDetails.containsKey("nfs.version")){ - nfsVersion = storeDetails.get("nfs.version"); - } - } - return nfsVersion; - } - protected Void createTemplateCallback(AsyncCallbackDispatcher callback, TemplateOpContext context) { TemplateObject template = context.getTemplate(); AsyncCompletionCallback parentCallback = context.getParentCallback(); diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java index 896342890c..5c41dcab0e 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java @@ -51,7 +51,7 @@ public MockLocalNfsSecondaryStorageResource() { } @Override - public String getRootDir(String secUrl) { + public String getRootDir(String secUrl, String nfsVersion) { return "/mnt"; } 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 602a544485..d51d96fe94 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -106,6 +106,7 @@ import com.cloud.org.Cluster.ClusterType; import com.cloud.secstorage.CommandExecLogDao; import com.cloud.server.ConfigurationServer; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.JavaStorageLayer; import com.cloud.storage.StorageLayer; import com.cloud.utils.FileUtil; @@ -553,16 +554,7 @@ public boolean needRecycle(String workerTag) { @Override public void prepareSecondaryStorageStore(String storageUrl, Long storeId) { - String nfsVersion = null; - if (storeId != null){ - Map details = _imageDetailsStoreDao.getDetails(storeId); - for (String detailKey : details.keySet()) { - if (detailKey.equals("nfs.version")){ - nfsVersion = details.get(detailKey); - } - } - } - String mountPoint = getMountPoint(storageUrl, nfsVersion); + String mountPoint = getMountPoint(storageUrl, ImageStoreDetailsUtil.getNfsVersion(storeId)); GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm"); try { diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index f87fe6c4a8..b41a14725c 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -77,6 +77,7 @@ import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.hypervisor.vmware.util.VmwareHelper; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.JavaStorageLayer; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; @@ -156,7 +157,7 @@ public String createOvaForTemplate(TemplateObjectTO template) { String secStorageUrl = nfsStore.getUrl(); assert (secStorageUrl != null); String installPath = template.getPath(); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, ImageStoreDetailsUtil.getNfsVersionByUuid(storeTO.getUuid())); String installFullPath = secondaryMountPoint + "/" + installPath; try { if (installFullPath.endsWith(".ova")) { @@ -194,7 +195,7 @@ public String createOvaForVolume(VolumeObjectTO volume) { String installPath = volume.getPath(); int index = installPath.lastIndexOf(File.separator); String volumeUuid = installPath.substring(index + 1); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, ImageStoreDetailsUtil.getNfsVersionByUuid(storeTO.getUuid())); //The real volume path String volumePath = installPath + File.separator + volumeUuid + ".ova"; String installFullPath = secondaryMountPoint + "/" + installPath; @@ -271,7 +272,8 @@ public Answer execute(VmwareHostService hostService, PrimaryStorageDownloadComma assert (morDs != null); DatastoreMO primaryStorageDatastoreMo = new DatastoreMO(context, morDs); - copyTemplateFromSecondaryToPrimary(hyperHost, primaryStorageDatastoreMo, secondaryStorageUrl, mountPoint, templateName, templateUuidName); + copyTemplateFromSecondaryToPrimary(hyperHost, primaryStorageDatastoreMo, secondaryStorageUrl, mountPoint, templateName, templateUuidName, + cmd.getNfsVersion()); } else { s_logger.info("Template " + templateName + " has already been setup, skip the template setup process in primary storage"); } @@ -345,7 +347,7 @@ public Answer execute(VmwareHostService hostService, BackupSnapshotCommand cmd) snapshotBackupUuid = backupSnapshotToSecondaryStorage(vmMo, accountId, volumeId, cmd.getVolumePath(), snapshotUuid, secondaryStorageUrl, prevSnapshotUuid, prevBackupUuid, - hostService.getWorkerName(context, cmd, 1)); + hostService.getWorkerName(context, cmd, 1), cmd.getNfsVersion()); success = (snapshotBackupUuid != null); if (success) { @@ -413,7 +415,7 @@ public Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromVo Ternary result = createTemplateFromVolume(vmMo, accountId, templateId, cmd.getUniqueName(), secondaryStoragePoolURL, volumePath, - hostService.getWorkerName(context, cmd, 0)); + hostService.getWorkerName(context, cmd, 0), cmd.getNfsVersion()); return new CreatePrivateTemplateAnswer(cmd, true, null, result.first(), result.third(), result.second(), cmd.getUniqueName(), ImageFormat.OVA); @@ -441,7 +443,8 @@ public Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromSn VmwareContext context = hostService.getServiceContext(cmd); try { - Ternary result = createTemplateFromSnapshot(accountId, newTemplateId, uniqeName, secondaryStorageUrl, volumeId, backedUpSnapshotUuid); + Ternary result = createTemplateFromSnapshot(accountId, newTemplateId, uniqeName, secondaryStorageUrl, volumeId, backedUpSnapshotUuid, + cmd.getNfsVersion()); return new CreatePrivateTemplateAnswer(cmd, true, null, result.first(), result.third(), result.second(), uniqeName, ImageFormat.OVA); } catch (Throwable e) { @@ -471,7 +474,7 @@ public Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd) { if (cmd.toSecondaryStorage()) { result = copyVolumeToSecStorage(hostService, hyperHost, cmd, vmName, volumeId, cmd.getPool().getUuid(), volumePath, secondaryStorageURL, - hostService.getWorkerName(context, cmd, 0)); + hostService.getWorkerName(context, cmd, 0), cmd.getNfsVersion()); } else { StorageFilerTO poolTO = cmd.getPool(); @@ -484,8 +487,9 @@ public Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd) { } } - result = copyVolumeFromSecStorage(hyperHost, volumeId, new DatastoreMO(context, morDatastore), secondaryStorageURL, volumePath); - deleteVolumeDirOnSecondaryStorage(volumeId, secondaryStorageURL); + result = copyVolumeFromSecStorage(hyperHost, volumeId, new DatastoreMO(context, morDatastore), secondaryStorageURL, volumePath, + cmd.getNfsVersion()); + deleteVolumeDirOnSecondaryStorage(volumeId, secondaryStorageURL, cmd.getNfsVersion()); } return new CopyVolumeAnswer(cmd, true, null, result.first(), result.second()); } catch (Throwable e) { @@ -523,7 +527,8 @@ public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCom } DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs); - details = createVolumeFromSnapshot(hyperHost, primaryDsMo, newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid); + details = createVolumeFromSnapshot(hyperHost, primaryDsMo, newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid, + cmd.getNfsVersion()); if (details == null) { success = true; } @@ -542,12 +547,12 @@ public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCom // templateName: name in secondary storage // templateUuid: will be used at hypervisor layer private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl, - String templatePathAtSecondaryStorage, String templateName, String templateUuid) throws Exception { + String templatePathAtSecondaryStorage, String templateName, String templateUuid, String nfsVersion) throws Exception { s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: " + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage + ", templateName: " + templateName); - String secondaryMountPoint = _mountService.getMountPoint(secondaryStorageUrl, null); + String secondaryMountPoint = _mountService.getMountPoint(secondaryStorageUrl, nfsVersion); s_logger.info("Secondary storage mount point: " + secondaryMountPoint); String srcOVAFileName = secondaryMountPoint + "/" + templatePathAtSecondaryStorage + templateName + "." + ImageFormat.OVA.getFileExtension(); @@ -598,9 +603,9 @@ private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, } private Ternary createTemplateFromVolume(VirtualMachineMO vmMo, long accountId, long templateId, String templateUniqueName, String secStorageUrl, - String volumePath, String workerVmName) throws Exception { + String volumePath, String workerVmName, String nfsVersion) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId); String installFullPath = secondaryMountPoint + "/" + installPath; synchronized (installPath.intern()) { @@ -663,9 +668,9 @@ private Ternary createTemplateFromVolume(VirtualMachineMO vm } private Ternary createTemplateFromSnapshot(long accountId, long templateId, String templateUniqueName, String secStorageUrl, long volumeId, - String backedUpSnapshotUuid) throws Exception { + String backedUpSnapshotUuid, String nfsVersion) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId); String installFullPath = secondaryMountPoint + "/" + installPath; String installFullOVAName = installFullPath + "/" + templateUniqueName + ".ova"; //Note: volss for tmpl @@ -847,16 +852,16 @@ private void writeMetaOvaForTemplate(String installFullPath, String ovfFilename, } private String createVolumeFromSnapshot(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, long accountId, long volumeId, - String secStorageUrl, String snapshotBackupUuid) throws Exception { + String secStorageUrl, String snapshotBackupUuid, String nfsVersion) throws Exception { - restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), snapshotBackupUuid); + restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), snapshotBackupUuid, nfsVersion); return null; } private void restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, String secStorageUrl, String secStorageDir, - String backupName) throws Exception { + String backupName, String nfsVersion) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String srcOVAFileName = secondaryMountPoint + "/" + secStorageDir + "/" + backupName + "." + ImageFormat.OVA.getFileExtension(); String snapshotDir = ""; if (backupName.contains("/")) { @@ -914,17 +919,17 @@ private void restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, Datasto } private String backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, long accountId, long volumeId, String volumePath, String snapshotUuid, String secStorageUrl, - String prevSnapshotUuid, String prevBackupUuid, String workerVmName) throws Exception { + String prevSnapshotUuid, String prevBackupUuid, String workerVmName, String nfsVersion) throws Exception { String backupUuid = UUID.randomUUID().toString(); - exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), backupUuid, workerVmName); + exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), backupUuid, workerVmName, nfsVersion); return backupUuid + "/" + backupUuid; } private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath, String secStorageUrl, String secStorageDir, String exportName, - String workerVmName) throws Exception { + String workerVmName, String nfsVersion) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String exportPath = secondaryMountPoint + "/" + secStorageDir + "/" + exportName; synchronized (exportPath.intern()) { @@ -967,7 +972,7 @@ private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volume } private Pair copyVolumeToSecStorage(VmwareHostService hostService, VmwareHypervisorHost hyperHost, CopyVolumeCommand cmd, String vmName, - long volumeId, String poolId, String volumePath, String secStorageUrl, String workerVmName) throws Exception { + long volumeId, String poolId, String volumePath, String secStorageUrl, String workerVmName, String nfsVersion) throws Exception { String volumeFolder = String.valueOf(volumeId) + "/"; VirtualMachineMO workerVm = null; @@ -1004,7 +1009,7 @@ private Pair copyVolumeToSecStorage(VmwareHostService hostServic vmMo.createSnapshot(exportName, "Temporary snapshot for copy-volume command", false, false); exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, "volumes/" + volumeFolder, exportName, - hostService.getWorkerName(hyperHost.getContext(), cmd, 1)); + hostService.getWorkerName(hyperHost.getContext(), cmd, 1), nfsVersion); return new Pair(volumeFolder, exportName); } finally { @@ -1025,12 +1030,12 @@ private String getVolumePathInDatastore(DatastoreMO dsMo, String volumeFileName) return datastoreVolumePath; } - private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, long volumeId, DatastoreMO dsMo, String secStorageUrl, String exportName) + private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, long volumeId, DatastoreMO dsMo, String secStorageUrl, String exportName, String nfsVersion) throws Exception { String volumeFolder = String.valueOf(volumeId) + "/"; String newVolume = UUID.randomUUID().toString().replaceAll("-", ""); - restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, "volumes/" + volumeFolder, exportName); + restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, "volumes/" + volumeFolder, exportName, nfsVersion); return new Pair(volumeFolder, newVolume); } @@ -1445,8 +1450,8 @@ public RevertToVMSnapshotAnswer execute(VmwareHostService hostService, RevertToV } } - private String deleteVolumeDirOnSecondaryStorage(long volumeId, String secStorageUrl) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, null); + private String deleteVolumeDirOnSecondaryStorage(long volumeId, String secStorageUrl, String nfsVersion) throws Exception { + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String volumeMountRoot = secondaryMountPoint + "/" + getVolumeRelativeDirInSecStroage(volumeId); return deleteDir(volumeMountRoot); diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index 35e775fbc7..2163324917 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -96,6 +96,7 @@ import com.cloud.hypervisor.vmware.util.VmwareHelper; import com.cloud.serializer.GsonHelper; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.JavaStorageLayer; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; @@ -155,12 +156,12 @@ private String getOVFFilePath(String srcOVAFileName) { } private VirtualMachineMO copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl, - String templatePathAtSecondaryStorage, String templateName, String templateUuid, boolean createSnapshot) throws Exception { + String templatePathAtSecondaryStorage, String templateName, String templateUuid, boolean createSnapshot, String nfsVersion) throws Exception { s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: " + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage + ", templateName: " + templateName); - String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl, null); + String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl, nfsVersion); s_logger.info("Secondary storage mount point: " + secondaryMountPoint); String srcOVAFileName = @@ -316,7 +317,7 @@ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { if (managed) { VirtualMachineMO vmMo = copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), - managedStoragePoolRootVolumeName, false); + managedStoragePoolRootVolumeName, false, ImageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); vmMo.unregisterVm(); @@ -333,7 +334,7 @@ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { } else { copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), - templateUuidName, true); + templateUuidName, true, ImageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); } } else { s_logger.info("Template " + templateInfo.second() + " has already been setup, skip the template setup process in primary storage"); @@ -518,7 +519,7 @@ public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd) { } } - private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, String srcVolumePath, DatastoreMO dsMo, String secStorageUrl, long wait) throws Exception { + private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, String srcVolumePath, DatastoreMO dsMo, String secStorageUrl, long wait, String nfsVersion) throws Exception { String volumeFolder = null; String volumeName = null; @@ -533,13 +534,13 @@ private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyper } String newVolume = VmwareHelper.getVCenterSafeUuid(); - restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, volumeFolder, volumeName, wait); + restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, volumeFolder, volumeName, wait, nfsVersion); return new Pair(volumeFolder, newVolume); } - private String deleteVolumeDirOnSecondaryStorage(String volumeDir, String secStorageUrl) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, null); + private String deleteVolumeDirOnSecondaryStorage(String volumeDir, String secStorageUrl, String nfsVersion) throws Exception { + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String volumeMountRoot = secondaryMountPoint + File.separator + volumeDir; return deleteDir(volumeMountRoot); @@ -578,8 +579,8 @@ public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd) { } } - Pair result = copyVolumeFromSecStorage(hyperHost, srcVolume.getPath(), new DatastoreMO(context, morDatastore), srcStore.getUrl(), (long)cmd.getWait() * 1000); - deleteVolumeDirOnSecondaryStorage(result.first(), srcStore.getUrl()); + Pair result = copyVolumeFromSecStorage(hyperHost, srcVolume.getPath(), new DatastoreMO(context, morDatastore), srcStore.getUrl(), (long)cmd.getWait() * 1000, ImageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); + deleteVolumeDirOnSecondaryStorage(result.first(), srcStore.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(uuid)); VolumeObjectTO newVolume = new VolumeObjectTO(); newVolume.setPath(result.second()); return new CopyCmdAnswer(newVolume); @@ -636,7 +637,8 @@ private Pair copyVolumeToSecStorage(VmwareHostService hostServic vmMo.createSnapshot(exportName, "Temporary snapshot for copy-volume command", false, false); - exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, destVolumePath, exportName, hostService.getWorkerName(hyperHost.getContext(), cmd, 1)); + exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, destVolumePath, exportName, hostService.getWorkerName(hyperHost.getContext(), cmd, 1), + ImageStoreDetailsUtil.getNfsVersionByUuid(cmd.getDestTO().getDataStore().getUuid())); return new Pair(destVolumePath, exportName); } finally { @@ -720,9 +722,9 @@ private void postCreatePrivateTemplate(String installFullPath, long templateId, } private Ternary createTemplateFromVolume(VirtualMachineMO vmMo, String installPath, long templateId, String templateUniqueName, - String secStorageUrl, String volumePath, String workerVmName) throws Exception { + String secStorageUrl, String volumePath, String workerVmName, String nfsVersion) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, null); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String installFullPath = secondaryMountPoint + "/" + installPath; synchronized (installPath.intern()) { Script command = new Script(false, "mkdir", _timeout, s_logger); @@ -838,7 +840,7 @@ public Answer createTemplateFromVolume(CopyCommand cmd) { Ternary result = createTemplateFromVolume(vmMo, template.getPath(), template.getId(), template.getName(), secondaryStoragePoolURL, volumePath, - hostService.getWorkerName(context, cmd, 0)); + hostService.getWorkerName(context, cmd, 0), ImageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(result.first()); @@ -885,7 +887,7 @@ private void writeMetaOvaForTemplate(String installFullPath, String ovfFilename, } private Ternary createTemplateFromSnapshot(String installPath, String templateUniqueName, String secStorageUrl, String snapshotPath, - Long templateId, long wait) throws Exception { + Long templateId, long wait, String nfsVersion) throws Exception { //Snapshot path is decoded in this form: /snapshots/account/volumeId/uuid/uuid String backupSSUuid; String snapshotFolder; @@ -899,7 +901,7 @@ private Ternary createTemplateFromSnapshot(String installPat snapshotFolder = StringUtils.join(tokens, File.separator, 0, tokens.length - 1); } - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, null); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String installFullPath = secondaryMountPoint + "/" + installPath; String installFullOVAName = installFullPath + "/" + templateUniqueName + ".ova"; //Note: volss for tmpl String snapshotRoot = secondaryMountPoint + "/" + snapshotFolder; @@ -1029,7 +1031,8 @@ public Answer createTemplateFromSnapshot(CopyCommand cmd) { } NfsTO nfsSvr = (NfsTO)imageStore; - Ternary result = createTemplateFromSnapshot(template.getPath(), uniqeName, nfsSvr.getUrl(), snapshot.getPath(), template.getId(), (long)cmd.getWait() * 1000); + Ternary result = createTemplateFromSnapshot(template.getPath(), uniqeName, nfsSvr.getUrl(), snapshot.getPath(), template.getId(), (long)cmd.getWait() * 1000, + ImageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(result.first()); @@ -1052,9 +1055,9 @@ public Answer createTemplateFromSnapshot(CopyCommand cmd) { // return Pair private Pair exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath, String secStorageUrl, String secStorageDir, - String exportName, String workerVmName) throws Exception { + String exportName, String workerVmName, String nfsVersion) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, null); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String exportPath = secondaryMountPoint + "/" + secStorageDir + "/" + exportName; synchronized (exportPath.intern()) { @@ -1096,10 +1099,10 @@ private Pair exportVolumeToSecondaryStroage(VirtualMachineMO v // Ternary private Ternary backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, String installPath, String volumePath, String snapshotUuid, - String secStorageUrl, String prevSnapshotUuid, String prevBackupUuid, String workerVmName) throws Exception { + String secStorageUrl, String prevSnapshotUuid, String prevBackupUuid, String workerVmName, String nfsVersion) throws Exception { String backupUuid = UUID.randomUUID().toString(); - Pair snapshotInfo = exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, installPath, backupUuid, workerVmName); + Pair snapshotInfo = exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, installPath, backupUuid, workerVmName, nfsVersion); return new Ternary(backupUuid, snapshotInfo.first(), snapshotInfo.second()); } @@ -1172,9 +1175,10 @@ public Answer backupSnapshot(CopyCommand cmd) { throw new Exception("Failed to take snapshot " + srcSnapshot.getName() + " on vm: " + vmName); } + String nfsVersion = ImageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid()); backupResult = backupSnapshotToSecondaryStorage(vmMo, destSnapshot.getPath(), srcSnapshot.getVolume().getPath(), snapshotUuid, secondaryStorageUrl, - prevSnapshotUuid, prevBackupUuid, hostService.getWorkerName(context, cmd, 1)); + prevSnapshotUuid, prevBackupUuid, hostService.getWorkerName(context, cmd, 1), nfsVersion); snapshotBackupUuid = backupResult.first(); success = (snapshotBackupUuid != null); @@ -1186,7 +1190,7 @@ public Answer backupSnapshot(CopyCommand cmd) { // Get snapshot physical size long physicalSize = 0l; - String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl, null); + String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl, nfsVersion); String snapshotDir = destSnapshot.getPath() + "/" + snapshotBackupUuid; File[] files = new File(secondaryMountPoint + "/" + snapshotDir).listFiles(); if(files != null) { @@ -2144,7 +2148,7 @@ private List getManagedIqnsFromVirtualDisks(List virtualDis } private Long restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, String secStorageUrl, String secStorageDir, - String backupName, long wait) throws Exception { + String backupName, long wait, String nfsVersion) throws Exception { String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, null); String srcOVAFileName = null; @@ -2248,7 +2252,7 @@ public Answer createVolumeFromSnapshot(CopyCommand cmd) { backedUpSnapshotUuid = backedUpSnapshotUuid.replace(".ovf", ""); } DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs); - restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secondaryStorageUrl, backupPath, backedUpSnapshotUuid, (long)cmd.getWait() * 1000); + restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secondaryStorageUrl, backupPath, backedUpSnapshotUuid, (long)cmd.getWait() * 1000, ImageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); VolumeObjectTO newVol = new VolumeObjectTO(); newVol.setPath(newVolumeName); diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java index 5beab056c5..77a71f549e 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java @@ -21,7 +21,6 @@ import java.io.File; import org.apache.log4j.Logger; - import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.DeleteCommand; @@ -38,6 +37,7 @@ import com.cloud.agent.api.to.SwiftTO; import com.cloud.hypervisor.vmware.manager.VmwareStorageManager; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ImageStoreDetailsUtil; public class VmwareStorageSubsystemCommandHandler extends StorageSubsystemCommandHandlerBase { private static final Logger s_logger = Logger.getLogger(VmwareStorageSubsystemCommandHandler.class); @@ -78,11 +78,12 @@ protected Answer execute(CopyCommand cmd) { } } + String nfsVersion = ImageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid()); if (srcDataStore.getRole() == DataStoreRole.ImageCache && destDataStore.getRole() == DataStoreRole.Image) { //need to take extra processing for vmware, such as packing to ova, before sending to S3 if (srcData.getObjectType() == DataObjectType.VOLUME) { NfsTO cacheStore = (NfsTO)srcDataStore; - String parentPath = storageResource.getRootDir(cacheStore.getUrl(), null); + String parentPath = storageResource.getRootDir(cacheStore.getUrl(), nfsVersion); VolumeObjectTO vol = (VolumeObjectTO)srcData; String path = vol.getPath(); int index = path.lastIndexOf(File.separator); @@ -95,7 +96,7 @@ protected Answer execute(CopyCommand cmd) { } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT) { // pack ova first // sync snapshot from NFS cache to S3 in NFS migration to S3 case - String parentPath = storageResource.getRootDir(srcDataStore.getUrl(), null); + String parentPath = storageResource.getRootDir(srcDataStore.getUrl(), nfsVersion); SnapshotObjectTO snap = (SnapshotObjectTO)srcData; String path = snap.getPath(); int index = path.lastIndexOf(File.separator); @@ -138,7 +139,7 @@ protected Answer execute(CopyCommand cmd) { return answer; } NfsTO cacheStore = (NfsTO)cmd.getCacheTO().getDataStore(); - String parentPath = storageResource.getRootDir(cacheStore.getUrl(), null); + String parentPath = storageResource.getRootDir(cacheStore.getUrl(), nfsVersion); SnapshotObjectTO newSnapshot = (SnapshotObjectTO)answer.getNewData(); String path = newSnapshot.getPath(); int index = path.lastIndexOf(File.separator); diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index c66ada8d3f..cb73ecbd4d 100644 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -36,7 +36,6 @@ import org.apache.cloudstack.utils.usage.UsageUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; @@ -91,6 +90,7 @@ import com.cloud.resource.ResourceState; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.StorageManager; import com.cloud.storage.StorageStats; import com.cloud.storage.VolumeStats; @@ -718,7 +718,7 @@ protected void runInContext() { continue; } - GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO(), getNfsVersion(store.getId())); + GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO(), ImageStoreDetailsUtil.getNfsVersion(store.getId())); EndPoint ssAhost = _epSelector.select(store); if (ssAhost == null) { s_logger.debug("There is no secondary storage VM for secondary storage host " + store.getName()); @@ -766,16 +766,6 @@ protected void runInContext() { } } - private String getNfsVersion(long storeId) { - String nfsVersion = null; - if (_imageStoreDetailsDao.getDetails(storeId) != null){ - Map storeDetails = _imageStoreDetailsDao.getDetails(storeId); - if (storeDetails != null && storeDetails.containsKey("nfs.version")){ - nfsVersion = storeDetails.get("nfs.version"); - } - } - return nfsVersion; - } } class AutoScaleMonitor extends ManagedContextRunnable { diff --git a/server/src/com/cloud/storage/ImageStoreDetailsUtil.java b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java new file mode 100755 index 0000000000..48b33fa522 --- /dev/null +++ b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java @@ -0,0 +1,59 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.storage; + +import java.util.Map; + +import javax.inject.Inject; + +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; + +public class ImageStoreDetailsUtil { + + @Inject + private static ImageStoreDao imageStoreDao; + @Inject + private static ImageStoreDetailsDao imageStoreDetailsDao; + + /** + * Obtain NFS protocol version (if provided) for a store id.
+ * It can be set by adding an entry in {@code image_store_details} table, providing {@code name=nfs.version} and {@code value=X} (e.g. 3) + * @param storeId image store id + * @return {@code null} if {@code nfs.version} is not found for storeId
+ * {@code X} if {@code nfs.version} is found found for storeId + */ + public static String getNfsVersion(long storeId) { + String nfsVersion = null; + if (imageStoreDetailsDao.getDetails(storeId) != null){ + Map storeDetails = imageStoreDetailsDao.getDetails(storeId); + if (storeDetails != null && storeDetails.containsKey("nfs.version")){ + nfsVersion = storeDetails.get("nfs.version"); + } + } + return nfsVersion; + } + + public static String getNfsVersionByUuid(String storeUuid){ + ImageStoreVO imageStore = imageStoreDao.findByUuid(storeUuid); + if (imageStore != null){ + return getNfsVersion(imageStore.getId()); + } + return null; + } +} diff --git a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java index 1ae5d5b304..a51b8d52c7 100644 --- a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java @@ -39,7 +39,6 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.security.keystore.KeystoreManager; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; -import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; @@ -102,6 +101,7 @@ import com.cloud.resource.UnableDeleteHostException; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.Storage; import com.cloud.storage.UploadVO; import com.cloud.storage.VMTemplateVO; @@ -237,8 +237,6 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar @Inject ImageStoreDao _imageStoreDao; @Inject - ImageStoreDetailsDao _imageStoreDetailsDao; - @Inject TemplateDataStoreDao _tmplStoreDao; @Inject VolumeDataStoreDao _volumeStoreDao; @@ -313,7 +311,7 @@ public boolean generateSetupCommand(Long ssHostId) { setupCmd = new SecStorageSetupCommand(ssStore.getTO(), secUrl, certs); } - setupCmd.setNfsVersion(getNfsVersion(ssStore.getId())); + setupCmd.setNfsVersion(ImageStoreDetailsUtil.getNfsVersion(ssStore.getId())); //template/volume file upload key String postUploadKey = _configDao.getValue(Config.SSVMPSK.key()); @@ -363,17 +361,6 @@ else if( cssHost.getType() == Host.Type.SecondaryStorage ) { return true; } - private String getNfsVersion(long storeId) { - String nfsVersion = null; - if (_imageStoreDetailsDao.getDetails(storeId) != null){ - Map storeDetails = _imageStoreDetailsDao.getDetails(storeId); - if (storeDetails != null && storeDetails.containsKey("nfs.version")){ - nfsVersion = storeDetails.get("nfs.version"); - } - } - return nfsVersion; - } - @Override public boolean generateVMSetupCommand(Long ssAHostId) { HostVO ssAHost = _hostDao.findById(ssAHostId); @@ -1446,4 +1433,5 @@ public List getSecondaryStorageVmAllocators() { public void setSecondaryStorageVmAllocators(List ssVmAllocators) { _ssVmAllocators = ssVmAllocators; } + } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index b71c96f113..3b32961d6f 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -53,6 +53,7 @@ import com.cloud.utils.EncryptionUtil; import com.google.gson.Gson; import com.google.gson.GsonBuilder; + import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; @@ -66,6 +67,7 @@ import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; + import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand; import org.apache.cloudstack.storage.template.UploadEntity; import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; @@ -144,6 +146,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ServerResourceBase; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.VMTemplateStorageResourceAssoc; @@ -165,6 +168,7 @@ import com.cloud.utils.script.OutputInterpreter; import com.cloud.utils.script.Script; import com.cloud.vm.SecondaryStorageVm; + import org.joda.time.DateTime; import org.joda.time.format.ISODateTimeFormat; @@ -364,7 +368,7 @@ protected Answer copyFromSwiftToNfs(CopyCommand cmd, DataTO srcData, SwiftTO swi final String storagePath = destImageStore.getUrl(); final String destPath = destData.getPath(); try { - String downloadPath = determineStorageTemplatePath(storagePath, destPath); + String downloadPath = determineStorageTemplatePath(storagePath, destPath, ImageStoreDetailsUtil.getNfsVersionByUuid(destImageStore.getUuid())); final File downloadDirectory = _storage.getFile(downloadPath); if (downloadDirectory.exists()) { @@ -391,7 +395,7 @@ protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataT try { - String downloadPath = determineStorageTemplatePath(storagePath, destPath); + String downloadPath = determineStorageTemplatePath(storagePath, destPath, ImageStoreDetailsUtil.getNfsVersionByUuid(destImageStore.getUuid())); final File downloadDirectory = _storage.getFile(downloadPath); if (downloadDirectory.exists()) { @@ -424,7 +428,7 @@ protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataT protected Answer copySnapshotToTemplateFromNfsToNfsXenserver(CopyCommand cmd, SnapshotObjectTO srcData, NfsTO srcDataStore, TemplateObjectTO destData, NfsTO destDataStore) { - String srcMountPoint = getRootDir(srcDataStore.getUrl(), null); + String srcMountPoint = getRootDir(srcDataStore.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); String snapshotPath = srcData.getPath(); int index = snapshotPath.lastIndexOf("/"); String snapshotName = snapshotPath.substring(index + 1); @@ -434,7 +438,7 @@ protected Answer copySnapshotToTemplateFromNfsToNfsXenserver(CopyCommand cmd, Sn snapshotPath = snapshotPath.substring(0, index); snapshotPath = srcMountPoint + File.separator + snapshotPath; - String destMountPoint = getRootDir(destDataStore.getUrl(), null); + String destMountPoint = getRootDir(destDataStore.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(destDataStore.getUuid())); String destPath = destMountPoint + File.separator + destData.getPath(); String errMsg = null; @@ -492,8 +496,8 @@ protected Answer copySnapshotToTemplateFromNfsToNfs(CopyCommand cmd, SnapshotObj if (srcData.getHypervisorType() == HypervisorType.XenServer) { return copySnapshotToTemplateFromNfsToNfsXenserver(cmd, srcData, srcDataStore, destData, destDataStore); } else if (srcData.getHypervisorType() == HypervisorType.KVM) { - File srcFile = getFile(srcData.getPath(), srcDataStore.getUrl()); - File destFile = getFile(destData.getPath(), destDataStore.getUrl()); + File srcFile = getFile(srcData.getPath(), srcDataStore.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); + File destFile = getFile(destData.getPath(), destDataStore.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(destDataStore.getUuid())); VolumeObjectTO volumeObjectTO = srcData.getVolume(); ImageFormat srcFormat = null; @@ -577,8 +581,8 @@ protected Answer copySnapshotToTemplateFromNfsToNfs(CopyCommand cmd, SnapshotObj return new CopyCmdAnswer(""); } - protected File getFile(String path, String nfsPath) { - String filePath = getRootDir(nfsPath, null) + File.separator + path; + protected File getFile(String path, String nfsPath, String nfsVersion) { + String filePath = getRootDir(nfsPath, nfsVersion) + File.separator + path; File f = new File(filePath); if (!f.exists()) { _storage.mkdirs(filePath); @@ -610,7 +614,7 @@ protected Answer createTemplateFromSnapshot(CopyCommand cmd) { } s_logger.debug("starting copy template to swift"); DataTO newTemplate = answer.getNewData(); - File templateFile = getFile(newTemplate.getPath(), ((NfsTO)srcDataStore).getUrl()); + File templateFile = getFile(newTemplate.getPath(), ((NfsTO)srcDataStore).getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); SwiftTO swift = (SwiftTO)destDataStore; String containterName = SwiftUtil.getContainerName(destData.getObjectType().toString(), destData.getId()); String swiftPath = SwiftUtil.putObject(swift, templateFile, containterName, templateFile.getName()); @@ -717,8 +721,8 @@ protected Long determineS3VolumeIdFromKey(String key) { return Long.parseLong(StringUtils.substringAfterLast(StringUtils.substringBeforeLast(key, S3Utils.SEPARATOR), S3Utils.SEPARATOR)); } - private String determineStorageTemplatePath(final String storagePath, String dataPath) { - return join(asList(getRootDir(storagePath, null), dataPath), File.separator); + private String determineStorageTemplatePath(final String storagePath, String dataPath, String nfsVersion) { + return join(asList(getRootDir(storagePath, nfsVersion), dataPath), File.separator); } protected File downloadFromUrlToNfs(String url, NfsTO nfs, String path, String name) { @@ -732,7 +736,7 @@ protected File downloadFromUrlToNfs(String url, NfsTO nfs, String path, String n throw new CloudRuntimeException("Failed to get url: " + url); } - String nfsMountPath = getRootDir(nfs.getUrl(), null); + String nfsMountPath = getRootDir(nfs.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(nfs.getUuid())); String filePath = nfsMountPath + File.separator + path; File directory = new File(filePath); @@ -897,7 +901,7 @@ protected Answer copyFromNfsToS3(CopyCommand cmd) { final S3TO s3 = (S3TO)destDataStore; try { - final String templatePath = determineStorageTemplatePath(srcStore.getUrl(), srcData.getPath()); + final String templatePath = determineStorageTemplatePath(srcStore.getUrl(), srcData.getPath(), ImageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); if (s_logger.isDebugEnabled()) { s_logger.debug("Found " + srcData.getObjectType() + " from directory " + templatePath + " to upload to S3."); @@ -1110,7 +1114,7 @@ public Answer execute(DeleteSnapshotsDirCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeSnapshotPath = cmd.getDirectory(); - String parent = getRootDir(nfs.getUrl(), null); + String parent = getRootDir(nfs.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); if (relativeSnapshotPath.startsWith(File.separator)) { relativeSnapshotPath = relativeSnapshotPath.substring(1); @@ -1188,7 +1192,7 @@ private Answer execute(ComputeChecksumCommand cmd) { return new Answer(cmd, false, "can't handle non nfs data store"); } NfsTO nfsStore = (NfsTO)store; - String parent = getRootDir(nfsStore.getUrl(), null); + String parent = getRootDir(nfsStore.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(store.getUuid())); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); @@ -1409,7 +1413,7 @@ protected Answer deleteSnapshot(final DeleteCommand cmd) { DataStoreTO dstore = obj.getDataStore(); if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; - String parent = getRootDir(nfs.getUrl(), null); + String parent = getRootDir(nfs.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); if (!parent.endsWith(File.separator)) { parent += File.separator; } @@ -1602,7 +1606,7 @@ private Answer execute(ListVolumeCommand cmd) { } DataStoreTO store = cmd.getDataStore(); if (store instanceof NfsTO) { - String root = getRootDir(cmd.getSecUrl(), null); + String root = getRootDir(cmd.getSecUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(store.getUuid())); Map templateInfos = _dlMgr.gatherVolumeInfo(root); return new ListVolumeAnswer(cmd.getSecUrl(), templateInfos); } else if (store instanceof S3TO) { @@ -1771,7 +1775,7 @@ protected Answer deleteTemplate(DeleteCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeTemplatePath = obj.getPath(); - String parent = getRootDir(nfs.getUrl(), null); + String parent = getRootDir(nfs.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); @@ -1875,7 +1879,7 @@ protected Answer deleteVolume(final DeleteCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeVolumePath = obj.getPath(); - String parent = getRootDir(nfs.getUrl(), null); + String parent = getRootDir(nfs.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); if (relativeVolumePath.startsWith(File.separator)) { relativeVolumePath = relativeVolumePath.substring(1); @@ -2672,7 +2676,7 @@ public UploadEntity createUploadEntity(String uuid, String metadata, long conten //relative path with out ssvm mount info. uploadEntity.setTemplatePath(absolutePath); String dataStoreUrl = cmd.getDataTo(); - String installPathPrefix = this.getRootDir(dataStoreUrl, null) + File.separator + absolutePath; + String installPathPrefix = this.getRootDir(dataStoreUrl, cmd.getNfsVersion()) + File.separator + absolutePath; uploadEntity.setInstallPathPrefix(installPathPrefix); uploadEntity.setHvm(cmd.getRequiresHvm()); uploadEntity.setChksum(cmd.getChecksum()); @@ -2694,7 +2698,7 @@ public UploadEntity createUploadEntity(String uuid, String metadata, long conten } private synchronized void checkSecondaryStorageResourceLimit(TemplateOrVolumePostUploadCommand cmd, int contentLengthInGB) { - String rootDir = this.getRootDir(cmd.getDataTo(), null) + File.separator; + String rootDir = this.getRootDir(cmd.getDataTo(), cmd.getNfsVersion()) + File.separator; long accountId = cmd.getAccountId(); long accountTemplateDirSize = 0; @@ -2741,7 +2745,7 @@ private String getSnapshotPathForAccount(long accountId) { private boolean isOneTimePostUrlUsed(TemplateOrVolumePostUploadCommand cmd) { String uuid = cmd.getEntityUUID(); - String uploadPath = this.getRootDir(cmd.getDataTo(), null) + File.separator + cmd.getAbsolutePath(); + String uploadPath = this.getRootDir(cmd.getDataTo(), cmd.getNfsVersion()) + File.separator + cmd.getAbsolutePath(); return uploadEntityStateMap.containsKey(uuid) || new File(uploadPath).exists(); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java index 7829bf6625..dec6005043 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java @@ -53,6 +53,7 @@ import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.S3TO; import com.cloud.exception.InternalErrorException; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.VMTemplateHostVO; @@ -708,7 +709,7 @@ public DownloadAnswer handleDownloadCommand(SecondaryStorageResource resource, D String installPathPrefix = cmd.getInstallPath(); // for NFS, we need to get mounted path if (dstore instanceof NfsTO) { - installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl(), null) + File.separator + installPathPrefix; + installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())) + File.separator + installPathPrefix; } String user = null; String password = null; From cc50c20b4b1aceb8b5817c820fb1be173d805a14 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Mon, 1 Feb 2016 12:56:04 -0800 Subject: [PATCH 049/203] CLOUDSTACK-9252: Remove static dependencies, refactor --- ...ring-engine-storage-image-core-context.xml | 4 +- .../storage/image/TemplateServiceImpl.java | 4 +- .../vmware/manager/VmwareManagerImpl.java | 5 +- .../manager/VmwareStorageManagerImpl.java | 10 +- .../resource/VmwareStorageProcessor.java | 24 +++-- .../VmwareStorageSubsystemCommandHandler.java | 8 +- .../vmware/VmwareDatacenterApiUnitTest.java | 21 +++- .../src/com/cloud/server/StatsCollector.java | 5 +- .../cloud/storage/ImageStoreDetailsUtil.java | 40 +++----- .../storage/ImageStoreDetailsUtilImpl.java | 97 +++++++++++++++++++ .../SecondaryStorageManagerImpl.java | 4 +- .../resource/NfsSecondaryStorageResource.java | 35 ++++--- .../storage/template/DownloadManagerImpl.java | 8 +- 13 files changed, 195 insertions(+), 70 deletions(-) create mode 100755 server/src/com/cloud/storage/ImageStoreDetailsUtilImpl.java diff --git a/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml b/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml index db517dbd86..40f724b643 100644 --- a/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml +++ b/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml @@ -29,7 +29,7 @@ + depends-on="dataObjectManagerImpl, dataStoreManagerImpl, dataMotionServiceImpl, objectInDataStoreManagerImpl, defaultEndPointSelector, templateDataFactoryImpl, imageStoreDetailsUtilImpl" /> @@ -38,6 +38,8 @@ class="org.apache.cloudstack.storage.image.datastore.ImageStoreHelper" /> + diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index 2a6159e85f..edad9776db 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -136,6 +136,8 @@ public class TemplateServiceImpl implements TemplateService { ConfigurationDao _configDao; @Inject StorageCacheManager _cacheMgr; + @Inject + ImageStoreDetailsUtil _imageStoreDetailsUtil; class TemplateOpContext extends AsyncRpcContext { final TemplateObject template; @@ -565,7 +567,7 @@ public void associateCrosszoneTemplatesToZone(long dcId) { } private Map listTemplate(DataStore ssStore) { - ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO(), ImageStoreDetailsUtil.getNfsVersion(ssStore.getId())); + ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO(), _imageStoreDetailsUtil.getNfsVersion(ssStore.getId())); EndPoint ep = _epSelector.select(ssStore); Answer answer = null; if (ep == null) { 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 d51d96fe94..bf478453de 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -46,7 +46,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.utils.identity.ManagementServerNode; import com.cloud.agent.AgentManager; @@ -170,7 +169,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw @Inject private ClusterManager _clusterMgr; @Inject - private ImageStoreDetailsDao _imageDetailsStoreDao; + private ImageStoreDetailsUtil _imageStoreDetailsUtil; private String _mountParent; private StorageLayer _storage; @@ -554,7 +553,7 @@ public boolean needRecycle(String workerTag) { @Override public void prepareSecondaryStorageStore(String storageUrl, Long storeId) { - String mountPoint = getMountPoint(storageUrl, ImageStoreDetailsUtil.getNfsVersion(storeId)); + String mountPoint = getMountPoint(storageUrl, _imageStoreDetailsUtil.getNfsVersion(storeId)); GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm"); try { diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index b41a14725c..35d1dad7b7 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -29,6 +29,8 @@ import java.util.Properties; import java.util.UUID; +import javax.inject.Inject; + import org.apache.log4j.Logger; import com.vmware.vim25.FileInfo; @@ -93,6 +95,10 @@ import com.cloud.vm.snapshot.VMSnapshot; public class VmwareStorageManagerImpl implements VmwareStorageManager { + + @Inject + ImageStoreDetailsUtil _imageStoreDetailsUtil; + @Override public boolean execute(VmwareHostService hostService, CreateEntityDownloadURLCommand cmd) { DataTO data = cmd.getData(); @@ -157,7 +163,7 @@ public String createOvaForTemplate(TemplateObjectTO template) { String secStorageUrl = nfsStore.getUrl(); assert (secStorageUrl != null); String installPath = template.getPath(); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, ImageStoreDetailsUtil.getNfsVersionByUuid(storeTO.getUuid())); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, _imageStoreDetailsUtil.getNfsVersionByUuid(storeTO.getUuid())); String installFullPath = secondaryMountPoint + "/" + installPath; try { if (installFullPath.endsWith(".ova")) { @@ -195,7 +201,7 @@ public String createOvaForVolume(VolumeObjectTO volume) { String installPath = volume.getPath(); int index = installPath.lastIndexOf(File.separator); String volumeUuid = installPath.substring(index + 1); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, ImageStoreDetailsUtil.getNfsVersionByUuid(storeTO.getUuid())); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, _imageStoreDetailsUtil.getNfsVersionByUuid(storeTO.getUuid())); //The real volume path String volumePath = installPath + File.separator + volumeUuid + ".ova"; String installFullPath = secondaryMountPoint + "/" + installPath; diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index 2163324917..b469ae2887 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -33,6 +33,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import javax.inject.Inject; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -110,6 +112,10 @@ import com.cloud.vm.VmDetailConstants; public class VmwareStorageProcessor implements StorageProcessor { + + @Inject + ImageStoreDetailsUtil _imageStoreDetailsUtil; + private static final Logger s_logger = Logger.getLogger(VmwareStorageProcessor.class); private static final int DEFAULT_NFS_PORT = 2049; @@ -317,7 +323,7 @@ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { if (managed) { VirtualMachineMO vmMo = copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), - managedStoragePoolRootVolumeName, false, ImageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); + managedStoragePoolRootVolumeName, false, _imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); vmMo.unregisterVm(); @@ -334,7 +340,7 @@ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { } else { copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), - templateUuidName, true, ImageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); + templateUuidName, true, _imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); } } else { s_logger.info("Template " + templateInfo.second() + " has already been setup, skip the template setup process in primary storage"); @@ -579,8 +585,8 @@ public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd) { } } - Pair result = copyVolumeFromSecStorage(hyperHost, srcVolume.getPath(), new DatastoreMO(context, morDatastore), srcStore.getUrl(), (long)cmd.getWait() * 1000, ImageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); - deleteVolumeDirOnSecondaryStorage(result.first(), srcStore.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(uuid)); + Pair result = copyVolumeFromSecStorage(hyperHost, srcVolume.getPath(), new DatastoreMO(context, morDatastore), srcStore.getUrl(), (long)cmd.getWait() * 1000, _imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); + deleteVolumeDirOnSecondaryStorage(result.first(), srcStore.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(uuid)); VolumeObjectTO newVolume = new VolumeObjectTO(); newVolume.setPath(result.second()); return new CopyCmdAnswer(newVolume); @@ -638,7 +644,7 @@ private Pair copyVolumeToSecStorage(VmwareHostService hostServic vmMo.createSnapshot(exportName, "Temporary snapshot for copy-volume command", false, false); exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, destVolumePath, exportName, hostService.getWorkerName(hyperHost.getContext(), cmd, 1), - ImageStoreDetailsUtil.getNfsVersionByUuid(cmd.getDestTO().getDataStore().getUuid())); + _imageStoreDetailsUtil.getNfsVersionByUuid(cmd.getDestTO().getDataStore().getUuid())); return new Pair(destVolumePath, exportName); } finally { @@ -840,7 +846,7 @@ public Answer createTemplateFromVolume(CopyCommand cmd) { Ternary result = createTemplateFromVolume(vmMo, template.getPath(), template.getId(), template.getName(), secondaryStoragePoolURL, volumePath, - hostService.getWorkerName(context, cmd, 0), ImageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); + hostService.getWorkerName(context, cmd, 0), _imageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(result.first()); @@ -1032,7 +1038,7 @@ public Answer createTemplateFromSnapshot(CopyCommand cmd) { NfsTO nfsSvr = (NfsTO)imageStore; Ternary result = createTemplateFromSnapshot(template.getPath(), uniqeName, nfsSvr.getUrl(), snapshot.getPath(), template.getId(), (long)cmd.getWait() * 1000, - ImageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); + _imageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(result.first()); @@ -1175,7 +1181,7 @@ public Answer backupSnapshot(CopyCommand cmd) { throw new Exception("Failed to take snapshot " + srcSnapshot.getName() + " on vm: " + vmName); } - String nfsVersion = ImageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid()); + String nfsVersion = _imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid()); backupResult = backupSnapshotToSecondaryStorage(vmMo, destSnapshot.getPath(), srcSnapshot.getVolume().getPath(), snapshotUuid, secondaryStorageUrl, prevSnapshotUuid, prevBackupUuid, hostService.getWorkerName(context, cmd, 1), nfsVersion); @@ -2252,7 +2258,7 @@ public Answer createVolumeFromSnapshot(CopyCommand cmd) { backedUpSnapshotUuid = backedUpSnapshotUuid.replace(".ovf", ""); } DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs); - restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secondaryStorageUrl, backupPath, backedUpSnapshotUuid, (long)cmd.getWait() * 1000, ImageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); + restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secondaryStorageUrl, backupPath, backedUpSnapshotUuid, (long)cmd.getWait() * 1000, _imageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); VolumeObjectTO newVol = new VolumeObjectTO(); newVol.setPath(newVolumeName); diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java index 77a71f549e..b8544d086f 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java @@ -20,6 +20,8 @@ import java.io.File; +import javax.inject.Inject; + import org.apache.log4j.Logger; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; @@ -40,6 +42,10 @@ import com.cloud.storage.ImageStoreDetailsUtil; public class VmwareStorageSubsystemCommandHandler extends StorageSubsystemCommandHandlerBase { + + @Inject + ImageStoreDetailsUtil _imageStoreDetailsUtil; + private static final Logger s_logger = Logger.getLogger(VmwareStorageSubsystemCommandHandler.class); private VmwareStorageManager storageManager; private PremiumSecondaryStorageResource storageResource; @@ -78,7 +84,7 @@ protected Answer execute(CopyCommand cmd) { } } - String nfsVersion = ImageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid()); + String nfsVersion = _imageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid()); if (srcDataStore.getRole() == DataStoreRole.ImageCache && destDataStore.getRole() == DataStoreRole.Image) { //need to take extra processing for vmware, such as packing to ova, before sending to S3 if (srcData.getObjectType() == DataObjectType.VOLUME) { diff --git a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java index 6b89e7bb9c..c4c48a5dd0 100644 --- a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java +++ b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java @@ -28,6 +28,7 @@ import javax.naming.ConfigurationException; import com.cloud.user.User; + import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -48,12 +49,12 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; - import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd; import org.apache.cloudstack.api.command.admin.zone.RemoveVmwareDcCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.test.utils.SpringUtils; @@ -87,6 +88,7 @@ import com.cloud.org.Managed.ManagedState; import com.cloud.secstorage.CommandExecLogDao; import com.cloud.server.ConfigurationServer; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.AccountService; @@ -131,6 +133,9 @@ public class VmwareDatacenterApiUnitTest { @Inject AccountManager _acctMgr; + @Inject + ImageStoreDetailsUtil _imageStoreDetailsUtil; + long zoneId; long podId; long clusterId; @@ -225,6 +230,8 @@ public void testSetUp() { Mockito.when(addCmd.getPassword()).thenReturn(password); Mockito.when(addCmd.getName()).thenReturn(vmwareDcName); Mockito.when(removeCmd.getZoneId()).thenReturn(1L); + Mockito.when(_imageStoreDetailsUtil.getNfsVersion(Mockito.anyLong())).thenReturn(null); + Mockito.when(_imageStoreDetailsUtil.getNfsVersionByUuid(Mockito.anyString())).thenReturn(null); } @After @@ -433,7 +440,17 @@ public DataStoreManager dataStoreManager() { } @Bean - public ImageStoreDetailsDao imageStoreDetailsDao(){ + public ImageStoreDetailsUtil imageStoreDetailsUtil() { + return Mockito.mock(ImageStoreDetailsUtil.class); + } + + @Bean + public ImageStoreDao imageStoreDao() { + return Mockito.mock(ImageStoreDao.class); + } + + @Bean + public ImageStoreDetailsDao imageStoreDetailsDao() { return Mockito.mock(ImageStoreDetailsDao.class); } diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index cb73ecbd4d..b5d6b799d3 100644 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -43,7 +43,6 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; -import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.utils.graphite.GraphiteClient; @@ -200,7 +199,7 @@ public String toString() { @Inject private HostGpuGroupsDao _hostGpuGroupsDao; @Inject - private ImageStoreDetailsDao _imageStoreDetailsDao; + ImageStoreDetailsUtil _imageStoreDetailsUtil; private ConcurrentHashMap _hostStats = new ConcurrentHashMap(); private final ConcurrentHashMap _VmStats = new ConcurrentHashMap(); @@ -718,7 +717,7 @@ protected void runInContext() { continue; } - GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO(), ImageStoreDetailsUtil.getNfsVersion(store.getId())); + GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO(), _imageStoreDetailsUtil.getNfsVersion(store.getId())); EndPoint ssAhost = _epSelector.select(store); if (ssAhost == null) { s_logger.debug("There is no secondary storage VM for secondary storage host " + store.getName()); diff --git a/server/src/com/cloud/storage/ImageStoreDetailsUtil.java b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java index 48b33fa522..201fdb4866 100755 --- a/server/src/com/cloud/storage/ImageStoreDetailsUtil.java +++ b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java @@ -16,20 +16,10 @@ // under the License. package com.cloud.storage; -import java.util.Map; +import com.cloud.utils.component.Manager; -import javax.inject.Inject; -import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; -import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; -import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; - -public class ImageStoreDetailsUtil { - - @Inject - private static ImageStoreDao imageStoreDao; - @Inject - private static ImageStoreDetailsDao imageStoreDetailsDao; +public interface ImageStoreDetailsUtil extends Manager { /** * Obtain NFS protocol version (if provided) for a store id.
@@ -38,22 +28,14 @@ public class ImageStoreDetailsUtil { * @return {@code null} if {@code nfs.version} is not found for storeId
* {@code X} if {@code nfs.version} is found found for storeId */ - public static String getNfsVersion(long storeId) { - String nfsVersion = null; - if (imageStoreDetailsDao.getDetails(storeId) != null){ - Map storeDetails = imageStoreDetailsDao.getDetails(storeId); - if (storeDetails != null && storeDetails.containsKey("nfs.version")){ - nfsVersion = storeDetails.get("nfs.version"); - } - } - return nfsVersion; - } + public String getNfsVersion(long storeId); - public static String getNfsVersionByUuid(String storeUuid){ - ImageStoreVO imageStore = imageStoreDao.findByUuid(storeUuid); - if (imageStore != null){ - return getNfsVersion(imageStore.getId()); - } - return null; - } + /** + * Obtain NFS protocol version (if provided) for a store uuid.
+ * It can be set by adding an entry in {@code image_store_details} table, providing {@code name=nfs.version} and {@code value=X} (e.g. 3) + * @param storeId image store id + * @return {@code null} if {@code nfs.version} is not found for storeUuid
+ * {@code X} if {@code nfs.version} is found found for storeUuid + */ + public String getNfsVersionByUuid(String storeUuid); } diff --git a/server/src/com/cloud/storage/ImageStoreDetailsUtilImpl.java b/server/src/com/cloud/storage/ImageStoreDetailsUtilImpl.java new file mode 100755 index 0000000000..d0207ba131 --- /dev/null +++ b/server/src/com/cloud/storage/ImageStoreDetailsUtilImpl.java @@ -0,0 +1,97 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.storage; + +import java.util.Map; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; +import org.springframework.stereotype.Component; + +@Component +public class ImageStoreDetailsUtilImpl implements ImageStoreDetailsUtil { + + @Inject + private ImageStoreDao imageStoreDao; + @Inject + private ImageStoreDetailsDao imageStoreDetailsDao; + + public String getNfsVersion(long storeId) { + String nfsVersion = null; + if (imageStoreDetailsDao.getDetails(storeId) != null){ + Map storeDetails = imageStoreDetailsDao.getDetails(storeId); + if (storeDetails != null && storeDetails.containsKey("nfs.version")){ + nfsVersion = storeDetails.get("nfs.version"); + } + } + return nfsVersion; + } + + public String getNfsVersionByUuid(String storeUuid){ + ImageStoreVO imageStore = imageStoreDao.findByUuid(storeUuid); + if (imageStore != null){ + return getNfsVersion(imageStore.getId()); + } + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public void setName(String name) { + } + + @Override + public void setConfigParams(Map params) { + } + + @Override + public Map getConfigParams() { + return null; + } + + @Override + public int getRunLevel() { + return 0; + } + + @Override + public void setRunLevel(int level) { + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + return false; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return false; + } +} diff --git a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java index a51b8d52c7..ba17b552ee 100644 --- a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java @@ -240,6 +240,8 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar TemplateDataStoreDao _tmplStoreDao; @Inject VolumeDataStoreDao _volumeStoreDao; + @Inject + ImageStoreDetailsUtil _imageStoreDetailsUtil; private long _capacityScanInterval = DEFAULT_CAPACITY_SCAN_INTERVAL; private int _secStorageVmMtuSize; @@ -311,7 +313,7 @@ public boolean generateSetupCommand(Long ssHostId) { setupCmd = new SecStorageSetupCommand(ssStore.getTO(), secUrl, certs); } - setupCmd.setNfsVersion(ImageStoreDetailsUtil.getNfsVersion(ssStore.getId())); + setupCmd.setNfsVersion(_imageStoreDetailsUtil.getNfsVersion(ssStore.getId())); //template/volume file upload key String postUploadKey = _configDao.getValue(Config.SSVMPSK.key()); diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index 3b32961d6f..bae66b62c5 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -146,7 +146,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ServerResourceBase; import com.cloud.storage.DataStoreRole; -import com.cloud.storage.ImageStoreDetailsUtil; +import com.cloud.storage.ImageStoreDetailsUtilImpl; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.VMTemplateStorageResourceAssoc; @@ -174,6 +174,9 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements SecondaryStorageResource { + @Inject + ImageStoreDetailsUtilImpl _imageStoreDetailsUtil; + private static final Logger s_logger = Logger.getLogger(NfsSecondaryStorageResource.class); private static final String TEMPLATE_ROOT_DIR = "template/tmpl"; @@ -368,7 +371,7 @@ protected Answer copyFromSwiftToNfs(CopyCommand cmd, DataTO srcData, SwiftTO swi final String storagePath = destImageStore.getUrl(); final String destPath = destData.getPath(); try { - String downloadPath = determineStorageTemplatePath(storagePath, destPath, ImageStoreDetailsUtil.getNfsVersionByUuid(destImageStore.getUuid())); + String downloadPath = determineStorageTemplatePath(storagePath, destPath, _imageStoreDetailsUtil.getNfsVersionByUuid(destImageStore.getUuid())); final File downloadDirectory = _storage.getFile(downloadPath); if (downloadDirectory.exists()) { @@ -395,7 +398,7 @@ protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataT try { - String downloadPath = determineStorageTemplatePath(storagePath, destPath, ImageStoreDetailsUtil.getNfsVersionByUuid(destImageStore.getUuid())); + String downloadPath = determineStorageTemplatePath(storagePath, destPath, _imageStoreDetailsUtil.getNfsVersionByUuid(destImageStore.getUuid())); final File downloadDirectory = _storage.getFile(downloadPath); if (downloadDirectory.exists()) { @@ -428,7 +431,7 @@ protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataT protected Answer copySnapshotToTemplateFromNfsToNfsXenserver(CopyCommand cmd, SnapshotObjectTO srcData, NfsTO srcDataStore, TemplateObjectTO destData, NfsTO destDataStore) { - String srcMountPoint = getRootDir(srcDataStore.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); + String srcMountPoint = getRootDir(srcDataStore.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); String snapshotPath = srcData.getPath(); int index = snapshotPath.lastIndexOf("/"); String snapshotName = snapshotPath.substring(index + 1); @@ -438,7 +441,7 @@ protected Answer copySnapshotToTemplateFromNfsToNfsXenserver(CopyCommand cmd, Sn snapshotPath = snapshotPath.substring(0, index); snapshotPath = srcMountPoint + File.separator + snapshotPath; - String destMountPoint = getRootDir(destDataStore.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(destDataStore.getUuid())); + String destMountPoint = getRootDir(destDataStore.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(destDataStore.getUuid())); String destPath = destMountPoint + File.separator + destData.getPath(); String errMsg = null; @@ -496,8 +499,8 @@ protected Answer copySnapshotToTemplateFromNfsToNfs(CopyCommand cmd, SnapshotObj if (srcData.getHypervisorType() == HypervisorType.XenServer) { return copySnapshotToTemplateFromNfsToNfsXenserver(cmd, srcData, srcDataStore, destData, destDataStore); } else if (srcData.getHypervisorType() == HypervisorType.KVM) { - File srcFile = getFile(srcData.getPath(), srcDataStore.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); - File destFile = getFile(destData.getPath(), destDataStore.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(destDataStore.getUuid())); + File srcFile = getFile(srcData.getPath(), srcDataStore.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); + File destFile = getFile(destData.getPath(), destDataStore.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(destDataStore.getUuid())); VolumeObjectTO volumeObjectTO = srcData.getVolume(); ImageFormat srcFormat = null; @@ -614,7 +617,7 @@ protected Answer createTemplateFromSnapshot(CopyCommand cmd) { } s_logger.debug("starting copy template to swift"); DataTO newTemplate = answer.getNewData(); - File templateFile = getFile(newTemplate.getPath(), ((NfsTO)srcDataStore).getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); + File templateFile = getFile(newTemplate.getPath(), ((NfsTO)srcDataStore).getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); SwiftTO swift = (SwiftTO)destDataStore; String containterName = SwiftUtil.getContainerName(destData.getObjectType().toString(), destData.getId()); String swiftPath = SwiftUtil.putObject(swift, templateFile, containterName, templateFile.getName()); @@ -736,7 +739,7 @@ protected File downloadFromUrlToNfs(String url, NfsTO nfs, String path, String n throw new CloudRuntimeException("Failed to get url: " + url); } - String nfsMountPath = getRootDir(nfs.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(nfs.getUuid())); + String nfsMountPath = getRootDir(nfs.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(nfs.getUuid())); String filePath = nfsMountPath + File.separator + path; File directory = new File(filePath); @@ -901,7 +904,7 @@ protected Answer copyFromNfsToS3(CopyCommand cmd) { final S3TO s3 = (S3TO)destDataStore; try { - final String templatePath = determineStorageTemplatePath(srcStore.getUrl(), srcData.getPath(), ImageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); + final String templatePath = determineStorageTemplatePath(srcStore.getUrl(), srcData.getPath(), _imageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); if (s_logger.isDebugEnabled()) { s_logger.debug("Found " + srcData.getObjectType() + " from directory " + templatePath + " to upload to S3."); @@ -1114,7 +1117,7 @@ public Answer execute(DeleteSnapshotsDirCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeSnapshotPath = cmd.getDirectory(); - String parent = getRootDir(nfs.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); + String parent = getRootDir(nfs.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); if (relativeSnapshotPath.startsWith(File.separator)) { relativeSnapshotPath = relativeSnapshotPath.substring(1); @@ -1192,7 +1195,7 @@ private Answer execute(ComputeChecksumCommand cmd) { return new Answer(cmd, false, "can't handle non nfs data store"); } NfsTO nfsStore = (NfsTO)store; - String parent = getRootDir(nfsStore.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(store.getUuid())); + String parent = getRootDir(nfsStore.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(store.getUuid())); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); @@ -1413,7 +1416,7 @@ protected Answer deleteSnapshot(final DeleteCommand cmd) { DataStoreTO dstore = obj.getDataStore(); if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; - String parent = getRootDir(nfs.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); + String parent = getRootDir(nfs.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); if (!parent.endsWith(File.separator)) { parent += File.separator; } @@ -1606,7 +1609,7 @@ private Answer execute(ListVolumeCommand cmd) { } DataStoreTO store = cmd.getDataStore(); if (store instanceof NfsTO) { - String root = getRootDir(cmd.getSecUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(store.getUuid())); + String root = getRootDir(cmd.getSecUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(store.getUuid())); Map templateInfos = _dlMgr.gatherVolumeInfo(root); return new ListVolumeAnswer(cmd.getSecUrl(), templateInfos); } else if (store instanceof S3TO) { @@ -1775,7 +1778,7 @@ protected Answer deleteTemplate(DeleteCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeTemplatePath = obj.getPath(); - String parent = getRootDir(nfs.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); + String parent = getRootDir(nfs.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); @@ -1879,7 +1882,7 @@ protected Answer deleteVolume(final DeleteCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeVolumePath = obj.getPath(); - String parent = getRootDir(nfs.getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); + String parent = getRootDir(nfs.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); if (relativeVolumePath.startsWith(File.separator)) { relativeVolumePath = relativeVolumePath.substring(1); diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java index dec6005043..c6f2ac8406 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java @@ -38,6 +38,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.cloudstack.storage.command.DownloadCommand; @@ -53,7 +54,7 @@ import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.S3TO; import com.cloud.exception.InternalErrorException; -import com.cloud.storage.ImageStoreDetailsUtil; +import com.cloud.storage.ImageStoreDetailsUtilImpl; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.VMTemplateHostVO; @@ -90,6 +91,9 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager StorageLayer _storage; public Map _processors; + @Inject + ImageStoreDetailsUtilImpl _imageStoreDetailsUtil; + public class Completion implements DownloadCompleteCallback { private final String jobId; @@ -709,7 +713,7 @@ public DownloadAnswer handleDownloadCommand(SecondaryStorageResource resource, D String installPathPrefix = cmd.getInstallPath(); // for NFS, we need to get mounted path if (dstore instanceof NfsTO) { - installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl(), ImageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())) + File.separator + installPathPrefix; + installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())) + File.separator + installPathPrefix; } String user = null; String password = null; From 3fb18bd4946caf0ba89a00aa7504b472c4806a09 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Wed, 3 Feb 2016 07:08:39 -0800 Subject: [PATCH 050/203] CLOUDSTACK-9252: New refactor --- ...ring-engine-storage-image-core-context.xml | 6 +- .../storage/image/TemplateServiceImpl.java | 4 +- .../vmware/manager/VmwareManagerImpl.java | 8 +- .../manager/VmwareStorageManagerImpl.java | 12 +-- .../resource/VmwareStorageProcessor.java | 26 ++--- .../VmwareStorageSubsystemCommandHandler.java | 10 +- .../vmware/VmwareDatacenterApiUnitTest.java | 6 +- .../src/com/cloud/server/StatsCollector.java | 4 +- .../cloud/storage/ImageStoreDetailsUtil.java | 36 ++++++- .../storage/ImageStoreDetailsUtilImpl.java | 97 ------------------- .../SecondaryStorageManagerImpl.java | 4 +- .../resource/NfsSecondaryStorageResource.java | 4 +- .../storage/template/DownloadManagerImpl.java | 11 ++- 13 files changed, 81 insertions(+), 147 deletions(-) delete mode 100755 server/src/com/cloud/storage/ImageStoreDetailsUtilImpl.java diff --git a/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml b/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml index 40f724b643..2441d1c56f 100644 --- a/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml +++ b/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml @@ -29,7 +29,7 @@ + depends-on="dataObjectManagerImpl, dataStoreManagerImpl, dataMotionServiceImpl, objectInDataStoreManagerImpl, defaultEndPointSelector, templateDataFactoryImpl, imageStoreDetailsUtil" /> @@ -38,8 +38,8 @@ class="org.apache.cloudstack.storage.image.datastore.ImageStoreHelper" /> - + diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index edad9776db..a1d10e3280 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -137,7 +137,7 @@ public class TemplateServiceImpl implements TemplateService { @Inject StorageCacheManager _cacheMgr; @Inject - ImageStoreDetailsUtil _imageStoreDetailsUtil; + ImageStoreDetailsUtil imageStoreDetailsUtil; class TemplateOpContext extends AsyncRpcContext { final TemplateObject template; @@ -567,7 +567,7 @@ public void associateCrosszoneTemplatesToZone(long dcId) { } private Map listTemplate(DataStore ssStore) { - ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO(), _imageStoreDetailsUtil.getNfsVersion(ssStore.getId())); + ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO(), imageStoreDetailsUtil.getNfsVersion(ssStore.getId())); EndPoint ep = _epSelector.select(ssStore); Answer answer = null; if (ep == null) { 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 bf478453de..71383c3333 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -47,6 +47,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.utils.identity.ManagementServerNode; +import org.springframework.context.ApplicationContext; import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; @@ -168,8 +169,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw private ManagementServerHostPeerDao _mshostPeerDao; @Inject private ClusterManager _clusterMgr; - @Inject - private ImageStoreDetailsUtil _imageStoreDetailsUtil; + private ImageStoreDetailsUtil imageStoreDetailsUtil; private String _mountParent; private StorageLayer _storage; @@ -202,6 +202,8 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw public VmwareManagerImpl() { _storageMgr = new VmwareStorageManagerImpl(this); + ApplicationContext applicationContext = com.cloud.utils.component.ComponentContext.getApplicationContext(); + imageStoreDetailsUtil = applicationContext.getBean("imageStoreDetailsUtil", ImageStoreDetailsUtil.class); } @Override @@ -553,7 +555,7 @@ public boolean needRecycle(String workerTag) { @Override public void prepareSecondaryStorageStore(String storageUrl, Long storeId) { - String mountPoint = getMountPoint(storageUrl, _imageStoreDetailsUtil.getNfsVersion(storeId)); + String mountPoint = getMountPoint(storageUrl, imageStoreDetailsUtil.getNfsVersion(storeId)); GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm"); try { diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index 35d1dad7b7..8d5fc10458 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -29,8 +29,6 @@ import java.util.Properties; import java.util.UUID; -import javax.inject.Inject; - import org.apache.log4j.Logger; import com.vmware.vim25.FileInfo; @@ -44,6 +42,7 @@ import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.springframework.context.ApplicationContext; import com.cloud.agent.api.Answer; import com.cloud.agent.api.BackupSnapshotAnswer; @@ -96,8 +95,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { - @Inject - ImageStoreDetailsUtil _imageStoreDetailsUtil; + private ImageStoreDetailsUtil imageStoreDetailsUtil; @Override public boolean execute(VmwareHostService hostService, CreateEntityDownloadURLCommand cmd) { @@ -143,6 +141,8 @@ public void createOva(String path, String name) { public VmwareStorageManagerImpl(VmwareStorageMount mountService) { assert (mountService != null); _mountService = mountService; + ApplicationContext applicationContext = com.cloud.utils.component.ComponentContext.getApplicationContext(); + imageStoreDetailsUtil = applicationContext.getBean("imageStoreDetailsUtil", ImageStoreDetailsUtil.class); } public void configure(Map params) { @@ -163,7 +163,7 @@ public String createOvaForTemplate(TemplateObjectTO template) { String secStorageUrl = nfsStore.getUrl(); assert (secStorageUrl != null); String installPath = template.getPath(); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, _imageStoreDetailsUtil.getNfsVersionByUuid(storeTO.getUuid())); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, imageStoreDetailsUtil.getNfsVersionByUuid(storeTO.getUuid())); String installFullPath = secondaryMountPoint + "/" + installPath; try { if (installFullPath.endsWith(".ova")) { @@ -201,7 +201,7 @@ public String createOvaForVolume(VolumeObjectTO volume) { String installPath = volume.getPath(); int index = installPath.lastIndexOf(File.separator); String volumeUuid = installPath.substring(index + 1); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, _imageStoreDetailsUtil.getNfsVersionByUuid(storeTO.getUuid())); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, imageStoreDetailsUtil.getNfsVersionByUuid(storeTO.getUuid())); //The real volume path String volumePath = installPath + File.separator + volumeUuid + ".ova"; String installFullPath = secondaryMountPoint + "/" + installPath; diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index b469ae2887..660b93bb90 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -33,8 +33,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import javax.inject.Inject; - import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -69,6 +67,7 @@ import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.springframework.context.ApplicationContext; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; @@ -113,8 +112,7 @@ public class VmwareStorageProcessor implements StorageProcessor { - @Inject - ImageStoreDetailsUtil _imageStoreDetailsUtil; + private ImageStoreDetailsUtil imageStoreDetailsUtil; private static final Logger s_logger = Logger.getLogger(VmwareStorageProcessor.class); private static final int DEFAULT_NFS_PORT = 2049; @@ -137,6 +135,8 @@ public VmwareStorageProcessor(VmwareHostService hostService, boolean fullCloneFl this.resource = resource; _shutdownWaitMs = shutdownWaitMs; _gson = GsonHelper.getGsonLogger(); + ApplicationContext applicationContext = com.cloud.utils.component.ComponentContext.getApplicationContext(); + imageStoreDetailsUtil = applicationContext.getBean("imageStoreDetailsUtil", ImageStoreDetailsUtil.class); } @Override @@ -323,7 +323,7 @@ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { if (managed) { VirtualMachineMO vmMo = copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), - managedStoragePoolRootVolumeName, false, _imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); + managedStoragePoolRootVolumeName, false, imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); vmMo.unregisterVm(); @@ -340,7 +340,7 @@ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { } else { copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), - templateUuidName, true, _imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); + templateUuidName, true, imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); } } else { s_logger.info("Template " + templateInfo.second() + " has already been setup, skip the template setup process in primary storage"); @@ -585,8 +585,8 @@ public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd) { } } - Pair result = copyVolumeFromSecStorage(hyperHost, srcVolume.getPath(), new DatastoreMO(context, morDatastore), srcStore.getUrl(), (long)cmd.getWait() * 1000, _imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); - deleteVolumeDirOnSecondaryStorage(result.first(), srcStore.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(uuid)); + Pair result = copyVolumeFromSecStorage(hyperHost, srcVolume.getPath(), new DatastoreMO(context, morDatastore), srcStore.getUrl(), (long)cmd.getWait() * 1000, imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); + deleteVolumeDirOnSecondaryStorage(result.first(), srcStore.getUrl(), imageStoreDetailsUtil.getNfsVersionByUuid(uuid)); VolumeObjectTO newVolume = new VolumeObjectTO(); newVolume.setPath(result.second()); return new CopyCmdAnswer(newVolume); @@ -644,7 +644,7 @@ private Pair copyVolumeToSecStorage(VmwareHostService hostServic vmMo.createSnapshot(exportName, "Temporary snapshot for copy-volume command", false, false); exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, destVolumePath, exportName, hostService.getWorkerName(hyperHost.getContext(), cmd, 1), - _imageStoreDetailsUtil.getNfsVersionByUuid(cmd.getDestTO().getDataStore().getUuid())); + imageStoreDetailsUtil.getNfsVersionByUuid(cmd.getDestTO().getDataStore().getUuid())); return new Pair(destVolumePath, exportName); } finally { @@ -846,7 +846,7 @@ public Answer createTemplateFromVolume(CopyCommand cmd) { Ternary result = createTemplateFromVolume(vmMo, template.getPath(), template.getId(), template.getName(), secondaryStoragePoolURL, volumePath, - hostService.getWorkerName(context, cmd, 0), _imageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); + hostService.getWorkerName(context, cmd, 0), imageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(result.first()); @@ -1038,7 +1038,7 @@ public Answer createTemplateFromSnapshot(CopyCommand cmd) { NfsTO nfsSvr = (NfsTO)imageStore; Ternary result = createTemplateFromSnapshot(template.getPath(), uniqeName, nfsSvr.getUrl(), snapshot.getPath(), template.getId(), (long)cmd.getWait() * 1000, - _imageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); + imageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(result.first()); @@ -1181,7 +1181,7 @@ public Answer backupSnapshot(CopyCommand cmd) { throw new Exception("Failed to take snapshot " + srcSnapshot.getName() + " on vm: " + vmName); } - String nfsVersion = _imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid()); + String nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid()); backupResult = backupSnapshotToSecondaryStorage(vmMo, destSnapshot.getPath(), srcSnapshot.getVolume().getPath(), snapshotUuid, secondaryStorageUrl, prevSnapshotUuid, prevBackupUuid, hostService.getWorkerName(context, cmd, 1), nfsVersion); @@ -2258,7 +2258,7 @@ public Answer createVolumeFromSnapshot(CopyCommand cmd) { backedUpSnapshotUuid = backedUpSnapshotUuid.replace(".ovf", ""); } DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs); - restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secondaryStorageUrl, backupPath, backedUpSnapshotUuid, (long)cmd.getWait() * 1000, _imageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); + restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secondaryStorageUrl, backupPath, backedUpSnapshotUuid, (long)cmd.getWait() * 1000, imageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); VolumeObjectTO newVol = new VolumeObjectTO(); newVol.setPath(newVolumeName); diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java index b8544d086f..212c8111bf 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java @@ -20,8 +20,6 @@ import java.io.File; -import javax.inject.Inject; - import org.apache.log4j.Logger; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; @@ -29,6 +27,7 @@ import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.springframework.context.ApplicationContext; import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.DataObjectType; @@ -43,8 +42,7 @@ public class VmwareStorageSubsystemCommandHandler extends StorageSubsystemCommandHandlerBase { - @Inject - ImageStoreDetailsUtil _imageStoreDetailsUtil; + private ImageStoreDetailsUtil imageStoreDetailsUtil; private static final Logger s_logger = Logger.getLogger(VmwareStorageSubsystemCommandHandler.class); private VmwareStorageManager storageManager; @@ -68,6 +66,8 @@ public void setStorageManager(VmwareStorageManager storageManager) { public VmwareStorageSubsystemCommandHandler(StorageProcessor processor) { super(processor); + ApplicationContext applicationContext = com.cloud.utils.component.ComponentContext.getApplicationContext(); + imageStoreDetailsUtil = applicationContext.getBean("imageStoreDetailsUtil", ImageStoreDetailsUtil.class); } @Override @@ -84,7 +84,7 @@ protected Answer execute(CopyCommand cmd) { } } - String nfsVersion = _imageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid()); + String nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid()); if (srcDataStore.getRole() == DataStoreRole.ImageCache && destDataStore.getRole() == DataStoreRole.Image) { //need to take extra processing for vmware, such as packing to ova, before sending to S3 if (srcData.getObjectType() == DataObjectType.VOLUME) { diff --git a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java index c4c48a5dd0..c72d9d44f5 100644 --- a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java +++ b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java @@ -134,7 +134,7 @@ public class VmwareDatacenterApiUnitTest { AccountManager _acctMgr; @Inject - ImageStoreDetailsUtil _imageStoreDetailsUtil; + ImageStoreDetailsUtil imageStoreDetailsUtil; long zoneId; long podId; @@ -230,8 +230,8 @@ public void testSetUp() { Mockito.when(addCmd.getPassword()).thenReturn(password); Mockito.when(addCmd.getName()).thenReturn(vmwareDcName); Mockito.when(removeCmd.getZoneId()).thenReturn(1L); - Mockito.when(_imageStoreDetailsUtil.getNfsVersion(Mockito.anyLong())).thenReturn(null); - Mockito.when(_imageStoreDetailsUtil.getNfsVersionByUuid(Mockito.anyString())).thenReturn(null); + Mockito.when(imageStoreDetailsUtil.getNfsVersion(Mockito.anyLong())).thenReturn(null); + Mockito.when(imageStoreDetailsUtil.getNfsVersionByUuid(Mockito.anyString())).thenReturn(null); } @After diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index b5d6b799d3..6f0c928197 100644 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -199,7 +199,7 @@ public String toString() { @Inject private HostGpuGroupsDao _hostGpuGroupsDao; @Inject - ImageStoreDetailsUtil _imageStoreDetailsUtil; + ImageStoreDetailsUtil imageStoreDetailsUtil; private ConcurrentHashMap _hostStats = new ConcurrentHashMap(); private final ConcurrentHashMap _VmStats = new ConcurrentHashMap(); @@ -717,7 +717,7 @@ protected void runInContext() { continue; } - GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO(), _imageStoreDetailsUtil.getNfsVersion(store.getId())); + GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO(), imageStoreDetailsUtil.getNfsVersion(store.getId())); EndPoint ssAhost = _epSelector.select(store); if (ssAhost == null) { s_logger.debug("There is no secondary storage VM for secondary storage host " + store.getName()); diff --git a/server/src/com/cloud/storage/ImageStoreDetailsUtil.java b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java index 201fdb4866..4ce0bd7271 100755 --- a/server/src/com/cloud/storage/ImageStoreDetailsUtil.java +++ b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java @@ -16,10 +16,22 @@ // under the License. package com.cloud.storage; -import com.cloud.utils.component.Manager; +import java.util.Map; +import javax.inject.Inject; -public interface ImageStoreDetailsUtil extends Manager { +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; +import org.springframework.stereotype.Component; + +@Component +public class ImageStoreDetailsUtil { + + @Inject + protected ImageStoreDao imageStoreDao; + @Inject + protected ImageStoreDetailsDao imageStoreDetailsDao; /** * Obtain NFS protocol version (if provided) for a store id.
@@ -28,7 +40,16 @@ public interface ImageStoreDetailsUtil extends Manager { * @return {@code null} if {@code nfs.version} is not found for storeId
* {@code X} if {@code nfs.version} is found found for storeId */ - public String getNfsVersion(long storeId); + public String getNfsVersion(long storeId) { + String nfsVersion = null; + if (imageStoreDetailsDao.getDetails(storeId) != null){ + Map storeDetails = imageStoreDetailsDao.getDetails(storeId); + if (storeDetails != null && storeDetails.containsKey("nfs.version")){ + nfsVersion = storeDetails.get("nfs.version"); + } + } + return nfsVersion; + } /** * Obtain NFS protocol version (if provided) for a store uuid.
@@ -37,5 +58,12 @@ public interface ImageStoreDetailsUtil extends Manager { * @return {@code null} if {@code nfs.version} is not found for storeUuid
* {@code X} if {@code nfs.version} is found found for storeUuid */ - public String getNfsVersionByUuid(String storeUuid); + public String getNfsVersionByUuid(String storeUuid){ + ImageStoreVO imageStore = imageStoreDao.findByUuid(storeUuid); + if (imageStore != null){ + return getNfsVersion(imageStore.getId()); + } + return null; + } + } diff --git a/server/src/com/cloud/storage/ImageStoreDetailsUtilImpl.java b/server/src/com/cloud/storage/ImageStoreDetailsUtilImpl.java deleted file mode 100755 index d0207ba131..0000000000 --- a/server/src/com/cloud/storage/ImageStoreDetailsUtilImpl.java +++ /dev/null @@ -1,97 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package com.cloud.storage; - -import java.util.Map; - -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; -import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; -import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; -import org.springframework.stereotype.Component; - -@Component -public class ImageStoreDetailsUtilImpl implements ImageStoreDetailsUtil { - - @Inject - private ImageStoreDao imageStoreDao; - @Inject - private ImageStoreDetailsDao imageStoreDetailsDao; - - public String getNfsVersion(long storeId) { - String nfsVersion = null; - if (imageStoreDetailsDao.getDetails(storeId) != null){ - Map storeDetails = imageStoreDetailsDao.getDetails(storeId); - if (storeDetails != null && storeDetails.containsKey("nfs.version")){ - nfsVersion = storeDetails.get("nfs.version"); - } - } - return nfsVersion; - } - - public String getNfsVersionByUuid(String storeUuid){ - ImageStoreVO imageStore = imageStoreDao.findByUuid(storeUuid); - if (imageStore != null){ - return getNfsVersion(imageStore.getId()); - } - return null; - } - - @Override - public String getName() { - return null; - } - - @Override - public void setName(String name) { - } - - @Override - public void setConfigParams(Map params) { - } - - @Override - public Map getConfigParams() { - return null; - } - - @Override - public int getRunLevel() { - return 0; - } - - @Override - public void setRunLevel(int level) { - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - return false; - } - - @Override - public boolean start() { - return true; - } - - @Override - public boolean stop() { - return false; - } -} diff --git a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java index ba17b552ee..c1445ad944 100644 --- a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java @@ -241,7 +241,7 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar @Inject VolumeDataStoreDao _volumeStoreDao; @Inject - ImageStoreDetailsUtil _imageStoreDetailsUtil; + ImageStoreDetailsUtil imageStoreDetailsUtil; private long _capacityScanInterval = DEFAULT_CAPACITY_SCAN_INTERVAL; private int _secStorageVmMtuSize; @@ -313,7 +313,7 @@ public boolean generateSetupCommand(Long ssHostId) { setupCmd = new SecStorageSetupCommand(ssStore.getTO(), secUrl, certs); } - setupCmd.setNfsVersion(_imageStoreDetailsUtil.getNfsVersion(ssStore.getId())); + setupCmd.setNfsVersion(imageStoreDetailsUtil.getNfsVersion(ssStore.getId())); //template/volume file upload key String postUploadKey = _configDao.getValue(Config.SSVMPSK.key()); diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index bae66b62c5..25a987844a 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -146,7 +146,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ServerResourceBase; import com.cloud.storage.DataStoreRole; -import com.cloud.storage.ImageStoreDetailsUtilImpl; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.VMTemplateStorageResourceAssoc; @@ -175,7 +175,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements SecondaryStorageResource { @Inject - ImageStoreDetailsUtilImpl _imageStoreDetailsUtil; + ImageStoreDetailsUtil _imageStoreDetailsUtil; private static final Logger s_logger = Logger.getLogger(NfsSecondaryStorageResource.class); diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java index c6f2ac8406..6fb2aa239a 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java @@ -38,7 +38,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.cloudstack.storage.command.DownloadCommand; @@ -47,6 +46,7 @@ import org.apache.cloudstack.storage.command.DownloadProgressCommand.RequestType; import org.apache.cloudstack.storage.resource.SecondaryStorageResource; import org.apache.log4j.Logger; +import org.springframework.context.ApplicationContext; import com.cloud.agent.api.storage.DownloadAnswer; import com.cloud.utils.net.Proxy; @@ -54,7 +54,7 @@ import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.S3TO; import com.cloud.exception.InternalErrorException; -import com.cloud.storage.ImageStoreDetailsUtilImpl; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.VMTemplateHostVO; @@ -91,8 +91,7 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager StorageLayer _storage; public Map _processors; - @Inject - ImageStoreDetailsUtilImpl _imageStoreDetailsUtil; + private ImageStoreDetailsUtil imageStoreDetailsUtil; public class Completion implements DownloadCompleteCallback { private final String jobId; @@ -713,7 +712,7 @@ public DownloadAnswer handleDownloadCommand(SecondaryStorageResource resource, D String installPathPrefix = cmd.getInstallPath(); // for NFS, we need to get mounted path if (dstore instanceof NfsTO) { - installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())) + File.separator + installPathPrefix; + installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl(), imageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())) + File.separator + installPathPrefix; } String user = null; String password = null; @@ -955,6 +954,8 @@ public boolean drain() { } public DownloadManagerImpl() { + ApplicationContext applicationContext = com.cloud.utils.component.ComponentContext.getApplicationContext(); + imageStoreDetailsUtil = applicationContext.getBean("imageStoreDetailsUtil", ImageStoreDetailsUtil.class); } @Override From 068fceae95c620c1b86e27a64aa20b5137744808 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Wed, 3 Feb 2016 07:09:08 -0800 Subject: [PATCH 051/203] CLOUDSTACK-9252: Add unit tests --- .../storage/ImageStoreDetailsUtilTest.java | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100755 server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java diff --git a/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java b/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java new file mode 100755 index 0000000000..e588029eb9 --- /dev/null +++ b/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java @@ -0,0 +1,79 @@ +package com.cloud.storage; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; +import org.junit.Before; +import org.junit.Test; + +public class ImageStoreDetailsUtilTest { + + private final static long STORE_ID = 1l; + private final static String STORE_UUID = "aaaa-aaaa-aaaa-aaaa"; + private final static String NFS_VERSION = "3"; + + ImageStoreDetailsUtil imageStoreDetailsUtil = new ImageStoreDetailsUtil(); + + ImageStoreDao imgStoreDao = mock(ImageStoreDao.class); + ImageStoreDetailsDao imgStoreDetailsDao = mock(ImageStoreDetailsDao.class); + + @Before + public void setup() throws Exception { + Map imgStoreDetails = new HashMap(); + imgStoreDetails.put("nfs.version", NFS_VERSION); + when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails); + + ImageStoreVO imgStoreVO = mock(ImageStoreVO.class); + when(imgStoreVO.getId()).thenReturn(Long.valueOf(STORE_ID)); + when(imgStoreDao.findByUuid(STORE_UUID)).thenReturn(imgStoreVO); + + imageStoreDetailsUtil.imageStoreDao = imgStoreDao; + imageStoreDetailsUtil.imageStoreDetailsDao = imgStoreDetailsDao; + } + + @Test + public void testGetNfsVersion(){ + String nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); + assertEquals(NFS_VERSION, nfsVersion); + } + + @Test + public void testGetNfsVersionNotFound(){ + Map imgStoreDetails = new HashMap(); + imgStoreDetails.put("other.prop", "propValue"); + when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails); + + String nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); + assertNull(nfsVersion); + } + + @Test + public void testGetNfsVersionNoDetails(){ + Map imgStoreDetails = new HashMap(); + when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails); + + String nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); + assertNull(nfsVersion); + } + + @Test + public void testGetNfsVersionByUuid(){ + String nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(STORE_UUID); + assertEquals(NFS_VERSION, nfsVersion); + } + + @Test + public void testGetNfsVersionByUuidNoImgStore(){ + when(imgStoreDao.findByUuid(STORE_UUID)).thenReturn(null); + String nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(STORE_UUID); + assertNull(nfsVersion); + } +} \ No newline at end of file From 94281f952d910b789c09028490479ea544afcf88 Mon Sep 17 00:00:00 2001 From: shweta agarwal Date: Thu, 4 Feb 2016 16:57:08 +0530 Subject: [PATCH 052/203] added suggested changes to coreos automation --- test/integration/component/test_coreos.py | 5 +++-- tools/marvin/marvin/config/test_data.py | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/integration/component/test_coreos.py b/test/integration/component/test_coreos.py index ad1c1ab6b7..a56d7c259b 100644 --- a/test/integration/component/test_coreos.py +++ b/test/integration/component/test_coreos.py @@ -114,7 +114,7 @@ def tearDownClass(cls): raise Exception("Warning: Exception during cleanup : %s" % e) return - @attr(tags=["advanced"], required_hardware="true") + @attr(tags=["advanced","tt"], required_hardware="true") def test1_coreos_VM_creation(self): self.hypervisor = str(get_hypervisor_type(self.api_client)).lower() @@ -226,7 +226,7 @@ def test1_coreos_VM_creation(self): ) else: list_router_response = list_routers( - self.api_Client, + self.api_client, account=self.account.name, domainid=self.account.domainid ) @@ -287,5 +287,6 @@ def test1_coreos_VM_creation(self): res.__contains__("name: docker.service"), True, "Userdata Not applied Check the failures") + self.account.delete(self.api_client) return diff --git a/tools/marvin/marvin/config/test_data.py b/tools/marvin/marvin/config/test_data.py index 0a7c4d218b..08dc91853c 100644 --- a/tools/marvin/marvin/config/test_data.py +++ b/tools/marvin/marvin/config/test_data.py @@ -789,8 +789,7 @@ "name": "coreos", "passwordenabled": False, "ostype": "Coreos", - "urlvmware":"http://dl.openvm.eu/cloudstack/coreos/x86_64/" \ - "coreos_production_cloudstack_image-vmware.vmdk.bz2", + "urlvmware":"http://10.147.28.7/templates/coreos/coreos_production_vmware.ova", "urlxen":"http://dl.openvm.eu/cloudstack/coreos/x86_64/" "coreos_production_cloudstack_image-xen.vhd.bz2", "urlkvm": "http://dl.openvm.eu/cloudstack/coreos/x86_64/" \ From c5677cf634c66d1bc85ae8dbb3a8b50fb8823969 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Thu, 4 Feb 2016 09:50:25 -0800 Subject: [PATCH 053/203] CLOUDSTACK-9252: Mock application context for unit test --- .../vmware/manager/VmwareManagerImpl.java | 7 ++-- .../vmware/VmwareDatacenterApiUnitTest.java | 32 ++++++------------- 2 files changed, 15 insertions(+), 24 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 71383c3333..a477437612 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -112,6 +112,7 @@ import com.cloud.utils.FileUtil; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; +import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; @@ -200,10 +201,12 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw private final ScheduledExecutorService _hostScanScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Vmware-Host-Scan")); + private ApplicationContext applicationContext; + public VmwareManagerImpl() { - _storageMgr = new VmwareStorageManagerImpl(this); - ApplicationContext applicationContext = com.cloud.utils.component.ComponentContext.getApplicationContext(); + applicationContext = ComponentContext.getApplicationContext(); imageStoreDetailsUtil = applicationContext.getBean("imageStoreDetailsUtil", ImageStoreDetailsUtil.class); + _storageMgr = new VmwareStorageManagerImpl(this); } @Override diff --git a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java index c72d9d44f5..0f056ee5b2 100644 --- a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java +++ b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java @@ -38,6 +38,8 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; @@ -54,8 +56,6 @@ import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; -import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.test.utils.SpringUtils; import com.cloud.agent.AgentManager; @@ -101,6 +101,7 @@ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class) +@PrepareForTest({ComponentContext.class, ApplicationContext.class}) public class VmwareDatacenterApiUnitTest { @Inject @@ -133,9 +134,6 @@ public class VmwareDatacenterApiUnitTest { @Inject AccountManager _acctMgr; - @Inject - ImageStoreDetailsUtil imageStoreDetailsUtil; - long zoneId; long podId; long clusterId; @@ -163,6 +161,13 @@ public class VmwareDatacenterApiUnitTest { @BeforeClass public static void setUp() throws ConfigurationException { + ComponentContext ctx = new ComponentContext(); + ImageStoreDetailsUtil imgSDUtil = Mockito.mock(ImageStoreDetailsUtil.class); + Mockito.when(imgSDUtil.getNfsVersion(Mockito.anyLong())).thenReturn("3"); + Mockito.when(imgSDUtil.getNfsVersionByUuid(Mockito.anyString())).thenReturn("3"); + ApplicationContext appCtx = Mockito.mock(ApplicationContext.class); + Mockito.when(appCtx.getBean(Mockito.anyString(), Mockito.any(ImageStoreDetailsUtil.class))).thenReturn(imgSDUtil); + ctx.setApplicationContext(appCtx); } @Before @@ -230,8 +235,6 @@ public void testSetUp() { Mockito.when(addCmd.getPassword()).thenReturn(password); Mockito.when(addCmd.getName()).thenReturn(vmwareDcName); Mockito.when(removeCmd.getZoneId()).thenReturn(1L); - Mockito.when(imageStoreDetailsUtil.getNfsVersion(Mockito.anyLong())).thenReturn(null); - Mockito.when(imageStoreDetailsUtil.getNfsVersionByUuid(Mockito.anyString())).thenReturn(null); } @After @@ -439,21 +442,6 @@ public DataStoreManager dataStoreManager() { return Mockito.mock(DataStoreManager.class); } - @Bean - public ImageStoreDetailsUtil imageStoreDetailsUtil() { - return Mockito.mock(ImageStoreDetailsUtil.class); - } - - @Bean - public ImageStoreDao imageStoreDao() { - return Mockito.mock(ImageStoreDao.class); - } - - @Bean - public ImageStoreDetailsDao imageStoreDetailsDao() { - return Mockito.mock(ImageStoreDetailsDao.class); - } - public static class Library implements TypeFilter { @Override From 64c6debf0046e26dde81e915bb23a85fa3eae250 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Fri, 5 Feb 2016 06:22:23 -0800 Subject: [PATCH 054/203] CLOUDSTACK-9252: Little refactor --- .../spring-engine-storage-image-core-context.xml | 2 -- .../core/spring-engine-storage-core-context.xml | 2 ++ .../vmware/manager/VmwareManagerImpl.java | 4 +--- .../resource/NfsSecondaryStorageResource.java | 13 ------------- 4 files changed, 3 insertions(+), 18 deletions(-) diff --git a/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml b/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml index 2441d1c56f..51be9d99fa 100644 --- a/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml +++ b/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml @@ -38,8 +38,6 @@ class="org.apache.cloudstack.storage.image.datastore.ImageStoreHelper" /> - diff --git a/engine/storage/resources/META-INF/cloudstack/core/spring-engine-storage-core-context.xml b/engine/storage/resources/META-INF/cloudstack/core/spring-engine-storage-core-context.xml index 8040d801b3..a45e4ee3e4 100644 --- a/engine/storage/resources/META-INF/cloudstack/core/spring-engine-storage-core-context.xml +++ b/engine/storage/resources/META-INF/cloudstack/core/spring-engine-storage-core-context.xml @@ -69,5 +69,7 @@ + + 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 a477437612..a938d38f78 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -201,10 +201,8 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw private final ScheduledExecutorService _hostScanScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Vmware-Host-Scan")); - private ApplicationContext applicationContext; - public VmwareManagerImpl() { - applicationContext = ComponentContext.getApplicationContext(); + ApplicationContext applicationContext = ComponentContext.getApplicationContext(); imageStoreDetailsUtil = applicationContext.getBean("imageStoreDetailsUtil", ImageStoreDetailsUtil.class); _storageMgr = new VmwareStorageManagerImpl(this); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index 25a987844a..0fa2b54901 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -96,7 +96,6 @@ import org.apache.cloudstack.storage.command.UploadStatusAnswer.UploadStatus; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; -import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.command.UploadStatusCommand; import org.apache.cloudstack.storage.template.DownloadManager; import org.apache.cloudstack.storage.template.DownloadManagerImpl; @@ -229,8 +228,6 @@ public void setTimeout(int timeout) { @Inject ImageStoreDetailsDao detailsStoreDao; - public static final String IMAGE_STORE_PARAMETER_ID = "imageStoreId"; - public void setParentPath(String path) { _parent = path; } @@ -1316,16 +1313,6 @@ private void configCerts(KeystoreManager.Certificates certs) { } } - private Long getImageStoreId(DataStoreTO dataStore){ - Long imgStoreId = null; - if (dataStore.getRole().equals(DataStoreRole.Image)){ - String uuid = dataStore.getUuid(); - ImageStoreVO imageStoreVO = dataStoreDao.findByUuid(uuid); - imgStoreId = imageStoreVO.getId(); - } - return imgStoreId; - } - private Answer execute(SecStorageSetupCommand cmd) { if (!_inSystemVM) { return new Answer(cmd, true, null); From 5c0728a792de5f9707a3c1740b067839faf1252f Mon Sep 17 00:00:00 2001 From: nvazquez Date: Fri, 5 Feb 2016 08:33:54 -0800 Subject: [PATCH 055/203] CLOUDSTACK-9252: Add missing licence header --- .../cloud/storage/ImageStoreDetailsUtilTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java b/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java index e588029eb9..026a7d346d 100755 --- a/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java +++ b/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java @@ -1,3 +1,19 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. package com.cloud.storage; import static org.junit.Assert.assertEquals; From 3d9919ecfb6c13cfff2798b2d1731b717dd17eca Mon Sep 17 00:00:00 2001 From: Remi Bergsma Date: Wed, 10 Feb 2016 10:28:18 +0100 Subject: [PATCH 056/203] Revert "Merge pull request #1011 from shwetaag/coreos" This reverts commit 56859c99041c66d417bf0af9a93b1d6e1e79005b, reversing changes made to cd71e05b1ef5fcae018f35dec30abbec1ea012f1. --- test/integration/component/test_coreos.py | 292 ---------------------- tools/marvin/marvin/config/test_data.py | 12 - tools/marvin/marvin/lib/base.py | 8 +- 3 files changed, 1 insertion(+), 311 deletions(-) delete mode 100644 test/integration/component/test_coreos.py diff --git a/test/integration/component/test_coreos.py b/test/integration/component/test_coreos.py deleted file mode 100644 index a56d7c259b..0000000000 --- a/test/integration/component/test_coreos.py +++ /dev/null @@ -1,292 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -""" P1 tests for coreos template and vm -""" - -from marvin.lib.base import ( - VirtualMachine, - ServiceOffering, - Account, - SSHKeyPair, - Host, Template) -from marvin.lib.common import ( - get_zone, - get_template, - list_routers) -from marvin.lib.utils import ( - cleanup_resources, - get_hypervisor_type, - get_process_status) -from marvin.cloudstackTestCase import cloudstackTestCase -# Import System modules -import tempfile -import time -import os -import base64 -from nose.plugins.attrib import attr -from marvin.sshClient import SshClient - - -class TestDeployVmWithCoreosTemplate(cloudstackTestCase): - """Tests for deploying VM using coreos template - """ - - @classmethod - def setUpClass(cls): - cls._cleanup = [] - cls.testClient = super( - TestDeployVmWithCoreosTemplate, - cls).getClsTestClient() - cls.api_client = cls.testClient.getApiClient() - cls.services = cls.testClient.getParsedTestDataConfig() - cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) - cls.service_offering = ServiceOffering.create( - cls.api_client, services=cls.services["service_offerings"]["medium"]) - cls.account = Account.create( - cls.api_client, services=cls.services["account"]) - cls.cleanup = [cls.account] - cls.template = get_template( - cls.api_client, - cls.zone.id, - cls.services["ostype"] - ) - cls.services["coreos"][ - "hypervisor"] = cls.testClient.getHypervisorInfo() - cls.userdata = '#cloud-config\n\ncoreos:\n units:\n - name: docker.service\n command: start\n ' \ - '- name: web.service\n command: start\n content: |\n [Unit]\n ' \ - 'After=docker.service\n Requires=docker.service\n Description=Starts web server ' \ - 'container\n [Service]\n TimeoutStartSec=0\n ' \ - 'ExecStartPre=/usr/bin/docker pull httpd:2.4\n ' \ - 'ExecStart=/usr/bin/docker run -d -p 8000:80 httpd:2.4' - cls.services["virtual_machine"]["userdata"] = cls.userdata - - cls.keypair = SSHKeyPair.create( - cls.api_client, - name="coreos", - account=cls.account.name, - domainid=cls.account.domainid - ) - cls.debug("Created a new keypair with name: %s" % cls.keypair.name) - - cls.debug("Writing the private key to local file") - cls.keyPairFilePath = tempfile.gettempdir() + os.sep + cls.keypair.name - # Clenaup at end of execution - cls.cleanup.append(cls.keyPairFilePath) - - cls.debug("File path: %s" % cls.keyPairFilePath) - - f = open(cls.keyPairFilePath, "w+") - f.write(cls.keypair.privatekey) - f.close() - os.system("chmod 400 " + cls.keyPairFilePath) - cls.mgtSvrDetails = cls.config.__dict__["mgtSvr"][0].__dict__ - return - - def setUp(self): - self.api_client = self.testClient.getApiClient() - return - - def tearDown(self): - # Clean up, terminate the created volumes - cleanup_resources(self.api_client, self.cleanup) - return - - @classmethod - def tearDownClass(cls): - try: - cleanup_resources(cls.api_client, cls._cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return - - @attr(tags=["advanced","tt"], required_hardware="true") - def test1_coreos_VM_creation(self): - - self.hypervisor = str(get_hypervisor_type(self.api_client)).lower() - self.services["virtual_machine"][ - "hypervisor"] = self.hypervisor.upper() - if self.hypervisor == "vmware": - self.services["coreos"][ - "url"] = self.services["coreos"]["urlvmware"] - self.services["coreos"]["format"] = "OVA" - elif self.hypervisor == "xenserver": - self.services["coreos"][ - "url"] = self.services["coreos"]["urlxen"] - self.services["coreos"]["format"] = "VHD" - elif self.hypervisor == "kvm": - self.services["coreos"][ - "url"] = self.services["coreos"]["urlkvm"] - self.services["coreos"]["format"] = "QCOW2" - elif self.hypervisor == "hyperv": - self.services["coreos"][ - "url"] = self.services["coreos"]["urlxen"] - self.services["coreos"]["format"] = "VHD" - - template_created = Template.register( - self.api_client, - self.services["coreos"], - self.zone.id, - account=self.account.name, - domainid=self.account.domainid) - self.assertIsNotNone(template_created, "Template creation failed") - # Wait for template to download - template_created.download(self.api_client) - self.cleanup.append(template_created) - # Wait for template status to be changed across - time.sleep(self.services["sleep"]) - - self.debug("Deploying instance in the account: %s" % self.account.name) - - virtual_machine = VirtualMachine.create( - self.api_client, - self.services["virtual_machine"], - templateid=template_created.id, - accountid=self.account.name, - domainid=self.account.domainid, - zoneid=self.zone.id, - serviceofferingid=self.service_offering.id, - keypair=self.keypair.name, - hypervisor=self.hypervisor, - mode=self.zone.networktype, - method="POST" - - ) - - self.debug("Check if the VM is properly deployed or not?") - vms = VirtualMachine.list( - self.api_client, - id=virtual_machine.id, - listall=True - ) - self.assertEqual( - isinstance(vms, list), - True, - "List VMs should return the valid list" - ) - vm = vms[0] - self.assertEqual( - vm.state, - "Running", - "VM state should be running after deployment" - ) - virtual_machine.stop(self.api_client) - virtual_machine.update( - self.api_client, - userdata=base64.b64encode( - self.userdata)) - virtual_machine.start(self.api_client) - self.assertEqual( - vm.state, - "Running", - "VM state should be running" - ) - # Wait for docker service to start - time.sleep(300) - - # Should be able to SSH VM - try: - - self.debug("SSH into VM: %s" % virtual_machine.ssh_ip) - cmd = "docker ps" - ssh = SshClient(virtual_machine.ssh_ip, 22, "core", - "", keyPairFiles=self.keyPairFilePath) - result = ssh.execute(cmd) - - except Exception as e: - self.fail( - "SSH Access failed for %s: %s" % - (virtual_machine.ssh_ip, e) - ) - - res = str(result) - self.assertEqual( - res.__contains__("httpd"), - True, - "docker web service not started in coreos vm ") - - if self.zone.networktype == "Basic": - list_router_response = list_routers( - self.api_client, - listall="true" - ) - else: - list_router_response = list_routers( - self.api_client, - account=self.account.name, - domainid=self.account.domainid - ) - - self.assertEqual( - isinstance(list_router_response, list), - True, - "Check list response returns a valid list" - ) - router = list_router_response[0] - hosts = Host.list(self.api_client, id=router.hostid) - self.assertEqual( - isinstance(hosts, list), - True, - "Check list host returns a valid list" - ) - host = hosts[0] - self.debug("Router ID: %s, state: %s" % (router.id, router.state)) - - self.assertEqual( - router.state, - 'Running', - "Check list router response for router state" - ) - cmd = "cat /var/www/html/userdata/" + virtual_machine.ipaddress + "/user-data" - - if self.hypervisor.lower() in ('vmware', 'hyperv'): - - try: - result = get_process_status( - self.api_client.connection.mgtSvr, - 22, - self.api_client.connection.user, - self.api_client.connection.passwd, - router.linklocalip, - cmd, - hypervisor=self.hypervisor - ) - - except KeyError: - self.skipTest( - "Marvin configuration has no host credentials to check USERDATA") - - else: - try: - result = get_process_status( - host.ipaddress, - 22, - self.services["configurableData"]["host"]["username"], - self.services["configurableData"]["host"]["password"], - router.linklocalip, cmd - ) - except KeyError: - self.skipTest( - "Marvin configuration has no host credentials to check router user data") - res = str(result) - self.assertEqual( - res.__contains__("name: docker.service"), - True, - "Userdata Not applied Check the failures") - self.account.delete(self.api_client) - - return diff --git a/tools/marvin/marvin/config/test_data.py b/tools/marvin/marvin/config/test_data.py index 4e9fa3369f..3d4745d0cd 100644 --- a/tools/marvin/marvin/config/test_data.py +++ b/tools/marvin/marvin/config/test_data.py @@ -790,18 +790,6 @@ "format": "OVA", "ispublic": "true" }, - "coreos": { - "displaytext": "coreos", - "name": "coreos", - "passwordenabled": False, - "ostype": "Coreos", - "urlvmware":"http://10.147.28.7/templates/coreos/coreos_production_vmware.ova", - "urlxen":"http://dl.openvm.eu/cloudstack/coreos/x86_64/" - "coreos_production_cloudstack_image-xen.vhd.bz2", - "urlkvm": "http://dl.openvm.eu/cloudstack/coreos/x86_64/" \ - "coreos_production_cloudstack_image-kvm.qcow2.bz2", - "urlhyperv":"http://dl.openvm.eu/cloudstack/coreos/x86_64/coreos_production_cloudstack_image-hyperv.vhd.zip" - }, "template_2": { "displaytext": "Public Template", "name": "Public template", diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index 88fef4d0c0..0be8909af3 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -551,7 +551,7 @@ def restore(self, apiclient, templateid=None): def get_ssh_client( self, ipaddress=None, reconnect=False, port=None, - keyPairFileLocation=None,username=None,password=None, retries=20): + keyPairFileLocation=None, retries=20): """Get SSH object of VM""" # If NAT Rules are not created while VM deployment in Advanced mode @@ -564,12 +564,6 @@ def get_ssh_client( if keyPairFileLocation is not None: self.password = None - if username is not None: - self.username=username - - if password is not None: - self.password=password - if reconnect: self.ssh_client = is_server_ssh_ready( self.ssh_ip, From f8c2c955e665b32d7ae972450d77e6f6714833fc Mon Sep 17 00:00:00 2001 From: Priti Sarap Date: Wed, 9 Dec 2015 15:04:50 +0530 Subject: [PATCH 057/203] CLOUDSTACK-9128: Testcase to verify if snapshot_store_ref table stores actual size of back snapshot in secondary storage --- .../testpaths/testpath_snapshot_limits.py | 135 +++++++++++++++++- 1 file changed, 132 insertions(+), 3 deletions(-) diff --git a/test/integration/testpaths/testpath_snapshot_limits.py b/test/integration/testpaths/testpath_snapshot_limits.py index 855d3a21a1..7a27febe61 100644 --- a/test/integration/testpaths/testpath_snapshot_limits.py +++ b/test/integration/testpaths/testpath_snapshot_limits.py @@ -31,10 +31,13 @@ ) from marvin.lib.common import (get_domain, get_zone, - get_template + get_template, + createChecksum, + list_volumes ) -from marvin.codes import (BACKED_UP, PASS, FAIL) +from marvin.codes import (BACKED_UP, PASS, FAIL, ROOT) +import time class TestStorageSnapshotsLimits(cloudstackTestCase): @@ -99,6 +102,7 @@ def setUpClass(cls): domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, zoneid=cls.zone.id, + mode=cls.zone.networktype ) except Exception as e: @@ -137,7 +141,6 @@ def tearDown(self): PASS, "DATA Volume List Validation Failed") - if data_volumes_list: self.vm.detach_volume( self.userapiclient, data_volumes_list[0] @@ -359,3 +362,129 @@ def test_01_storage_snapshots_limits(self): ) return + + @attr(tags=["advanced", "basic"], required_hardware="true") + def test_02_snapshot_size_check(self): + """ Check Snapshots size in database + 1. Create file on ROOT disk of deployed VM. + 2. Create Snapshot of ROOT disk. + 3. Check if physiacal_size parameter of snapshot_store_ref table + has physical size of snapshot + """ + if self.hypervisor.lower() not in ["xenserver", "vmware"]: + self.skipTest("Test not to be run on %s" % self.hypervisor) + + root_volumes_list = list_volumes( + self.apiclient, + virtualmachineid=self.vm.id, + type=ROOT, + listall=True + ) + + status = validateList(root_volumes_list) + self.assertEqual( + status[0], + PASS, + "Check listVolumes response for ROOT Disk") + + root_volume = root_volumes_list[0] + + # Get Secondary Storage Value from Database + qryresult_before_snapshot = self.dbclient.execute( + " select id, account_name, secondaryStorageTotal\ + from account_view where account_name = '%s';" % + self.account.name) + + self.assertNotEqual( + len(qryresult_before_snapshot), + 0, + "Check sql query to return SecondaryStorageTotal of account") + + storage_qry_result_old = qryresult_before_snapshot[0] + secondary_storage_old = storage_qry_result_old[2] + + createChecksum( + self.testdata, + self.vm, + root_volume, + "rootdiskdevice") + + time.sleep(30) + + root_vol_snapshot = Snapshot.create( + self.apiclient, + root_volume.id) + + snapshots_list = Snapshot.list(self.apiclient, + id=root_vol_snapshot.id) + + status = validateList(snapshots_list) + self.assertEqual(status[0], PASS, "Check listSnapshots response") + # Verify Snapshot state + self.assertEqual( + snapshots_list[0].state.lower() in [ + BACKED_UP, + ], + True, + "Snapshot state is not as expected. It is %s" % + snapshots_list[0].state + ) + + self.assertEqual( + snapshots_list[0].volumeid, + root_volume.id, + "Snapshot volume id is not matching with the vm's volume id") + + qryresult_snp_id = self.dbclient.execute( + "select id\ + from snapshots where uuid = '%s';" % + snapshots_list[0].id) + + self.assertNotEqual( + len(qryresult_snp_id), + 0, + "Check sql query to return physical size of the snapshot") + + snp_id_result = qryresult_snp_id[0] + snp_id = snp_id_result[0] + + qryresult_physical_size = self.dbclient.execute( + " select id, store_id, physical_size\ + from snapshot_store_ref where snapshot_id = '%s' \ + and store_role='Image';" % + snp_id) + + self.assertNotEqual( + len(qryresult_physical_size), + 0, + "Check sql query to return SecondaryStorageTotal of account") + + snapshot_physical_size_result = qryresult_physical_size[0] + snapshot_physical_size = snapshot_physical_size_result[ + 2] + + # Step 3 + qryresult_after_snapshot = self.dbclient.execute( + " select id, account_name, secondaryStorageTotal\ + from account_view where account_name = '%s';" % + self.account.name) + self.assertNotEqual( + len(qryresult_after_snapshot), + 0, + "Check sql query to return SecondaryStorageTotal of account") + + storage_qry_result_from_database = qryresult_after_snapshot[0] + secondary_storage_new = storage_qry_result_from_database[ + 2] + + secondary_storage_after_snapshot = secondary_storage_new - \ + secondary_storage_old + + self.assertEqual( + snapshot_physical_size, + secondary_storage_after_snapshot, + "Check if physical_size attribute of snapshot_store_ref table \ + stores correct value" + ) + + return From ce180796e9c6f2a1a96d5ae51f8a1ab592c42090 Mon Sep 17 00:00:00 2001 From: David Amorim Faria Date: Wed, 10 Feb 2016 16:46:03 +0100 Subject: [PATCH 058/203] CLOUDSTACK-9283: add pid to java arguments in systemd/cloudstack-usage.service --- packaging/systemd/cloudstack-usage.service | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packaging/systemd/cloudstack-usage.service b/packaging/systemd/cloudstack-usage.service index 9a1827da61..d80aba6f6f 100644 --- a/packaging/systemd/cloudstack-usage.service +++ b/packaging/systemd/cloudstack-usage.service @@ -27,10 +27,11 @@ Environment=JAVA_HOME=/usr/lib/jvm/jre Environment=JAVA_HEAP_INITIAL=256m Environment=JAVA_HEAP_MAX=2048m Environment=JAVA_CLASS=com.cloud.usage.UsageServer +Environment=JAVA_PID=$$ ExecStart=/bin/sh -ec '\ export UCP=`ls /usr/share/cloudstack-usage/cloud-usage-*.jar /usr/share/cloudstack-usage/lib/*.jar | tr "\\n" ":"`; \ export CLASSPATH="$UCP:/etc/cloudstack/usage:/usr/share/java/mysql-connector-java.jar"; \ - ${JAVA_HOME}/bin/java -Xms${JAVA_HEAP_INITIAL} -Xmx${JAVA_HEAP_MAX} -cp "$CLASSPATH" $JAVA_CLASS' + ${JAVA_HOME}/bin/java -Dpid=${JAVA_PID} -Xms${JAVA_HEAP_INITIAL} -Xmx${JAVA_HEAP_MAX} -cp "$CLASSPATH" $JAVA_CLASS' Restart=always RestartSec=10s From 7332e88ec935f7bdcec4e0659dfac88d537d898a Mon Sep 17 00:00:00 2001 From: Remi Bergsma Date: Thu, 11 Feb 2016 20:31:00 +0100 Subject: [PATCH 059/203] Revert "Merge pull request #667 from pritisarap12/CLOUDSTACK-8717-Failed-to-start-instance-after-restoring-the-running-instance" This reverts commit cc8508d808b5c68bb3133e8d6c966c0df1bb9532, reversing changes made to d3dc053b7d0da74b62121379dc7d4c9cf95dbf4e. --- .../testpaths/testpath_restore_vm.py | 211 ------------------ 1 file changed, 211 deletions(-) delete mode 100644 test/integration/testpaths/testpath_restore_vm.py diff --git a/test/integration/testpaths/testpath_restore_vm.py b/test/integration/testpaths/testpath_restore_vm.py deleted file mode 100644 index d73499ad21..0000000000 --- a/test/integration/testpaths/testpath_restore_vm.py +++ /dev/null @@ -1,211 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -""" -Test restore running VM on VMWare with one cluster having 2 Primary Storage -""" - - -from nose.plugins.attrib import attr -from marvin.cloudstackTestCase import cloudstackTestCase -from marvin.lib.utils import cleanup_resources, validateList -from marvin.lib.base import (Account, - ServiceOffering, - VirtualMachine, - StoragePool - ) -from marvin.lib.common import (get_domain, - get_zone, - get_template, - list_volumes, - list_virtual_machines - ) - -from marvin.codes import CLUSTERTAG1, ROOT, PASS -import time - - -class TestRestoreVM(cloudstackTestCase): - - @classmethod - def setUpClass(cls): - testClient = super(TestRestoreVM, cls).getClsTestClient() - cls.apiclient = testClient.getApiClient() - cls.testdata = testClient.getParsedTestDataConfig() - cls.hypervisor = cls.testClient.getHypervisorInfo() - - # Get Zone, Domain and templates - cls.domain = get_domain(cls.apiclient) - cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) - - cls.template = get_template( - cls.apiclient, - cls.zone.id, - cls.testdata["ostype"]) - - cls._cleanup = [] - - try: - cls.skiptest = False - if cls.hypervisor.lower() not in ["vmware"]: - cls.skiptest = True - return - - # Create an account - cls.account = Account.create( - cls.apiclient, - cls.testdata["account"], - domainid=cls.domain.id - ) - cls._cleanup.append(cls.account) - # Create user api client of the account - cls.userapiclient = testClient.getUserApiClient( - UserName=cls.account.name, - DomainName=cls.account.domain - ) - # Create Service offering - cls.service_offering_cwps = ServiceOffering.create( - cls.apiclient, - cls.testdata["service_offering"], - tags=CLUSTERTAG1 - ) - cls._cleanup.append(cls.service_offering_cwps) - except Exception as e: - cls.tearDownClass() - raise e - return - - @classmethod - def tearDownClass(cls): - try: - cleanup_resources(cls.apiclient, cls._cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - - def setUp(self): - - self.cleanup = [] - if self.skiptest: - self.skipTest("This test is to be checked on VMWare only \ - Hence, skip for %s" % self.hypervisor) - - self.apiclient = self.testClient.getApiClient() - self.dbclient = self.testClient.getDbConnection() - - def tearDown(self): - try: - if self.pools: - StoragePool.update( - self.apiclient, - id=self.pools[0].id, - tags="") - - cleanup_resources(self.apiclient, self.cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return - - @attr(tags=["advanced", "basic"], required_hardware="true") - def test_01_recover_VM(self): - """ Test Restore VM on VMWare - 1. Deploy a VM without datadisk - 2. Restore the VM - 3. Verify that VM comes up in Running state - """ - try: - self.pools = StoragePool.list( - self.apiclient, - zoneid=self.zone.id, - scope="CLUSTER") - - status = validateList(self.pools) - - # Step 3 - self.assertEqual( - status[0], - PASS, - "Check: Failed to list cluster wide storage pools") - - if len(self.pools) < 2: - self.skipTest("There must be at atleast two cluster wide\ - storage pools available in the setup") - - except Exception as e: - self.skipTest(e) - - # Adding tags to Storage Pools - cluster_no = 1 - StoragePool.update( - self.apiclient, - id=self.pools[0].id, - tags=[CLUSTERTAG1[:-1] + repr(cluster_no)]) - - self.vm = VirtualMachine.create( - self.apiclient, - self.testdata["small"], - accountid=self.account.name, - templateid=self.template.id, - domainid=self.account.domainid, - serviceofferingid=self.service_offering_cwps.id, - zoneid=self.zone.id, - ) - # Step 2 - - volumes_root_list = list_volumes( - self.apiclient, - virtualmachineid=self.vm.id, - type=ROOT, - listall=True - ) - - root_volume = volumes_root_list[0] - - # Restore VM till its ROOT disk is recreated on onother Primary Storage - while True: - self.vm.restore(self.apiclient) - volumes_root_list = list_volumes( - self.apiclient, - virtualmachineid=self.vm.id, - type=ROOT, - listall=True - ) - - root_volume = volumes_root_list[0] - - if root_volume.storage != self.pools[0].name: - break - - # Step 3 - vm_list = list_virtual_machines( - self.apiclient, - id=self.vm.id) - - state = vm_list[0].state - i = 0 - while(state != "Running"): - vm_list = list_virtual_machines( - self.apiclient, - id=self.vm.id) - - time.sleep(10) - i = i + 1 - state = vm_list[0].state - if i >= 10: - self.fail("Restore VM Failed") - break - - return From 8c7f5ab93d56c2aa0cde194509b728511173f7a9 Mon Sep 17 00:00:00 2001 From: Priti Sarap Date: Fri, 7 Aug 2015 17:57:54 +0530 Subject: [PATCH 060/203] Squashing two commits in to single commit CLOUDSTACK-8717: Failed to start instance after restoring the running instance -Modified code to add tag to aonly one cluster wide SP -Added validateList function -Added code to clear tags in tearDown class --- .../testpaths/testpath_restore_vm.py | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 test/integration/testpaths/testpath_restore_vm.py diff --git a/test/integration/testpaths/testpath_restore_vm.py b/test/integration/testpaths/testpath_restore_vm.py new file mode 100644 index 0000000000..d73499ad21 --- /dev/null +++ b/test/integration/testpaths/testpath_restore_vm.py @@ -0,0 +1,211 @@ +# 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. + +""" +Test restore running VM on VMWare with one cluster having 2 Primary Storage +""" + + +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.lib.utils import cleanup_resources, validateList +from marvin.lib.base import (Account, + ServiceOffering, + VirtualMachine, + StoragePool + ) +from marvin.lib.common import (get_domain, + get_zone, + get_template, + list_volumes, + list_virtual_machines + ) + +from marvin.codes import CLUSTERTAG1, ROOT, PASS +import time + + +class TestRestoreVM(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + testClient = super(TestRestoreVM, cls).getClsTestClient() + cls.apiclient = testClient.getApiClient() + cls.testdata = testClient.getParsedTestDataConfig() + cls.hypervisor = cls.testClient.getHypervisorInfo() + + # Get Zone, Domain and templates + cls.domain = get_domain(cls.apiclient) + cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) + + cls.template = get_template( + cls.apiclient, + cls.zone.id, + cls.testdata["ostype"]) + + cls._cleanup = [] + + try: + cls.skiptest = False + if cls.hypervisor.lower() not in ["vmware"]: + cls.skiptest = True + return + + # Create an account + cls.account = Account.create( + cls.apiclient, + cls.testdata["account"], + domainid=cls.domain.id + ) + cls._cleanup.append(cls.account) + # Create user api client of the account + cls.userapiclient = testClient.getUserApiClient( + UserName=cls.account.name, + DomainName=cls.account.domain + ) + # Create Service offering + cls.service_offering_cwps = ServiceOffering.create( + cls.apiclient, + cls.testdata["service_offering"], + tags=CLUSTERTAG1 + ) + cls._cleanup.append(cls.service_offering_cwps) + except Exception as e: + cls.tearDownClass() + raise e + return + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.apiclient, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + def setUp(self): + + self.cleanup = [] + if self.skiptest: + self.skipTest("This test is to be checked on VMWare only \ + Hence, skip for %s" % self.hypervisor) + + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + + def tearDown(self): + try: + if self.pools: + StoragePool.update( + self.apiclient, + id=self.pools[0].id, + tags="") + + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["advanced", "basic"], required_hardware="true") + def test_01_recover_VM(self): + """ Test Restore VM on VMWare + 1. Deploy a VM without datadisk + 2. Restore the VM + 3. Verify that VM comes up in Running state + """ + try: + self.pools = StoragePool.list( + self.apiclient, + zoneid=self.zone.id, + scope="CLUSTER") + + status = validateList(self.pools) + + # Step 3 + self.assertEqual( + status[0], + PASS, + "Check: Failed to list cluster wide storage pools") + + if len(self.pools) < 2: + self.skipTest("There must be at atleast two cluster wide\ + storage pools available in the setup") + + except Exception as e: + self.skipTest(e) + + # Adding tags to Storage Pools + cluster_no = 1 + StoragePool.update( + self.apiclient, + id=self.pools[0].id, + tags=[CLUSTERTAG1[:-1] + repr(cluster_no)]) + + self.vm = VirtualMachine.create( + self.apiclient, + self.testdata["small"], + accountid=self.account.name, + templateid=self.template.id, + domainid=self.account.domainid, + serviceofferingid=self.service_offering_cwps.id, + zoneid=self.zone.id, + ) + # Step 2 + + volumes_root_list = list_volumes( + self.apiclient, + virtualmachineid=self.vm.id, + type=ROOT, + listall=True + ) + + root_volume = volumes_root_list[0] + + # Restore VM till its ROOT disk is recreated on onother Primary Storage + while True: + self.vm.restore(self.apiclient) + volumes_root_list = list_volumes( + self.apiclient, + virtualmachineid=self.vm.id, + type=ROOT, + listall=True + ) + + root_volume = volumes_root_list[0] + + if root_volume.storage != self.pools[0].name: + break + + # Step 3 + vm_list = list_virtual_machines( + self.apiclient, + id=self.vm.id) + + state = vm_list[0].state + i = 0 + while(state != "Running"): + vm_list = list_virtual_machines( + self.apiclient, + id=self.vm.id) + + time.sleep(10) + i = i + 1 + state = vm_list[0].state + if i >= 10: + self.fail("Restore VM Failed") + break + + return From db3e18df313f1be043e3f1fc920aa4e7c2771afd Mon Sep 17 00:00:00 2001 From: nvazquez Date: Fri, 12 Feb 2016 10:07:32 -0800 Subject: [PATCH 061/203] CLOUDSTACK-9252: Last refactor, passing nfs version to ssvm --- .../vmware/manager/VmwareManagerImpl.java | 5 +-- .../manager/VmwareStorageManagerImpl.java | 16 ++++--- .../vmware/resource/VmwareResource.java | 4 +- .../PremiumSecondaryStorageResource.java | 2 +- ...VmwareSecondaryStorageResourceHandler.java | 8 ++-- .../resource/VmwareStorageProcessor.java | 33 ++++++-------- .../VmwareStorageSubsystemCommandHandler.java | 17 +++---- .../vmware/VmwareDatacenterApiUnitTest.java | 31 +++++++------ .../src/com/cloud/server/StatsCollector.java | 2 +- .../cloud/storage/ImageStoreDetailsUtil.java | 2 - .../SecondaryStorageManagerImpl.java | 5 ++- .../resource/NfsSecondaryStorageResource.java | 45 +++++++------------ .../storage/template/DownloadManagerImpl.java | 9 ++-- 13 files changed, 78 insertions(+), 101 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 a938d38f78..f27e938e73 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -47,7 +47,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.utils.identity.ManagementServerNode; -import org.springframework.context.ApplicationContext; import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; @@ -112,7 +111,6 @@ import com.cloud.utils.FileUtil; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; -import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; @@ -170,6 +168,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw private ManagementServerHostPeerDao _mshostPeerDao; @Inject private ClusterManager _clusterMgr; + @Inject private ImageStoreDetailsUtil imageStoreDetailsUtil; private String _mountParent; @@ -202,8 +201,6 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw private final ScheduledExecutorService _hostScanScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Vmware-Host-Scan")); public VmwareManagerImpl() { - ApplicationContext applicationContext = ComponentContext.getApplicationContext(); - imageStoreDetailsUtil = applicationContext.getBean("imageStoreDetailsUtil", ImageStoreDetailsUtil.class); _storageMgr = new VmwareStorageManagerImpl(this); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index 8d5fc10458..c7c53bacba 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -42,7 +42,6 @@ import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; -import org.springframework.context.ApplicationContext; import com.cloud.agent.api.Answer; import com.cloud.agent.api.BackupSnapshotAnswer; @@ -78,7 +77,6 @@ import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.hypervisor.vmware.util.VmwareHelper; -import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.JavaStorageLayer; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; @@ -95,7 +93,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { - private ImageStoreDetailsUtil imageStoreDetailsUtil; + private String _nfsVersion; @Override public boolean execute(VmwareHostService hostService, CreateEntityDownloadURLCommand cmd) { @@ -141,8 +139,12 @@ public void createOva(String path, String name) { public VmwareStorageManagerImpl(VmwareStorageMount mountService) { assert (mountService != null); _mountService = mountService; - ApplicationContext applicationContext = com.cloud.utils.component.ComponentContext.getApplicationContext(); - imageStoreDetailsUtil = applicationContext.getBean("imageStoreDetailsUtil", ImageStoreDetailsUtil.class); + } + + public VmwareStorageManagerImpl(VmwareStorageMount mountService, String nfsVersion) { + assert (mountService != null); + _mountService = mountService; + _nfsVersion = nfsVersion; } public void configure(Map params) { @@ -163,7 +165,7 @@ public String createOvaForTemplate(TemplateObjectTO template) { String secStorageUrl = nfsStore.getUrl(); assert (secStorageUrl != null); String installPath = template.getPath(); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, imageStoreDetailsUtil.getNfsVersionByUuid(storeTO.getUuid())); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, _nfsVersion); String installFullPath = secondaryMountPoint + "/" + installPath; try { if (installFullPath.endsWith(".ova")) { @@ -201,7 +203,7 @@ public String createOvaForVolume(VolumeObjectTO volume) { String installPath = volume.getPath(); int index = installPath.lastIndexOf(File.separator); String volumeUuid = installPath.substring(index + 1); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, imageStoreDetailsUtil.getNfsVersionByUuid(storeTO.getUuid())); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, _nfsVersion); //The real volume path String volumePath = installPath + File.separator + volumeUuid + ".ova"; String installFullPath = secondaryMountPoint + "/" + installPath; diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 56f929824c..e71425b948 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -5197,8 +5197,8 @@ else if (value != null && value.equalsIgnoreCase("ide")) value = (String)params.get("scripts.timeout"); int timeout = NumbersUtil.parseInt(value, 1440) * 1000; - _storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, _fullCloneFlag, (VmwareStorageMount)mgr, timeout, this, _shutdownWaitMs, null); - storageHandler = new VmwareStorageSubsystemCommandHandler(_storageProcessor); + _storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, _fullCloneFlag, (VmwareStorageMount)mgr, timeout, this, _shutdownWaitMs, null, (String)params.get("nfsVersion")); + storageHandler = new VmwareStorageSubsystemCommandHandler(_storageProcessor, (String)params.get("nfsVersion")); _vrResource = new VirtualRoutingResource(this); if (!_vrResource.configure(name, params)) { diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java index 8e4a0d2a83..1ec4958509 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java @@ -102,7 +102,7 @@ public boolean configure(String name, Map params) throws Configu VmwareSecondaryStorageContextFactory.initFactoryEnvironment(); } - registerHandler(Hypervisor.HypervisorType.VMware, new VmwareSecondaryStorageResourceHandler(this)); + registerHandler(Hypervisor.HypervisorType.VMware, new VmwareSecondaryStorageResourceHandler(this, (String)params.get("nfsVersion"))); return true; } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java index c3f65cbc47..3c4e6340d3 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java @@ -66,13 +66,13 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe * private Map _activeHosts = new HashMap(); */ - public VmwareSecondaryStorageResourceHandler(PremiumSecondaryStorageResource resource) { + public VmwareSecondaryStorageResourceHandler(PremiumSecondaryStorageResource resource, String nfsVersion) { _resource = resource; - _storageMgr = new VmwareStorageManagerImpl(this); + _storageMgr = new VmwareStorageManagerImpl(this, nfsVersion); _gson = GsonHelper.getGsonLogger(); - VmwareStorageProcessor storageProcessor = new VmwareStorageProcessor(this, true, this, resource.getTimeout(), null, null, _resource); - VmwareStorageSubsystemCommandHandler vmwareStorageSubsystemCommandHandler = new VmwareStorageSubsystemCommandHandler(storageProcessor); + VmwareStorageProcessor storageProcessor = new VmwareStorageProcessor(this, true, this, resource.getTimeout(), null, null, _resource, nfsVersion); + VmwareStorageSubsystemCommandHandler vmwareStorageSubsystemCommandHandler = new VmwareStorageSubsystemCommandHandler(storageProcessor, nfsVersion); vmwareStorageSubsystemCommandHandler.setStorageResource(_resource); vmwareStorageSubsystemCommandHandler.setStorageManager(_storageMgr); storageSubsystemHandler = vmwareStorageSubsystemCommandHandler; diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index 660b93bb90..ffa839d459 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -67,7 +67,6 @@ import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; -import org.springframework.context.ApplicationContext; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; @@ -97,7 +96,6 @@ import com.cloud.hypervisor.vmware.util.VmwareHelper; import com.cloud.serializer.GsonHelper; import com.cloud.storage.DataStoreRole; -import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.JavaStorageLayer; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; @@ -112,8 +110,6 @@ public class VmwareStorageProcessor implements StorageProcessor { - private ImageStoreDetailsUtil imageStoreDetailsUtil; - private static final Logger s_logger = Logger.getLogger(VmwareStorageProcessor.class); private static final int DEFAULT_NFS_PORT = 2049; @@ -125,9 +121,10 @@ public class VmwareStorageProcessor implements StorageProcessor { protected Integer _shutdownWaitMs; private final Gson _gson; private final StorageLayer _storage = new JavaStorageLayer(); + private String _nfsVersion; public VmwareStorageProcessor(VmwareHostService hostService, boolean fullCloneFlag, VmwareStorageMount mountService, Integer timeout, VmwareResource resource, - Integer shutdownWaitMs, PremiumSecondaryStorageResource storageResource) { + Integer shutdownWaitMs, PremiumSecondaryStorageResource storageResource, String nfsVersion) { this.hostService = hostService; _fullCloneFlag = fullCloneFlag; this.mountService = mountService; @@ -135,8 +132,7 @@ public VmwareStorageProcessor(VmwareHostService hostService, boolean fullCloneFl this.resource = resource; _shutdownWaitMs = shutdownWaitMs; _gson = GsonHelper.getGsonLogger(); - ApplicationContext applicationContext = com.cloud.utils.component.ComponentContext.getApplicationContext(); - imageStoreDetailsUtil = applicationContext.getBean("imageStoreDetailsUtil", ImageStoreDetailsUtil.class); + _nfsVersion = nfsVersion; } @Override @@ -323,7 +319,7 @@ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { if (managed) { VirtualMachineMO vmMo = copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), - managedStoragePoolRootVolumeName, false, imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); + managedStoragePoolRootVolumeName, false, _nfsVersion); vmMo.unregisterVm(); @@ -340,7 +336,7 @@ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { } else { copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), - templateUuidName, true, imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); + templateUuidName, true, _nfsVersion); } } else { s_logger.info("Template " + templateInfo.second() + " has already been setup, skip the template setup process in primary storage"); @@ -585,8 +581,8 @@ public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd) { } } - Pair result = copyVolumeFromSecStorage(hyperHost, srcVolume.getPath(), new DatastoreMO(context, morDatastore), srcStore.getUrl(), (long)cmd.getWait() * 1000, imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid())); - deleteVolumeDirOnSecondaryStorage(result.first(), srcStore.getUrl(), imageStoreDetailsUtil.getNfsVersionByUuid(uuid)); + Pair result = copyVolumeFromSecStorage(hyperHost, srcVolume.getPath(), new DatastoreMO(context, morDatastore), srcStore.getUrl(), (long)cmd.getWait() * 1000, _nfsVersion); + deleteVolumeDirOnSecondaryStorage(result.first(), srcStore.getUrl(), _nfsVersion); VolumeObjectTO newVolume = new VolumeObjectTO(); newVolume.setPath(result.second()); return new CopyCmdAnswer(newVolume); @@ -643,8 +639,7 @@ private Pair copyVolumeToSecStorage(VmwareHostService hostServic vmMo.createSnapshot(exportName, "Temporary snapshot for copy-volume command", false, false); - exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, destVolumePath, exportName, hostService.getWorkerName(hyperHost.getContext(), cmd, 1), - imageStoreDetailsUtil.getNfsVersionByUuid(cmd.getDestTO().getDataStore().getUuid())); + exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, destVolumePath, exportName, hostService.getWorkerName(hyperHost.getContext(), cmd, 1), _nfsVersion); return new Pair(destVolumePath, exportName); } finally { @@ -846,7 +841,7 @@ public Answer createTemplateFromVolume(CopyCommand cmd) { Ternary result = createTemplateFromVolume(vmMo, template.getPath(), template.getId(), template.getName(), secondaryStoragePoolURL, volumePath, - hostService.getWorkerName(context, cmd, 0), imageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); + hostService.getWorkerName(context, cmd, 0), _nfsVersion); TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(result.first()); @@ -1037,8 +1032,7 @@ public Answer createTemplateFromSnapshot(CopyCommand cmd) { } NfsTO nfsSvr = (NfsTO)imageStore; - Ternary result = createTemplateFromSnapshot(template.getPath(), uniqeName, nfsSvr.getUrl(), snapshot.getPath(), template.getId(), (long)cmd.getWait() * 1000, - imageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); + Ternary result = createTemplateFromSnapshot(template.getPath(), uniqeName, nfsSvr.getUrl(), snapshot.getPath(), template.getId(), (long)cmd.getWait() * 1000, _nfsVersion); TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(result.first()); @@ -1181,10 +1175,9 @@ public Answer backupSnapshot(CopyCommand cmd) { throw new Exception("Failed to take snapshot " + srcSnapshot.getName() + " on vm: " + vmName); } - String nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(destStore.getUuid()); backupResult = backupSnapshotToSecondaryStorage(vmMo, destSnapshot.getPath(), srcSnapshot.getVolume().getPath(), snapshotUuid, secondaryStorageUrl, - prevSnapshotUuid, prevBackupUuid, hostService.getWorkerName(context, cmd, 1), nfsVersion); + prevSnapshotUuid, prevBackupUuid, hostService.getWorkerName(context, cmd, 1), _nfsVersion); snapshotBackupUuid = backupResult.first(); success = (snapshotBackupUuid != null); @@ -1196,7 +1189,7 @@ public Answer backupSnapshot(CopyCommand cmd) { // Get snapshot physical size long physicalSize = 0l; - String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl, nfsVersion); + String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl, _nfsVersion); String snapshotDir = destSnapshot.getPath() + "/" + snapshotBackupUuid; File[] files = new File(secondaryMountPoint + "/" + snapshotDir).listFiles(); if(files != null) { @@ -2258,7 +2251,7 @@ public Answer createVolumeFromSnapshot(CopyCommand cmd) { backedUpSnapshotUuid = backedUpSnapshotUuid.replace(".ovf", ""); } DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs); - restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secondaryStorageUrl, backupPath, backedUpSnapshotUuid, (long)cmd.getWait() * 1000, imageStoreDetailsUtil.getNfsVersionByUuid(imageStore.getUuid())); + restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secondaryStorageUrl, backupPath, backedUpSnapshotUuid, (long)cmd.getWait() * 1000, _nfsVersion); VolumeObjectTO newVol = new VolumeObjectTO(); newVol.setPath(newVolumeName); diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java index 212c8111bf..40fa47b03b 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java @@ -27,7 +27,6 @@ import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; -import org.springframework.context.ApplicationContext; import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.DataObjectType; @@ -38,15 +37,13 @@ import com.cloud.agent.api.to.SwiftTO; import com.cloud.hypervisor.vmware.manager.VmwareStorageManager; import com.cloud.storage.DataStoreRole; -import com.cloud.storage.ImageStoreDetailsUtil; public class VmwareStorageSubsystemCommandHandler extends StorageSubsystemCommandHandlerBase { - private ImageStoreDetailsUtil imageStoreDetailsUtil; - private static final Logger s_logger = Logger.getLogger(VmwareStorageSubsystemCommandHandler.class); private VmwareStorageManager storageManager; private PremiumSecondaryStorageResource storageResource; + private String _nfsVersion; public PremiumSecondaryStorageResource getStorageResource() { return storageResource; @@ -64,10 +61,9 @@ public void setStorageManager(VmwareStorageManager storageManager) { this.storageManager = storageManager; } - public VmwareStorageSubsystemCommandHandler(StorageProcessor processor) { + public VmwareStorageSubsystemCommandHandler(StorageProcessor processor, String nfsVersion) { super(processor); - ApplicationContext applicationContext = com.cloud.utils.component.ComponentContext.getApplicationContext(); - imageStoreDetailsUtil = applicationContext.getBean("imageStoreDetailsUtil", ImageStoreDetailsUtil.class); + this._nfsVersion = nfsVersion; } @Override @@ -84,12 +80,11 @@ protected Answer execute(CopyCommand cmd) { } } - String nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid()); if (srcDataStore.getRole() == DataStoreRole.ImageCache && destDataStore.getRole() == DataStoreRole.Image) { //need to take extra processing for vmware, such as packing to ova, before sending to S3 if (srcData.getObjectType() == DataObjectType.VOLUME) { NfsTO cacheStore = (NfsTO)srcDataStore; - String parentPath = storageResource.getRootDir(cacheStore.getUrl(), nfsVersion); + String parentPath = storageResource.getRootDir(cacheStore.getUrl(), _nfsVersion); VolumeObjectTO vol = (VolumeObjectTO)srcData; String path = vol.getPath(); int index = path.lastIndexOf(File.separator); @@ -102,7 +97,7 @@ protected Answer execute(CopyCommand cmd) { } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT) { // pack ova first // sync snapshot from NFS cache to S3 in NFS migration to S3 case - String parentPath = storageResource.getRootDir(srcDataStore.getUrl(), nfsVersion); + String parentPath = storageResource.getRootDir(srcDataStore.getUrl(), _nfsVersion); SnapshotObjectTO snap = (SnapshotObjectTO)srcData; String path = snap.getPath(); int index = path.lastIndexOf(File.separator); @@ -145,7 +140,7 @@ protected Answer execute(CopyCommand cmd) { return answer; } NfsTO cacheStore = (NfsTO)cmd.getCacheTO().getDataStore(); - String parentPath = storageResource.getRootDir(cacheStore.getUrl(), nfsVersion); + String parentPath = storageResource.getRootDir(cacheStore.getUrl(), _nfsVersion); SnapshotObjectTO newSnapshot = (SnapshotObjectTO)answer.getNewData(); String path = newSnapshot.getPath(); int index = path.lastIndexOf(File.separator); diff --git a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java index 0f056ee5b2..fec2aba40f 100644 --- a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java +++ b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java @@ -25,13 +25,11 @@ import java.util.UUID; import javax.inject.Inject; -import javax.naming.ConfigurationException; import com.cloud.user.User; import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Matchers; @@ -56,6 +54,8 @@ import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.test.utils.SpringUtils; import com.cloud.agent.AgentManager; @@ -159,17 +159,6 @@ public class VmwareDatacenterApiUnitTest { @Mock private static RemoveVmwareDcCmd removeCmd; - @BeforeClass - public static void setUp() throws ConfigurationException { - ComponentContext ctx = new ComponentContext(); - ImageStoreDetailsUtil imgSDUtil = Mockito.mock(ImageStoreDetailsUtil.class); - Mockito.when(imgSDUtil.getNfsVersion(Mockito.anyLong())).thenReturn("3"); - Mockito.when(imgSDUtil.getNfsVersionByUuid(Mockito.anyString())).thenReturn("3"); - ApplicationContext appCtx = Mockito.mock(ApplicationContext.class); - Mockito.when(appCtx.getBean(Mockito.anyString(), Mockito.any(ImageStoreDetailsUtil.class))).thenReturn(imgSDUtil); - ctx.setApplicationContext(appCtx); - } - @Before public void testSetUp() { Mockito.when(_configDao.isPremium()).thenReturn(true); @@ -442,6 +431,22 @@ public DataStoreManager dataStoreManager() { return Mockito.mock(DataStoreManager.class); } + @Bean + public ImageStoreDetailsUtil imageStoreDetailsUtil() { + return Mockito.mock(ImageStoreDetailsUtil.class); + } + + //Mocks for ImageStoreDetailsUtil + @Bean + public ImageStoreDao imageStoreDao() { + return Mockito.mock(ImageStoreDao.class); + } + + @Bean + public ImageStoreDetailsDao imageStoreDetailsDao() { + return Mockito.mock(ImageStoreDetailsDao.class); + } + public static class Library implements TypeFilter { @Override diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index 6f0c928197..0702335308 100644 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -199,7 +199,7 @@ public String toString() { @Inject private HostGpuGroupsDao _hostGpuGroupsDao; @Inject - ImageStoreDetailsUtil imageStoreDetailsUtil; + private ImageStoreDetailsUtil imageStoreDetailsUtil; private ConcurrentHashMap _hostStats = new ConcurrentHashMap(); private final ConcurrentHashMap _VmStats = new ConcurrentHashMap(); diff --git a/server/src/com/cloud/storage/ImageStoreDetailsUtil.java b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java index 4ce0bd7271..63bd5c54d6 100755 --- a/server/src/com/cloud/storage/ImageStoreDetailsUtil.java +++ b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java @@ -23,9 +23,7 @@ import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; -import org.springframework.stereotype.Component; -@Component public class ImageStoreDetailsUtil { @Inject diff --git a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java index c1445ad944..2ff54c8dc9 100644 --- a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java @@ -241,7 +241,7 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar @Inject VolumeDataStoreDao _volumeStoreDao; @Inject - ImageStoreDetailsUtil imageStoreDetailsUtil; + private ImageStoreDetailsUtil imageStoreDetailsUtil; private long _capacityScanInterval = DEFAULT_CAPACITY_SCAN_INTERVAL; private int _secStorageVmMtuSize; @@ -1051,7 +1051,6 @@ private String getSecStorageVmLockName(long id) { @Override public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) { - SecondaryStorageVmVO vm = _secStorageVmDao.findById(profile.getId()); Map details = _vmDetailsDao.listDetailsKeyPairs(vm.getId()); vm.setDetails(details); @@ -1136,6 +1135,8 @@ public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, Depl if (dc.getDns2() != null) { buf.append(" dns2=").append(dc.getDns2()); } + String nfsVersion = imageStoreDetailsUtil != null ? imageStoreDetailsUtil.getNfsVersion(secStore.getId()) : null; + buf.append(" nfsVersion=").append(nfsVersion); String bootArgs = buf.toString(); if (s_logger.isDebugEnabled()) { diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index 0fa2b54901..663699aad2 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -44,7 +44,6 @@ import java.util.Map; import java.util.UUID; -import javax.inject.Inject; import javax.naming.ConfigurationException; import com.cloud.exception.InvalidParameterValueException; @@ -94,8 +93,6 @@ import org.apache.cloudstack.storage.command.DownloadProgressCommand; import org.apache.cloudstack.storage.command.UploadStatusAnswer; import org.apache.cloudstack.storage.command.UploadStatusAnswer.UploadStatus; -import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; -import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.storage.command.UploadStatusCommand; import org.apache.cloudstack.storage.template.DownloadManager; import org.apache.cloudstack.storage.template.DownloadManagerImpl; @@ -145,7 +142,6 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ServerResourceBase; import com.cloud.storage.DataStoreRole; -import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.VMTemplateStorageResourceAssoc; @@ -173,9 +169,6 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements SecondaryStorageResource { - @Inject - ImageStoreDetailsUtil _imageStoreDetailsUtil; - private static final Logger s_logger = Logger.getLogger(NfsSecondaryStorageResource.class); private static final String TEMPLATE_ROOT_DIR = "template/tmpl"; @@ -215,6 +208,7 @@ public void setTimeout(int timeout) { private String _storageIp; private String _storageNetmask; private String _storageGateway; + private String _nfsVersion; private final List nfsIps = new ArrayList(); protected String _parent = "/mnt/SecStorage"; final private String _tmpltpp = "template.properties"; @@ -222,12 +216,6 @@ public void setTimeout(int timeout) { private HashMap uploadEntityStateMap = new HashMap(); private String _ssvmPSK = null; - @Inject - ImageStoreDao dataStoreDao; - - @Inject - ImageStoreDetailsDao detailsStoreDao; - public void setParentPath(String path) { _parent = path; } @@ -368,7 +356,7 @@ protected Answer copyFromSwiftToNfs(CopyCommand cmd, DataTO srcData, SwiftTO swi final String storagePath = destImageStore.getUrl(); final String destPath = destData.getPath(); try { - String downloadPath = determineStorageTemplatePath(storagePath, destPath, _imageStoreDetailsUtil.getNfsVersionByUuid(destImageStore.getUuid())); + String downloadPath = determineStorageTemplatePath(storagePath, destPath, _nfsVersion); final File downloadDirectory = _storage.getFile(downloadPath); if (downloadDirectory.exists()) { @@ -395,7 +383,7 @@ protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataT try { - String downloadPath = determineStorageTemplatePath(storagePath, destPath, _imageStoreDetailsUtil.getNfsVersionByUuid(destImageStore.getUuid())); + String downloadPath = determineStorageTemplatePath(storagePath, destPath, _nfsVersion); final File downloadDirectory = _storage.getFile(downloadPath); if (downloadDirectory.exists()) { @@ -428,7 +416,7 @@ protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataT protected Answer copySnapshotToTemplateFromNfsToNfsXenserver(CopyCommand cmd, SnapshotObjectTO srcData, NfsTO srcDataStore, TemplateObjectTO destData, NfsTO destDataStore) { - String srcMountPoint = getRootDir(srcDataStore.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); + String srcMountPoint = getRootDir(srcDataStore.getUrl(), _nfsVersion); String snapshotPath = srcData.getPath(); int index = snapshotPath.lastIndexOf("/"); String snapshotName = snapshotPath.substring(index + 1); @@ -438,7 +426,7 @@ protected Answer copySnapshotToTemplateFromNfsToNfsXenserver(CopyCommand cmd, Sn snapshotPath = snapshotPath.substring(0, index); snapshotPath = srcMountPoint + File.separator + snapshotPath; - String destMountPoint = getRootDir(destDataStore.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(destDataStore.getUuid())); + String destMountPoint = getRootDir(destDataStore.getUrl(), _nfsVersion); String destPath = destMountPoint + File.separator + destData.getPath(); String errMsg = null; @@ -496,8 +484,8 @@ protected Answer copySnapshotToTemplateFromNfsToNfs(CopyCommand cmd, SnapshotObj if (srcData.getHypervisorType() == HypervisorType.XenServer) { return copySnapshotToTemplateFromNfsToNfsXenserver(cmd, srcData, srcDataStore, destData, destDataStore); } else if (srcData.getHypervisorType() == HypervisorType.KVM) { - File srcFile = getFile(srcData.getPath(), srcDataStore.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); - File destFile = getFile(destData.getPath(), destDataStore.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(destDataStore.getUuid())); + File srcFile = getFile(srcData.getPath(), srcDataStore.getUrl(), _nfsVersion); + File destFile = getFile(destData.getPath(), destDataStore.getUrl(), _nfsVersion); VolumeObjectTO volumeObjectTO = srcData.getVolume(); ImageFormat srcFormat = null; @@ -614,7 +602,7 @@ protected Answer createTemplateFromSnapshot(CopyCommand cmd) { } s_logger.debug("starting copy template to swift"); DataTO newTemplate = answer.getNewData(); - File templateFile = getFile(newTemplate.getPath(), ((NfsTO)srcDataStore).getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); + File templateFile = getFile(newTemplate.getPath(), ((NfsTO)srcDataStore).getUrl(), _nfsVersion); SwiftTO swift = (SwiftTO)destDataStore; String containterName = SwiftUtil.getContainerName(destData.getObjectType().toString(), destData.getId()); String swiftPath = SwiftUtil.putObject(swift, templateFile, containterName, templateFile.getName()); @@ -736,7 +724,7 @@ protected File downloadFromUrlToNfs(String url, NfsTO nfs, String path, String n throw new CloudRuntimeException("Failed to get url: " + url); } - String nfsMountPath = getRootDir(nfs.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(nfs.getUuid())); + String nfsMountPath = getRootDir(nfs.getUrl(), _nfsVersion); String filePath = nfsMountPath + File.separator + path; File directory = new File(filePath); @@ -901,7 +889,7 @@ protected Answer copyFromNfsToS3(CopyCommand cmd) { final S3TO s3 = (S3TO)destDataStore; try { - final String templatePath = determineStorageTemplatePath(srcStore.getUrl(), srcData.getPath(), _imageStoreDetailsUtil.getNfsVersionByUuid(srcDataStore.getUuid())); + final String templatePath = determineStorageTemplatePath(srcStore.getUrl(), srcData.getPath(), _nfsVersion); if (s_logger.isDebugEnabled()) { s_logger.debug("Found " + srcData.getObjectType() + " from directory " + templatePath + " to upload to S3."); @@ -1114,7 +1102,7 @@ public Answer execute(DeleteSnapshotsDirCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeSnapshotPath = cmd.getDirectory(); - String parent = getRootDir(nfs.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); + String parent = getRootDir(nfs.getUrl(), _nfsVersion); if (relativeSnapshotPath.startsWith(File.separator)) { relativeSnapshotPath = relativeSnapshotPath.substring(1); @@ -1192,7 +1180,7 @@ private Answer execute(ComputeChecksumCommand cmd) { return new Answer(cmd, false, "can't handle non nfs data store"); } NfsTO nfsStore = (NfsTO)store; - String parent = getRootDir(nfsStore.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(store.getUuid())); + String parent = getRootDir(nfsStore.getUrl(), _nfsVersion); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); @@ -1403,7 +1391,7 @@ protected Answer deleteSnapshot(final DeleteCommand cmd) { DataStoreTO dstore = obj.getDataStore(); if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; - String parent = getRootDir(nfs.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); + String parent = getRootDir(nfs.getUrl(), _nfsVersion); if (!parent.endsWith(File.separator)) { parent += File.separator; } @@ -1596,7 +1584,7 @@ private Answer execute(ListVolumeCommand cmd) { } DataStoreTO store = cmd.getDataStore(); if (store instanceof NfsTO) { - String root = getRootDir(cmd.getSecUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(store.getUuid())); + String root = getRootDir(cmd.getSecUrl(), _nfsVersion); Map templateInfos = _dlMgr.gatherVolumeInfo(root); return new ListVolumeAnswer(cmd.getSecUrl(), templateInfos); } else if (store instanceof S3TO) { @@ -1765,7 +1753,7 @@ protected Answer deleteTemplate(DeleteCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeTemplatePath = obj.getPath(); - String parent = getRootDir(nfs.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); + String parent = getRootDir(nfs.getUrl(), _nfsVersion); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); @@ -1869,7 +1857,7 @@ protected Answer deleteVolume(final DeleteCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeVolumePath = obj.getPath(); - String parent = getRootDir(nfs.getUrl(), _imageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())); + String parent = getRootDir(nfs.getUrl(), _nfsVersion); if (relativeVolumePath.startsWith(File.separator)) { relativeVolumePath = relativeVolumePath.substring(1); @@ -2134,6 +2122,7 @@ public boolean configure(String name, Map params) throws Configu startAdditionalServices(); _params.put("install.numthreads", "50"); _params.put("secondary.storage.vm", "true"); + _nfsVersion = (String)params.get("nfsVersion"); } try { diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java index 6fb2aa239a..affe8a716a 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java @@ -46,7 +46,6 @@ import org.apache.cloudstack.storage.command.DownloadProgressCommand.RequestType; import org.apache.cloudstack.storage.resource.SecondaryStorageResource; import org.apache.log4j.Logger; -import org.springframework.context.ApplicationContext; import com.cloud.agent.api.storage.DownloadAnswer; import com.cloud.utils.net.Proxy; @@ -54,7 +53,6 @@ import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.S3TO; import com.cloud.exception.InternalErrorException; -import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.VMTemplateHostVO; @@ -91,7 +89,7 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager StorageLayer _storage; public Map _processors; - private ImageStoreDetailsUtil imageStoreDetailsUtil; + private String _nfsVersion; public class Completion implements DownloadCompleteCallback { private final String jobId; @@ -712,7 +710,7 @@ public DownloadAnswer handleDownloadCommand(SecondaryStorageResource resource, D String installPathPrefix = cmd.getInstallPath(); // for NFS, we need to get mounted path if (dstore instanceof NfsTO) { - installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl(), imageStoreDetailsUtil.getNfsVersionByUuid(dstore.getUuid())) + File.separator + installPathPrefix; + installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl(), _nfsVersion) + File.separator + installPathPrefix; } String user = null; String password = null; @@ -954,8 +952,6 @@ public boolean drain() { } public DownloadManagerImpl() { - ApplicationContext applicationContext = com.cloud.utils.component.ComponentContext.getApplicationContext(); - imageStoreDetailsUtil = applicationContext.getBean("imageStoreDetailsUtil", ImageStoreDetailsUtil.class); } @Override @@ -988,6 +984,7 @@ public boolean configure(String name, Map params) throws Configu String inSystemVM = (String)params.get("secondary.storage.vm"); if (inSystemVM != null && "true".equalsIgnoreCase(inSystemVM)) { s_logger.info("DownloadManager: starting additional services since we are inside system vm"); + _nfsVersion = (String)params.get("nfsVersion"); startAdditionalServices(); blockOutgoingOnPrivate(); } From d159af93b4e6485b30424026e1a84ce85a3c7abf Mon Sep 17 00:00:00 2001 From: sanjeev Date: Wed, 17 Feb 2016 11:53:07 +0530 Subject: [PATCH 062/203] Revert "Merge pull request #1411 from pritisarap12/CLOUDSTACK-8717-Failed-to-start-instance-after-restoring-the-running-instance" This reverts commit 13f4e5a253c6fac8ff38ffc0a43d237be290d084, reversing changes made to 7332e88ec935f7bdcec4e0659dfac88d537d898a. --- .../testpaths/testpath_restore_vm.py | 211 ------------------ 1 file changed, 211 deletions(-) delete mode 100644 test/integration/testpaths/testpath_restore_vm.py diff --git a/test/integration/testpaths/testpath_restore_vm.py b/test/integration/testpaths/testpath_restore_vm.py deleted file mode 100644 index d73499ad21..0000000000 --- a/test/integration/testpaths/testpath_restore_vm.py +++ /dev/null @@ -1,211 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -""" -Test restore running VM on VMWare with one cluster having 2 Primary Storage -""" - - -from nose.plugins.attrib import attr -from marvin.cloudstackTestCase import cloudstackTestCase -from marvin.lib.utils import cleanup_resources, validateList -from marvin.lib.base import (Account, - ServiceOffering, - VirtualMachine, - StoragePool - ) -from marvin.lib.common import (get_domain, - get_zone, - get_template, - list_volumes, - list_virtual_machines - ) - -from marvin.codes import CLUSTERTAG1, ROOT, PASS -import time - - -class TestRestoreVM(cloudstackTestCase): - - @classmethod - def setUpClass(cls): - testClient = super(TestRestoreVM, cls).getClsTestClient() - cls.apiclient = testClient.getApiClient() - cls.testdata = testClient.getParsedTestDataConfig() - cls.hypervisor = cls.testClient.getHypervisorInfo() - - # Get Zone, Domain and templates - cls.domain = get_domain(cls.apiclient) - cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) - - cls.template = get_template( - cls.apiclient, - cls.zone.id, - cls.testdata["ostype"]) - - cls._cleanup = [] - - try: - cls.skiptest = False - if cls.hypervisor.lower() not in ["vmware"]: - cls.skiptest = True - return - - # Create an account - cls.account = Account.create( - cls.apiclient, - cls.testdata["account"], - domainid=cls.domain.id - ) - cls._cleanup.append(cls.account) - # Create user api client of the account - cls.userapiclient = testClient.getUserApiClient( - UserName=cls.account.name, - DomainName=cls.account.domain - ) - # Create Service offering - cls.service_offering_cwps = ServiceOffering.create( - cls.apiclient, - cls.testdata["service_offering"], - tags=CLUSTERTAG1 - ) - cls._cleanup.append(cls.service_offering_cwps) - except Exception as e: - cls.tearDownClass() - raise e - return - - @classmethod - def tearDownClass(cls): - try: - cleanup_resources(cls.apiclient, cls._cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - - def setUp(self): - - self.cleanup = [] - if self.skiptest: - self.skipTest("This test is to be checked on VMWare only \ - Hence, skip for %s" % self.hypervisor) - - self.apiclient = self.testClient.getApiClient() - self.dbclient = self.testClient.getDbConnection() - - def tearDown(self): - try: - if self.pools: - StoragePool.update( - self.apiclient, - id=self.pools[0].id, - tags="") - - cleanup_resources(self.apiclient, self.cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return - - @attr(tags=["advanced", "basic"], required_hardware="true") - def test_01_recover_VM(self): - """ Test Restore VM on VMWare - 1. Deploy a VM without datadisk - 2. Restore the VM - 3. Verify that VM comes up in Running state - """ - try: - self.pools = StoragePool.list( - self.apiclient, - zoneid=self.zone.id, - scope="CLUSTER") - - status = validateList(self.pools) - - # Step 3 - self.assertEqual( - status[0], - PASS, - "Check: Failed to list cluster wide storage pools") - - if len(self.pools) < 2: - self.skipTest("There must be at atleast two cluster wide\ - storage pools available in the setup") - - except Exception as e: - self.skipTest(e) - - # Adding tags to Storage Pools - cluster_no = 1 - StoragePool.update( - self.apiclient, - id=self.pools[0].id, - tags=[CLUSTERTAG1[:-1] + repr(cluster_no)]) - - self.vm = VirtualMachine.create( - self.apiclient, - self.testdata["small"], - accountid=self.account.name, - templateid=self.template.id, - domainid=self.account.domainid, - serviceofferingid=self.service_offering_cwps.id, - zoneid=self.zone.id, - ) - # Step 2 - - volumes_root_list = list_volumes( - self.apiclient, - virtualmachineid=self.vm.id, - type=ROOT, - listall=True - ) - - root_volume = volumes_root_list[0] - - # Restore VM till its ROOT disk is recreated on onother Primary Storage - while True: - self.vm.restore(self.apiclient) - volumes_root_list = list_volumes( - self.apiclient, - virtualmachineid=self.vm.id, - type=ROOT, - listall=True - ) - - root_volume = volumes_root_list[0] - - if root_volume.storage != self.pools[0].name: - break - - # Step 3 - vm_list = list_virtual_machines( - self.apiclient, - id=self.vm.id) - - state = vm_list[0].state - i = 0 - while(state != "Running"): - vm_list = list_virtual_machines( - self.apiclient, - id=self.vm.id) - - time.sleep(10) - i = i + 1 - state = vm_list[0].state - if i >= 10: - self.fail("Restore VM Failed") - break - - return From 764afb49fe7b489de626c6e4d9d7e1e7fb8b40b3 Mon Sep 17 00:00:00 2001 From: Priti Sarap Date: Fri, 11 Dec 2015 15:47:21 +0530 Subject: [PATCH 063/203] CLOUDSTACK-9140: Testcase to verify if Dedicated cluster is used for virtual routers that belong to non dedicated account --Adding verification steps to make sure that vm and VR are being deployed on dedicated cluster --- .../maint/testpath_disable_enable_zone.py | 199 +++++++++++++++++- 1 file changed, 196 insertions(+), 3 deletions(-) diff --git a/test/integration/component/maint/testpath_disable_enable_zone.py b/test/integration/component/maint/testpath_disable_enable_zone.py index a15173ebbd..1537fc5457 100644 --- a/test/integration/component/maint/testpath_disable_enable_zone.py +++ b/test/integration/component/maint/testpath_disable_enable_zone.py @@ -21,6 +21,11 @@ from marvin.cloudstackTestCase import cloudstackTestCase from marvin.lib.utils import (cleanup_resources, validateList) +from marvin.cloudstackAPI import (dedicateCluster, + listDedicatedClusters, + releaseDedicatedCluster, + listAffinityGroups) + from marvin.lib.base import (Account, VirtualMachine, ServiceOffering, @@ -40,7 +45,10 @@ get_template, list_volumes, list_snapshots, - get_builtin_template_info + get_builtin_template_info, + list_routers, + list_virtual_machines, + list_hosts ) from marvin.cloudstackAPI import (updateZone, @@ -280,7 +288,7 @@ def test_01_disable_enable_zone(self): self.testdata["privatetemplate"]["hypervisor"] = builtin_info[1] self.testdata["privatetemplate"]["format"] = builtin_info[2] """ - //commenting it for now will uncomment once expected behaviour is known + //commenting it for now will uncomment once expected behaviour is known Template.register( self.apiclient, self.testdata["privatetemplate"], @@ -295,7 +303,7 @@ def test_01_disable_enable_zone(self): diskofferingid=self.disk_offering.id ) """ - //commenting it for now will uncomment once expected behaviour is known + //commenting it for now will uncomment once expected behaviour is known Iso.create( self.apiclient, self.testdata["iso2"], @@ -1691,3 +1699,188 @@ def test_01_disable_enable_host(self): ) return + + +class TestClusterDedication(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + testClient = super(TestClusterDedication, cls).getClsTestClient() + cls.apiclient = testClient.getApiClient() + cls.testdata = testClient.getParsedTestDataConfig() + cls.hypervisor = cls.testClient.getHypervisorInfo() + + # Get Zone, Domain and templates + cls.domain = get_domain(cls.apiclient) + cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) + + cls.template = get_template( + cls.apiclient, + cls.zone.id, + cls.testdata["ostype"]) + + cls.Skiptest = False + cls._cleanup = [] + cls.clusters = Cluster.list(cls.apiclient, zoneid=cls.zone.id) + if len(cls.clusters) < 2: + cls.Skiptest = True + + try: + # Create an account + cls.account_1 = Account.create( + cls.apiclient, + cls.testdata["account"], + domainid=cls.domain.id + ) + + cls._cleanup.append(cls.account_1) + + cls.account_2 = Account.create( + cls.apiclient, + cls.testdata["account"], + domainid=cls.domain.id + ) + + cls._cleanup.append(cls.account_2) + # Create user api client of the account + cls.userapiclient_1 = testClient.getUserApiClient( + UserName=cls.account_1.name, + DomainName=cls.account_1.domain + ) + cls.userapiclient_2 = testClient.getUserApiClient( + UserName=cls.account_2.name, + DomainName=cls.account_2.domain + ) + + # Create Service offering + cls.service_offering = ServiceOffering.create( + cls.apiclient, + cls.testdata["service_offering"], + ) + cls._cleanup.append(cls.service_offering) + + cls.disk_offering = DiskOffering.create( + cls.apiclient, + cls.testdata["disk_offering"], + ) + + cls._cleanup.append(cls.disk_offering) + + except Exception as e: + cls.tearDownClass() + raise e + return + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.apiclient, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + def setUp(self): + + if self.Skiptest: + self.skipTest("Insufficient clusters to run the test") + + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + try: + listClusterscmd = listDedicatedClusters.listDedicatedClustersCmd() + listClusterscmd.clusterid = self.clusters[0].id + ret_list = self.apiclient.listDedicatedClusters(listClusterscmd) + if ret_list: + dedicateCmd = releaseDedicatedCluster.\ + releaseDedicatedClusterCmd() + dedicateCmd.clusterid = self.clusters[0].id + self.apiclient.releaseDedicatedCluster(dedicateCmd) + + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["basic", "advanced"], required_hardware="false") + def test_01_dedicated_cluster_allocation(self): + """ Dedicated cluster and router allocation + 1. Dedicate a cluster to one account + 2. Deploy a VM on dedicated account + 3. Deploy another VM on another account. + 4. Verify the dedicated cluster is not used for + virtual routers that belong to non-dedicated account + """ + + # Step 1 + dedicateCmd = dedicateCluster.dedicateClusterCmd() + dedicateCmd.clusterid = self.clusters[0].id + dedicateCmd.domainid = self.domain.id + dedicateCmd.account = self.account_1.name + self.apiclient.dedicateCluster(dedicateCmd) + + afcmd = listAffinityGroups.listAffinityGroupsCmd() + afcmd.account = self.account_1.name + afcmd.domainid = self.account_1.domainid + affinitygr_list = self.apiclient.listAffinityGroups(afcmd) + + # Step 2 + self.vm = VirtualMachine.create( + self.userapiclient_1, + self.testdata["small"], + templateid=self.template.id, + accountid=self.account_1.name, + domainid=self.account_1.domainid, + serviceofferingid=self.service_offering.id, + affinitygroupids=[affinitygr_list[0].id], + zoneid=self.zone.id, + mode=self.zone.networktype + ) + # Steps to verify if VM is created on dedicated account + vmlist = list_virtual_machines(self.apiclient, + id=self.vm.id) + + hostlist = list_hosts(self.apiclient, + id=vmlist[0].hostid) + + self.assertEqual(hostlist[0].clusterid, + self.clusters[0].id, + "check if vm gets deployed on dedicated clusture" + ) + # Step 3 + self.vm_1 = VirtualMachine.create( + self.userapiclient_2, + self.testdata["small"], + templateid=self.template.id, + accountid=self.account_2.name, + domainid=self.account_2.domainid, + serviceofferingid=self.service_offering.id, + zoneid=self.zone.id, + mode=self.zone.networktype + ) + + # Steps to verify if VM is created on dedicated account + vmlist_1 = list_virtual_machines(self.apiclient, + id=self.vm_1.id) + + hostlist_1 = list_hosts(self.apiclient, + id=vmlist_1[0].hostid) + + self.assertNotEqual(hostlist_1[0].clusterid, + self.clusters[0].id, + "check if vm gets deployed on correct clusture" + ) + + # Step 4 + routerList = list_routers(self.apiclient, + clusterid=self.clusters[0].id, + networkid=self.vm_1.nic[0].networkid + ) + self.assertEqual( + routerList, + None, + "Check Dedicated cluster is used for virtual routers \ + that belong to non-dedicated account") + + return From 207b7e3b5004b930abbb0b2ecbda5aa79909ee5f Mon Sep 17 00:00:00 2001 From: Priti Sarap Date: Wed, 4 Nov 2015 14:48:38 +0530 Subject: [PATCH 064/203] CLOUDSTACK-9026: Modifying testpath for adding missing parameter --- test/integration/testpaths/testpath_storage_migration.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/integration/testpaths/testpath_storage_migration.py b/test/integration/testpaths/testpath_storage_migration.py index 3ef31f0cac..848594daf6 100644 --- a/test/integration/testpaths/testpath_storage_migration.py +++ b/test/integration/testpaths/testpath_storage_migration.py @@ -248,6 +248,13 @@ def setUpClass(cls): DomainName=cls.account.domain ) # Create Service offering + cls.service_offering = ServiceOffering.create( + cls.apiclient, + cls.testdata["service_offering"] + ) + + cls._cleanup.append(cls.service_offering) + cls.service_offering_zone1 = ServiceOffering.create( cls.apiclient, cls.testdata["service_offering"], From 783aac8268398a68dd73d282893a4b517fce5666 Mon Sep 17 00:00:00 2001 From: Nuno Tavares Date: Wed, 2 Mar 2016 11:11:34 +0100 Subject: [PATCH 065/203] ADD be explicit about the underlying limitation - OpenSwan --- .../api/command/user/vpn/CreateVpnCustomerGatewayCmd.java | 2 +- .../api/command/user/vpn/UpdateVpnCustomerGatewayCmd.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java index 0fb496cc04..e1131092f0 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java @@ -51,7 +51,7 @@ public class CreateVpnCustomerGatewayCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.STRING, required = true, description = "guest cidr list of the customer gateway") private String peerCidrList; - @Parameter(name = ApiConstants.IPSEC_PSK, type = CommandType.STRING, required = true, description = "IPsec Preshared-Key of the customer gateway") + @Parameter(name = ApiConstants.IPSEC_PSK, type = CommandType.STRING, required = true, description = "IPsec Preshared-Key of the customer gateway. Cannot contain newline or double quotes.") private String ipsecPsk; @Parameter(name = ApiConstants.IKE_POLICY, type = CommandType.STRING, required = true, description = "IKE policy of the customer gateway") diff --git a/api/src/org/apache/cloudstack/api/command/user/vpn/UpdateVpnCustomerGatewayCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpn/UpdateVpnCustomerGatewayCmd.java index 3b188b85ca..bb5914111b 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpn/UpdateVpnCustomerGatewayCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpn/UpdateVpnCustomerGatewayCmd.java @@ -57,7 +57,7 @@ public class UpdateVpnCustomerGatewayCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.STRING, required = true, description = "guest cidr of the customer gateway") private String guestCidrList; - @Parameter(name = ApiConstants.IPSEC_PSK, type = CommandType.STRING, required = true, description = "IPsec Preshared-Key of the customer gateway") + @Parameter(name = ApiConstants.IPSEC_PSK, type = CommandType.STRING, required = true, description = "IPsec Preshared-Key of the customer gateway. Cannot contain newline or double quotes.") private String ipsecPsk; @Parameter(name = ApiConstants.IKE_POLICY, type = CommandType.STRING, required = true, description = "IKE policy of the customer gateway") From c22659d76d73f00f41c13776c490e17a50aacd20 Mon Sep 17 00:00:00 2001 From: Simon Weller Date: Fri, 4 Mar 2016 06:53:44 -0600 Subject: [PATCH 066/203] Addresses CLOUDSTACK-9300 where the MySQL HA StaticStrategy class fails to load successfully --- client/tomcatconf/catalina.properties.in | 2 +- packaging/centos7/cloud-management.sysconfig | 2 +- packaging/centos7/tomcat7/catalina.properties | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/tomcatconf/catalina.properties.in b/client/tomcatconf/catalina.properties.in index 282892bb76..e0baf61261 100644 --- a/client/tomcatconf/catalina.properties.in +++ b/client/tomcatconf/catalina.properties.in @@ -44,7 +44,7 @@ package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache # "foo/*.jar": Add all the JARs of the specified folder as class # repositories # "foo/bar.jar": Add bar.jar as a class repository -common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,/usr/share/java/mysql-connector-java.jar,/usr/share/cloudstack-mysql-ha/lib/*jar +common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,/usr/share/java/mysql-connector-java.jar,/usr/share/cloudstack-mysql-ha/lib/*.jar # # List of comma-separated paths defining the contents of the "server" diff --git a/packaging/centos7/cloud-management.sysconfig b/packaging/centos7/cloud-management.sysconfig index c262b11518..6e5fcf9d8d 100644 --- a/packaging/centos7/cloud-management.sysconfig +++ b/packaging/centos7/cloud-management.sysconfig @@ -45,5 +45,5 @@ SHUTDOWN_VERBOSE="false" # Set the TOMCAT_PID location CATALINA_PID="/var/run/cloudstack-management.pid" -CLASSPATH=/etc/cloudstack/management:/usr/share/cloudstack-common:/usr/share/cloudstack-management/setup:/usr/share/java/mysql-connector-java.jar +CLASSPATH=/etc/cloudstack/management:/usr/share/cloudstack-common:/usr/share/cloudstack-management/setup diff --git a/packaging/centos7/tomcat7/catalina.properties b/packaging/centos7/tomcat7/catalina.properties index 282892bb76..e0baf61261 100644 --- a/packaging/centos7/tomcat7/catalina.properties +++ b/packaging/centos7/tomcat7/catalina.properties @@ -44,7 +44,7 @@ package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache # "foo/*.jar": Add all the JARs of the specified folder as class # repositories # "foo/bar.jar": Add bar.jar as a class repository -common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,/usr/share/java/mysql-connector-java.jar,/usr/share/cloudstack-mysql-ha/lib/*jar +common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,/usr/share/java/mysql-connector-java.jar,/usr/share/cloudstack-mysql-ha/lib/*.jar # # List of comma-separated paths defining the contents of the "server" From 3c8d3d0ee1288931369650195c8c316508483757 Mon Sep 17 00:00:00 2001 From: Sowmya Date: Tue, 8 Mar 2016 18:13:24 -0800 Subject: [PATCH 067/203] Add nuagevsp userdata testcase (Cloudstack-9095) & Refactor existing testcases --- test/integration/component/test_nuage_vsp.py | 334 ------- .../plugins/nuagevsp/nuageTestCase.py | 830 ++++++++++++++++++ .../nuagevsp/test_nuage_password_reset.py | 249 ++++++ .../nuagevsp/test_nuage_vpc_network.py | 98 +++ .../plugins/nuagevsp/test_nuage_vsp.py | 106 +++ tools/marvin/marvin/config/test_data.py | 110 +++ tools/marvin/marvin/lib/base.py | 55 ++ 7 files changed, 1448 insertions(+), 334 deletions(-) delete mode 100644 test/integration/component/test_nuage_vsp.py create mode 100644 test/integration/plugins/nuagevsp/nuageTestCase.py create mode 100644 test/integration/plugins/nuagevsp/test_nuage_password_reset.py create mode 100644 test/integration/plugins/nuagevsp/test_nuage_vpc_network.py create mode 100644 test/integration/plugins/nuagevsp/test_nuage_vsp.py diff --git a/test/integration/component/test_nuage_vsp.py b/test/integration/component/test_nuage_vsp.py deleted file mode 100644 index e7bd10e201..0000000000 --- a/test/integration/component/test_nuage_vsp.py +++ /dev/null @@ -1,334 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -""" P1 tests for NuageVsp network Plugin -""" -# Import Local Modules -from nose.plugins.attrib import attr -from marvin.cloudstackTestCase import cloudstackTestCase -from marvin.cloudstackAPI import (listPhysicalNetworks, - listNetworkServiceProviders, - addNetworkServiceProvider, - deleteNetworkServiceProvider, - deleteNuageVspDevice, - updateNetworkServiceProvider, - addNuageVspDevice, - destroyVirtualMachine) -from marvin.lib.utils import (cleanup_resources) -from marvin.lib.base import (Account, - VirtualMachine, - ServiceOffering, - NetworkOffering, - Network) -from marvin.lib.common import (get_domain, - get_zone, - get_template) - -import logging -import unittest - - -class Services: - - """Test NuageVsp plugin - """ - - def __init__(self): - print "in __init__" - self.services = { - "account": { - "email": "cloudstack@cloudmonkey.com", - "firstname": "cloudstack", - "lastname": "bob", - "username": "admin", - "password": "password", - }, - "service_offering": { - "name": "Tiny Instance", - "displaytext": "Tiny Instance", - "cpunumber": 1, - "cpuspeed": 100, # in MHz - "memory": 128, # In MBs - }, - "virtual_machine": { - "displayname": "TestVM", - "username": "root", - "password": "password", - "ssh_port": 22, - "hypervisor": 'KVM', - "privateport": 22, - "publicport": 22, - "protocol": 'TCP', - }, - "nuage_vsp_device": { - "hostname": '172.31.222.162', - "username": 'cloudstackuser1', - "password": 'cloudstackuser1', - "port": '8443', - "apiversion": 'v3_2', - "retrycount": '4', - "retryinterval": '60' - }, - # services supported by Nuage for isolated networks. - "network_offering": { - "name": 'nuage_marvin', - "displaytext": 'nuage_marvin', - "guestiptype": 'Isolated', - "supportedservices": - 'Dhcp,SourceNat,Connectivity,StaticNat,UserData,Firewall', - "traffictype": 'GUEST', - "availability": 'Optional', - "serviceProviderList": { - "UserData": 'VirtualRouter', - "Dhcp": 'NuageVsp', - "Connectivity": 'NuageVsp', - "StaticNat": 'NuageVsp', - "SourceNat": 'NuageVsp', - "Firewall": 'NuageVsp' - }, - "serviceCapabilityList": { - "SourceNat": {"SupportedSourceNatTypes": "perzone"}, - } - }, - "network": { - "name": "nuage", - "displaytext": "nuage", - }, - "ostype": 'CentOS 5.5 (64-bit)', - "sleep": 60, - "timeout": 10 - } - - -class TestNuageVsp(cloudstackTestCase): - - @classmethod - def setUpClass(cls): - print "In setup class" - cls._cleanup = [] - cls.testClient = super(TestNuageVsp, cls).getClsTestClient() - cls.api_client = cls.testClient.getApiClient() - - cls.services = Services().services - # Get Zone, Domain and templates - cls.domain = get_domain(cls.api_client) - cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) - cls.template = get_template( - cls.api_client, - cls.zone.id, - cls.services["ostype"] - ) - # nuage vsp device brings the Nuage virtual service platform into play - cls.nuage_services = cls.services["nuage_vsp_device"] - try: - - resp = listPhysicalNetworks.listPhysicalNetworksCmd() - print "in cls.setupClass- resp: %s" % resp - resp.zoneid = cls.zone.id - physical_networks = cls.api_client.listPhysicalNetworks(resp) - for pn in physical_networks: - if pn.isolationmethods=='VSP': - physical_network = pn - #if isinstance(physical_networks, list): - # physical_network = physical_networks[1] - resp = listNetworkServiceProviders.listNetworkServiceProvidersCmd() - resp.name = 'NuageVsp' - resp.physicalnetworkid = physical_network.id - nw_service_providers = cls.api_client.listNetworkServiceProviders( - resp) - if not isinstance(nw_service_providers, list): - # create network service provider and add nuage vsp device - resp_add_nsp =\ - addNetworkServiceProvider.addNetworkServiceProviderCmd() - resp_add_nsp.name = 'NuageVsp' - resp_add_nsp.physicalnetworkid = physical_network.id - cls.api_client.addNetworkServiceProvider(resp_add_nsp) - #Get NSP ID - nw_service_providers = cls.api_client.listNetworkServiceProviders( - resp) - cls.debug("NuageVsp NSP ID: %s" % nw_service_providers[0].id) - - resp_add_device = addNuageVspDevice.addNuageVspDeviceCmd() - resp_add_device.physicalnetworkid = physical_network.id - resp_add_device.username = cls.nuage_services["username"] - resp_add_device.password = cls.nuage_services["password"] - resp_add_device.hostname = cls.nuage_services["hostname"] - resp_add_device.port = cls.nuage_services["port"] - resp_add_device.apiversion = cls.nuage_services[ - "apiversion"] - resp_add_device.retrycount = cls.nuage_services[ - "retrycount"] - resp_add_device.retryinterval = cls.nuage_services[ - "retryinterval"] - cls.nuage = cls.api_client.addNuageVspDevice( - resp_add_device) - #Enable NuageVsp NSP - cls.debug("NuageVsp NSP ID : %s" % nw_service_providers[0].id) - resp_up_nsp = \ - updateNetworkServiceProvider.updateNetworkServiceProviderCmd() - resp_up_nsp.id = nw_service_providers[0].id - resp_up_nsp.state = 'Enabled' - cls.api_client.updateNetworkServiceProvider(resp_up_nsp) - - cls.network_offering = NetworkOffering.create( - cls.api_client, - cls.services["network_offering"], - conservemode=True - ) - cls._cleanup.append(cls.network_offering) - - cls.network_offering.update(cls.api_client, state='Enabled') - cls.services["virtual_machine"]["zoneid"] = cls.zone.id - cls.services["virtual_machine"]["template"] = cls.template.id - cls.service_offering = ServiceOffering.create( - cls.api_client, - cls.services["service_offering"] - ) - cls._cleanup.append(cls.service_offering) - except Exception as e: - cls.tearDownClass() - raise unittest.SkipTest("Unable to add VSP device") - return - - @classmethod - def tearDownClass(cls): - try: - cleanup_resources(cls.api_client, cls._cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return - - - def setUp(self): - self.apiclient = self.testClient.getApiClient() - self.dbclient = self.testClient.getDbConnection() - self.account = Account.create( - self.apiclient, - self.services["account"], - admin=True, - domainid=self.domain.id - ) - self.cleanup = [self.account] - return - - - def tearDown(self): - try: - self.debug("Cleaning up the resources") - cleanup_resources(self.apiclient, self.cleanup) - self.debug("Cleanup complete!") - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return - - @attr(tags=["advanced"]) - def test_network_vsp(self): - """Test nuage Network and VM Creation - """ - - self.debug("Creating network with network offering: %s" % - self.network_offering.id) - self.network = Network.create( - self.apiclient, - self.services["network"], - accountid=self.account.name, - domainid=self.account.domainid, - networkofferingid=self.network_offering.id, - zoneid=self.zone.id, - gateway = "10.1.1.1", - netmask = '255.255.255.0' - ) - self.debug("Created network with ID: %s" % self.network.id) - - self.debug("Deploying VM in account: %s" % self.account.name) - - virtual_machine_1 = VirtualMachine.create( - self.apiclient, - self.services["virtual_machine"], - accountid=self.account.name, - domainid=self.account.domainid, - serviceofferingid=self.service_offering.id, - networkids=[str(self.network.id)] - ) - self.debug("Deployed VM in network: %s" % self.network.id) - list_vm_response = VirtualMachine.list( - self.apiclient, - id=virtual_machine_1.id - ) - - self.debug( - "Verify listVirtualMachines response for virtual machine: %s" - % virtual_machine_1.id - ) - - self.assertEqual( - isinstance(list_vm_response, list), - True, - "Check list response returns a valid list" - ) - vm_response = list_vm_response[0] - - self.assertEqual( - vm_response.state, - "Running", - "VM state should be running after deployment" - ) - - self.debug("Deploying another VM in account: %s" % - self.account.name) - - virtual_machine_2 = VirtualMachine.create( - self.apiclient, - self.services["virtual_machine"], - accountid=self.account.name, - domainid=self.account.domainid, - serviceofferingid=self.service_offering.id, - networkids=[str(self.network.id)] - ) - self.debug("Deployed VM in network: %s" % self.network.id) - list_vm_response = VirtualMachine.list( - self.apiclient, - id=virtual_machine_2.id - ) - - self.debug( - "Verify listVirtualMachines response for virtual machine: %s" - % virtual_machine_2.id - ) - - self.assertEqual( - isinstance(list_vm_response, list), - True, - "Check list response returns a valid list" - ) - vm_response = list_vm_response[0] - - self.assertEqual( - vm_response.state, - "Running", - "VM state should be running after deployment" - ) - - VirtualMachine.delete(virtual_machine_1, self.apiclient, expunge=True) - - # # Deleting a single VM - VirtualMachine.delete(virtual_machine_2, self.apiclient, expunge=True) - - # Delete Network - Network.delete(self.network, self.apiclient) - - return diff --git a/test/integration/plugins/nuagevsp/nuageTestCase.py b/test/integration/plugins/nuagevsp/nuageTestCase.py new file mode 100644 index 0000000000..123f2bcaa2 --- /dev/null +++ b/test/integration/plugins/nuagevsp/nuageTestCase.py @@ -0,0 +1,830 @@ +# 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. + +""" Custom base class for NuageVsp network Plugin specific Marvin tests +""" +# Import Local Modules +from marvin.cloudstackTestCase import cloudstackTestCase, unittest +from marvin.lib.base import (NetworkServiceProvider, + ServiceOffering, + NetworkOffering, + Network, + Router, + Nuage, + VPC, + VpcOffering, + PublicIPAddress, + VirtualMachine, + StaticNATRule, + NetworkACLList, + NetworkACL, + FireWallRule, + EgressFireWallRule, + Host) +from marvin.lib.common import (get_zone, + get_domain, + get_template, + list_templates, + wait_for_cleanup) +from marvin.lib.utils import cleanup_resources +from marvin.cloudstackAPI import (listPhysicalNetworks, + updateConfiguration, + updateTemplate, + listConfigurations, + listHypervisors, + stopRouter, + startRouter) +# Import nosetests Modules +from nose.plugins.attrib import attr + +# Import System Modules +import socket +import importlib +import logging + + +class nuageTestCase(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.debug("setUpClass nuageTestCase") + + # We want to fail quicker, if it's a failure + socket.setdefaulttimeout(60) + + test_client = super(nuageTestCase, cls).getClsTestClient() + cls.api_client = test_client.getApiClient() + cls.db_client = test_client.getDbConnection() + cls.test_data = test_client.getParsedTestDataConfig() + + # Get Zone, Domain and templates + cls.zone = get_zone(cls.api_client) + cls.domain = get_domain(cls.api_client) + cls.template = get_template(cls.api_client, + cls.zone.id, + cls.test_data["ostype"] + ) + cls.test_data["virtual_machine"]["zoneid"] = cls.zone.id + cls.test_data["virtual_machine"]["template"] = cls.template.id + + # Create service offering + cls.service_offering = ServiceOffering.create(cls.api_client, + cls.test_data["service_offering"] + ) + cls._cleanup = [cls.service_offering] + + # Get configured Nuage Vsp device details + try: + resp = listPhysicalNetworks.listPhysicalNetworksCmd() + resp.zoneid = cls.zone.id + physical_networks = cls.api_client.listPhysicalNetworks(resp) + for pn in physical_networks: + if pn.isolationmethods == 'VSP': + cls.vsp_physical_network = pn + cls.nuage_vsp_device = Nuage.list(cls.api_client, + physicalnetworkid=cls.vsp_physical_network.id + )[0] + pns = cls.config.zones[0].physical_networks + providers = filter(lambda physical_network: 'VSP' in physical_network.isolationmethods, pns)[0].providers + devices = filter(lambda provider: provider.name == 'NuageVsp', providers)[0].devices + cls.nuage_vsp_device.username = devices[0].username + cls.nuage_vsp_device.password = devices[0].password + listConfigurationsCmd = listConfigurations.listConfigurationsCmd() + listConfigurationsCmd.name = "nuagevsp.cms.id" + listConfigurationsCmd.scopename = "global" + cs_config_dict = cls.api_client.listConfigurations(listConfigurationsCmd) + cls.cms_id = str(cs_config_dict[0].value).split(":")[1] + except Exception as e: + cls.tearDownClass() + raise unittest.SkipTest("Warning: Couldn't get configured Nuage Vsp device details: %s" % e) + + # Check if the host hypervisor type is simulator + resp = listHypervisors.listHypervisorsCmd() + resp.zoneid = cls.zone.id + cls.isSimulator = cls.api_client.listHypervisors(resp)[0].name == 'Simulator' + + # VSD is a Python SDK for Nuage Vsp + try: + vspk_module = "vspk." + cls.nuage_vsp_device.apiversion if int(cls.nuage_vsp_device.apiversion[1]) >= 4 \ + else "vspk.vsdk." + cls.nuage_vsp_device.apiversion + vsdk = importlib.import_module(vspk_module) + vspk_utils_module = "vspk.utils" if int(cls.nuage_vsp_device.apiversion[1]) >= 4 \ + else "vspk.vsdk." + cls.nuage_vsp_device.apiversion + ".utils" + vsdk_utils = importlib.import_module(vspk_utils_module) + set_log_level = getattr(vsdk_utils, "set_log_level") + from cms_vspk_wrapper.cms_vspk_wrapper import Cms_vspk_wrapper + except: + raise unittest.SkipTest("vspk (and/or) cms_vspk_wrapper import failure") + + # Configure VSD session + cls._session = vsdk.NUVSDSession(username=cls.nuage_vsp_device.username, + password=cls.nuage_vsp_device.password, + enterprise="csp", api_url="https://%s:%d" % + (cls.nuage_vsp_device.hostname, + cls.nuage_vsp_device.port) + ) + cls._session.start() + + # Configure cms_vspk_wrapper session + cls.log_handler = logging.getLogger("CSLog").handlers[0] + vsd_info = cls.nuage_vsp_device.__dict__ + vsd_info["port"] = str(vsd_info["port"]) + cls.vsd = Cms_vspk_wrapper(vsd_info, cls.log_handler) + + set_log_level(logging.INFO) + + cls.debug("setUpClass nuageTestCase [DONE]") + + def setUp(self): + self.cleanup = [] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + cls.debug("Warning: Exception during cleanup : %s" % e) + return + + def tearDown(self): + # Cleanup resources used + self.debug("Cleaning up the resources") + for obj in reversed(self.cleanup): + try: + if isinstance(obj, VirtualMachine): + obj.delete(self.api_client, expunge=True) + else: + obj.delete(self.api_client) + except Exception as e: + self.error("Failed to cleanup %s, got %s" % (obj, e)) + # cleanup_resources(self.api_client, self.cleanup) + self.cleanup = [] + self.debug("Cleanup complete!") + return + + def getConfigurationValue(self, name, scope="global"): + listConfigurationsCmd = listConfigurations.listConfigurationsCmd() + listConfigurationsCmd.name = name + listConfigurationsCmd.scopename = scope + if scope is "zone": + listConfigurationsCmd.zoneid = self.zone.id + return self.api_client.listConfigurations(listConfigurationsCmd) + + def setConfigurationValue(self, name, value, scope="global"): + cmd = updateConfiguration.updateConfigurationCmd() + cmd.name = name + cmd.scopename = scope + if scope is "zone": + cmd.zoneid = self.zone.id + cmd.value = value + self.api_client.updateConfiguration(cmd) + + def updateTemplate(self, value): + self.debug("UPDATE TEMPLATE") + cmd = updateTemplate.updateTemplateCmd() + cmd.id = self.template.id + cmd.passwordenabled = value + self.api_client.updateTemplate(cmd) + list_template_response = list_templates(self.api_client, + templatefilter="all", + id=self.template.id + ) + self.template = list_template_response[0] + + # Creates the vpc offering + def create_VpcOffering(self, vpc_offering, suffix=None): + self.debug('Create VpcOffering') + if suffix: + vpc_offering["name"] = "VPC_OFF-" + str(suffix) + vpc_off = VpcOffering.create(self.api_client, + vpc_offering + ) + # Enable VPC offering + vpc_off.update(self.api_client, state='Enabled') + self.cleanup.append(vpc_off) + self.debug('Created and Enabled VpcOffering') + return vpc_off + + # create_Vpc - Takes the vpc offering as arguments and creates the VPC + def create_Vpc(self, vpc_offering, cidr='10.1.1.1/16', cleanup=True): + self.debug("Creating a VPC network in the account: %s" % self.account.name) + self.test_data["vpc"]["cidr"] = cidr + vpc = VPC.create( + self.api_client, + self.test_data["vpc"], + vpcofferingid=vpc_offering.id, + zoneid=self.zone.id, + account=self.account.name, + domainid=self.account.domainid + ) + self.debug("Created VPC with ID: %s" % vpc.id) + if cleanup: + self.cleanup.append(vpc) + return vpc + + # create_NetworkOffering - Takes the network offering as argument and creates the Network Offering + def create_NetworkOffering(self, net_offering, suffix=None, conserve_mode=False): + self.debug('Create NetworkOffering') + if suffix: + net_offering["name"] = "NET_OFF-" + str(suffix) + nw_off = NetworkOffering.create(self.api_client, + net_offering, + conservemode=conserve_mode + ) + # Enable Network offering + nw_off.update(self.api_client, state='Enabled') + self.cleanup.append(nw_off) + self.debug('Created and Enabled NetworkOffering') + return nw_off + + # create_Network - Takes the network offering as argument and nw_key and creates the network + def create_Network(self, nw_off, nw_key="network", gateway='10.1.1.1', netmask='255.255.255.0', vpc=None, acl_list=None): + if not hasattr(nw_off, "id"): + nw_off = self.create_NetworkOffering(nw_off) + self.debug('Adding Network=%s' % self.test_data[nw_key]) + self.test_data[nw_key]["netmask"] = netmask + obj_network = Network.create(self.api_client, + self.test_data[nw_key], + accountid=self.account.name, + domainid=self.account.domainid, + networkofferingid=nw_off.id, + zoneid=self.zone.id, + gateway=gateway, + vpcid=vpc.id if vpc else self.vpc.id if hasattr(self, "vpc") else None, + aclid=acl_list.id if acl_list else None + ) + self.debug("Created network with ID: %s" % obj_network.id) + self.cleanup.append(obj_network) + return obj_network + + # upgrade_Network - Upgrades the given network + def upgrade_Network(self, nw_off, network): + if not hasattr(nw_off, "id"): + nw_off = self.create_NetworkOffering(nw_off, network.gateway) + self.debug('Update Network=%s' % network) + network.update( + self.api_client, + networkofferingid=nw_off.id, + changecidr=False + ) + self.debug("Updated network with ID: %s" % network.id) + + # delete_Network - Deletes the given network + def delete_Network(self, network): + self.debug('Deleting Network - %s' % network.name) + # Wait for network garbage collection before network deletion + wait_for_cleanup(self.api_client, + ["network.gc.interval", "network.gc.wait"] + ) + network.delete(self.api_client) + if network in self.cleanup: + self.cleanup.remove(network) + self.debug('Deleted Network - %s' % network.name) + + # create_VM_in_Network - Creates a VM in the given network, the vm_key - is the key for the services on the vm. + def create_VM_in_Network(self, network, vm_key="virtual_machine", host_id=None, start_vm=True): + self.debug('Creating VM in network=%s' % network.name) + self.debug('Passed vm_key=%s' % vm_key) + self.test_data[vm_key]["zoneid"] = self.zone.id + self.test_data[vm_key]["template"] = self.template.id + vm = VirtualMachine.create( + self.api_client, + self.test_data[vm_key], + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + networkids=[str(network.id)], + startvm=start_vm, + hostid=host_id + ) + self.debug('Created VM=%s in network=%s' % (vm.id, network.name)) + self.cleanup.append(vm) + return vm + + # starts the given vm + def start(self, apiclient): + """Start the instance""" + cmd = startVirtualMachine.startVirtualMachineCmd() + cmd.id = self.id + apiclient.startVirtualMachine(cmd) + response = self.getState(apiclient, VirtualMachine.RUNNING) + if response[0] == FAIL: + raise Exception(response[1]) + return + + # stops the given vm + def stop(self, apiclient, forced=None): + """Stop the instance""" + cmd = stopVirtualMachine.stopVirtualMachineCmd() + cmd.id = self.id + if forced: + cmd.forced = forced + apiclient.stopVirtualMachine(cmd) + response = self.getState(apiclient, VirtualMachine.STOPPED) + if response[0] == FAIL: + raise Exception(response[1]) + return + + # delete_VM - Deletes the given VM + def delete_VM(self, vm): + self.debug('Deleting VM - %s' % vm.name) + vm.delete(self.api_client) + # Wait for expunge interval to cleanup VM + wait_for_cleanup(self.api_client, + ["expunge.delay", "expunge.interval"] + ) + if vm in self.cleanup: + self.cleanup.remove(vm) + self.debug('Deleted VM - %s' % vm.name) + + # acquire_Public_IP - Acquires a public IP for the given network + def acquire_Public_IP(self, network, vpc=None): + self.debug("Associating public IP for network: %s" % network.name) + public_ip = PublicIPAddress.create(self.api_client, + accountid=self.account.name, + zoneid=self.zone.id, + domainid=self.account.domainid, + networkid=network.id if vpc is None else None, + vpcid=vpc.id if vpc else self.vpc.id if hasattr(self, "vpc") else None + ) + self.debug("Associated %s with network %s" % (public_ip.ipaddress.ipaddress, + network.id)) + return public_ip + + # create_StaticNatRule_For_VM - Creates static NAT rule for the given network , VM on the given public ip + def create_StaticNatRule_For_VM(self, vm, public_ip, network, vmguestip=None): + self.debug("Enabling static NAT for IP: %s" % + public_ip.ipaddress.ipaddress) + StaticNATRule.enable( + self.api_client, + ipaddressid=public_ip.ipaddress.id, + virtualmachineid=vm.id, + networkid=network.id, + vmguestip=vmguestip + ) + self.debug("Static NAT enabled for IP: %s" % + public_ip.ipaddress.ipaddress) + + # delete_StaticNatRule_For_VM - Deletes the static NAT rule for the given VM + def delete_StaticNatRule_For_VM(self, vm, public_ip): + self.debug("Disabling static NAT for IP: %s" % + public_ip.ipaddress.ipaddress) + StaticNATRule.disable( + self.api_client, + ipaddressid=public_ip.ipaddress.id, + virtualmachineid=vm.id + ) + self.debug("Static NAT disabled for IP: %s" % + public_ip.ipaddress.ipaddress) + + # create_firewall_rule - Creates the Ingress firewall rule on the given public ip + def create_firewall_rule(self, public_ip, rule=None): + if not rule: + rule = self.test_data["ingress_rule"] + self.debug("Adding an Ingress Firewall rule to make Guest VMs accessible through Static NAT") + return FireWallRule.create(self.api_client, + ipaddressid=public_ip.ipaddress.id, + protocol=rule["protocol"], + cidrlist=rule["cidrlist"], + startport=rule["startport"], + endport=rule["endport"] + ) + + # create_egress_firewall_rule - Creates the Egress firewall rule on the given public ip + def create_egress_firewall_rule(self, network, rule): + self.debug("Adding an Egress Firewall rule to allow/deny outgoing traffic from Guest VMs") + return EgressFireWallRule.create(self.api_client, + networkid=network.id, + protocol=rule["protocol"], + cidrlist=rule["cidrlist"], + startport=rule["startport"], + endport=rule["endport"] + ) + + # create_network_acl_list - Creates network ACL list in the given VPC + def create_network_acl_list(self, name, description, vpc): + self.debug("Adding NetworkACL list in VPC: %s" % vpc.id) + return NetworkACLList.create(self.api_client, + services={}, + name=name, + description=description, + vpcid=vpc.id + ) + + # create_network_acl_rule - Creates network ACL rule Ingree/Egress in the given network + def create_network_acl_rule(self, rule, traffic_type="Ingress", network=None, acl_list=None): + self.debug("Adding NetworkACL rule: %s" % rule) + return NetworkACL.create(self.api_client, + networkid=network.id if network else None, + services=rule, + traffictype=traffic_type, + aclid=acl_list.id if acl_list else None + ) + + # migrate_vm - Migrates the VM to a different host if available + def migrate_vm(self, vm): + self.debug("Checking if a host is available for migration?") + hosts = Host.listForMigration(self.api_client) + self.assertEqual(isinstance(hosts, list), True, + "List hosts should return a valid list" + ) + # Remove the host of current VM from the hosts list + hosts[:] = [host for host in hosts if host.id != vm.hostid] + if len(hosts) <= 0: + self.skipTest("No host available for migration. Test requires at-least 2 hosts") + host = hosts[0] + self.debug("Migrating VM-ID: %s to Host: %s" % (vm.id, host.id)) + try: + vm.migrate(self.api_client, hostid=host.id) + except Exception as e: + self.fail("Failed to migrate instance, %s" % e) + + # get_network_router - returns the router for the given network + def get_network_router(self, network): + self.debug("Finding the virtual router for network: %s" % network.name) + routers = Router.list(self.api_client, + networkid=network.id, + listall=True + ) + self.assertEqual(isinstance(routers, list), True, + "List routers should return a valid virtual router for network" + ) + return routers[0] + + # stop_network_router - Stops the given network router + def stop_network_router(self, router): + self.debug("Stopping Router with ID: %s" % router.id) + cmd = stopRouter.stopRouterCmd() + cmd.id = router.id + self.api_client.stopRouter(cmd) + + # start_network_router - Starts the given network router + def start_network_router(self, router): + self.debug("Starting Router with ID: %s" % router.id) + cmd = startRouter.startRouterCmd() + cmd.id = router.id + self.api_client.startRouter(cmd) + + # ssh_into_vm - Gets into the shell of the given VM + def ssh_into_vm(self, vm, public_ip): + self.debug("SSH into VM=%s on public_ip=%s" % (vm.name, public_ip.ipaddress.ipaddress)) + ssh_client = vm.get_ssh_client(ipaddress=public_ip.ipaddress.ipaddress) + return ssh_client + + # execute_cmd - Executes the given command on the given ssh client + def execute_cmd(self, ssh_client, cmd): + self.debug("EXECUTE SSH COMMAND: " + cmd) + ret_data = "" + out_list = ssh_client.execute(cmd) + if out_list is not None: + ret_data = ' '.join(map(str, out_list)).strip() + self.debug("ssh execute cmd result=" + ret_data) + else: + self.debug("ssh execute cmd result is None") + return ret_data + + # wget_from_server - fetches the index.html file from the given public Ip + def wget_from_server(self, public_ip): + import urllib + self.debug("wget from a http server on public_ip=%s" % public_ip.ipaddress.ipaddress) + wget_file = urllib.urlretrieve("http://%s/index.html" % public_ip.ipaddress.ipaddress, + filename="index.html" + ) + return wget_file + + # validate_NetworkServiceProvider - Validates the Network Service Provider + # in the Nuage VSP Physical Network - matches the given provider name + # against the list of providers fetched + def validate_NetworkServiceProvider(self, provider_name, state=None): + """Validates the Network Service Provider in the Nuage VSP Physical Network""" + self.debug("Check if the Network Service Provider is created successfully ?") + providers = NetworkServiceProvider.list(self.api_client, + name=provider_name, + physicalnetworkid=self.vsp_physical_network.id) + self.assertEqual(isinstance(providers, list), True, + "List Network Service Provider should return a valid list" + ) + self.assertEqual(provider_name, providers[0].name, + "Name of the Network Service Provider should match with the returned list data" + ) + if state: + self.assertEqual(providers[0].state, state, + "Network Service Provider state should be '%s'" % state + ) + self.debug("Network Service Provider creation successfully validated - %s" % provider_name) + + # validate_vpc_offering - Validates the VPC offering, matches the given VPC off name against the list of VPC offerings fetched + def validate_vpc_offering(self, vpc_offering, state=None): + """Validates the VPC offering""" + self.debug("Check if the VPC offering is created successfully ?") + vpc_offs = VpcOffering.list(self.api_client, + id=vpc_offering.id + ) + self.assertEqual(isinstance(vpc_offs, list), True, + "List VPC offering should return a valid list" + ) + self.assertEqual(vpc_offering.name, vpc_offs[0].name, + "Name of the VPC offering should match with the returned list data" + ) + if state: + self.assertEqual(vpc_offs[0].state, state, + "VPC offering state should be '%s'" % state + ) + self.debug("VPC offering creation successfully validated - %s" % vpc_offering.name) + + # validate_vpc - Validates the given VPC matches, the given VPC name against the list of VPCs fetched + def validate_vpc(self, vpc, state=None): + """Validates the VPC""" + self.debug("Check if the VPC is created successfully ?") + vpcs = VPC.list(self.api_client, + id=vpc.id + ) + self.assertEqual(isinstance(vpcs, list), True, + "List VPC should return a valid list" + ) + self.assertEqual(vpc.name, vpcs[0].name, + "Name of the VPC should match with the returned list data" + ) + if state: + self.assertEqual(vpcs[0].state, state, + "VPC state should be '%s'" % state + ) + self.debug("VPC creation successfully validated - %s" % vpc.name) + + # validate_network_offering - Validates the given Network offering + # matches the given network offering name against the list of network + # offerings fetched + def validate_network_offering(self, net_offering, state=None): + """Validates the Network offering""" + self.debug("Check if the Network offering is created successfully ?") + net_offs = NetworkOffering.list(self.api_client, + id=net_offering.id + ) + self.assertEqual(isinstance(net_offs, list), True, + "List Network offering should return a valid list" + ) + self.assertEqual(net_offering.name, net_offs[0].name, + "Name of the Network offering should match with the returned list data" + ) + if state: + self.assertEqual(net_offs[0].state, state, + "Network offering state should be '%s'" % state + ) + self.debug("Network offering creation successfully validated - %s" % net_offering.name) + + # validate_network - Validates the network - matches the given network name against the list of networks fetched + def validate_network(self, network, state=None): + """Validates the network""" + self.debug("Check if the network is created successfully ?") + networks = Network.list(self.api_client, + id=network.id + ) + self.assertEqual(isinstance(networks, list), True, + "List network should return a valid list" + ) + self.assertEqual(network.name, networks[0].name, + "Name of the network should match with with the returned list data" + ) + if state: + self.assertEqual(networks[0].state, state, + "Network state should be '%s'" % state + ) + self.debug("Network creation successfully validated - %s" % network.name) + + # check_router_state - Fetches the list of routers and their states and matches the given router's state + def check_router_state(self, router, state=None): + self.debug("Check if the virtual router is in state - %s" % state) + routers = Router.list(self.api_client, + id=router.id, + listall=True + ) + self.assertEqual(isinstance(routers, list), True, + "List router should return a valid list" + ) + if state: + self.assertEqual(routers[0].state, state, + "Virtual router is not in the expected state" + ) + self.debug("Virtual router is in the expected state - %s" % state) + + # check_vm_state - Fetches the list of VMs and their states and matches the given VM's state + def check_vm_state(self, vm, state=None): + self.debug("Check if the VM instance is in state - %s" % state) + vms = VirtualMachine.list(self.api_client, + id=vm.id, + listall=True + ) + self.assertEqual(isinstance(vms, list), True, + "List virtual machine should return a valid list" + ) + if state: + self.assertEqual(vms[0].state, state, + "Virtual machine is not in the expected state" + ) + self.debug("Virtual machine is in the expected state - %s" % state) + + # validate_Public_IP - Looks if the given public ip is in the allocated state form the list of fetched public IPs + def validate_Public_IP(self, public_ip, network, static_nat=False, vm=None): + """Validates the Public IP""" + self.debug("Check if the Public IP is successfully assigned to the network ?") + public_ips = PublicIPAddress.list(self.api_client, + id=public_ip.ipaddress.id, + networkid=network.id, + isstaticnat=static_nat, + listall=True + ) + self.assertEqual(isinstance(public_ips, list), True, + "List public Ip for network should return a valid list" + ) + self.assertEqual(public_ips[0].ipaddress, public_ip.ipaddress.ipaddress, + "List public Ip for network should list the assigned public Ip address" + ) + self.assertEqual(public_ips[0].state, "Allocated", + "Assigned public Ip is not in the allocated state" + ) + if static_nat and vm: + self.assertEqual(public_ips[0].virtualmachineid, vm.id, + "Static NAT Rule not enabled for the VM using the assigned public Ip" + ) + self.debug("Assigned Public IP is successfully validated - %s" % public_ip.ipaddress.ipaddress) + + # VSD verifications + + def fetch_by_external_id(self, fetcher, *cs_objects): + """ Fetches a child object by external id using the given fetcher, and uuids of the given cloudstack objects. + E.G. + - fetch_by_external_id(vsdk.NUSubnet(id="954de425-b860-410b-be09-c560e7dbb474").vms, cs_vm) + - fetch_by_external_id(session.user.floating_ips, cs_network, cs_public_ip) + :param fetcher: VSPK Fetcher to use to find the child entity + :param cs_objects: Cloudstack objects to take the UUID from. + :return: the VSPK object having the correct externalID + """ + return fetcher.get_first(filter="externalID BEGINSWITH '%s'" % ":".join([o.id for o in cs_objects])) + + # VSD verifications using cms_vspk_wrapper + + def get_externalID(self, object_id): + return object_id + "@" + self.cms_id + + # verify_vsp_network - Fetches the vsd domain, vsd zone and vsd subnet and Verifies the given network/VPC values match the fetched values + def verify_vsp_network(self, domain_id, network, vpc=None): + vsd_enterprise = self.vsd.get_enterprise(name=domain_id) + if vpc: + ext_network_id = self.get_externalID(vpc.id) + else: + ext_network_id = self.get_externalID(network.id) + ext_subnet_id = self.get_externalID(network.id) + vsd_domain = self.vsd.get_domain(externalID=ext_network_id) + vsd_zone = self.vsd.get_zone(externalID=ext_network_id) + vsd_subnet = self.vsd.get_subnet(externalID=ext_subnet_id) + self.debug("SHOW ENTERPRISE DATA FORMAT IN VSD") + self.debug(vsd_enterprise) + self.assertNotEqual(vsd_enterprise, None, + "VSD Enterprise data format should not be a None type" + ) + self.debug("SHOW NETWORK DATA FORMAT IN VSD") + self.debug(vsd_domain) + self.debug(vsd_zone) + self.debug(vsd_subnet) + if vpc: + self.assertEqual(vsd_domain['description'], "VPC_" + vpc.name, + "VSD domain description should match VPC name in CloudStack" + ) + self.assertEqual(vsd_zone['description'], "VPC_" + vpc.name, + "VSD zone description should match VPC name in CloudStack" + ) + else: + self.assertEqual(vsd_domain['description'], network.name, + "VSD domain description should match Isolated Network name in CloudStack" + ) + self.assertEqual(vsd_zone['description'], network.name, + "VSD zone description should match Isolated Network name in CloudStack" + ) + self.assertEqual(vsd_subnet['description'], network.name, + "VSD subnet description should match Isolated Network name in CloudStack" + ) + + # verify_vsp_vm - Fetches the vsd vport, vsd vm and interface and Verifies the given VM values match the fetched values + def verify_vsp_vm(self, vm, stopped=None): + ext_vm_id = self.get_externalID(vm.id) + for nic in vm.nic: + ext_network_id = self.get_externalID(nic.networkid) + ext_nic_id = self.get_externalID(nic.id) + vsd_vport = self.vsd.get_vport(subnet_externalID=ext_network_id, vport_externalID=ext_nic_id) + vsd_vm_interface = self.vsd.get_vm_interface(externalID=ext_nic_id) + self.debug("SHOW VPORT and VM INTERFACE DATA FORMAT IN VSD") + self.debug(vsd_vport) + self.debug(vsd_vm_interface) + self.assertEqual(vsd_vport['active'], True, + "VSD VM vport should be active" + ) + self.assertEqual(vsd_vm_interface['IPAddress'], nic.ipaddress, + "VSD VM interface IP address should match VM's NIC IP address in CloudStack" + ) + vsd_vm = self.vsd.get_vm(externalID=ext_vm_id) + self.debug("SHOW VM DATA FORMAT IN VSD") + self.debug(vsd_vm) + if not self.isSimulator: + if stopped: + self.assertEqual(vsd_vm['status'], "DELETE_PENDING", + "VM state in VSD should be DELETE_PENDING" + ) + else: + self.assertEqual(vsd_vm['status'], vm.state.upper(), + "VM state in VSD should match its state in CloudStack" + ) + # verify_vsp_router - Fetches the vsd router and Verifies the given router status match the fetched status + + def verify_vsp_router(self, router, stopped=None): + ext_router_id = self.get_externalID(router.id) + vsd_router = self.vsd.get_vm(externalID=ext_router_id) + self.debug("SHOW VIRTUAL ROUTER DATA FORMAT IN VSD") + self.debug(vsd_router) + if not self.isSimulator: + if stopped: + self.assertEqual(vsd_router['status'], "DELETE_PENDING", + "Router state in VSD should be DELETE_PENDING" + ) + else: + self.assertEqual(vsd_router['status'], router.state.upper(), + "Router state in VSD should match its state in CloudStack" + ) + + # verify_vsp_floating_ip - Verifies the floating IPs on the given public IP against the VSD FIP + def verify_vsp_floating_ip(self, network, vm, public_ipaddress, vpc=None): + ext_fip_id = self.get_externalID(network.id + ":" + public_ipaddress.id) + vsd_fip = self.vsd.get_floating_ip(externalID=ext_fip_id) + self.debug("SHOW FLOATING IP DATA FORMAT IN VSD") + self.debug(vsd_fip) + self.assertEqual(vsd_fip['address'], public_ipaddress.ipaddress, + "Floating IP address in VSD should match acquired Public IP address in CloudStack" + ) + if vpc: + ext_network_id = self.get_externalID(vpc.id) + else: + ext_network_id = self.get_externalID(network.id) + vsd_domain = self.vsd.get_domain(externalID=ext_network_id) + self.debug("SHOW NETWORK DATA FORMAT IN VSD") + self.debug(vsd_domain) + self.assertEqual(vsd_domain['ID'], vsd_fip['parentID'], + "Floating IP in VSD should be associated with the correct VSD domain, " + "which in turn should correspond to the correct VPC (or) Isolated network in CloudStack" + ) + ext_subnet_id = self.get_externalID(network.id) + vsd_subnet = self.vsd.get_subnet(externalID=ext_subnet_id) + for nic in vm.nic: + if nic.networkname == vsd_subnet['description']: + ext_network_id = self.get_externalID(nic.networkid) + ext_nic_id = self.get_externalID(nic.id) + vsd_vport = self.vsd.get_vport(subnet_externalID=ext_network_id, vport_externalID=ext_nic_id) + self.debug("SHOW VM VPORT DATA FORMAT IN VSD") + self.debug(vsd_vport) + self.assertEqual(vsd_vport['associatedFloatingIPID'], vsd_fip['ID'], + "Floating IP in VSD should be associated to the correct VSD vport, " + "which in turn should correspond to the correct Static NAT enabled VM " + "and Isolated Network in CloudStack" + ) + + # verify_vsp_firewall_rule - Verifies the start port, destination port, + # protocol of the given firewall rule Ingress/Egress against the VSD + # firewall rule + def verify_vsp_firewall_rule(self, firewall_rule, traffic_type="Ingress"): + ext_fw_id = self.get_externalID(firewall_rule.id) + if traffic_type is "Ingress": + vsd_fw_rule = self.vsd.get_egress_acl_entry(externalID=ext_fw_id) + else: + vsd_fw_rule = self.vsd.get_ingress_acl_entry(externalID=ext_fw_id) + self.debug("SHOW ACL ENTRY IN VSD") + self.debug(vsd_fw_rule) + dest_port = str(firewall_rule.startport) + "-" + str(firewall_rule.endport) + self.assertEqual(vsd_fw_rule['destinationPort'], dest_port, + "Destination Port in VSD should match Destination Port in CloudStack" + ) + vsd_protocol = str(vsd_fw_rule['protocol']) + self.debug("vsd protocol " + vsd_protocol) + protocol = "tcp" + if vsd_protocol == 6: + protocol = "tcp" + elif vsd_protocol == 1: + protocol = "icmp" + elif vsd_protocol == 17: + protocol = "udp" + self.assertEqual(protocol, firewall_rule.protocol.lower(), + "Protocol in VSD should match Protocol in CloudStack" + ) diff --git a/test/integration/plugins/nuagevsp/test_nuage_password_reset.py b/test/integration/plugins/nuagevsp/test_nuage_password_reset.py new file mode 100644 index 0000000000..3e600c2dc6 --- /dev/null +++ b/test/integration/plugins/nuagevsp/test_nuage_password_reset.py @@ -0,0 +1,249 @@ +# 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. + +""" Component tests for - userdata +""" +# Import Local Modules +from marvin.lib.base import (VirtualMachine, + Account, + PublicIPAddress) +from nose.plugins.attrib import attr +from nuageTestCase import nuageTestCase +from marvin.cloudstackAPI import (createTemplate, + listVolumes) +import base64 + + +class TestNuagePasswordReset(nuageTestCase): + + @classmethod + def setUpClass(cls): + super(TestNuagePasswordReset, cls).setUpClass() + + return + + def setUp(self): + self.cleanup = [] + self.apiclient = self.testClient.getApiClient() + + self.account = Account.create( + self.apiclient, + self.test_data["account"], + admin=True, + domainid=self.domain.id + ) + + self.cleanup.append(self.account) + self.remove_vm2 = False + return + + # tearDown() - Cleans up the setup, removes the VMs + def tearDown(self): + self.debug("CLEANUP: TEARDOWN") + self.apiclient = self.testClient.getApiClient() + self.updateTemplate(self.defaultTemplateVal) + self.vm_1.delete(self.apiclient, expunge=True) + if self.remove_vm2: + self.vm_2.delete(self.apiclient, expunge=True) + + try: + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + self.debug("Warning: Exception during cleanup : %s" % e) + return + + # create_template - Takes the VM object as the argument to create the template + def create_template(self, vm): + self.debug("CREATE TEMPLATE") + list_volume = list_volumes( + self.apiclient, + virtualmachineid=vm.id, + type='ROOT', + listall=True + ) + if isinstance(list_volume, list): + self.volume = list_volume[0] + else: + raise Exception("Exception: Unable to find root volume for VM: %s" % vm.id) + + self.test_data["template_pr"]["ostype"] = self.test_data["ostype_pr"] + self.pw_enabled_template = Template.create( + self.apiclient, + self.test_data["template_pr"], + self.volume.id, + account=self.account.name, + domainid=self.account.domainid + ) + self.assertEqual(self.pw_enabled_template.passwordenabled, True, "template is not passwordenabled") + self.cleanup.append(self.pw_enabled_template) + + # VM object is passed as an argument and its interface id is returned + def get_vm_interface_id(self, vm): + self.debug("GET VM INTERFACE ID") + nic_ext_id = self.get_externalID(vm.nic[0].id) + vm_interface = self.vsd.get_vm_interface(externalID=nic_ext_id) + vm_interface_id = vm_interface["ID"] + return vm_interface_id + + # VM object is passed as an argument and its userdata URL is returned + def get_userdata_url(self, vm): + self.debug("GET USER DATA URL") + nic = vm.nic[0] + gateway = str(nic.gateway) + self.debug("GATEWAY: " + gateway) + user_data_url = 'curl "http://' + gateway + ':80/latest/user-data"' + return user_data_url + + # Creates and verifies the firewall rule + def create_and_verify_fw(self, vm, public_ip, network): + self.debug("CREATE AND VERIFY FIREWALL RULE") + self.create_StaticNatRule_For_VM(vm, public_ip, network) + + # VSD verification + self.verify_vsp_floating_ip(network, vm, public_ip.ipaddress) + vm_public_ip = public_ip.ipaddress.ipaddress + + fw_rule = self.create_firewall_rule(public_ip, self.test_data["ingress_rule"]) + self.verify_vsp_firewall_rule(fw_rule) + vm_interface_id = self.get_vm_interface_id(vm) + pd = self.vsd.get_vm_interface_policydecisions(id=vm_interface_id) + self.debug(pd) + egressAcls = pd['egressACLs'][0]['entries'] + gotFirewallPolicy = False + for acl in egressAcls: + if acl['destinationPort'] == "22-22": + gotFirewallPolicy = True + break + if not gotFirewallPolicy: + raise ValueError('No firewall policy decision in vm interface') + + @attr(tags=["advanced", "nuagevsp"], required_hardware="true") + def test_01_UserDataPasswordReset(self): + self.debug("START USER DATA PASSWORD RESET ON VM") + """ + Validate the following: + 1) user data + 2) reset vm password. + + Steps: + 1. Set password enabled to false in the template. + 2. Create an Isolated network - Test Network (10.1.1.1/24). + 3. Deploy VM1 in Test Network + 4. Verify domain,zone subnet, vm. + 5. create public ip , Create Static Nat rule firewall rule and verify + 6. SSH to VM should be successful + 7. verify userdata + 8. check cloud-set-guest-password exist. + 9. if cloud-set-guest-password exist. + 9.1 change template password enabled to true + 9.2 verify that template is password enbalded + 9.3 SSH with new password should be successful + 10. else cloud-set-guest-password does not exist. + 10.1 get the cloud-set-guest-password file + 10.2 stop vm + 10.3 create a new template with password enabled. Verify that template is password enabled. + 10.4 create vm 2 with new template in Test Network + 10.5 Verify vm. + 10.6 create public ip , Create Static Nat rule firewall rule and verify + 10.7 SSH to VM 2 should be successful + 11. Reset VM password (VM_1 if guest password file exist. else it is VM2) + 12 Starting VM and SSH to VM to verify new password + """ + + self.defaultTemplateVal = self.template.passwordenabled + if self.template.passwordenabled: + self.updateTemplate(False) + + self.debug("CREATE AN ISOLATED NETWORK") + self.network_1 = self.create_Network(self.test_data["network_offering_pr"]) + self.cleanup.append(self.network_1) + expUserData = "hello world vm1" + userdata = base64.b64encode(expUserData) + self.test_data["virtual_machine_pr"]["userdata"] = userdata + self.debug("DEPLOY VM 1 IN TEST NETWORK") + # Pass the network and name of the vm type from the testdata with the configuration for the vm + self.vm_1 = self.create_VM_in_Network(self.network_1, "virtual_machine_pr") + + self.vm_1.password = self.test_data["virtual_machine_pr"]["password"] + user_data_cmd = self.get_userdata_url(self.vm_1) + + # VSD verification + self.debug("VERIFY DOMAIN, ZONE, NETWORK , and VM 1") + self.verify_vsp_network(self.domain.id, self.network_1) + self.verify_vsp_vm(self.vm_1) + + self.debug("CREATE PUBLIC IP, STATIC NAT RULE, FLOATING IP, FIREWALL AND VERIFY") + public_ip_1 = self.acquire_Public_IP(self.network_1) + self.create_and_verify_fw(self.vm_1, public_ip_1, self.network_1) + + self.debug("SSH TO VM") + ssh = self.ssh_into_vm(self.vm_1, public_ip_1) + + self.debug("VERIFY USER DATA") + self.debug("Get User Data with command: " + user_data_cmd) + adata = self.execute_cmd(ssh, user_data_cmd) + actUserData = base64.b64decode(adata) + self.debug("Response User Data=" + actUserData + ", Expected=" + expUserData) + self.assertEqual(actUserData, expUserData, "User Data Did Not Match ") + + # check /etc/init.d/cloud-set-quest-password + ls_cmd = "ls /etc/init.d/cloud-set-guest-password" + ls_result = self.execute_cmd(ssh, ls_cmd) + ls_result = ls_result.lower() + self.debug("reponse from ls_cmd: " + ls_result) + if "no such file" in ls_result: + self.debug("NO CLOUD-SET_GUEST_PASSWORD FILE. NEED TO GET ONE") + self.install_cloud_set_guest_password_script(ssh) + self.stop_vm(self.vm_1) + self.create_template(self.vm_1) + self.debug("DEPLOY VM 2 IN TEST NETWORK WITH NEW TEMPLATE") + self.vm_1 = self.create_VM_in_Network(self.network_1, "virtual_machine_pr") + self.remove_vm2 = True + self.debug("STARTING VM_2 ") + startCmd = startVirtualMachine.startVirtualMachineCmd() + startCmd.id = self.vm_2.id + vm_2a = self.apiclient.startVirtualMachine(startCmd) + self.vm_2.password = vm_2a.password.strip() + self.vm_2.nic = vm_2a.nic + self.debug("VM - %s password %s !" % (self.vm_2.name, self.vm_2.password)) + self.assertNotEqual(self.vm_2.password, + self.test_data["virtual_machine_pr"]["password"], + "Password enabled not working. Password same as virtual_machine password " + ) + self.verify_vsp_vm(vm_2a) + self.debug("GET PUBLIC IP, CREATE AND VERIFY FIREWALL RULES") + public_ip_2 = self.acquire_Public_IP(self.network_1) + self.create_and_verify_fw(self.vm_2, public_ip_2, self.network_1) + + ssh = self.ssh_into_vm(self.vm_2, public_ip_2) + vm_test = self.vm_2 + vm_test_public_ip = public_ip_2 + + else: + self.debug("UPDATE TEMPLATE TO PASSWORD ENABLED") + self.updateTemplate(True) + self.assertEqual(self.template.passwordenabled, True, "Template is not password enabled") + vm_test = self.vm_1 + vm_test_public_ip = public_ip_1 + + self.debug("RESETTING VM PASSWORD for VM: %s" % vm_test.name) + vm_test.password = vm_test.resetPassword(self.apiclient) + self.debug("Password reset to: %s" % vm_test.password) + self.debug("STARTING VM AND SSH TO VM TO VERIFY NEW PASSWORD") + vm_test.start(self.apiclient) + self.debug("VM - %s started!" % vm_test.name) + self.ssh_into_vm(vm_test, vm_test_public_ip) diff --git a/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py b/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py new file mode 100644 index 0000000000..3fc9c32cfe --- /dev/null +++ b/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py @@ -0,0 +1,98 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" Tests for Basic VPC Network Functionality with NuageVsp network Plugin +""" +# Import Local Modules +from marvin.lib.base import Account +from nose.plugins.attrib import attr +from nuageTestCase import nuageTestCase + + +class TestVpcNetworkNuage(nuageTestCase): + """ Test Basic VPC Network Functionality with NuageVsp network Plugin + """ + + @classmethod + def setUpClass(cls): + super(TestVpcNetworkNuage, cls).setUpClass() + return + + def setUp(self): + # Create an account + self.account = Account.create(self.api_client, + self.test_data["account"], + admin=True, + domainid=self.domain.id + ) + self.cleanup = [self.account] + return + + @attr(tags=["advanced", "nuagevsp"], required_hardware="false") + def test_nuage_vpc_network(self): + """ Test Basic VPC Network Functionality with NuageVsp network Plugin + """ + + # 1. Create Nuage VSP VPC offering, check if it is successfully created and enabled. + # 2. Create a VPC with Nuage VSP VPC offering, check if it is successfully created and enabled. + # 3. Create Nuage Vsp VPC Network offering, check if it is successfully created and enabled. + # 4. Create an ACL list in the created VPC, and add an ACL item to it. + # 5. Create a VPC Network with Nuage Vsp VPC Network offering and the created ACL list, check if it is + # successfully created, is in the "Implemented" state, and is added to the VPC VR. + # 6. Deploy a VM in the created VPC network, check if the VM is successfully deployed and is in the "Running" + # state. + # 7. Verify that the created ACL item is successfully implemented in Nuage Vsp. + + # Creating a VPC offering + self.debug("Creating Nuage VSP VPC offering...") + vpc_offering = self.create_VpcOffering(self.test_data["nuage_vsp_services"]["vpc_offering"]) + self.validate_vpc_offering(vpc_offering, state="Enabled") + + # Creating a VPC + self.debug("Creating a VPC with Nuage VSP VPC offering...") + vpc = self.create_Vpc(vpc_offering, cidr='10.1.0.0/16') + self.validate_vpc(vpc, state="Enabled") + + # Creating a network offering + self.debug("Creating Nuage Vsp VPC Network offering...") + network_offering = self.create_NetworkOffering(self.test_data["nuage_vsp_services"]["vpc_network_offering"]) + self.validate_network_offering(network_offering, state="Enabled") + + # Creating an ACL list + acl_list = self.create_network_acl_list(name="acl", description="acl", vpc=vpc) + + # Creating an ACL item + acl_item = self.create_network_acl_rule(self.test_data["ingress_rule"], acl_list=acl_list) + + # Creating a VPC network in the VPC + self.debug("Creating a VPC network with Nuage Vsp VPC Network offering...") + vpc_network = self.create_Network(network_offering, gateway='10.1.1.1', vpc=vpc, acl_list=acl_list) + self.validate_network(vpc_network, state="Implemented") + vr = self.get_network_router(vpc_network) + self.check_router_state(vr, state="Running") + + # Deploying a VM in the VPC network + vm = self.create_VM_in_Network(vpc_network) + self.check_vm_state(vm, state="Running") + + # VSPK verification + self.verify_vsp_network(self.domain.id, vpc_network, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(vm) + + # VSPK verification for ACL item + self.verify_vsp_firewall_rule(acl_item) diff --git a/test/integration/plugins/nuagevsp/test_nuage_vsp.py b/test/integration/plugins/nuagevsp/test_nuage_vsp.py new file mode 100644 index 0000000000..a6ec7e1fee --- /dev/null +++ b/test/integration/plugins/nuagevsp/test_nuage_vsp.py @@ -0,0 +1,106 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" P1 tests for NuageVsp network Plugin +""" +# Import Local Modules +from marvin.lib.base import Account +from nose.plugins.attrib import attr +from nuageTestCase import nuageTestCase + + +class TestNuageVsp(nuageTestCase): + """ Test NuageVsp network plugin + """ + + @classmethod + def setUpClass(cls): + super(TestNuageVsp, cls).setUpClass() + return + + def setUp(self): + # Create an account + self.account = Account.create(self.api_client, + self.test_data["account"], + admin=True, + domainid=self.domain.id + ) + self.cleanup = [self.account] + return + + @attr(tags=["advanced", "nuagevsp"], required_hardware="false") + def test_nuage_vsp(self): + """ Test NuageVsp network plugin with basic Isolated Network functionality + """ + + # 1. Verify that the NuageVsp network service provider is successfully created and enabled. + # 2. Create and enable Nuage Vsp Isolated Network offering, check if it is successfully created and enabled. + # 3. Create an Isolated Network with Nuage Vsp Isolated Network offering, check if it is successfully created + # and is in the "Allocated" state. + # 4. Deploy a VM in the created Isolated network, check if the Isolated network state is changed to + # "Implemented", and both the VM & VR are successfully deployed and are in the "Running" state. + # 5. Deploy one more VM in the created Isolated network, check if the VM is successfully deployed and is in the + # "Running" state. + # 6. Delete the created Isolated Network after destroying its VMs, check if the Isolated network is successfully + # deleted. + + self.debug("Validating the NuageVsp network service provider...") + self.validate_NetworkServiceProvider("NuageVsp", state="Enabled") + + # Creating a network offering + self.debug("Creating and enabling Nuage Vsp Isolated Network offering...") + network_offering = self.create_NetworkOffering( + self.test_data["nuage_vsp_services"]["isolated_network_offering"]) + self.validate_network_offering(network_offering, state="Enabled") + + # Creating a network + self.debug("Creating an Isolated Network with Nuage Vsp Isolated Network offering...") + network = self.create_Network(network_offering, gateway='10.1.1.1') + self.validate_network(network, state="Allocated") + + # Deploying a VM in the network + vm_1 = self.create_VM_in_Network(network) + self.validate_network(network, state="Implemented") + vr = self.get_network_router(network) + self.check_router_state(vr, state="Running") + self.check_vm_state(vm_1, state="Running") + + # VSPK verification + self.verify_vsp_network(self.domain.id, network) + self.verify_vsp_router(vr) + self.verify_vsp_vm(vm_1) + + # Deploying one more VM in the network + vm_2 = self.create_VM_in_Network(network) + self.check_vm_state(vm_2, state="Running") + + # VSPK verification + self.verify_vsp_vm(vm_2) + + # Deleting the network + self.debug("Deleting the Isolated Network with Nuage Vsp Isolated Network offering...") + self.delete_VM(vm_1) + self.delete_VM(vm_2) + self.delete_Network(network) + with self.assertRaises(Exception): + self.validate_network(network) + self.debug("Isolated Network successfully deleted in CloudStack") + + # VSPK verification + with self.assertRaises(Exception): + self.verify_vsp_network(self.domain.id, network) + self.debug("Isolated Network successfully deleted in VSD") diff --git a/tools/marvin/marvin/config/test_data.py b/tools/marvin/marvin/config/test_data.py index 3d4745d0cd..352f8a2307 100644 --- a/tools/marvin/marvin/config/test_data.py +++ b/tools/marvin/marvin/config/test_data.py @@ -1695,5 +1695,115 @@ "ostype": 'CentOS 5.3 (64-bit)', "mode": 'HTTP_DOWNLOAD' } + }, + # Nuage Vsp supported services + "nuage_vsp_services": { + # Services supported by Nuage Vsp for Isolated networks + "isolated_network_offering": { + "name": 'nuage_marvin', + "displaytext": 'nuage_marvin', + "guestiptype": 'Isolated', + "supportedservices": 'Dhcp,SourceNat,Connectivity,StaticNat,UserData,Firewall', + "traffictype": 'GUEST', + "availability": 'Optional', + "serviceProviderList": { + "Dhcp": 'NuageVsp', + "StaticNat": 'NuageVsp', + "SourceNat": 'NuageVsp', + "Firewall": 'NuageVsp', + "Connectivity": 'NuageVsp', + "UserData": 'VirtualRouter' + }, + "serviceCapabilityList": { + "SourceNat": {"SupportedSourceNatTypes": "perzone"} + } + }, + # Services supported by Nuage Vsp for VPC networks + "vpc_network_offering": { + "name": 'nuage_vpc_marvin', + "displaytext": 'nuage_vpc_marvin', + "guestiptype": 'Isolated', + "supportedservices": 'Dhcp,StaticNat,SourceNat,NetworkACL,Connectivity,UserData', + "traffictype": 'GUEST', + "availability": 'Optional', + "useVpc": 'on', + "ispersistent": 'True', + "serviceProviderList": { + "Dhcp": "NuageVsp", + "StaticNat": "NuageVsp", + "SourceNat": "NuageVsp", + "NetworkACL": "NuageVsp", + "Connectivity": "NuageVsp", + "UserData": "VpcVirtualRouter" + }, + "serviceCapabilityList": { + "SourceNat": {"SupportedSourceNatTypes": "perzone"} + } + }, + # Nuage Vsp supports only pre-defined and custom VPC offerings + "vpc_offering": { + "name": 'Nuage VSP VPC offering', + "displaytext": 'Nuage VSP VPC offering', + "supportedservices": 'Dhcp,StaticNat,SourceNat,NetworkACL,Connectivity,UserData', + "serviceProviderList": { + "Dhcp": "NuageVsp", + "StaticNat": "NuageVsp", + "SourceNat": "NuageVsp", + "NetworkACL": "NuageVsp", + "Connectivity": "NuageVsp", + "UserData": "VpcVirtualRouter" + } } + }, + + #_pr -_ passwordreset - below services used in test_nuage_password_reset + "network_offering_pr": { + "name": 'nuage_marvin', + "displaytext": 'nuage_marvin', + "guestiptype": 'Isolated', + "supportedservices": + 'Dhcp,SourceNat,Connectivity,StaticNat,UserData,Firewall', + "traffictype": 'GUEST', + "availability": 'Optional', + "serviceProviderList": { + "UserData": 'VirtualRouter', + "Dhcp": 'NuageVsp', + "Connectivity": 'NuageVsp', + "StaticNat": 'NuageVsp', + "SourceNat": 'NuageVsp', + "Firewall": 'NuageVsp' + }, + }, + "network_pr": { + "name": "Test Network", + "displaytext": "Test Network", + "netmask": '255.255.255.0' + }, + "fw_rule_pr": { + "startport": 1, + "endport": 6000, + "cidr": '0.0.0.0/0', + # Any network (For creating FW rule) + "protocol": "TCP" + }, + "virtual_machine_pr": { + "displayname": "Test VM", + "username": "root", + "password": "password", + "ssh_port": 22, + "hypervisor": 'kvm', + # Hypervisor type should be same as + # hypervisor type of cluster + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + "userdata": "This is sample data", + }, + "template_pr": { + "displaytext": "Cent OS Template", + "name": "Cent OS Template", + "passwordenabled": True, + }, + "ostype_pr": 'CentOS 5.5 (64-bit)', + } diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index 0be8909af3..e2f4a2c864 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -3957,6 +3957,61 @@ def list(cls, apiclient, **kwargs): return(apiclient.listNetworkServiceProviders(cmd)) +class Nuage: + """Manage external nuage VSD device""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def add(cls, apiclient, services, physicalnetworkid, username=None, password=None): + """Add external nuage VSD device to cloudstack""" + + cmd = addNuageVspDevice.addNuageVspDeviceCmd() + cmd.physicalnetworkid = physicalnetworkid + if username: + cmd.username = username + else: + cmd.username = services["username"] + + if password: + cmd.password = password + else: + cmd.password = services["password"] + + cmd.hostname = services["hostname"] + cmd.port = services["port"] + cmd.retrycount = services["retrycount"] + cmd.retryinterval = services["retryinterval"] + cmd.apiversion = services["apiversion"] + + return Nuage(apiclient.addNuageVspDevice(cmd).__dict__) + + def update(self, apiclient, **kwargs): + """Deletes a nuage VSD device from CloudStack""" + + cmd = updateNuageVspDevice.updateNuageVspDeviceCmd() + cmd.physicalnetworkid = self.physicalnetworkid + [setattr(cmd, k, v) for k, v in kwargs.items()] + return apiclient.updateNuageVspDevice(cmd) + + def delete(self, apiclient): + """Deletes a nuage VSD device from CloudStack""" + + cmd = deleteNuageVspDevice.deleteNuageVspDeviceCmd() + cmd.vspdeviceid = self.vspdeviceid + apiclient.deleteNuageVspDevice(cmd) + return + + @classmethod + def list(cls, apiclient, **kwargs): + """List already registered netscaler devices""" + + cmd = listNuageVspDevices.listNuageVspDevicesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listNuageVspDevices(cmd)) + + class Router: """Manage router life cycle""" From 226026342581eb07b0de9718fa207f6cd8299732 Mon Sep 17 00:00:00 2001 From: Sowmya Date: Tue, 8 Mar 2016 18:57:24 -0800 Subject: [PATCH 068/203] deleted: test_vpcnetwork_nuage.py new file: ../plugins/nuagevsp/__init__.py --- .../component/test_vpcnetwork_nuage.py | 295 ------------------ test/integration/plugins/nuagevsp/__init__.py | 16 + 2 files changed, 16 insertions(+), 295 deletions(-) delete mode 100644 test/integration/component/test_vpcnetwork_nuage.py create mode 100644 test/integration/plugins/nuagevsp/__init__.py diff --git a/test/integration/component/test_vpcnetwork_nuage.py b/test/integration/component/test_vpcnetwork_nuage.py deleted file mode 100644 index be76fa65ec..0000000000 --- a/test/integration/component/test_vpcnetwork_nuage.py +++ /dev/null @@ -1,295 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -""" Tests for NuageNetwork VPC -""" -#Import Local Modules -from marvin.cloudstackTestCase import cloudstackTestCase, unittest -from marvin.lib.utils import (cleanup_resources) -from marvin.cloudstackAPI import (listPhysicalNetworks, - listNetworkServiceProviders, - addNetworkServiceProvider, - updateNetworkServiceProvider, - addNuageVspDevice, - destroyVirtualMachine) -from marvin.lib.base import (VirtualMachine, - ServiceOffering, - Account, - NetworkOffering, - Network, - VPC, - VpcOffering, - NetworkACL, - NetworkACLList) -from marvin.lib.common import (get_zone, - get_domain, - get_template, - wait_for_cleanup, - list_networks) - -from nose.plugins.attrib import attr - -class Services: - - """Test NuageVsp plugin - """ - - def __init__(self): - self.services = { - "account": { - "email": "cloudstack@cloudmonkey.com", - "firstname": "cloudstack", - "lastname": "bob", - "username": "admin", - "password": "password", - }, - "service_offering": { - "name": "Tiny Instance", - "displaytext": "Tiny Instance", - "cpunumber": 1, - "cpuspeed": 100, # in MHz - "memory": 128, # In MBs - }, - "virtual_machine": { - "displayname": "TestVM", - "username": "root", - "password": "password", - "ssh_port": 22, - "hypervisor": 'KVM', - "privateport": 22, - "publicport": 22, - "protocol": 'TCP', - }, - "nuage_vsp_device": { - #"hostname": '192.168.0.7', - #"hostname": '10.31.43.226', - "hostname": '172.31.222.162', - "username": 'cloudstackuser1', - "password": 'cloudstackuser1', - "port": '8443', - "apiversion": 'v3_2', - "retrycount": '4', - "retryinterval": '60' - }, - # services supported by Nuage for VPC networks. - "vpc_network_offering": { - "name": 'nuage_vpc_marvin', - "displaytext": 'nuage_vpc_marvin', - "guestiptype": 'Isolated', - "supportedservices": 'UserData,Dhcp,SourceNat,StaticNat,NetworkACL,Connectivity', - "traffictype": 'GUEST', - "useVpc": 'on', - "serviceProviderList": { - "Dhcp": "NuageVsp", - "SourceNat": "NuageVsp", - "StaticNat": "NuageVsp", - "NetworkACL": "NuageVsp", - "UserData": "VpcVirtualRouter", - "Connectivity": "NuageVsp" - }, - "serviceCapabilityList": { - "SourceNat": {"SupportedSourceNatTypes": "perzone"} - } - }, - "vpc": { - "name": "vpc-networkacl-nuage", - "displaytext": "vpc-networkacl-nuage", - "cidr": '10.1.0.0/16' - }, - "vpcnetwork": { - "name": "nuagevpcnetwork", - "displaytext": "nuagevpcnetwork", - "netmask": '255.255.255.128' - }, - "ostype": 'CentOS 5.5 (64-bit)', - "sleep": 60, - "timeout": 10 - } - - -class TestVpcNetworkNuage(cloudstackTestCase): - - @classmethod - def setUpClass(cls): - cls._cleanup = [] - cls.testClient = super(TestVpcNetworkNuage, cls).getClsTestClient() - cls.api_client = cls.testClient.getApiClient() - - cls.services = Services().services - # Get Zone, Domain and templates - cls.domain = get_domain(cls.api_client) - cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) - cls.template = get_template( - cls.api_client, - cls.zone.id, - cls.services["ostype"] - ) - # nuage vsp device brings the Nuage virtual service platform into play - cls.nuage_services = cls.services["nuage_vsp_device"] - try: - - resp = listPhysicalNetworks.listPhysicalNetworksCmd() - print "in cls.setupClass- resp: %s" % resp - resp.zoneid = cls.zone.id - physical_networks = cls.api_client.listPhysicalNetworks(resp) - for pn in physical_networks: - if pn.isolationmethods=='VSP': - physical_network = pn - #if isinstance(physical_networks, list): - # physical_network = physical_networks[1] - resp = listNetworkServiceProviders.listNetworkServiceProvidersCmd() - resp.name = 'NuageVsp' - resp.physicalnetworkid = physical_network.id - nw_service_providers = cls.api_client.listNetworkServiceProviders( - resp) - if not isinstance(nw_service_providers, list): - # create network service provider and add nuage vsp device - resp_add_nsp = \ - addNetworkServiceProvider.addNetworkServiceProviderCmd() - resp_add_nsp.name = 'NuageVsp' - resp_add_nsp.physicalnetworkid = physical_network.id - cls.api_client.addNetworkServiceProvider(resp_add_nsp) - #Get NSP ID - nw_service_providers = cls.api_client.listNetworkServiceProviders( - resp) - cls.debug("NuageVsp NSP ID: %s" % nw_service_providers[0].id) - - resp_add_device = addNuageVspDevice.addNuageVspDeviceCmd() - resp_add_device.physicalnetworkid = physical_network.id - resp_add_device.username = cls.nuage_services["username"] - resp_add_device.password = cls.nuage_services["password"] - resp_add_device.hostname = cls.nuage_services["hostname"] - resp_add_device.port = cls.nuage_services["port"] - resp_add_device.apiversion = cls.nuage_services[ - "apiversion"] - resp_add_device.retrycount = cls.nuage_services[ - "retrycount"] - resp_add_device.retryinterval = cls.nuage_services[ - "retryinterval"] - cls.nuage = cls.api_client.addNuageVspDevice( - resp_add_device) - #Enable NuageVsp NSP - cls.debug("NuageVsp NSP ID : %s" % nw_service_providers[0].id) - resp_up_nsp = \ - updateNetworkServiceProvider.updateNetworkServiceProviderCmd() - resp_up_nsp.id = nw_service_providers[0].id - resp_up_nsp.state = 'Enabled' - cls.api_client.updateNetworkServiceProvider(resp_up_nsp) - - cls.network_offering = NetworkOffering.create( - cls.api_client, - cls.services["vpc_network_offering"], - conservemode=False - ) - cls._cleanup.append(cls.network_offering) - - cls.network_offering.update(cls.api_client, state='Enabled') - cls.services["virtual_machine"]["zoneid"] = cls.zone.id - cls.services["virtual_machine"]["template"] = cls.template.id - cls.service_offering = ServiceOffering.create( - cls.api_client, - cls.services["service_offering"] - ) - cls._cleanup.append(cls.service_offering) - except Exception as e: - cls.tearDownClass() - raise unittest.SkipTest("Unable to add VSP device") - return - - @attr(tags=["advanced"]) - def test_vpcnetwork_nuage(self): - """Test network VPC for Nuage""" - - # 1) Create VPC with Nuage VPC offering - vpcOffering = VpcOffering.list(self.apiclient,name="Nuage VSP VPC offering") - self.assert_(vpcOffering is not None and len(vpcOffering)>0, "Nuage VPC offering not found") - vpc = VPC.create( - apiclient=self.apiclient, - services=self.services["vpc"], - networkDomain="vpc.networkacl", - vpcofferingid=vpcOffering[0].id, - zoneid=self.zone.id, - account=self.account.name, - domainid=self.account.domainid - ) - self.assert_(vpc is not None, "VPC creation failed") - - # 2) Create ACL - aclgroup = NetworkACLList.create(apiclient=self.apiclient, services={}, name="acl", description="acl", vpcid=vpc.id) - self.assertIsNotNone(aclgroup, "Failed to create NetworkACL list") - self.debug("Created a network ACL list %s" % aclgroup.name) - - # 3) Create ACL Item - aclitem = NetworkACL.create(apiclient=self.apiclient, services={}, - protocol="TCP", number="10", action="Deny", aclid=aclgroup.id, cidrlist=["0.0.0.0/0"]) - self.assertIsNotNone(aclitem, "Network failed to aclItem") - self.debug("Added a network ACL %s to ACL list %s" % (aclitem.id, aclgroup.name)) - - # 4) Create network with ACL - nwNuage = Network.create( - self.apiclient, - self.services["vpcnetwork"], - accountid=self.account.name, - domainid=self.account.domainid, - networkofferingid=self.network_offering.id, - zoneid=self.zone.id, - vpcid=vpc.id, - aclid=aclgroup.id, - gateway='10.1.0.1' - ) - self.debug("Network %s created in VPC %s" %(nwNuage.id, vpc.id)) - - # 5) Deploy a vm - vm = VirtualMachine.create( - self.apiclient, - self.services["virtual_machine"], - accountid=self.account.name, - domainid=self.account.domainid, - serviceofferingid=self.service_offering.id, - networkids=[str(nwNuage.id)] - ) - self.assert_(vm is not None, "VM failed to deploy") - self.assert_(vm.state == 'Running', "VM is not running") - self.debug("VM %s deployed in VPC %s" %(vm.id, vpc.id)) - - @classmethod - def tearDownClass(cls): - try: - cleanup_resources(cls.api_client, cls._cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return - - def setUp(self): - self.apiclient = self.testClient.getApiClient() - self.dbclient = self.testClient.getDbConnection() - self.account = Account.create( - self.apiclient, - self.services["account"], - admin=True, - domainid=self.domain.id - ) - self.cleanup = [self.account] - return - - def tearDown(self): - try: - self.debug("Cleaning up the resources") - cleanup_resources(self.apiclient, self.cleanup) - self.debug("Cleanup complete!") - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return diff --git a/test/integration/plugins/nuagevsp/__init__.py b/test/integration/plugins/nuagevsp/__init__.py new file mode 100644 index 0000000000..13a83393a9 --- /dev/null +++ b/test/integration/plugins/nuagevsp/__init__.py @@ -0,0 +1,16 @@ +# 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. From 255b7464b0ebe869a463534107142eedc8ca2bf4 Mon Sep 17 00:00:00 2001 From: Sowmya Date: Tue, 8 Mar 2016 19:40:43 -0800 Subject: [PATCH 069/203] CLOUDSTACK-9304 - Modified Description --- test/integration/plugins/nuagevsp/nuageTestCase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/plugins/nuagevsp/nuageTestCase.py b/test/integration/plugins/nuagevsp/nuageTestCase.py index 123f2bcaa2..d1298a046e 100644 --- a/test/integration/plugins/nuagevsp/nuageTestCase.py +++ b/test/integration/plugins/nuagevsp/nuageTestCase.py @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -""" Custom base class for NuageVsp network Plugin specific Marvin tests +""" Custom base class for NuageVsp SDN Plugin specific Marvin tests """ # Import Local Modules from marvin.cloudstackTestCase import cloudstackTestCase, unittest From fea264c5da30d5773f31797f7d1ee715a723661d Mon Sep 17 00:00:00 2001 From: gabrascher Date: Wed, 9 Mar 2016 22:43:55 -0300 Subject: [PATCH 070/203] VmDetailConstants "ROOK_DISK_CONTROLLER" to "ROOT_DISK_CONTROLLER" The ROOK_DISK_CONTROLLER variable stores the "rootDiskController" String; thus, this commit changes the name to "ROOT_DISK_CONTROLLER". --- api/src/com/cloud/vm/VmDetailConstants.java | 2 +- .../src/com/cloud/hypervisor/guru/VMwareGuru.java | 4 ++-- .../hypervisor/vmware/resource/VmwareResource.java | 10 +++++----- .../cloud/storage/resource/VmwareStorageProcessor.java | 2 +- server/src/com/cloud/storage/VolumeApiServiceImpl.java | 2 +- server/src/com/cloud/vm/UserVmManagerImpl.java | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/api/src/com/cloud/vm/VmDetailConstants.java b/api/src/com/cloud/vm/VmDetailConstants.java index d06ad67197..d34afc13a1 100644 --- a/api/src/com/cloud/vm/VmDetailConstants.java +++ b/api/src/com/cloud/vm/VmDetailConstants.java @@ -19,7 +19,7 @@ public interface VmDetailConstants { public static final String KEYBOARD = "keyboard"; public static final String NIC_ADAPTER = "nicAdapter"; - public static final String ROOK_DISK_CONTROLLER = "rootDiskController"; + public static final String ROOT_DISK_CONTROLLER = "rootDiskController"; public static final String NESTED_VIRTUALIZATION_FLAG = "nestedVirtualizationFlag"; public static final String HYPERVISOR_TOOLS_VERSION = "hypervisortoolsversion"; public static final String DATA_DISK_CONTROLLER = "dataDiskController"; diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java index fd96bc8357..986000aa93 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java @@ -200,10 +200,10 @@ public VirtualMachineTO implement(VirtualMachineProfile vm) { } } - String diskDeviceType = details.get(VmDetailConstants.ROOK_DISK_CONTROLLER); + String diskDeviceType = details.get(VmDetailConstants.ROOT_DISK_CONTROLLER); if (userVm) { if (diskDeviceType == null) { - details.put(VmDetailConstants.ROOK_DISK_CONTROLLER, _vmwareMgr.getRootDiskController()); + details.put(VmDetailConstants.ROOT_DISK_CONTROLLER, _vmwareMgr.getRootDiskController()); } } String diskController = details.get(VmDetailConstants.DATA_DISK_CONTROLLER); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index b6b9851bd4..184159a94a 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1413,7 +1413,7 @@ protected StartAnswer execute(StartCommand cmd) { String vmInternalCSName = names.first(); String vmNameOnVcenter = names.second(); String dataDiskController = vmSpec.getDetails().get(VmDetailConstants.DATA_DISK_CONTROLLER); - String rootDiskController = vmSpec.getDetails().get(VmDetailConstants.ROOK_DISK_CONTROLLER); + String rootDiskController = vmSpec.getDetails().get(VmDetailConstants.ROOT_DISK_CONTROLLER); // If root disk controller is scsi, then data disk controller would also be scsi instead of using 'osdefault' // This helps avoid mix of different scsi subtype controllers in instance. @@ -2400,14 +2400,14 @@ private int getDiskController(VirtualMachineDiskInfo matchingExistingDisk, DiskT if (vol.getType() == Volume.Type.ROOT) { Map vmDetails = vmSpec.getDetails(); - if (vmDetails != null && vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER) != null) { - if (vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER).equalsIgnoreCase("scsi")) { + if (vmDetails != null && vmDetails.get(VmDetailConstants.ROOT_DISK_CONTROLLER) != null) { + if (vmDetails.get(VmDetailConstants.ROOT_DISK_CONTROLLER).equalsIgnoreCase("scsi")) { s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi, based on root disk controller settings: " + - vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER)); + vmDetails.get(VmDetailConstants.ROOT_DISK_CONTROLLER)); controllerKey = scsiControllerKey; } else { s_logger.info("Chose disk controller for vol " + vol.getType() + " -> ide, based on root disk controller settings: " + - vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER)); + vmDetails.get(VmDetailConstants.ROOT_DISK_CONTROLLER)); controllerKey = ideControllerKey; } } else { diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index ffa839d459..f3bf91c4e5 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -1367,7 +1367,7 @@ private Answer attachVolume(Command cmd, DiskTO disk, boolean isAttach, boolean if (isAttach) { String dataDiskController = controllerInfo.get(VmDetailConstants.DATA_DISK_CONTROLLER); - String rootDiskController = controllerInfo.get(VmDetailConstants.ROOK_DISK_CONTROLLER); + String rootDiskController = controllerInfo.get(VmDetailConstants.ROOT_DISK_CONTROLLER); DiskControllerType rootDiskControllerType = DiskControllerType.getType(rootDiskController); if (dataDiskController == null) { diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index 5a53f9c531..742450ab56 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -2472,7 +2472,7 @@ private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volumeToAttach, L } _userVmDao.loadDetails(vm); Map controllerInfo = new HashMap(); - controllerInfo.put(VmDetailConstants.ROOK_DISK_CONTROLLER, vm.getDetail(VmDetailConstants.ROOK_DISK_CONTROLLER)); + controllerInfo.put(VmDetailConstants.ROOT_DISK_CONTROLLER, vm.getDetail(VmDetailConstants.ROOT_DISK_CONTROLLER)); controllerInfo.put(VmDetailConstants.DATA_DISK_CONTROLLER, vm.getDetail(VmDetailConstants.DATA_DISK_CONTROLLER)); cmd.setControllerInfo(controllerInfo); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index f94778ea91..26a48f4377 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -3505,15 +3505,15 @@ public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCap if (hypervisorType.equals(HypervisorType.VMware)) { if (guestOS.getDisplayName().toLowerCase().contains("apple mac os")) { vm.setDetail("smc.present", "TRUE"); - vm.setDetail(VmDetailConstants.ROOK_DISK_CONTROLLER, "scsi"); + vm.setDetail(VmDetailConstants.ROOT_DISK_CONTROLLER, "scsi"); vm.setDetail(VmDetailConstants.DATA_DISK_CONTROLLER, "scsi"); vm.setDetail("firmware", "efi"); s_logger.info("guestOS is OSX : overwrite root disk controller to scsi, use smc and efi"); } else { String controllerSetting = _configDao.getValue("vmware.root.disk.controller"); // Don't override if VM already has root/data disk controller detail - if (vm.getDetail(VmDetailConstants.ROOK_DISK_CONTROLLER) == null) { - vm.setDetail(VmDetailConstants.ROOK_DISK_CONTROLLER, controllerSetting); + if (vm.getDetail(VmDetailConstants.ROOT_DISK_CONTROLLER) == null) { + vm.setDetail(VmDetailConstants.ROOT_DISK_CONTROLLER, controllerSetting); } if (vm.getDetail(VmDetailConstants.DATA_DISK_CONTROLLER) == null) { if (controllerSetting.equalsIgnoreCase("scsi")) { From db54b26fed51d55879f2f704bcfbc25e52e15461 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Mon, 29 Feb 2016 07:37:12 -0800 Subject: [PATCH 071/203] CLOUDSTACK-9298: Improve ListTemplatesCmd, ListVolumesCmd and ListVMsCmd performance --- .../api/BaseResponseWithTagInformation.java | 40 ++ .../api/response/ResourceTagResponse.java | 4 + .../api/response/TemplateResponse.java | 13 +- .../api/response/UserVmResponse.java | 16 +- .../api/response/VolumeResponse.java | 20 +- .../dao/GenericDaoBaseWithTagInformation.java | 51 +++ .../api/query/dao/TemplateJoinDaoImpl.java | 13 +- .../api/query/dao/UserVmJoinDaoImpl.java | 14 +- .../api/query/dao/VolumeJoinDaoImpl.java | 14 +- .../vo/BaseViewWithTagInformationVO.java | 171 ++++++++ .../cloud/api/query/vo/ResourceTagJoinVO.java | 52 +++ .../cloud/api/query/vo/TemplateJoinVO.java | 79 +--- .../com/cloud/api/query/vo/UserVmJoinVO.java | 75 +--- .../com/cloud/api/query/vo/VolumeJoinVO.java | 75 +--- ...ericDaoBaseWithTagInformationBaseTest.java | 90 ++++ .../query/dao/TemplateJoinDaoImplTest.java | 50 +++ .../api/query/dao/UserVmJoinDaoImplTest.java | 50 +++ .../api/query/dao/VolumeJoinDaoImplTest.java | 50 +++ setup/db/db/schema-481to490.sql | 399 ++++++++++++++++++ 19 files changed, 987 insertions(+), 289 deletions(-) create mode 100755 api/src/org/apache/cloudstack/api/BaseResponseWithTagInformation.java create mode 100755 server/src/com/cloud/api/query/dao/GenericDaoBaseWithTagInformation.java create mode 100755 server/src/com/cloud/api/query/vo/BaseViewWithTagInformationVO.java create mode 100755 server/test/com/cloud/api/query/dao/GenericDaoBaseWithTagInformationBaseTest.java create mode 100755 server/test/com/cloud/api/query/dao/TemplateJoinDaoImplTest.java create mode 100755 server/test/com/cloud/api/query/dao/UserVmJoinDaoImplTest.java create mode 100755 server/test/com/cloud/api/query/dao/VolumeJoinDaoImplTest.java diff --git a/api/src/org/apache/cloudstack/api/BaseResponseWithTagInformation.java b/api/src/org/apache/cloudstack/api/BaseResponseWithTagInformation.java new file mode 100755 index 0000000000..3d694a3141 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/BaseResponseWithTagInformation.java @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api; + +import java.util.Set; + +import org.apache.cloudstack.api.response.ResourceTagResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public abstract class BaseResponseWithTagInformation extends BaseResponse { + + @SerializedName(ApiConstants.TAGS) + @Param(description = "the list of resource tags associated", responseObject = ResourceTagResponse.class) + protected Set tags; + + public void addTag(ResourceTagResponse tag) { + this.tags.add(tag); + } + + public Set getTags(){ + return this.tags; + } + +} diff --git a/api/src/org/apache/cloudstack/api/response/ResourceTagResponse.java b/api/src/org/apache/cloudstack/api/response/ResourceTagResponse.java index ae61347b48..4432556053 100644 --- a/api/src/org/apache/cloudstack/api/response/ResourceTagResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ResourceTagResponse.java @@ -114,6 +114,10 @@ public String getKey() { return this.key; } + public String getValue() { + return this.value; + } + @Override public int hashCode() { final int prime = 31; diff --git a/api/src/org/apache/cloudstack/api/response/TemplateResponse.java b/api/src/org/apache/cloudstack/api/response/TemplateResponse.java index 3e21043e33..4986f2f636 100644 --- a/api/src/org/apache/cloudstack/api/response/TemplateResponse.java +++ b/api/src/org/apache/cloudstack/api/response/TemplateResponse.java @@ -24,7 +24,7 @@ import com.google.gson.annotations.SerializedName; import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.BaseResponseWithTagInformation; import org.apache.cloudstack.api.EntityReference; import com.cloud.serializer.Param; @@ -33,7 +33,7 @@ @EntityReference(value = VirtualMachineTemplate.class) @SuppressWarnings("unused") -public class TemplateResponse extends BaseResponse implements ControlledViewEntityResponse { +public class TemplateResponse extends BaseResponseWithTagInformation implements ControlledViewEntityResponse { @SerializedName(ApiConstants.ID) @Param(description = "the template ID") private String id; @@ -175,10 +175,6 @@ public class TemplateResponse extends BaseResponse implements ControlledViewEnti // @SerializedName("zones") @Param(description="list of zones associated with tempate", responseObject = TemplateZoneResponse.class) // private Set zones; - @SerializedName(ApiConstants.TAGS) - @Param(description = "the list of resource tags associated with tempate", responseObject = ResourceTagResponse.class) - private Set tags; - @SerializedName(ApiConstants.SSHKEY_ENABLED) @Param(description = "true if template is sshkey enabled, false otherwise") private Boolean sshKeyEnabled; @@ -346,10 +342,6 @@ public void setTags(Set tags) { this.tags = tags; } - public void addTag(ResourceTagResponse tag) { - this.tags.add(tag); - } - public void setSshKeyEnabled(boolean sshKeyEnabled) { this.sshKeyEnabled = sshKeyEnabled; } @@ -361,4 +353,5 @@ public void setDynamicallyScalable(boolean isDynamicallyScalable) { public String getZoneId() { return zoneId; } + } diff --git a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java index e8d1a9ed89..d4e612b001 100644 --- a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java +++ b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java @@ -24,7 +24,7 @@ import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.BaseResponseWithTagInformation; import org.apache.cloudstack.api.EntityReference; import com.cloud.network.router.VirtualRouter; @@ -35,7 +35,7 @@ @SuppressWarnings("unused") @EntityReference(value = {VirtualMachine.class, UserVm.class, VirtualRouter.class}) -public class UserVmResponse extends BaseResponse implements ControlledEntityResponse { +public class UserVmResponse extends BaseResponseWithTagInformation implements ControlledEntityResponse { @SerializedName(ApiConstants.ID) @Param(description = "the ID of the virtual machine") private String id; @@ -244,10 +244,6 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp @Param(description = "instance name of the user vm; this parameter is returned to the ROOT admin only", since = "3.0.1") private String instanceName; - @SerializedName(ApiConstants.TAGS) - @Param(description = "the list of resource tags associated with vm", responseObject = ResourceTagResponse.class) - private Set tags; - transient Set tagIds; @SerializedName(ApiConstants.DETAILS) @@ -514,10 +510,6 @@ public String getInstanceName() { return instanceName; } - public Set getTags() { - return tags; - } - public String getKeyPairName() { return keyPairName; } @@ -758,10 +750,6 @@ public void setTags(Set tags) { this.tags = tags; } - public void addTag(ResourceTagResponse tag) { - this.tags.add(tag); - } - public void setKeyPairName(String keyPairName) { this.keyPairName = keyPairName; } diff --git a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java index eeb4af9c9e..a934563e9f 100644 --- a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java +++ b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java @@ -22,7 +22,7 @@ import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.BaseResponseWithTagInformation; import org.apache.cloudstack.api.EntityReference; import com.cloud.serializer.Param; @@ -31,7 +31,7 @@ @EntityReference(value = Volume.class) @SuppressWarnings("unused") -public class VolumeResponse extends BaseResponse implements ControlledViewEntityResponse { +public class VolumeResponse extends BaseResponseWithTagInformation implements ControlledViewEntityResponse { @SerializedName(ApiConstants.ID) @Param(description = "ID of the disk volume") private String id; @@ -212,10 +212,6 @@ public class VolumeResponse extends BaseResponse implements ControlledViewEntity @Param(description = "the status of the volume") private String status; - @SerializedName(ApiConstants.TAGS) - @Param(description = "the list of resource tags associated with volume", responseObject = ResourceTagResponse.class) - private Set tags; - @SerializedName(ApiConstants.DISPLAY_VOLUME) @Param(description = "an optional field whether to the display the volume to the end user or not.", authorized = {RoleType.Admin}) private Boolean displayVolume; @@ -439,14 +435,6 @@ public void setProjectName(String projectName) { this.projectName = projectName; } - public void setTags(Set tags) { - this.tags = tags; - } - - public void addTag(ResourceTagResponse tag) { - this.tags.add(tag); - } - public void setDisplayVolume(Boolean displayVm) { this.displayVolume = displayVm; } @@ -522,4 +510,8 @@ public String getTemplateDisplayText() { public void setTemplateDisplayText(String templateDisplayText) { this.templateDisplayText = templateDisplayText; } + + public void setTags(Set tags) { + this.tags = tags; + } } diff --git a/server/src/com/cloud/api/query/dao/GenericDaoBaseWithTagInformation.java b/server/src/com/cloud/api/query/dao/GenericDaoBaseWithTagInformation.java new file mode 100755 index 0000000000..e6760d8a21 --- /dev/null +++ b/server/src/com/cloud/api/query/dao/GenericDaoBaseWithTagInformation.java @@ -0,0 +1,51 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.query.dao; + +import org.apache.cloudstack.api.BaseResponseWithTagInformation; + +import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.vo.BaseViewWithTagInformationVO; +import com.cloud.api.query.vo.ResourceTagJoinVO; +import com.cloud.utils.db.GenericDaoBase; + +public abstract class GenericDaoBaseWithTagInformation extends GenericDaoBase { + + /** + * Update tag information on baseResponse + * @param baseView base view containing tag information + * @param baseResponse response to update + */ + protected void addTagInformation(T baseView, Z baseResponse) { + ResourceTagJoinVO vtag = new ResourceTagJoinVO(); + vtag.setId(baseView.getTagId()); + vtag.setUuid(baseView.getTagUuid()); + vtag.setKey(baseView.getTagKey()); + vtag.setValue(baseView.getTagValue()); + vtag.setDomainId(baseView.getTagDomainId()); + vtag.setAccountId(baseView.getTagAccountId()); + vtag.setResourceId(baseView.getTagResourceId()); + vtag.setResourceUuid(baseView.getTagResourceUuid()); + vtag.setResourceType(baseView.getTagResourceType()); + vtag.setCustomer(baseView.getTagCustomer()); + vtag.setAccountName(baseView.getTagAccountName()); + vtag.setDomainName(baseView.getTagDomainName()); + vtag.setDomainUuid(baseView.getTagDomainUuid()); + baseResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); + } + +} diff --git a/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java index 5444eca6ba..38120af38c 100644 --- a/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java @@ -46,13 +46,12 @@ import com.cloud.user.AccountService; import com.cloud.utils.Pair; import com.cloud.utils.db.Filter; -import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; @Component -public class TemplateJoinDaoImpl extends GenericDaoBase implements TemplateJoinDao { +public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation implements TemplateJoinDao { public static final Logger s_logger = Logger.getLogger(TemplateJoinDaoImpl.class); @@ -188,10 +187,7 @@ public TemplateResponse newTemplateResponse(ResponseView view, TemplateJoinVO te // update tag information long tag_id = template.getTagId(); if (tag_id > 0) { - ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id); - if (vtag != null) { - templateResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); - } + addTagInformation(template, templateResponse); } templateResponse.setObjectName("template"); @@ -257,10 +253,7 @@ public TemplateResponse setTemplateResponse(ResponseView view, TemplateResponse // update tag information long tag_id = template.getTagId(); if (tag_id > 0) { - ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id); - if (vtag != null) { - templateResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); - } + addTagInformation(template, templateResponse); } return templateResponse; diff --git a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java index 7983065f31..079da57047 100644 --- a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java @@ -40,7 +40,6 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import com.cloud.api.ApiDBUtils; -import com.cloud.api.query.vo.ResourceTagJoinVO; import com.cloud.api.query.vo.UserVmJoinVO; import com.cloud.gpu.GPU; import com.cloud.hypervisor.Hypervisor.HypervisorType; @@ -50,7 +49,6 @@ import com.cloud.user.User; import com.cloud.user.dao.UserDao; import com.cloud.uservm.UserVm; -import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.vm.UserVmDetailVO; @@ -61,7 +59,7 @@ import com.cloud.vm.dao.UserVmDetailsDao; @Component -public class UserVmJoinDaoImpl extends GenericDaoBase implements UserVmJoinDao { +public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation implements UserVmJoinDao { public static final Logger s_logger = Logger.getLogger(UserVmJoinDaoImpl.class); @Inject @@ -283,10 +281,7 @@ public UserVmResponse newUserVmResponse(ResponseView view, String objectName, Us // update tag information long tag_id = userVm.getTagId(); if (tag_id > 0 && !userVmResponse.containTag(tag_id)) { - ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id); - if (vtag != null) { - userVmResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); - } + addTagInformation(userVm, userVmResponse); } if (details.contains(VMDetails.all) || details.contains(VMDetails.affgrp)) { @@ -383,10 +378,7 @@ public UserVmResponse setUserVmResponse(ResponseView view, UserVmResponse userVm long tag_id = uvo.getTagId(); if (tag_id > 0 && !userVmData.containTag(tag_id)) { - ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id); - if (vtag != null) { - userVmData.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); - } + addTagInformation(uvo, userVmData); } Long affinityGroupId = uvo.getAffinityGroupId(); diff --git a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java index 54d1ca164e..73e0c6d6cd 100644 --- a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java @@ -29,7 +29,6 @@ import com.cloud.api.ApiDBUtils; import com.cloud.api.ApiResponseHelper; -import com.cloud.api.query.vo.ResourceTagJoinVO; import com.cloud.api.query.vo.VolumeJoinVO; import com.cloud.offering.ServiceOffering; import com.cloud.storage.Storage; @@ -37,12 +36,11 @@ import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.Volume; import com.cloud.user.AccountManager; -import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; @Component -public class VolumeJoinDaoImpl extends GenericDaoBase implements VolumeJoinDao { +public class VolumeJoinDaoImpl extends GenericDaoBaseWithTagInformation implements VolumeJoinDao { public static final Logger s_logger = Logger.getLogger(VolumeJoinDaoImpl.class); @Inject @@ -221,10 +219,7 @@ public VolumeResponse newVolumeResponse(ResponseView view, VolumeJoinVO volume) // update tag information long tag_id = volume.getTagId(); if (tag_id > 0) { - ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id); - if (vtag != null) { - volResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); - } + addTagInformation(volume, volResponse); } volResponse.setExtractable(isExtractable); @@ -253,10 +248,7 @@ public VolumeResponse newVolumeResponse(ResponseView view, VolumeJoinVO volume) public VolumeResponse setVolumeResponse(ResponseView view, VolumeResponse volData, VolumeJoinVO vol) { long tag_id = vol.getTagId(); if (tag_id > 0) { - ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id); - if (vtag != null) { - volData.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); - } + addTagInformation(vol, volData); } return volData; } diff --git a/server/src/com/cloud/api/query/vo/BaseViewWithTagInformationVO.java b/server/src/com/cloud/api/query/vo/BaseViewWithTagInformationVO.java new file mode 100755 index 0000000000..075cde2d8d --- /dev/null +++ b/server/src/com/cloud/api/query/vo/BaseViewWithTagInformationVO.java @@ -0,0 +1,171 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.query.vo; + +import javax.persistence.Column; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; + +import com.cloud.server.ResourceTag.ResourceObjectType; + +public abstract class BaseViewWithTagInformationVO extends BaseViewVO { + + @Column(name = "tag_id") + private long tagId; + + @Column(name = "tag_uuid") + private String tagUuid; + + @Column(name = "tag_key") + private String tagKey; + + @Column(name = "tag_value") + private String tagValue; + + @Column(name = "tag_domain_id") + private long tagDomainId; + + @Column(name = "tag_account_id") + private long tagAccountId; + + @Column(name = "tag_resource_id") + private long tagResourceId; + + @Column(name = "tag_resource_uuid") + private String tagResourceUuid; + + @Column(name = "tag_resource_type") + @Enumerated(value = EnumType.STRING) + private ResourceObjectType tagResourceType; + + @Column(name = "tag_customer") + private String tagCustomer; + + @Column(name = "tag_account_name") + private String tagAccountName; + + @Column(name = "tag_domain_uuid") + private String tagDomainUuid; + + @Column(name = "tag_domain_name") + private String tagDomainName; + + public long getTagId() { + return tagId; + } + + public void setTagId(long tagId) { + this.tagId = tagId; + } + + public String getTagUuid() { + return tagUuid; + } + + public void setTagUuid(String tagUuid) { + this.tagUuid = tagUuid; + } + + public String getTagKey() { + return tagKey; + } + + public void setTagKey(String tagKey) { + this.tagKey = tagKey; + } + + public String getTagValue() { + return tagValue; + } + + public void setTagValue(String tagValue) { + this.tagValue = tagValue; + } + + public long getTagDomainId() { + return tagDomainId; + } + + public void setTagDomainId(long tagDomainId) { + this.tagDomainId = tagDomainId; + } + + public long getTagAccountId() { + return tagAccountId; + } + + public void setTagAccountId(long tagAccountId) { + this.tagAccountId = tagAccountId; + } + + public long getTagResourceId() { + return tagResourceId; + } + + public void setTagResourceId(long tagResourceId) { + this.tagResourceId = tagResourceId; + } + + public String getTagResourceUuid() { + return tagResourceUuid; + } + + public void setTagResourceUuid(String tagResourceUuid) { + this.tagResourceUuid = tagResourceUuid; + } + + public ResourceObjectType getTagResourceType() { + return tagResourceType; + } + + public void setTagResourceType(ResourceObjectType tagResourceType) { + this.tagResourceType = tagResourceType; + } + + public String getTagCustomer() { + return tagCustomer; + } + + public void setTagCustomer(String tagCustomer) { + this.tagCustomer = tagCustomer; + } + + public String getTagAccountName() { + return tagAccountName; + } + + public void setTagAccountName(String tagAccountName) { + this.tagAccountName = tagAccountName; + } + + public String getTagDomainUuid() { + return tagDomainUuid; + } + + public void setTagDomainUuid(String tagDomainUuid) { + this.tagDomainUuid = tagDomainUuid; + } + + public String getTagDomainName() { + return tagDomainName; + } + + public void setTagDomainName(String tagDomainName) { + this.tagDomainName = tagDomainName; + } + +} diff --git a/server/src/com/cloud/api/query/vo/ResourceTagJoinVO.java b/server/src/com/cloud/api/query/vo/ResourceTagJoinVO.java index 2c1ff47509..6758552ed3 100644 --- a/server/src/com/cloud/api/query/vo/ResourceTagJoinVO.java +++ b/server/src/com/cloud/api/query/vo/ResourceTagJoinVO.java @@ -184,4 +184,56 @@ public String getCustomer() { public Class getEntityType() { return ResourceTag.class; } + + public void setId(long id) { + this.id = id; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public void setKey(String key) { + this.key = key; + } + + public void setValue(String value) { + this.value = value; + } + + public void setResourceId(long resourceId) { + this.resourceId = resourceId; + } + + public void setResourceUuid(String resourceUuid) { + this.resourceUuid = resourceUuid; + } + + public void setResourceType(ResourceObjectType resourceType) { + this.resourceType = resourceType; + } + + public void setAccountId(long accountId) { + this.accountId = accountId; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public void setDomainId(long domainId) { + this.domainId = domainId; + } + + public void setDomainUuid(String domainUuid) { + this.domainUuid = domainUuid; + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + public void setCustomer(String customer) { + this.customer = customer; + } } diff --git a/server/src/com/cloud/api/query/vo/TemplateJoinVO.java b/server/src/com/cloud/api/query/vo/TemplateJoinVO.java index 834a9cedd0..c8eed0a453 100644 --- a/server/src/com/cloud/api/query/vo/TemplateJoinVO.java +++ b/server/src/com/cloud/api/query/vo/TemplateJoinVO.java @@ -30,7 +30,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.server.ResourceTag.ResourceObjectType; import com.cloud.storage.ScopeType; import com.cloud.storage.Storage; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; @@ -40,7 +39,7 @@ @Entity @Table(name = "template_view") -public class TemplateJoinVO extends BaseViewVO implements ControlledViewEntity { +public class TemplateJoinVO extends BaseViewWithTagInformationVO implements ControlledViewEntity { @Id @Column(name = "id") @@ -218,37 +217,6 @@ public class TemplateJoinVO extends BaseViewVO implements ControlledViewEntity { @Column(name = "detail_value") private String detailValue; - @Column(name = "tag_id") - private long tagId; - - @Column(name = "tag_uuid") - private String tagUuid; - - @Column(name = "tag_key") - private String tagKey; - - @Column(name = "tag_value") - private String tagValue; - - @Column(name = "tag_domain_id") - private long tagDomainId; - - @Column(name = "tag_account_id") - private long tagAccountId; - - @Column(name = "tag_resource_id") - private long tagResourceId; - - @Column(name = "tag_resource_uuid") - private String tagResourceUuid; - - @Column(name = "tag_resource_type") - @Enumerated(value = EnumType.STRING) - private ResourceObjectType tagResourceType; - - @Column(name = "tag_customer") - private String tagCustomer; - @Column(name = "state") @Enumerated(EnumType.STRING) ObjectInDataStoreStateMachine.State state; @@ -343,46 +311,6 @@ public Storage.TemplateType getTemplateType() { return templateType; } - public long getTagId() { - return tagId; - } - - public String getTagUuid() { - return tagUuid; - } - - public String getTagKey() { - return tagKey; - } - - public String getTagValue() { - return tagValue; - } - - public long getTagDomainId() { - return tagDomainId; - } - - public long getTagAccountId() { - return tagAccountId; - } - - public long getTagResourceId() { - return tagResourceId; - } - - public String getTagResourceUuid() { - return tagResourceUuid; - } - - public ResourceObjectType getTagResourceType() { - return tagResourceType; - } - - public String getTagCustomer() { - return tagCustomer; - } - public long getDataCenterId() { return dataCenterId; } @@ -547,4 +475,9 @@ public State getTemplateState() { public Class getEntityType() { return VirtualMachineTemplate.class; } + + public void setAccountId(long accountId) { + this.accountId = accountId; + } + } diff --git a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java index 54a48fb06a..2847c6b83b 100644 --- a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java @@ -31,7 +31,6 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.Network.GuestType; import com.cloud.network.Networks.TrafficType; -import com.cloud.server.ResourceTag.ResourceObjectType; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Volume; import com.cloud.utils.db.GenericDao; @@ -40,7 +39,7 @@ @Entity @Table(name = "user_vm_view") -public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { +public class UserVmJoinVO extends BaseViewWithTagInformationVO implements ControlledViewEntity { @Id @Column(name = "id", updatable = false, nullable = false) @@ -346,37 +345,6 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { @Column(name = "job_status") private int jobStatus; - @Column(name = "tag_id") - private long tagId; - - @Column(name = "tag_uuid") - private String tagUuid; - - @Column(name = "tag_key") - private String tagKey; - - @Column(name = "tag_value") - private String tagValue; - - @Column(name = "tag_domain_id") - private long tagDomainId; - - @Column(name = "tag_account_id") - private long tagAccountId; - - @Column(name = "tag_resource_id") - private long tagResourceId; - - @Column(name = "tag_resource_uuid") - private String tagResourceUuid; - - @Column(name = "tag_resource_type") - @Enumerated(value = EnumType.STRING) - private ResourceObjectType tagResourceType; - - @Column(name = "tag_customer") - private String tagCustomer; - @Column(name = "affinity_group_id") private long affinityGroupId; @@ -776,46 +744,6 @@ public String getKeypairName() { return keypairName; } - public long getTagId() { - return tagId; - } - - public String getTagUuid() { - return tagUuid; - } - - public String getTagKey() { - return tagKey; - } - - public String getTagValue() { - return tagValue; - } - - public long getTagDomainId() { - return tagDomainId; - } - - public long getTagAccountId() { - return tagAccountId; - } - - public long getTagResourceId() { - return tagResourceId; - } - - public String getTagResourceUuid() { - return tagResourceUuid; - } - - public ResourceObjectType getTagResourceType() { - return tagResourceType; - } - - public String getTagCustomer() { - return tagCustomer; - } - public boolean isLimitCpuUse() { return limitCpuUse; } @@ -907,4 +835,5 @@ public Boolean isDynamicallyScalable() { public Class getEntityType() { return VirtualMachine.class; } + } diff --git a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java index d9c482ce0a..e39b1b1c41 100644 --- a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java +++ b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java @@ -28,7 +28,6 @@ import javax.persistence.TemporalType; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.server.ResourceTag.ResourceObjectType; import com.cloud.storage.Storage; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.Volume; @@ -37,7 +36,7 @@ @Entity @Table(name = "volume_view") -public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity { +public class VolumeJoinVO extends BaseViewWithTagInformationVO implements ControlledViewEntity { @Id @Column(name = "id") @@ -252,37 +251,6 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity { @Column(name = "job_status") private int jobStatus; - @Column(name = "tag_id") - private long tagId; - - @Column(name = "tag_uuid") - private String tagUuid; - - @Column(name = "tag_key") - private String tagKey; - - @Column(name = "tag_value") - private String tagValue; - - @Column(name = "tag_domain_id") - private long tagDomainId; - - @Column(name = "tag_account_id") - private long tagAccountId; - - @Column(name = "tag_resource_id") - private long tagResourceId; - - @Column(name = "tag_resource_uuid") - private String tagResourceUuid; - - @Column(name = "tag_resource_type") - @Enumerated(value = EnumType.STRING) - private ResourceObjectType tagResourceType; - - @Column(name = "tag_customer") - private String tagCustomer; - @Column(name = "display_volume", updatable = true, nullable = false) protected boolean displayVolume; @@ -563,46 +531,6 @@ public int getJobStatus() { return jobStatus; } - public long getTagId() { - return tagId; - } - - public String getTagUuid() { - return tagUuid; - } - - public String getTagKey() { - return tagKey; - } - - public String getTagValue() { - return tagValue; - } - - public long getTagDomainId() { - return tagDomainId; - } - - public long getTagAccountId() { - return tagAccountId; - } - - public long getTagResourceId() { - return tagResourceId; - } - - public String getTagResourceUuid() { - return tagResourceUuid; - } - - public ResourceObjectType getTagResourceType() { - return tagResourceType; - } - - public String getTagCustomer() { - return tagCustomer; - } - public long getDataCenterId() { return dataCenterId; } @@ -636,4 +564,5 @@ public String getChainInfo() { public Class getEntityType() { return Volume.class; } + } diff --git a/server/test/com/cloud/api/query/dao/GenericDaoBaseWithTagInformationBaseTest.java b/server/test/com/cloud/api/query/dao/GenericDaoBaseWithTagInformationBaseTest.java new file mode 100755 index 0000000000..c7c65f8d93 --- /dev/null +++ b/server/test/com/cloud/api/query/dao/GenericDaoBaseWithTagInformationBaseTest.java @@ -0,0 +1,90 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.query.dao; + +import static org.junit.Assert.assertEquals; + +import org.apache.cloudstack.api.BaseResponseWithTagInformation; +import org.apache.cloudstack.api.response.ResourceTagResponse; +import org.powermock.api.mockito.PowerMockito; + +import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.vo.BaseViewWithTagInformationVO; +import com.cloud.server.ResourceTag.ResourceObjectType; + +public abstract class GenericDaoBaseWithTagInformationBaseTest { + + private final static long TAG_ID = 1l; + private final static String TAG_KEY = "type"; + private final static String TAG_VALUE = "supported"; + private final static String TAG_UUID = "aaaa-aaaa-aaaa-aaaa"; + private final static ResourceObjectType TAG_RESOURCE_TYPE = ResourceObjectType.Template; + private final static String TAG_RESOURCE_TYPE_STR = "Template"; + private final static String TAG_RESOURCE_UUID = "aaaa-aaaa-aaaa-aaaa"; + private final static long TAG_DOMAIN_ID = 123l; + private final static String TAG_DOMAIN_ID_STR = "123"; + private final static String TAG_DOMAIN_NAME = "aaaa-aaaa-aaaa-aaaa"; + private final static String TAG_CUSTOMER = "aaaa-aaaa-aaaa-aaaa"; + private final static String TAG_ACCOUNT_NAME = "admin"; + + private final static String RESPONSE_OBJECT_NAME = "tag"; + + public void prepareSetup(){ + PowerMockito.spy(ApiDBUtils.class); + PowerMockito.stub(PowerMockito.method(ApiDBUtils.class, "newResourceTagResponse")).toReturn(getResourceTagResponse()); + } + + private ResourceTagResponse getResourceTagResponse(){ + ResourceTagResponse tagResponse = new ResourceTagResponse(); + tagResponse.setKey(TAG_KEY); + tagResponse.setValue(TAG_VALUE); + tagResponse.setObjectName(RESPONSE_OBJECT_NAME); + tagResponse.setResourceType(TAG_RESOURCE_TYPE_STR); + tagResponse.setResourceId(TAG_RESOURCE_UUID); + tagResponse.setDomainId(TAG_DOMAIN_ID_STR); + tagResponse.setDomainName(TAG_DOMAIN_NAME); + tagResponse.setCustomer(TAG_CUSTOMER); + tagResponse.setAccountName(TAG_ACCOUNT_NAME); + return tagResponse; + } + + private void prepareBaseView(long tagId, T baseView){ + baseView.setTagId(tagId); + baseView.setTagKey(TAG_KEY); + baseView.setTagValue(TAG_VALUE); + baseView.setTagUuid(TAG_UUID); + baseView.setTagResourceType(TAG_RESOURCE_TYPE); + baseView.setTagAccountName(TAG_ACCOUNT_NAME); + baseView.setTagDomainId(TAG_DOMAIN_ID); + baseView.setTagDomainName(TAG_DOMAIN_NAME); + baseView.setTagCustomer(TAG_CUSTOMER); + baseView.setTagAccountName(TAG_ACCOUNT_NAME); + } + + public void testUpdateTagInformation(GenericDaoBaseWithTagInformation dao, T baseView, Z baseResponse){ + prepareBaseView(TAG_ID, baseView); + dao.addTagInformation(baseView, baseResponse); + ResourceTagResponse[] responseArray = new ResourceTagResponse[baseResponse.getTags().size()]; + baseResponse.getTags().toArray(responseArray); + assertEquals(1, responseArray.length); + assertEquals(TAG_KEY, responseArray[0].getKey()); + assertEquals(TAG_VALUE, responseArray[0].getValue()); + assertEquals(RESPONSE_OBJECT_NAME, responseArray[0].getObjectName()); + } + +} diff --git a/server/test/com/cloud/api/query/dao/TemplateJoinDaoImplTest.java b/server/test/com/cloud/api/query/dao/TemplateJoinDaoImplTest.java new file mode 100755 index 0000000000..d194e32c0f --- /dev/null +++ b/server/test/com/cloud/api/query/dao/TemplateJoinDaoImplTest.java @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.query.dao; + +import org.apache.cloudstack.api.response.TemplateResponse; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.vo.TemplateJoinVO; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(ApiDBUtils.class) +public class TemplateJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseTest { + + @InjectMocks + private TemplateJoinDaoImpl _templateJoinDaoImpl; + + private TemplateJoinVO template = new TemplateJoinVO(); + private TemplateResponse templateResponse = new TemplateResponse(); + + @Before + public void setup() { + prepareSetup(); + } + + @Test + public void testUpdateTemplateTagInfo(){ + testUpdateTagInformation(_templateJoinDaoImpl, template, templateResponse); + } + +} \ No newline at end of file diff --git a/server/test/com/cloud/api/query/dao/UserVmJoinDaoImplTest.java b/server/test/com/cloud/api/query/dao/UserVmJoinDaoImplTest.java new file mode 100755 index 0000000000..669143ebf4 --- /dev/null +++ b/server/test/com/cloud/api/query/dao/UserVmJoinDaoImplTest.java @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.query.dao; + +import org.apache.cloudstack.api.response.UserVmResponse; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.vo.UserVmJoinVO; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(ApiDBUtils.class) +public class UserVmJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseTest { + + @InjectMocks + private UserVmJoinDaoImpl _userVmJoinDaoImpl; + + private UserVmJoinVO userVm = new UserVmJoinVO(); + private UserVmResponse userVmResponse = new UserVmResponse(); + + @Before + public void setup() { + prepareSetup(); + } + + @Test + public void testUpdateUserVmTagInfo(){ + testUpdateTagInformation(_userVmJoinDaoImpl, userVm, userVmResponse); + } + +} \ No newline at end of file diff --git a/server/test/com/cloud/api/query/dao/VolumeJoinDaoImplTest.java b/server/test/com/cloud/api/query/dao/VolumeJoinDaoImplTest.java new file mode 100755 index 0000000000..b0b0ad2273 --- /dev/null +++ b/server/test/com/cloud/api/query/dao/VolumeJoinDaoImplTest.java @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.query.dao; + +import org.apache.cloudstack.api.response.VolumeResponse; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.vo.VolumeJoinVO; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(ApiDBUtils.class) +public class VolumeJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseTest { + + @InjectMocks + private VolumeJoinDaoImpl _volumeJoinDaoImpl; + + private VolumeJoinVO volume = new VolumeJoinVO(); + private VolumeResponse volumeResponse = new VolumeResponse(); + + @Before + public void setup() { + prepareSetup(); + } + + @Test + public void testUpdateVolumeTagInfo(){ + testUpdateTagInformation(_volumeJoinDaoImpl, volume, volumeResponse); + } + +} diff --git a/setup/db/db/schema-481to490.sql b/setup/db/db/schema-481to490.sql index 0f27e45582..cebe605685 100644 --- a/setup/db/db/schema-481to490.sql +++ b/setup/db/db/schema-481to490.sql @@ -21,3 +21,402 @@ ALTER TABLE `event` ADD INDEX `archived` (`archived`); ALTER TABLE `event` ADD INDEX `state` (`state`); + +DROP VIEW IF EXISTS `cloud`.`template_view`; +CREATE + ALGORITHM = UNDEFINED + DEFINER = `cloud`@`%` + SQL SECURITY DEFINER +VIEW `template_view` AS + SELECT + `vm_template`.`id` AS `id`, + `vm_template`.`uuid` AS `uuid`, + `vm_template`.`unique_name` AS `unique_name`, + `vm_template`.`name` AS `name`, + `vm_template`.`public` AS `public`, + `vm_template`.`featured` AS `featured`, + `vm_template`.`type` AS `type`, + `vm_template`.`hvm` AS `hvm`, + `vm_template`.`bits` AS `bits`, + `vm_template`.`url` AS `url`, + `vm_template`.`format` AS `format`, + `vm_template`.`created` AS `created`, + `vm_template`.`checksum` AS `checksum`, + `vm_template`.`display_text` AS `display_text`, + `vm_template`.`enable_password` AS `enable_password`, + `vm_template`.`dynamically_scalable` AS `dynamically_scalable`, + `vm_template`.`state` AS `template_state`, + `vm_template`.`guest_os_id` AS `guest_os_id`, + `guest_os`.`uuid` AS `guest_os_uuid`, + `guest_os`.`display_name` AS `guest_os_name`, + `vm_template`.`bootable` AS `bootable`, + `vm_template`.`prepopulate` AS `prepopulate`, + `vm_template`.`cross_zones` AS `cross_zones`, + `vm_template`.`hypervisor_type` AS `hypervisor_type`, + `vm_template`.`extractable` AS `extractable`, + `vm_template`.`template_tag` AS `template_tag`, + `vm_template`.`sort_key` AS `sort_key`, + `vm_template`.`removed` AS `removed`, + `vm_template`.`enable_sshkey` AS `enable_sshkey`, + `source_template`.`id` AS `source_template_id`, + `source_template`.`uuid` AS `source_template_uuid`, + `account`.`id` AS `account_id`, + `account`.`uuid` AS `account_uuid`, + `account`.`account_name` AS `account_name`, + `account`.`type` AS `account_type`, + `domain`.`id` AS `domain_id`, + `domain`.`uuid` AS `domain_uuid`, + `domain`.`name` AS `domain_name`, + `domain`.`path` AS `domain_path`, + `projects`.`id` AS `project_id`, + `projects`.`uuid` AS `project_uuid`, + `projects`.`name` AS `project_name`, + `data_center`.`id` AS `data_center_id`, + `data_center`.`uuid` AS `data_center_uuid`, + `data_center`.`name` AS `data_center_name`, + `launch_permission`.`account_id` AS `lp_account_id`, + `template_store_ref`.`store_id` AS `store_id`, + `image_store`.`scope` AS `store_scope`, + `template_store_ref`.`state` AS `state`, + `template_store_ref`.`download_state` AS `download_state`, + `template_store_ref`.`download_pct` AS `download_pct`, + `template_store_ref`.`error_str` AS `error_str`, + `template_store_ref`.`size` AS `size`, + `template_store_ref`.`destroyed` AS `destroyed`, + `template_store_ref`.`created` AS `created_on_store`, + `vm_template_details`.`name` AS `detail_name`, + `vm_template_details`.`value` AS `detail_value`, + `resource_tags`.`id` AS `tag_id`, + `resource_tags`.`uuid` AS `tag_uuid`, + `resource_tags`.`key` AS `tag_key`, + `resource_tags`.`value` AS `tag_value`, + `resource_tags`.`domain_id` AS `tag_domain_id`, + `domain`.`uuid` AS `tag_domain_uuid`, + `domain`.`name` AS `tag_domain_name`, + `resource_tags`.`account_id` AS `tag_account_id`, + `account`.`account_name` AS `tag_account_name`, + `resource_tags`.`resource_id` AS `tag_resource_id`, + `resource_tags`.`resource_uuid` AS `tag_resource_uuid`, + `resource_tags`.`resource_type` AS `tag_resource_type`, + `resource_tags`.`customer` AS `tag_customer`, + CONCAT(`vm_template`.`id`, + '_', + IFNULL(`data_center`.`id`, 0)) AS `temp_zone_pair` + FROM + ((((((((((((`vm_template` + JOIN `guest_os` ON ((`guest_os`.`id` = `vm_template`.`guest_os_id`))) + JOIN `account` ON ((`account`.`id` = `vm_template`.`account_id`))) + JOIN `domain` ON ((`domain`.`id` = `account`.`domain_id`))) + LEFT JOIN `projects` ON ((`projects`.`project_account_id` = `account`.`id`))) + LEFT JOIN `vm_template_details` ON ((`vm_template_details`.`template_id` = `vm_template`.`id`))) + LEFT JOIN `vm_template` `source_template` ON ((`source_template`.`id` = `vm_template`.`source_template_id`))) + LEFT JOIN `template_store_ref` ON (((`template_store_ref`.`template_id` = `vm_template`.`id`) + AND (`template_store_ref`.`store_role` = 'Image') + AND (`template_store_ref`.`destroyed` = 0)))) + LEFT JOIN `image_store` ON ((ISNULL(`image_store`.`removed`) + AND (`template_store_ref`.`store_id` IS NOT NULL) + AND (`image_store`.`id` = `template_store_ref`.`store_id`)))) + LEFT JOIN `template_zone_ref` ON (((`template_zone_ref`.`template_id` = `vm_template`.`id`) + AND ISNULL(`template_store_ref`.`store_id`) + AND ISNULL(`template_zone_ref`.`removed`)))) + LEFT JOIN `data_center` ON (((`image_store`.`data_center_id` = `data_center`.`id`) + OR (`template_zone_ref`.`zone_id` = `data_center`.`id`)))) + LEFT JOIN `launch_permission` ON ((`launch_permission`.`template_id` = `vm_template`.`id`))) + LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_template`.`id`) + AND ((`resource_tags`.`resource_type` = 'Template') + OR (`resource_tags`.`resource_type` = 'ISO'))))); + +DROP VIEW IF EXISTS `cloud`.`volume_view`; +CREATE + ALGORITHM = UNDEFINED + DEFINER = `cloud`@`%` + SQL SECURITY DEFINER +VIEW `volume_view` AS + SELECT + `volumes`.`id` AS `id`, + `volumes`.`uuid` AS `uuid`, + `volumes`.`name` AS `name`, + `volumes`.`device_id` AS `device_id`, + `volumes`.`volume_type` AS `volume_type`, + `volumes`.`provisioning_type` AS `provisioning_type`, + `volumes`.`size` AS `size`, + `volumes`.`min_iops` AS `min_iops`, + `volumes`.`max_iops` AS `max_iops`, + `volumes`.`created` AS `created`, + `volumes`.`state` AS `state`, + `volumes`.`attached` AS `attached`, + `volumes`.`removed` AS `removed`, + `volumes`.`pod_id` AS `pod_id`, + `volumes`.`display_volume` AS `display_volume`, + `volumes`.`format` AS `format`, + `volumes`.`path` AS `path`, + `volumes`.`chain_info` AS `chain_info`, + `account`.`id` AS `account_id`, + `account`.`uuid` AS `account_uuid`, + `account`.`account_name` AS `account_name`, + `account`.`type` AS `account_type`, + `domain`.`id` AS `domain_id`, + `domain`.`uuid` AS `domain_uuid`, + `domain`.`name` AS `domain_name`, + `domain`.`path` AS `domain_path`, + `projects`.`id` AS `project_id`, + `projects`.`uuid` AS `project_uuid`, + `projects`.`name` AS `project_name`, + `data_center`.`id` AS `data_center_id`, + `data_center`.`uuid` AS `data_center_uuid`, + `data_center`.`name` AS `data_center_name`, + `data_center`.`networktype` AS `data_center_type`, + `vm_instance`.`id` AS `vm_id`, + `vm_instance`.`uuid` AS `vm_uuid`, + `vm_instance`.`name` AS `vm_name`, + `vm_instance`.`state` AS `vm_state`, + `vm_instance`.`vm_type` AS `vm_type`, + `user_vm`.`display_name` AS `vm_display_name`, + `volume_store_ref`.`size` AS `volume_store_size`, + `volume_store_ref`.`download_pct` AS `download_pct`, + `volume_store_ref`.`download_state` AS `download_state`, + `volume_store_ref`.`error_str` AS `error_str`, + `volume_store_ref`.`created` AS `created_on_store`, + `disk_offering`.`id` AS `disk_offering_id`, + `disk_offering`.`uuid` AS `disk_offering_uuid`, + `disk_offering`.`name` AS `disk_offering_name`, + `disk_offering`.`display_text` AS `disk_offering_display_text`, + `disk_offering`.`use_local_storage` AS `use_local_storage`, + `disk_offering`.`system_use` AS `system_use`, + `disk_offering`.`bytes_read_rate` AS `bytes_read_rate`, + `disk_offering`.`bytes_write_rate` AS `bytes_write_rate`, + `disk_offering`.`iops_read_rate` AS `iops_read_rate`, + `disk_offering`.`iops_write_rate` AS `iops_write_rate`, + `disk_offering`.`cache_mode` AS `cache_mode`, + `storage_pool`.`id` AS `pool_id`, + `storage_pool`.`uuid` AS `pool_uuid`, + `storage_pool`.`name` AS `pool_name`, + `cluster`.`hypervisor_type` AS `hypervisor_type`, + `vm_template`.`id` AS `template_id`, + `vm_template`.`uuid` AS `template_uuid`, + `vm_template`.`extractable` AS `extractable`, + `vm_template`.`type` AS `template_type`, + `vm_template`.`name` AS `template_name`, + `vm_template`.`display_text` AS `template_display_text`, + `iso`.`id` AS `iso_id`, + `iso`.`uuid` AS `iso_uuid`, + `iso`.`name` AS `iso_name`, + `iso`.`display_text` AS `iso_display_text`, + `resource_tags`.`id` AS `tag_id`, + `resource_tags`.`uuid` AS `tag_uuid`, + `resource_tags`.`key` AS `tag_key`, + `resource_tags`.`value` AS `tag_value`, + `resource_tags`.`domain_id` AS `tag_domain_id`, + `domain`.`uuid` AS `tag_domain_uuid`, + `domain`.`name` AS `tag_domain_name`, + `resource_tags`.`account_id` AS `tag_account_id`, + `account`.`account_name` AS `tag_account_name`, + `resource_tags`.`resource_id` AS `tag_resource_id`, + `resource_tags`.`resource_uuid` AS `tag_resource_uuid`, + `resource_tags`.`resource_type` AS `tag_resource_type`, + `resource_tags`.`customer` AS `tag_customer`, + `async_job`.`id` AS `job_id`, + `async_job`.`uuid` AS `job_uuid`, + `async_job`.`job_status` AS `job_status`, + `async_job`.`account_id` AS `job_account_id` + FROM + ((((((((((((((`volumes` + JOIN `account` ON ((`volumes`.`account_id` = `account`.`id`))) + JOIN `domain` ON ((`volumes`.`domain_id` = `domain`.`id`))) + LEFT JOIN `projects` ON ((`projects`.`project_account_id` = `account`.`id`))) + LEFT JOIN `data_center` ON ((`volumes`.`data_center_id` = `data_center`.`id`))) + LEFT JOIN `vm_instance` ON ((`volumes`.`instance_id` = `vm_instance`.`id`))) + LEFT JOIN `user_vm` ON ((`user_vm`.`id` = `vm_instance`.`id`))) + LEFT JOIN `volume_store_ref` ON ((`volumes`.`id` = `volume_store_ref`.`volume_id`))) + LEFT JOIN `disk_offering` ON ((`volumes`.`disk_offering_id` = `disk_offering`.`id`))) + LEFT JOIN `storage_pool` ON ((`volumes`.`pool_id` = `storage_pool`.`id`))) + LEFT JOIN `cluster` ON ((`storage_pool`.`cluster_id` = `cluster`.`id`))) + LEFT JOIN `vm_template` ON ((`volumes`.`template_id` = `vm_template`.`id`))) + LEFT JOIN `vm_template` `iso` ON ((`iso`.`id` = `volumes`.`iso_id`))) + LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `volumes`.`id`) + AND (`resource_tags`.`resource_type` = 'Volume')))) + LEFT JOIN `async_job` ON (((`async_job`.`instance_id` = `volumes`.`id`) + AND (`async_job`.`instance_type` = 'Volume') + AND (`async_job`.`job_status` = 0)))); + +DROP VIEW IF EXISTS `cloud`.`user_vm__view`; + +CREATE + ALGORITHM = UNDEFINED + DEFINER = `cloud`@`%` + SQL SECURITY DEFINER +VIEW `user_vm_view` AS + SELECT + `vm_instance`.`id` AS `id`, + `vm_instance`.`name` AS `name`, + `user_vm`.`display_name` AS `display_name`, + `user_vm`.`user_data` AS `user_data`, + `account`.`id` AS `account_id`, + `account`.`uuid` AS `account_uuid`, + `account`.`account_name` AS `account_name`, + `account`.`type` AS `account_type`, + `domain`.`id` AS `domain_id`, + `domain`.`uuid` AS `domain_uuid`, + `domain`.`name` AS `domain_name`, + `domain`.`path` AS `domain_path`, + `projects`.`id` AS `project_id`, + `projects`.`uuid` AS `project_uuid`, + `projects`.`name` AS `project_name`, + `instance_group`.`id` AS `instance_group_id`, + `instance_group`.`uuid` AS `instance_group_uuid`, + `instance_group`.`name` AS `instance_group_name`, + `vm_instance`.`uuid` AS `uuid`, + `vm_instance`.`user_id` AS `user_id`, + `vm_instance`.`last_host_id` AS `last_host_id`, + `vm_instance`.`vm_type` AS `type`, + `vm_instance`.`limit_cpu_use` AS `limit_cpu_use`, + `vm_instance`.`created` AS `created`, + `vm_instance`.`state` AS `state`, + `vm_instance`.`removed` AS `removed`, + `vm_instance`.`ha_enabled` AS `ha_enabled`, + `vm_instance`.`hypervisor_type` AS `hypervisor_type`, + `vm_instance`.`instance_name` AS `instance_name`, + `vm_instance`.`guest_os_id` AS `guest_os_id`, + `vm_instance`.`display_vm` AS `display_vm`, + `guest_os`.`uuid` AS `guest_os_uuid`, + `vm_instance`.`pod_id` AS `pod_id`, + `host_pod_ref`.`uuid` AS `pod_uuid`, + `vm_instance`.`private_ip_address` AS `private_ip_address`, + `vm_instance`.`private_mac_address` AS `private_mac_address`, + `vm_instance`.`vm_type` AS `vm_type`, + `data_center`.`id` AS `data_center_id`, + `data_center`.`uuid` AS `data_center_uuid`, + `data_center`.`name` AS `data_center_name`, + `data_center`.`is_security_group_enabled` AS `security_group_enabled`, + `data_center`.`networktype` AS `data_center_type`, + `host`.`id` AS `host_id`, + `host`.`uuid` AS `host_uuid`, + `host`.`name` AS `host_name`, + `vm_template`.`id` AS `template_id`, + `vm_template`.`uuid` AS `template_uuid`, + `vm_template`.`name` AS `template_name`, + `vm_template`.`display_text` AS `template_display_text`, + `vm_template`.`enable_password` AS `password_enabled`, + `iso`.`id` AS `iso_id`, + `iso`.`uuid` AS `iso_uuid`, + `iso`.`name` AS `iso_name`, + `iso`.`display_text` AS `iso_display_text`, + `service_offering`.`id` AS `service_offering_id`, + `svc_disk_offering`.`uuid` AS `service_offering_uuid`, + `disk_offering`.`uuid` AS `disk_offering_uuid`, + `disk_offering`.`id` AS `disk_offering_id`, + (CASE + WHEN ISNULL(`service_offering`.`cpu`) THEN `custom_cpu`.`value` + ELSE `service_offering`.`cpu` + END) AS `cpu`, + (CASE + WHEN ISNULL(`service_offering`.`speed`) THEN `custom_speed`.`value` + ELSE `service_offering`.`speed` + END) AS `speed`, + (CASE + WHEN ISNULL(`service_offering`.`ram_size`) THEN `custom_ram_size`.`value` + ELSE `service_offering`.`ram_size` + END) AS `ram_size`, + `svc_disk_offering`.`name` AS `service_offering_name`, + `disk_offering`.`name` AS `disk_offering_name`, + `storage_pool`.`id` AS `pool_id`, + `storage_pool`.`uuid` AS `pool_uuid`, + `storage_pool`.`pool_type` AS `pool_type`, + `volumes`.`id` AS `volume_id`, + `volumes`.`uuid` AS `volume_uuid`, + `volumes`.`device_id` AS `volume_device_id`, + `volumes`.`volume_type` AS `volume_type`, + `security_group`.`id` AS `security_group_id`, + `security_group`.`uuid` AS `security_group_uuid`, + `security_group`.`name` AS `security_group_name`, + `security_group`.`description` AS `security_group_description`, + `nics`.`id` AS `nic_id`, + `nics`.`uuid` AS `nic_uuid`, + `nics`.`network_id` AS `network_id`, + `nics`.`ip4_address` AS `ip_address`, + `nics`.`ip6_address` AS `ip6_address`, + `nics`.`ip6_gateway` AS `ip6_gateway`, + `nics`.`ip6_cidr` AS `ip6_cidr`, + `nics`.`default_nic` AS `is_default_nic`, + `nics`.`gateway` AS `gateway`, + `nics`.`netmask` AS `netmask`, + `nics`.`mac_address` AS `mac_address`, + `nics`.`broadcast_uri` AS `broadcast_uri`, + `nics`.`isolation_uri` AS `isolation_uri`, + `vpc`.`id` AS `vpc_id`, + `vpc`.`uuid` AS `vpc_uuid`, + `networks`.`uuid` AS `network_uuid`, + `networks`.`name` AS `network_name`, + `networks`.`traffic_type` AS `traffic_type`, + `networks`.`guest_type` AS `guest_type`, + `user_ip_address`.`id` AS `public_ip_id`, + `user_ip_address`.`uuid` AS `public_ip_uuid`, + `user_ip_address`.`public_ip_address` AS `public_ip_address`, + `ssh_keypairs`.`keypair_name` AS `keypair_name`, + `resource_tags`.`id` AS `tag_id`, + `resource_tags`.`uuid` AS `tag_uuid`, + `resource_tags`.`key` AS `tag_key`, + `resource_tags`.`value` AS `tag_value`, + `resource_tags`.`domain_id` AS `tag_domain_id`, + `domain`.`uuid` AS `tag_domain_uuid`, + `domain`.`name` AS `tag_domain_name`, + `resource_tags`.`account_id` AS `tag_account_id`, + `account`.`account_name` AS `tag_account_name`, + `resource_tags`.`resource_id` AS `tag_resource_id`, + `resource_tags`.`resource_uuid` AS `tag_resource_uuid`, + `resource_tags`.`resource_type` AS `tag_resource_type`, + `resource_tags`.`customer` AS `tag_customer`, + `async_job`.`id` AS `job_id`, + `async_job`.`uuid` AS `job_uuid`, + `async_job`.`job_status` AS `job_status`, + `async_job`.`account_id` AS `job_account_id`, + `affinity_group`.`id` AS `affinity_group_id`, + `affinity_group`.`uuid` AS `affinity_group_uuid`, + `affinity_group`.`name` AS `affinity_group_name`, + `affinity_group`.`description` AS `affinity_group_description`, + `vm_instance`.`dynamically_scalable` AS `dynamically_scalable` + FROM + ((((((((((((((((((((((((((((((((`user_vm` + JOIN `vm_instance` ON (((`vm_instance`.`id` = `user_vm`.`id`) + AND ISNULL(`vm_instance`.`removed`)))) + JOIN `account` ON ((`vm_instance`.`account_id` = `account`.`id`))) + JOIN `domain` ON ((`vm_instance`.`domain_id` = `domain`.`id`))) + LEFT JOIN `guest_os` ON ((`vm_instance`.`guest_os_id` = `guest_os`.`id`))) + LEFT JOIN `host_pod_ref` ON ((`vm_instance`.`pod_id` = `host_pod_ref`.`id`))) + LEFT JOIN `projects` ON ((`projects`.`project_account_id` = `account`.`id`))) + LEFT JOIN `instance_group_vm_map` ON ((`vm_instance`.`id` = `instance_group_vm_map`.`instance_id`))) + LEFT JOIN `instance_group` ON ((`instance_group_vm_map`.`group_id` = `instance_group`.`id`))) + LEFT JOIN `data_center` ON ((`vm_instance`.`data_center_id` = `data_center`.`id`))) + LEFT JOIN `host` ON ((`vm_instance`.`host_id` = `host`.`id`))) + LEFT JOIN `vm_template` ON ((`vm_instance`.`vm_template_id` = `vm_template`.`id`))) + LEFT JOIN `vm_template` `iso` ON ((`iso`.`id` = `user_vm`.`iso_id`))) + LEFT JOIN `service_offering` ON ((`vm_instance`.`service_offering_id` = `service_offering`.`id`))) + LEFT JOIN `disk_offering` `svc_disk_offering` ON ((`vm_instance`.`service_offering_id` = `svc_disk_offering`.`id`))) + LEFT JOIN `disk_offering` ON ((`vm_instance`.`disk_offering_id` = `disk_offering`.`id`))) + LEFT JOIN `volumes` ON ((`vm_instance`.`id` = `volumes`.`instance_id`))) + LEFT JOIN `storage_pool` ON ((`volumes`.`pool_id` = `storage_pool`.`id`))) + LEFT JOIN `security_group_vm_map` ON ((`vm_instance`.`id` = `security_group_vm_map`.`instance_id`))) + LEFT JOIN `security_group` ON ((`security_group_vm_map`.`security_group_id` = `security_group`.`id`))) + LEFT JOIN `nics` ON (((`vm_instance`.`id` = `nics`.`instance_id`) + AND ISNULL(`nics`.`removed`)))) + LEFT JOIN `networks` ON ((`nics`.`network_id` = `networks`.`id`))) + LEFT JOIN `vpc` ON (((`networks`.`vpc_id` = `vpc`.`id`) + AND ISNULL(`vpc`.`removed`)))) + LEFT JOIN `user_ip_address` ON ((`user_ip_address`.`vm_id` = `vm_instance`.`id`))) + LEFT JOIN `user_vm_details` `ssh_details` ON (((`ssh_details`.`vm_id` = `vm_instance`.`id`) + AND (`ssh_details`.`name` = 'SSH.PublicKey')))) + LEFT JOIN `ssh_keypairs` ON (((`ssh_keypairs`.`public_key` = `ssh_details`.`value`) + AND (`ssh_keypairs`.`account_id` = `account`.`id`)))) + LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_instance`.`id`) + AND (`resource_tags`.`resource_type` = 'UserVm')))) + LEFT JOIN `async_job` ON (((`async_job`.`instance_id` = `vm_instance`.`id`) + AND (`async_job`.`instance_type` = 'VirtualMachine') + AND (`async_job`.`job_status` = 0)))) + LEFT JOIN `affinity_group_vm_map` ON ((`vm_instance`.`id` = `affinity_group_vm_map`.`instance_id`))) + LEFT JOIN `affinity_group` ON ((`affinity_group_vm_map`.`affinity_group_id` = `affinity_group`.`id`))) + LEFT JOIN `user_vm_details` `custom_cpu` ON (((`custom_cpu`.`vm_id` = `vm_instance`.`id`) + AND (`custom_cpu`.`name` = 'CpuNumber')))) + LEFT JOIN `user_vm_details` `custom_speed` ON (((`custom_speed`.`vm_id` = `vm_instance`.`id`) + AND (`custom_speed`.`name` = 'CpuSpeed')))) + LEFT JOIN `user_vm_details` `custom_ram_size` ON (((`custom_ram_size`.`vm_id` = `vm_instance`.`id`) + AND (`custom_ram_size`.`name` = 'memory')))); From 9857f41d9a4e99df58c71ea01e20178d18e03eb1 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Wed, 9 Mar 2016 11:42:34 -0800 Subject: [PATCH 072/203] CLOUDSTACK-9298: Add @MappedSuperClass support for persistence inheritance --- .../db/src/com/cloud/utils/db/SqlGenerator.java | 11 +++++++++++ .../api/query/vo/BaseViewWithTagInformationVO.java | 14 +++++++++++++- .../src/com/cloud/api/query/vo/TemplateJoinVO.java | 10 ---------- .../src/com/cloud/api/query/vo/UserVmJoinVO.java | 9 +++------ .../src/com/cloud/api/query/vo/VolumeJoinVO.java | 10 ---------- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/framework/db/src/com/cloud/utils/db/SqlGenerator.java b/framework/db/src/com/cloud/utils/db/SqlGenerator.java index 864ee73274..e6cb9cb889 100644 --- a/framework/db/src/com/cloud/utils/db/SqlGenerator.java +++ b/framework/db/src/com/cloud/utils/db/SqlGenerator.java @@ -38,10 +38,12 @@ import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.FetchType; +import javax.persistence.MappedSuperclass; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.SecondaryTable; import javax.persistence.TableGenerator; +import org.apache.commons.lang.ArrayUtils; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; import com.cloud.utils.db.Attribute.Flag; @@ -54,6 +56,7 @@ public class SqlGenerator { LinkedHashMap> _ids; HashMap _generators; ArrayList _ecAttrs; + Field[] _mappedSuperclassFields; public SqlGenerator(Class clazz) { _clazz = clazz; @@ -91,6 +94,12 @@ protected boolean checkMethods(Class clazz, Map attrs) { protected void buildAttributes(Class clazz, String tableName, AttributeOverride[] overrides, boolean embedded, boolean isId) { if (!embedded && clazz.getAnnotation(Entity.class) == null) { + // A class designated with the MappedSuperclass annotation can be mapped in the same way as an entity + // except that the mappings will apply only to its subclasses since no table exists for the mapped superclass itself + if (clazz.getAnnotation(MappedSuperclass.class) != null){ + Field[] declaredFields = clazz.getDeclaredFields(); + _mappedSuperclassFields = (Field[]) ArrayUtils.addAll(_mappedSuperclassFields, declaredFields); + } return; } @@ -105,6 +114,8 @@ protected void buildAttributes(Class clazz, String tableName, AttributeOverri } Field[] fields = clazz.getDeclaredFields(); + fields = (Field[]) ArrayUtils.addAll(fields, _mappedSuperclassFields); + _mappedSuperclassFields = null; for (Field field : fields) { field.setAccessible(true); diff --git a/server/src/com/cloud/api/query/vo/BaseViewWithTagInformationVO.java b/server/src/com/cloud/api/query/vo/BaseViewWithTagInformationVO.java index 075cde2d8d..ec2947ae1f 100755 --- a/server/src/com/cloud/api/query/vo/BaseViewWithTagInformationVO.java +++ b/server/src/com/cloud/api/query/vo/BaseViewWithTagInformationVO.java @@ -16,13 +16,21 @@ // under the License. package com.cloud.api.query.vo; +import java.io.Serializable; import javax.persistence.Column; import javax.persistence.EnumType; import javax.persistence.Enumerated; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; import com.cloud.server.ResourceTag.ResourceObjectType; -public abstract class BaseViewWithTagInformationVO extends BaseViewVO { +@MappedSuperclass +public abstract class BaseViewWithTagInformationVO extends BaseViewVO implements Serializable { + + @Id + @Column(name = "id") + private long id; @Column(name = "tag_id") private long tagId; @@ -168,4 +176,8 @@ public void setTagDomainName(String tagDomainName) { this.tagDomainName = tagDomainName; } + public long getId() { + return id; + } + } diff --git a/server/src/com/cloud/api/query/vo/TemplateJoinVO.java b/server/src/com/cloud/api/query/vo/TemplateJoinVO.java index c8eed0a453..43a9c3b09c 100644 --- a/server/src/com/cloud/api/query/vo/TemplateJoinVO.java +++ b/server/src/com/cloud/api/query/vo/TemplateJoinVO.java @@ -22,7 +22,6 @@ import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; -import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; @@ -41,10 +40,6 @@ @Table(name = "template_view") public class TemplateJoinVO extends BaseViewWithTagInformationVO implements ControlledViewEntity { - @Id - @Column(name = "id") - private long id; - @Column(name = "uuid") private String uuid; @@ -227,11 +222,6 @@ public class TemplateJoinVO extends BaseViewWithTagInformationVO implements Cont public TemplateJoinVO() { } - @Override - public long getId() { - return id; - } - @Override public String getUuid() { return uuid; diff --git a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java index 2847c6b83b..7ff557c8fc 100644 --- a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java @@ -20,6 +20,7 @@ import java.util.Date; import java.util.Map; +import javax.persistence.AttributeOverride; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; @@ -39,6 +40,7 @@ @Entity @Table(name = "user_vm_view") +@AttributeOverride( name="id", column = @Column(name = "id", updatable = false, nullable = false) ) public class UserVmJoinVO extends BaseViewWithTagInformationVO implements ControlledViewEntity { @Id @@ -372,11 +374,6 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro public UserVmJoinVO() { } - @Override - public long getId() { - return id; - } - @Override public String getUuid() { return uuid; @@ -793,7 +790,7 @@ public int getJobStatus() { @Override public String toString() { if (toString == null) { - toString = new StringBuilder("VM[").append(id).append("|").append(name).append("]").toString(); + toString = new StringBuilder("VM[").append(getId()).append("|").append(name).append("]").toString(); } return toString; } diff --git a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java index e39b1b1c41..77785b1de5 100644 --- a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java +++ b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java @@ -22,7 +22,6 @@ import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; -import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; @@ -38,10 +37,6 @@ @Table(name = "volume_view") public class VolumeJoinVO extends BaseViewWithTagInformationVO implements ControlledViewEntity { - @Id - @Column(name = "id") - private long id; - @Column(name = "uuid") private String uuid; @@ -263,11 +258,6 @@ public class VolumeJoinVO extends BaseViewWithTagInformationVO implements Contro public VolumeJoinVO() { } - @Override - public long getId() { - return id; - } - @Override public String getUuid() { return uuid; From 1446ecd715a7f2714db72cdef012875b8c5a470d Mon Sep 17 00:00:00 2001 From: Sowmya Date: Thu, 10 Mar 2016 18:10:39 -0800 Subject: [PATCH 073/203] CLOUDSTACK-9304 - Exit loop when Physical Network with isolation as VSP is found modified: nuageTestCase.py --- test/integration/plugins/nuagevsp/nuageTestCase.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/integration/plugins/nuagevsp/nuageTestCase.py b/test/integration/plugins/nuagevsp/nuageTestCase.py index d1298a046e..cb13f19241 100644 --- a/test/integration/plugins/nuagevsp/nuageTestCase.py +++ b/test/integration/plugins/nuagevsp/nuageTestCase.py @@ -95,6 +95,7 @@ def setUpClass(cls): for pn in physical_networks: if pn.isolationmethods == 'VSP': cls.vsp_physical_network = pn + break cls.nuage_vsp_device = Nuage.list(cls.api_client, physicalnetworkid=cls.vsp_physical_network.id )[0] From c19d8b47397ffb528e3836c9b86749f601b29dbe Mon Sep 17 00:00:00 2001 From: nvazquez Date: Fri, 11 Mar 2016 06:35:24 -0300 Subject: [PATCH 074/203] CLOUDSTACK-9298: Remove user definer from view creations --- setup/db/db/schema-481to490.sql | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/setup/db/db/schema-481to490.sql b/setup/db/db/schema-481to490.sql index cebe605685..75df7d0eb2 100644 --- a/setup/db/db/schema-481to490.sql +++ b/setup/db/db/schema-481to490.sql @@ -24,9 +24,6 @@ ALTER TABLE `event` ADD INDEX `state` (`state`); DROP VIEW IF EXISTS `cloud`.`template_view`; CREATE - ALGORITHM = UNDEFINED - DEFINER = `cloud`@`%` - SQL SECURITY DEFINER VIEW `template_view` AS SELECT `vm_template`.`id` AS `id`, @@ -128,9 +125,6 @@ VIEW `template_view` AS DROP VIEW IF EXISTS `cloud`.`volume_view`; CREATE - ALGORITHM = UNDEFINED - DEFINER = `cloud`@`%` - SQL SECURITY DEFINER VIEW `volume_view` AS SELECT `volumes`.`id` AS `id`, @@ -239,12 +233,8 @@ VIEW `volume_view` AS AND (`async_job`.`instance_type` = 'Volume') AND (`async_job`.`job_status` = 0)))); -DROP VIEW IF EXISTS `cloud`.`user_vm__view`; - +DROP VIEW IF EXISTS `cloud`.`user_vm_view`; CREATE - ALGORITHM = UNDEFINED - DEFINER = `cloud`@`%` - SQL SECURITY DEFINER VIEW `user_vm_view` AS SELECT `vm_instance`.`id` AS `id`, From b3de01a8dc039f36b8b19578936b52df50e79dc6 Mon Sep 17 00:00:00 2001 From: weingartner Date: Sun, 13 Mar 2016 10:16:47 -0300 Subject: [PATCH 075/203] Fix findbugs slow build 3455 --- .../resource/NfsSecondaryStorageResource.java | 95 ++++++++----------- 1 file changed, 40 insertions(+), 55 deletions(-) diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index 663699aad2..08eab337c9 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -16,8 +16,8 @@ // under the License. package org.apache.cloudstack.storage.resource; -import static com.cloud.utils.storage.S3.S3Utils.putFile; import static com.cloud.utils.StringUtils.join; +import static com.cloud.utils.storage.S3.S3Utils.putFile; import static java.lang.String.format; import static java.util.Arrays.asList; import static org.apache.commons.lang.StringUtils.substringAfterLast; @@ -46,63 +46,42 @@ import javax.naming.ConfigurationException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.storage.Storage; -import com.cloud.storage.template.TemplateConstants; -import com.cloud.utils.EncryptionUtil; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.handler.codec.http.HttpContentCompressor; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import io.netty.handler.logging.LogLevel; -import io.netty.handler.logging.LoggingHandler; - -import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand; -import org.apache.cloudstack.storage.template.UploadEntity; -import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.log4j.Logger; - -import com.amazonaws.services.s3.model.S3ObjectSummary; - import org.apache.cloudstack.framework.security.keystore.KeystoreManager; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.command.DownloadCommand; import org.apache.cloudstack.storage.command.DownloadProgressCommand; +import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand; import org.apache.cloudstack.storage.command.UploadStatusAnswer; import org.apache.cloudstack.storage.command.UploadStatusAnswer.UploadStatus; import org.apache.cloudstack.storage.command.UploadStatusCommand; import org.apache.cloudstack.storage.template.DownloadManager; import org.apache.cloudstack.storage.template.DownloadManagerImpl; import org.apache.cloudstack.storage.template.DownloadManagerImpl.ZfsPathParser; +import org.apache.cloudstack.storage.template.UploadEntity; import org.apache.cloudstack.storage.template.UploadManager; import org.apache.cloudstack.storage.template.UploadManagerImpl; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.log4j.Logger; +import org.joda.time.DateTime; +import org.joda.time.format.ISODateTimeFormat; +import com.amazonaws.services.s3.model.S3ObjectSummary; import com.cloud.agent.api.Answer; import com.cloud.agent.api.CheckHealthAnswer; import com.cloud.agent.api.CheckHealthCommand; @@ -137,11 +116,13 @@ import com.cloud.agent.api.to.S3TO; import com.cloud.agent.api.to.SwiftTO; import com.cloud.exception.InternalErrorException; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.host.Host; import com.cloud.host.Host.Type; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ServerResourceBase; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.Storage; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.VMTemplateStorageResourceAssoc; @@ -151,21 +132,36 @@ import com.cloud.storage.template.QCOW2Processor; import com.cloud.storage.template.RawImageProcessor; import com.cloud.storage.template.TARProcessor; +import com.cloud.storage.template.TemplateConstants; import com.cloud.storage.template.TemplateLocation; import com.cloud.storage.template.TemplateProp; import com.cloud.storage.template.VhdProcessor; import com.cloud.storage.template.VmdkProcessor; +import com.cloud.utils.EncryptionUtil; import com.cloud.utils.NumbersUtil; -import com.cloud.utils.storage.S3.S3Utils; import com.cloud.utils.SwiftUtil; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.utils.script.OutputInterpreter; import com.cloud.utils.script.Script; +import com.cloud.utils.storage.S3.S3Utils; import com.cloud.vm.SecondaryStorageVm; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; -import org.joda.time.DateTime; -import org.joda.time.format.ISODateTimeFormat; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.HttpContentCompressor; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; public class NfsSecondaryStorageResource extends ServerResourceBase implements SecondaryStorageResource { @@ -395,16 +391,9 @@ protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataT return new CopyCmdAnswer(errMsg); } } - File destFile = new File(downloadDirectory, substringAfterLast(srcData.getPath(), S3Utils.SEPARATOR)); - S3Utils.getFile(s3, s3.getBucketName(), srcData.getPath(), destFile).waitForCompletion(); - - if (destFile == null) { - return new CopyCmdAnswer("Can't find template"); - } - return postProcessing(destFile, downloadPath, destPath, srcData, destData); } catch (Exception e) { @@ -691,7 +680,6 @@ protected Answer execute(CopyCommand cmd) { return Answer.createUnsupportedCommandAnswer(cmd); } - @SuppressWarnings("unchecked") protected String determineS3TemplateDirectory(final Long accountId, final Long templateId, final String templateUniqueName) { return join(asList(TEMPLATE_ROOT_DIR, accountId, templateId, templateUniqueName), S3Utils.SEPARATOR); } @@ -700,7 +688,6 @@ private String determineS3TemplateNameFromKey(String key) { return StringUtils.substringAfterLast(StringUtils.substringBeforeLast(key, S3Utils.SEPARATOR), S3Utils.SEPARATOR); } - @SuppressWarnings("unchecked") protected String determineS3VolumeDirectory(final Long accountId, final Long volId) { return join(asList(VOLUME_ROOT_DIR, accountId, volId), S3Utils.SEPARATOR); } @@ -2306,7 +2293,7 @@ protected String mountUri(URI uri, String nfsVersion) throws UnknownHostExceptio String nfsPath = uriHostIp + ":" + uri.getPath(); // Single means of calculating mount directory regardless of scheme - String dir = UUID.nameUUIDFromBytes(nfsPath.getBytes()).toString(); + String dir = UUID.nameUUIDFromBytes(nfsPath.getBytes(com.cloud.utils.StringUtils.getPreferredCharset())).toString(); String localRootPath = _parent + "/" + dir; // remote device syntax varies by scheme. @@ -2318,9 +2305,7 @@ protected String mountUri(URI uri, String nfsVersion) throws UnknownHostExceptio remoteDevice = nfsPath; s_logger.debug("Mounting device with nfs-style path of " + remoteDevice); } - mount(localRootPath, remoteDevice, uri, nfsVersion); - return dir; } From 01034ea8d642102dadc2fd39d7a01e860cecfa79 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Sun, 13 Mar 2016 14:35:51 -0300 Subject: [PATCH 076/203] Removed Unused Void Class Removed the class Void.java from /cloud-framework-ipc/src/org/apache/cloudstack/framework/async/Void.java since the method public void AsyncMethod(Object realParam, AsyncCompletionCallback callback) does not exist and it does not seemed to be used in another place. Also, removed an unnecessary comment in /cloudstack-framework/ipc/test/org/apache/cloudstack/framework/codestyle/AsyncSampleListenerStyleCaller.java --- .../cloudstack/framework/async/Void.java | 27 ------------------- .../AsyncSampleListenerStyleCaller.java | 9 ------- 2 files changed, 36 deletions(-) delete mode 100644 framework/ipc/src/org/apache/cloudstack/framework/async/Void.java diff --git a/framework/ipc/src/org/apache/cloudstack/framework/async/Void.java b/framework/ipc/src/org/apache/cloudstack/framework/async/Void.java deleted file mode 100644 index b4c6d4a173..0000000000 --- a/framework/ipc/src/org/apache/cloudstack/framework/async/Void.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cloudstack.framework.async; - -/** - * This is place-holder class to help AsyncMethod to indicate void return value - * public void AsyncMethod(Object realParam, AsyncCompletionCallback callback) { - * - */ -public class Void { -} diff --git a/framework/ipc/test/org/apache/cloudstack/framework/codestyle/AsyncSampleListenerStyleCaller.java b/framework/ipc/test/org/apache/cloudstack/framework/codestyle/AsyncSampleListenerStyleCaller.java index b1dbfc5a16..2c7c86f0b6 100644 --- a/framework/ipc/test/org/apache/cloudstack/framework/codestyle/AsyncSampleListenerStyleCaller.java +++ b/framework/ipc/test/org/apache/cloudstack/framework/codestyle/AsyncSampleListenerStyleCaller.java @@ -23,14 +23,5 @@ public class AsyncSampleListenerStyleCaller { public void MethodThatWillCallAsyncMethod() { String vol = new String(); - - /* _ds.createVolume(vol, - new AsyncCompletionCallback() { - @Override - public void complete(String resultObject) { - // TODO Auto-generated method stub - - } - });*/ } } From 65d7ae379d8bf5bc39fc1aa384b1edbf61a248b0 Mon Sep 17 00:00:00 2001 From: Sowmya Date: Mon, 14 Mar 2016 18:06:28 -0700 Subject: [PATCH 077/203] Made the code Pyflakes compliant --- .../plugins/nuagevsp/nuageTestCase.py | 27 --------- .../nuagevsp/test_nuage_password_reset.py | 55 ++++++++++++++----- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/test/integration/plugins/nuagevsp/nuageTestCase.py b/test/integration/plugins/nuagevsp/nuageTestCase.py index cb13f19241..55199d5d80 100644 --- a/test/integration/plugins/nuagevsp/nuageTestCase.py +++ b/test/integration/plugins/nuagevsp/nuageTestCase.py @@ -48,9 +48,6 @@ listHypervisors, stopRouter, startRouter) -# Import nosetests Modules -from nose.plugins.attrib import attr - # Import System Modules import socket import importlib @@ -318,30 +315,6 @@ def create_VM_in_Network(self, network, vm_key="virtual_machine", host_id=None, self.cleanup.append(vm) return vm - # starts the given vm - def start(self, apiclient): - """Start the instance""" - cmd = startVirtualMachine.startVirtualMachineCmd() - cmd.id = self.id - apiclient.startVirtualMachine(cmd) - response = self.getState(apiclient, VirtualMachine.RUNNING) - if response[0] == FAIL: - raise Exception(response[1]) - return - - # stops the given vm - def stop(self, apiclient, forced=None): - """Stop the instance""" - cmd = stopVirtualMachine.stopVirtualMachineCmd() - cmd.id = self.id - if forced: - cmd.forced = forced - apiclient.stopVirtualMachine(cmd) - response = self.getState(apiclient, VirtualMachine.STOPPED) - if response[0] == FAIL: - raise Exception(response[1]) - return - # delete_VM - Deletes the given VM def delete_VM(self, vm): self.debug('Deleting VM - %s' % vm.name) diff --git a/test/integration/plugins/nuagevsp/test_nuage_password_reset.py b/test/integration/plugins/nuagevsp/test_nuage_password_reset.py index 3e600c2dc6..5582819d90 100644 --- a/test/integration/plugins/nuagevsp/test_nuage_password_reset.py +++ b/test/integration/plugins/nuagevsp/test_nuage_password_reset.py @@ -18,13 +18,14 @@ """ Component tests for - userdata """ # Import Local Modules -from marvin.lib.base import (VirtualMachine, - Account, - PublicIPAddress) +from marvin.lib.base import (Account, + VirtualMachine, + Volume, + Template) from nose.plugins.attrib import attr from nuageTestCase import nuageTestCase -from marvin.cloudstackAPI import (createTemplate, - listVolumes) +from marvin.lib.utils import cleanup_resources +from marvin.cloudstackAPI import startVirtualMachine import base64 @@ -69,12 +70,10 @@ def tearDown(self): # create_template - Takes the VM object as the argument to create the template def create_template(self, vm): self.debug("CREATE TEMPLATE") - list_volume = list_volumes( - self.apiclient, - virtualmachineid=vm.id, - type='ROOT', - listall=True - ) + list_volume = Volume.list(self.apiclient, + virtualmachineid=vm.id, + type='ROOT', + listall=True) if isinstance(list_volume, list): self.volume = list_volume[0] else: @@ -115,7 +114,6 @@ def create_and_verify_fw(self, vm, public_ip, network): # VSD verification self.verify_vsp_floating_ip(network, vm, public_ip.ipaddress) - vm_public_ip = public_ip.ipaddress.ipaddress fw_rule = self.create_firewall_rule(public_ip, self.test_data["ingress_rule"]) self.verify_vsp_firewall_rule(fw_rule) @@ -131,6 +129,35 @@ def create_and_verify_fw(self, vm, public_ip, network): if not gotFirewallPolicy: raise ValueError('No firewall policy decision in vm interface') + def stop_vm(self, vm): + self.debug("STOP VM") + vm.stop(self.apiclient) + list_vm_response = VirtualMachine.list(self.apiclient, + id=vm.id) + if isinstance(list_vm_response, list): + vm = list_vm_response[0] + if vm.state != 'Stopped': + raise Exception("Failed to stop VM (ID: %s) " % + self.vm.id) + else: + raise Exception("Invalid response from list_virtual_machines VM (ID: %s) " % + self.vm.id) + + def install_cloud_set_guest_password_script(self, ssh_client): + self.debug("GET CLOUD-SET-GUEST-PASSWORD") + cmd = "cd /etc/init.d;wget http://people.apache.org/~tsp/cloud-set-guest-password" + result = self.execute_cmd(ssh_client, cmd) + self.debug("WGET CLOUD-SET-GUEST-PASSWORD: " + result) + if "200 OK" not in result: + self.fail("failed to get file cloud-set-guest-password") + cmds = ["chmod +x /etc/init.d/cloud-set-guest-password", + "chkconfig --add cloud-set-guest-password" + ] + for c in cmds: + result = self.execute_cmd(ssh_client, c) + self.debug("get_set_password_file cmd " + c) + self.debug("get_set_password_file result " + result) + @attr(tags=["advanced", "nuagevsp"], required_hardware="true") def test_01_UserDataPasswordReset(self): self.debug("START USER DATA PASSWORD RESET ON VM") @@ -211,7 +238,7 @@ def test_01_UserDataPasswordReset(self): self.stop_vm(self.vm_1) self.create_template(self.vm_1) self.debug("DEPLOY VM 2 IN TEST NETWORK WITH NEW TEMPLATE") - self.vm_1 = self.create_VM_in_Network(self.network_1, "virtual_machine_pr") + self.vm_2 = self.create_VM_in_Network(self.network_1, "virtual_machine_pr") self.remove_vm2 = True self.debug("STARTING VM_2 ") startCmd = startVirtualMachine.startVirtualMachineCmd() @@ -225,7 +252,7 @@ def test_01_UserDataPasswordReset(self): "Password enabled not working. Password same as virtual_machine password " ) self.verify_vsp_vm(vm_2a) - self.debug("GET PUBLIC IP, CREATE AND VERIFY FIREWALL RULES") + self.debug("GET PUBLIC IP. CREATE AND VERIFIED FIREWALL RULES") public_ip_2 = self.acquire_Public_IP(self.network_1) self.create_and_verify_fw(self.vm_2, public_ip_2, self.network_1) From 732a85295dc1dbf06ca784a7c4c2e288ad7cd0d6 Mon Sep 17 00:00:00 2001 From: "Maneesha.P" Date: Fri, 9 Oct 2015 15:46:56 +0530 Subject: [PATCH 078/203] CLOUDSTACK-8800 : Improved the listVirtualMachines API call to include memory utilization information for a VM for xenserver,kvm and for vmware. --- api/src/com/cloud/vm/VmStats.java | 6 ++++ .../api/response/UserVmResponse.java | 36 +++++++++++++++++++ .../src/com/cloud/agent/api/VmStatsEntry.java | 35 +++++++++++++++++- .../resource/LibvirtComputingResource.java | 13 +++++++ .../LibvirtComputingResourceTest.java | 11 +++++- .../agent/manager/MockVmManagerImpl.java | 2 +- .../vmware/resource/VmwareResource.java | 24 ++++++++++--- .../resource/CitrixResourceBase.java | 12 +++++-- .../api/query/dao/UserVmJoinDaoImpl.java | 15 +++++--- .../src/com/cloud/server/StatsCollector.java | 7 ++++ 10 files changed, 148 insertions(+), 13 deletions(-) mode change 100755 => 100644 plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java diff --git a/api/src/com/cloud/vm/VmStats.java b/api/src/com/cloud/vm/VmStats.java index 2b7943883e..1c23c01ed8 100644 --- a/api/src/com/cloud/vm/VmStats.java +++ b/api/src/com/cloud/vm/VmStats.java @@ -32,4 +32,10 @@ public interface VmStats { public double getDiskWriteKBs(); + public double getMemoryKBs(); + + public double getIntFreeMemoryKBs(); + + public double getTargetMemoryKBs(); + } diff --git a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java index e8d1a9ed89..f1119ddbfb 100644 --- a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java +++ b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java @@ -196,6 +196,18 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp @Param(description = "the write (bytes) of disk on the vm") private Long diskKbsWrite; + @SerializedName("memorykbs") + @Param(description = "the memory used by the vm") + private Long memoryKBs; + + @SerializedName("memoryintfreekbs") + @Param(description = "the internal memory thats free in vm") + private Long memoryIntFreeKBs; + + @SerializedName("memorytargetkbs") + @Param(description = "the target memory in vm") + private Long memoryTargetKBs; + @SerializedName("diskioread") @Param(description = "the read (io) of disk on the vm") private Long diskIORead; @@ -466,6 +478,18 @@ public Long getDiskKbsWrite() { return diskKbsWrite; } + public Long getMemoryKBs() { + return memoryKBs; + } + + public Long getMemoryIntFreeKBs() { + return memoryIntFreeKBs; + } + + public Long getMemoryTargetKBs() { + return memoryTargetKBs; + } + public Long getDiskIORead() { return diskIORead; } @@ -645,6 +669,18 @@ public void setDiskIORead(Long diskIORead) { this.diskIORead = diskIORead; } + public void setMemoryKBs(Long memoryKBs) { + this.memoryKBs = memoryKBs; + } + + public void setMemoryIntFreeKBs(Long memoryIntFreeKBs) { + this.memoryIntFreeKBs = memoryIntFreeKBs; + } + + public void setMemoryTargetKBs(Long memoryTargetKBs) { + this.memoryTargetKBs = memoryTargetKBs; + } + public void setDiskIOWrite(Long diskIOWrite) { this.diskIOWrite = diskIOWrite; } diff --git a/core/src/com/cloud/agent/api/VmStatsEntry.java b/core/src/com/cloud/agent/api/VmStatsEntry.java index 0f30b6af53..e6063b9ab5 100644 --- a/core/src/com/cloud/agent/api/VmStatsEntry.java +++ b/core/src/com/cloud/agent/api/VmStatsEntry.java @@ -30,13 +30,19 @@ public class VmStatsEntry implements VmStats { double diskWriteIOs; double diskReadKBs; double diskWriteKBs; + double memoryKBs; + double intfreememoryKBs; + double targetmemoryKBs; int numCPUs; String entityType; public VmStatsEntry() { } - public VmStatsEntry(double cpuUtilization, double networkReadKBs, double networkWriteKBs, int numCPUs, String entityType) { + public VmStatsEntry(double memoryKBs,double intfreememoryKBs,double targetmemoryKBs, double cpuUtilization, double networkReadKBs, double networkWriteKBs, int numCPUs, String entityType) { + this.memoryKBs = memoryKBs; + this.intfreememoryKBs = intfreememoryKBs; + this.targetmemoryKBs = targetmemoryKBs; this.cpuUtilization = cpuUtilization; this.networkReadKBs = networkReadKBs; this.networkWriteKBs = networkWriteKBs; @@ -117,6 +123,33 @@ public void setDiskWriteKBs(double diskWriteKBs) { this.diskWriteKBs = diskWriteKBs; } + @Override + public double getMemoryKBs() { + return memoryKBs; + } + + public void setMemoryKBs(double memoryKBs) { + this.memoryKBs = memoryKBs; + } + + @Override + public double getIntFreeMemoryKBs() { + return intfreememoryKBs; + } + + public void setIntFreeMemoryKBs(double intfreememoryKBs) { + this.intfreememoryKBs = intfreememoryKBs; + } + + @Override + public double getTargetMemoryKBs() { + return targetmemoryKBs; + } + + public void setTargetMemoryKBs(double targetmemoryKBs) { + this.targetmemoryKBs = targetmemoryKBs; + } + public int getNumCPUs() { return numCPUs; } 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 old mode 100755 new mode 100644 index 883c8c9942..02cf872d92 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -57,6 +57,7 @@ import org.libvirt.Domain; import org.libvirt.DomainBlockStats; import org.libvirt.DomainInfo; +import org.libvirt.MemoryStatistic; import org.libvirt.DomainInfo.DomainState; import org.libvirt.DomainInterfaceStats; import org.libvirt.LibvirtException; @@ -190,6 +191,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv private long _hvVersion; private long _kernelVersion; private int _timeout; + private static final int NUMMEMSTATS =2; private KVMHAMonitor _monitor; public static final String SSHKEYSPATH = "/root/.ssh"; @@ -3018,6 +3020,9 @@ private class VmStats { long _ioWrote; long _bytesRead; long _bytesWrote; + long _intmemfree; + long _memory; + long _maxmemory; Calendar _timestamp; } @@ -3026,11 +3031,16 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li try { dm = getDomain(conn, vmName); final DomainInfo info = dm.getInfo(); + final MemoryStatistic[] mems = dm.memoryStats(NUMMEMSTATS); //number of memory statistics required. final VmStatsEntry stats = new VmStatsEntry(); + stats.setNumCPUs(info.nrVirtCpu); stats.setEntityType("vm"); + stats.setMemoryKBs(info.maxMem); + stats.setTargetMemoryKBs(info.memory); + stats.setIntFreeMemoryKBs((double) mems[0].getValue()); /* get cpu utilization */ VmStats oldStats = null; @@ -3115,6 +3125,9 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li newStat._bytesRead = bytes_rd; newStat._bytesWrote = bytes_wr; newStat._timestamp = now; + newStat._intmemfree = mems[0].getValue(); + newStat._memory = info.memory; + newStat._maxmemory = info.maxMem; _vmStats.put(vmName, newStat); return stats; } finally { diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 04a27f3d8c..47b9c40b88 100644 --- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -66,6 +66,8 @@ import org.libvirt.LibvirtException; import org.libvirt.NodeInfo; import org.libvirt.StorageVol; +import org.libvirt.MemoryStatistic; + import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.Mockito; @@ -417,7 +419,10 @@ public void testGetVmStat() throws LibvirtException { final Connect connect = Mockito.mock(Connect.class); final Domain domain = Mockito.mock(Domain.class); final DomainInfo domainInfo = new DomainInfo(); + final MemoryStatistic[] domainMem = new MemoryStatistic[2]; + domainMem[0] = Mockito.mock(MemoryStatistic.class); Mockito.when(domain.getInfo()).thenReturn(domainInfo); + Mockito.when(domain.memoryStats(2)).thenReturn(domainMem); Mockito.when(connect.domainLookupByName(VMNAME)).thenReturn(domain); final NodeInfo nodeInfo = new NodeInfo(); nodeInfo.cpus = 8; @@ -484,6 +489,10 @@ public List getDisks(final Connect conn, final String vmName) { // IO traffic as generated by the logic above, must be greater than zero Assert.assertTrue(vmStat.getDiskReadKBs() > 0); Assert.assertTrue(vmStat.getDiskWriteKBs() > 0); + // Memory limit of VM must be greater than zero + Assert.assertTrue(vmStat.getIntFreeMemoryKBs() >= 0); + Assert.assertTrue(vmStat.getMemoryKBs() >= 0); + Assert.assertTrue(vmStat.getTargetMemoryKBs() >= vmStat.getMemoryKBs()); } @Test @@ -5021,4 +5030,4 @@ public void testIsInterface () { } } } -} \ No newline at end of file +} diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java index 6602e1f1ad..9863b22dd8 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java @@ -319,7 +319,7 @@ public Answer getVmStats(final GetVmStatsCommand cmd) { final HashMap vmStatsNameMap = new HashMap(); final List vmNames = cmd.getVmNames(); for (final String vmName : vmNames) { - final VmStatsEntry entry = new VmStatsEntry(0, 0, 0, 0, "vm"); + final VmStatsEntry entry = new VmStatsEntry(0, 0, 0, 0, 0, 0, 0, "vm"); entry.setNetworkReadKBs(32768); // default values 256 KBps entry.setNetworkWriteKBs(16384); entry.setCPUUtilization(10); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index fdbc244997..921df77b39 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -99,6 +99,7 @@ import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.commons.lang.math.NumberUtils; import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; @@ -4862,8 +4863,14 @@ private HashMap getVmStats(List vmNames) throws Ex } String instanceNameCustomField = "value[" + key + "]"; + final String numCpuStr = "summary.config.numCpu"; + final String cpuUseStr = "summary.quickStats.overallCpuUsage"; + final String guestMemUseStr = "summary.quickStats.guestMemoryUsage"; + final String memLimitStr = "resourceConfig.memoryAllocation.limit"; + final String memMbStr = "config.hardware.memoryMB"; + ObjectContent[] ocs = - hyperHost.getVmPropertiesOnHyperHost(new String[] {"name", "summary.config.numCpu", "summary.quickStats.overallCpuUsage", instanceNameCustomField}); + hyperHost.getVmPropertiesOnHyperHost(new String[] {"name", numCpuStr, cpuUseStr ,guestMemUseStr ,memLimitStr ,memMbStr, instanceNameCustomField}); if (ocs != null && ocs.length > 0) { for (ObjectContent oc : ocs) { List objProps = oc.getPropSet(); @@ -4871,6 +4878,9 @@ private HashMap getVmStats(List vmNames) throws Ex String name = null; String numberCPUs = null; String maxCpuUsage = null; + String memlimit = null; + String memkb = null; + String guestMemusage = null; String vmNameOnVcenter = null; String vmInternalCSName = null; for (DynamicProperty objProp : objProps) { @@ -4879,10 +4889,16 @@ private HashMap getVmStats(List vmNames) throws Ex } else if (objProp.getName().contains(instanceNameCustomField)) { if (objProp.getVal() != null) vmInternalCSName = ((CustomFieldStringValue)objProp.getVal()).getValue(); - } else if (objProp.getName().equals("summary.config.numCpu")) { + }else if(objProp.getName().equals(guestMemusage)){ + guestMemusage = objProp.getVal().toString(); + }else if (objProp.getName().equals(numCpuStr)) { numberCPUs = objProp.getVal().toString(); - } else if (objProp.getName().equals("summary.quickStats.overallCpuUsage")) { + } else if (objProp.getName().equals(cpuUseStr)) { maxCpuUsage = objProp.getVal().toString(); + } else if (objProp.getName().equals(memLimitStr)) { + memlimit = objProp.getVal().toString(); + } else if (objProp.getName().equals(memMbStr)) { + memkb = objProp.getVal().toString(); } } new VirtualMachineMO(hyperHost.getContext(), oc.getObj()); @@ -4951,7 +4967,7 @@ private HashMap getVmStats(List vmNames) throws Ex } } } - vmResponseMap.put(name, new VmStatsEntry(Integer.parseInt(maxCpuUsage), networkReadKBs, networkWriteKBs, Integer.parseInt(numberCPUs), "vm")); + vmResponseMap.put(name, new VmStatsEntry( NumberUtils.toDouble(memkb)*1024,NumberUtils.toDouble(guestMemusage)*1024,NumberUtils.toDouble(memlimit)*1024, NumberUtils.toDouble(maxCpuUsage), networkReadKBs, networkWriteKBs, NumberUtils.toInt(numberCPUs), "vm")); } } } diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index 7c8bca7f1b..665ed77cbb 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -3278,7 +3278,7 @@ public HashMap getVmStats(final Connection conn, final Get final HashMap vmResponseMap = new HashMap(); for (final String vmUUID : vmUUIDs) { - vmResponseMap.put(vmUUID, new VmStatsEntry(0, 0, 0, 0, "vm")); + vmResponseMap.put(vmUUID, new VmStatsEntry(0,0,0,0, 0, 0, 0, "vm")); } final Object[] rrdData = getRRDData(conn, 2); // call rrddata with 2 for @@ -3332,7 +3332,14 @@ public HashMap getVmStats(final Connection conn, final Get vmStatsAnswer.setDiskReadKBs(vmStatsAnswer.getDiskReadKBs() + getDataAverage(dataNode, col, numRows) / 1000); } else if (param.matches("vbd_.*_write")) { vmStatsAnswer.setDiskWriteKBs(vmStatsAnswer.getDiskWriteKBs() + getDataAverage(dataNode, col, numRows) / 1000); + } else if (param.contains("memory_internal_free")) { + vmStatsAnswer.setIntFreeMemoryKBs(vmStatsAnswer.getIntFreeMemoryKBs() + getDataAverage(dataNode, col, numRows) / 1024); + } else if (param.contains("memory_target")) { + vmStatsAnswer.setTargetMemoryKBs(vmStatsAnswer.getTargetMemoryKBs() + getDataAverage(dataNode, col, numRows) / 1024); + } else if (param.contains("memory")) { + vmStatsAnswer.setMemoryKBs(vmStatsAnswer.getMemoryKBs() + getDataAverage(dataNode, col, numRows) / 1024); } + } } @@ -3348,6 +3355,7 @@ public HashMap getVmStats(final Connection conn, final Get s_logger.debug("Vm cpu utilization " + vmStatsAnswer.getCPUUtilization()); } } + return vmResponseMap; } @@ -5394,4 +5402,4 @@ public boolean attachConfigDriveToMigratedVm(Connection conn, String vmName, Str } -} \ No newline at end of file +} diff --git a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java index 7983065f31..a1e3dc911a 100644 --- a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java @@ -207,14 +207,21 @@ public UserVmResponse newUserVmResponse(ResponseView view, String objectName, Us userVmResponse.setNetworkKbsWrite((long)vmStats.getNetworkWriteKBs()); - if ((userVm.getHypervisorType() != null) && (userVm.getHypervisorType().equals(HypervisorType.KVM) || userVm.getHypervisorType().equals(HypervisorType.XenServer))) { // support KVM and XenServer only util 2013.06.25 + if ((userVm.getHypervisorType() != null) && (userVm.getHypervisorType().equals(HypervisorType.KVM) || userVm.getHypervisorType().equals(HypervisorType.XenServer) || userVm.getHypervisorType().equals(HypervisorType.VMware))) { // support KVM and XenServer only util 2013.06.25 . supporting Vmware from 2015.09.02 userVmResponse.setDiskKbsRead((long)vmStats.getDiskReadKBs()); - userVmResponse.setDiskKbsWrite((long)vmStats.getDiskWriteKBs()); + userVmResponse.setDiskKbsWrite((long) vmStats.getDiskWriteKBs()); - userVmResponse.setDiskIORead((long)vmStats.getDiskReadIOs()); + userVmResponse.setDiskIORead((long) vmStats.getDiskReadIOs()); + + userVmResponse.setDiskIOWrite((long) vmStats.getDiskWriteIOs()); + + userVmResponse.setMemoryKBs((long) vmStats.getMemoryKBs()); + + userVmResponse.setMemoryIntFreeKBs((long) vmStats.getIntFreeMemoryKBs()); + + userVmResponse.setMemoryTargetKBs((long) vmStats.getTargetMemoryKBs()); - userVmResponse.setDiskIOWrite((long)vmStats.getDiskWriteIOs()); } } } diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index ca86cfd080..8af1f75ca3 100644 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -462,6 +462,9 @@ protected void runInContext() { statsInMemory.setDiskReadIOs(statsInMemory.getDiskReadIOs() + statsForCurrentIteration.getDiskReadIOs()); statsInMemory.setDiskWriteIOs(statsInMemory.getDiskWriteIOs() + statsForCurrentIteration.getDiskWriteIOs()); statsInMemory.setDiskReadKBs(statsInMemory.getDiskReadKBs() + statsForCurrentIteration.getDiskReadKBs()); + statsInMemory.setMemoryKBs(statsForCurrentIteration.getMemoryKBs()); + statsInMemory.setIntFreeMemoryKBs(statsForCurrentIteration.getIntFreeMemoryKBs()); + statsInMemory.setTargetMemoryKBs(statsForCurrentIteration.getTargetMemoryKBs()); _VmStats.put(vmId, statsInMemory); } @@ -482,6 +485,10 @@ protected void runInContext() { metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".disk.read_kbs", statsForCurrentIteration.getDiskReadKBs()); metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".disk.write_iops", statsForCurrentIteration.getDiskWriteIOs()); metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".disk.read_iops", statsForCurrentIteration.getDiskReadIOs()); + metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".memory.total_kbs", statsForCurrentIteration.getMemoryKBs()); + metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".memory.internalfree_kbs", statsForCurrentIteration.getIntFreeMemoryKBs()); + metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".memory.target_kbs", statsForCurrentIteration.getTargetMemoryKBs()); + } } From 8d6370b21fd527dc0046c0a1d67dce35dbf15681 Mon Sep 17 00:00:00 2001 From: Alexandre Limas Santana Date: Sat, 19 Mar 2016 16:25:47 -0300 Subject: [PATCH 079/203] Fixed Profiler's unit tests bugs. Problem: The TestProfiler class was using Java Thread methods to test the Profiler's functionality. That was causing the tests to fail sometimes since the JVM's thread priority could be low on some OS. Fix: Using PowerMockito to mock the System calls, the threads could be removed. This makes the tests considerably faster, OS independent and still guarantees the correct implementation of the Profiler class. The changes on the Profiler's class was only to shorten the class's line size by not assigning the return value to a variable returning it straight out. --- .../main/java/com/cloud/utils/Profiler.java | 6 +- .../java/com/cloud/utils/TestProfiler.java | 93 +++++++++---------- 2 files changed, 46 insertions(+), 53 deletions(-) diff --git a/utils/src/main/java/com/cloud/utils/Profiler.java b/utils/src/main/java/com/cloud/utils/Profiler.java index f8e44bd323..b08e7c99c3 100644 --- a/utils/src/main/java/com/cloud/utils/Profiler.java +++ b/utils/src/main/java/com/cloud/utils/Profiler.java @@ -46,8 +46,7 @@ public long stop() { */ public long getDuration() { if (startTickNanoSeconds != null && stopTickNanoSeconds != null) { - final long timeInNanoSeconds = stopTickNanoSeconds - startTickNanoSeconds; - return timeInNanoSeconds; + return stopTickNanoSeconds - startTickNanoSeconds; } return -1; @@ -61,8 +60,7 @@ public long getDuration() { */ public long getDurationInMillis() { if (startTickNanoSeconds != null && stopTickNanoSeconds != null) { - final long timeInMillis = (stopTickNanoSeconds - startTickNanoSeconds) / (long)Math.pow(MILLIS_FACTOR, EXPONENT); - return timeInMillis; + return (stopTickNanoSeconds - startTickNanoSeconds) / (long)Math.pow(MILLIS_FACTOR, EXPONENT); } return -1; diff --git a/utils/src/test/java/com/cloud/utils/TestProfiler.java b/utils/src/test/java/com/cloud/utils/TestProfiler.java index f0e163e63f..ad48d78a29 100644 --- a/utils/src/test/java/com/cloud/utils/TestProfiler.java +++ b/utils/src/test/java/com/cloud/utils/TestProfiler.java @@ -19,84 +19,79 @@ package com.cloud.utils; -import org.apache.log4j.Logger; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import com.cloud.utils.testcase.Log4jEnabledTestCase; +@RunWith(PowerMockRunner.class) +@PrepareForTest({Profiler.class}) public class TestProfiler extends Log4jEnabledTestCase { - protected final static Logger s_logger = Logger.getLogger(TestProfiler.class); - - private static final long MILLIS_FACTOR = 1000l; - private static final int MARGIN = 100; - // Profiler uses System.nanoTime which is not reliable on the millisecond - // A sleep of 1000 milliseconds CAN be measured as 999 milliseconds - // Therefore make the second larger, by 10% of the margin - private static final long ONE_SECOND = 1000l + (MARGIN / 10); - private static final double EXPONENT = 3d; + private static final long SLEEP_TIME_NANO = 1000000000L; + private static Profiler pf; + + @Before + public void setUp(){ + pf = new Profiler(); + PowerMockito.mockStatic(System.class); + PowerMockito.when(System.nanoTime()).thenReturn(0L, SLEEP_TIME_NANO); + } + @Test public void testProfilerInMillis() { - s_logger.info("testProfiler() started"); - - final Profiler pf = new Profiler(); + //Given + final long sleepTimeMillis = SLEEP_TIME_NANO / 1000000L; + + //When pf.start(); - try { - Thread.sleep(ONE_SECOND); - } catch (final InterruptedException e) { - } pf.stop(); - final long durationInMillis = pf.getDurationInMillis(); - s_logger.info("Duration in Millis: " + durationInMillis); - - // An error margin in order to cover the time taken by the star/stop calls. - // 100 milliseconds margin seems too much, but it will avoid assertion error - // and also fail in case a duration in nanoseconds is used instead. - Assert.assertTrue(durationInMillis >= MILLIS_FACTOR && durationInMillis <= MILLIS_FACTOR + MARGIN); - - s_logger.info("testProfiler() stopped"); + //Then + Assert.assertTrue(pf.getDurationInMillis() == sleepTimeMillis); } @Test public void testProfilerInNano() { - final Profiler pf = new Profiler(); - pf.start(); - try { - Thread.sleep(ONE_SECOND); - } catch (final InterruptedException e) { - } + //Given + final long sleepTimeNano = SLEEP_TIME_NANO; + + //When + pf.start(); pf.stop(); - final long duration = pf.getDuration(); - s_logger.info("Duration in Nano: " + duration); - Assert.assertTrue(duration >= Math.pow(MILLIS_FACTOR, EXPONENT)); + //Then + Assert.assertTrue(pf.getDuration() == sleepTimeNano); } @Test public void testProfilerNoStart() { - final Profiler pf = new Profiler(); - try { - Thread.sleep(20); - } catch (final InterruptedException e) { - } - pf.stop(); + //Given + final long expectedAnswer = -1; + + //When + pf.stop(); - Assert.assertTrue(pf.getDurationInMillis() == -1); + //Then + Assert.assertTrue(pf.getDurationInMillis() == expectedAnswer); Assert.assertFalse(pf.isStarted()); } @Test public void testProfilerNoStop() { - final Profiler pf = new Profiler(); - pf.start(); - try { - Thread.sleep(20); - } catch (final InterruptedException e) { - } + //Given + final long expectedAnswer = -1; + + //When + pf.start(); - Assert.assertTrue(pf.getDurationInMillis() == -1); + //Then + Assert.assertTrue(pf.getDurationInMillis() == expectedAnswer); Assert.assertFalse(pf.isStopped()); } } \ No newline at end of file From c2afa584ae68f52cdf55a7204c01ed66a5be1912 Mon Sep 17 00:00:00 2001 From: Alexandre Limas Santana Date: Sun, 20 Mar 2016 11:49:04 -0300 Subject: [PATCH 080/203] Fixed changes to match code conventions --- .../main/java/com/cloud/utils/Profiler.java | 1 - .../java/com/cloud/utils/TestProfiler.java | 44 +++++++++---------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/utils/src/main/java/com/cloud/utils/Profiler.java b/utils/src/main/java/com/cloud/utils/Profiler.java index b08e7c99c3..addee2db20 100644 --- a/utils/src/main/java/com/cloud/utils/Profiler.java +++ b/utils/src/main/java/com/cloud/utils/Profiler.java @@ -24,7 +24,6 @@ public class Profiler { private static final long MILLIS_FACTOR = 1000l; private static final double EXPONENT = 2d; - private Long startTickNanoSeconds; private Long stopTickNanoSeconds; diff --git a/utils/src/test/java/com/cloud/utils/TestProfiler.java b/utils/src/test/java/com/cloud/utils/TestProfiler.java index ad48d78a29..0e68175133 100644 --- a/utils/src/test/java/com/cloud/utils/TestProfiler.java +++ b/utils/src/test/java/com/cloud/utils/TestProfiler.java @@ -35,19 +35,19 @@ public class TestProfiler extends Log4jEnabledTestCase { private static final long SLEEP_TIME_NANO = 1000000000L; private static Profiler pf; - + @Before - public void setUp(){ - pf = new Profiler(); - PowerMockito.mockStatic(System.class); - PowerMockito.when(System.nanoTime()).thenReturn(0L, SLEEP_TIME_NANO); + public void setUp() { + pf = new Profiler(); + PowerMockito.mockStatic(System.class); + PowerMockito.when(System.nanoTime()).thenReturn(0L, SLEEP_TIME_NANO); } - + @Test public void testProfilerInMillis() { //Given final long sleepTimeMillis = SLEEP_TIME_NANO / 1000000L; - + //When pf.start(); pf.stop(); @@ -58,11 +58,11 @@ public void testProfilerInMillis() { @Test public void testProfilerInNano() { - //Given - final long sleepTimeNano = SLEEP_TIME_NANO; - - //When - pf.start(); + //Given + final long sleepTimeNano = SLEEP_TIME_NANO; + + //When + pf.start(); pf.stop(); //Then @@ -71,26 +71,26 @@ public void testProfilerInNano() { @Test public void testProfilerNoStart() { - //Given - final long expectedAnswer = -1; + //Given + final long expectedAnswer = -1; - //When - pf.stop(); + //When + pf.stop(); - //Then + //Then Assert.assertTrue(pf.getDurationInMillis() == expectedAnswer); Assert.assertFalse(pf.isStarted()); } @Test public void testProfilerNoStop() { - //Given - final long expectedAnswer = -1; + //Given + final long expectedAnswer = -1; - //When - pf.start(); + //When + pf.start(); - //Then + //Then Assert.assertTrue(pf.getDurationInMillis() == expectedAnswer); Assert.assertFalse(pf.isStopped()); } From c48b6c33c0716d592d390ab01251664a59cd0e4f Mon Sep 17 00:00:00 2001 From: Will Stevens Date: Mon, 21 Mar 2016 17:38:04 -0400 Subject: [PATCH 081/203] Revert "Merge pull request #780 from maneesha-p/pull-19" due code quality issues and lack of CI results. This reverts commit dc0ba6bd1a774d3ff4bc4a4dcc00e1434ab1f6e3, reversing changes made to 63f58dd5785ff2515b087d907bdf686347c75727. --- api/src/com/cloud/vm/VmStats.java | 6 ---- .../api/response/UserVmResponse.java | 36 ------------------- .../src/com/cloud/agent/api/VmStatsEntry.java | 35 +----------------- .../resource/LibvirtComputingResource.java | 13 ------- .../LibvirtComputingResourceTest.java | 11 +----- .../agent/manager/MockVmManagerImpl.java | 2 +- .../vmware/resource/VmwareResource.java | 24 +++---------- .../resource/CitrixResourceBase.java | 12 ++----- .../api/query/dao/UserVmJoinDaoImpl.java | 15 +++----- .../src/com/cloud/server/StatsCollector.java | 7 ---- 10 files changed, 13 insertions(+), 148 deletions(-) mode change 100644 => 100755 plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java diff --git a/api/src/com/cloud/vm/VmStats.java b/api/src/com/cloud/vm/VmStats.java index 1c23c01ed8..2b7943883e 100644 --- a/api/src/com/cloud/vm/VmStats.java +++ b/api/src/com/cloud/vm/VmStats.java @@ -32,10 +32,4 @@ public interface VmStats { public double getDiskWriteKBs(); - public double getMemoryKBs(); - - public double getIntFreeMemoryKBs(); - - public double getTargetMemoryKBs(); - } diff --git a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java index f1119ddbfb..e8d1a9ed89 100644 --- a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java +++ b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java @@ -196,18 +196,6 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp @Param(description = "the write (bytes) of disk on the vm") private Long diskKbsWrite; - @SerializedName("memorykbs") - @Param(description = "the memory used by the vm") - private Long memoryKBs; - - @SerializedName("memoryintfreekbs") - @Param(description = "the internal memory thats free in vm") - private Long memoryIntFreeKBs; - - @SerializedName("memorytargetkbs") - @Param(description = "the target memory in vm") - private Long memoryTargetKBs; - @SerializedName("diskioread") @Param(description = "the read (io) of disk on the vm") private Long diskIORead; @@ -478,18 +466,6 @@ public Long getDiskKbsWrite() { return diskKbsWrite; } - public Long getMemoryKBs() { - return memoryKBs; - } - - public Long getMemoryIntFreeKBs() { - return memoryIntFreeKBs; - } - - public Long getMemoryTargetKBs() { - return memoryTargetKBs; - } - public Long getDiskIORead() { return diskIORead; } @@ -669,18 +645,6 @@ public void setDiskIORead(Long diskIORead) { this.diskIORead = diskIORead; } - public void setMemoryKBs(Long memoryKBs) { - this.memoryKBs = memoryKBs; - } - - public void setMemoryIntFreeKBs(Long memoryIntFreeKBs) { - this.memoryIntFreeKBs = memoryIntFreeKBs; - } - - public void setMemoryTargetKBs(Long memoryTargetKBs) { - this.memoryTargetKBs = memoryTargetKBs; - } - public void setDiskIOWrite(Long diskIOWrite) { this.diskIOWrite = diskIOWrite; } diff --git a/core/src/com/cloud/agent/api/VmStatsEntry.java b/core/src/com/cloud/agent/api/VmStatsEntry.java index e6063b9ab5..0f30b6af53 100644 --- a/core/src/com/cloud/agent/api/VmStatsEntry.java +++ b/core/src/com/cloud/agent/api/VmStatsEntry.java @@ -30,19 +30,13 @@ public class VmStatsEntry implements VmStats { double diskWriteIOs; double diskReadKBs; double diskWriteKBs; - double memoryKBs; - double intfreememoryKBs; - double targetmemoryKBs; int numCPUs; String entityType; public VmStatsEntry() { } - public VmStatsEntry(double memoryKBs,double intfreememoryKBs,double targetmemoryKBs, double cpuUtilization, double networkReadKBs, double networkWriteKBs, int numCPUs, String entityType) { - this.memoryKBs = memoryKBs; - this.intfreememoryKBs = intfreememoryKBs; - this.targetmemoryKBs = targetmemoryKBs; + public VmStatsEntry(double cpuUtilization, double networkReadKBs, double networkWriteKBs, int numCPUs, String entityType) { this.cpuUtilization = cpuUtilization; this.networkReadKBs = networkReadKBs; this.networkWriteKBs = networkWriteKBs; @@ -123,33 +117,6 @@ public void setDiskWriteKBs(double diskWriteKBs) { this.diskWriteKBs = diskWriteKBs; } - @Override - public double getMemoryKBs() { - return memoryKBs; - } - - public void setMemoryKBs(double memoryKBs) { - this.memoryKBs = memoryKBs; - } - - @Override - public double getIntFreeMemoryKBs() { - return intfreememoryKBs; - } - - public void setIntFreeMemoryKBs(double intfreememoryKBs) { - this.intfreememoryKBs = intfreememoryKBs; - } - - @Override - public double getTargetMemoryKBs() { - return targetmemoryKBs; - } - - public void setTargetMemoryKBs(double targetmemoryKBs) { - this.targetmemoryKBs = targetmemoryKBs; - } - public int getNumCPUs() { return numCPUs; } 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 old mode 100644 new mode 100755 index 02cf872d92..883c8c9942 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -57,7 +57,6 @@ import org.libvirt.Domain; import org.libvirt.DomainBlockStats; import org.libvirt.DomainInfo; -import org.libvirt.MemoryStatistic; import org.libvirt.DomainInfo.DomainState; import org.libvirt.DomainInterfaceStats; import org.libvirt.LibvirtException; @@ -191,7 +190,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv private long _hvVersion; private long _kernelVersion; private int _timeout; - private static final int NUMMEMSTATS =2; private KVMHAMonitor _monitor; public static final String SSHKEYSPATH = "/root/.ssh"; @@ -3020,9 +3018,6 @@ private class VmStats { long _ioWrote; long _bytesRead; long _bytesWrote; - long _intmemfree; - long _memory; - long _maxmemory; Calendar _timestamp; } @@ -3031,16 +3026,11 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li try { dm = getDomain(conn, vmName); final DomainInfo info = dm.getInfo(); - final MemoryStatistic[] mems = dm.memoryStats(NUMMEMSTATS); //number of memory statistics required. final VmStatsEntry stats = new VmStatsEntry(); - stats.setNumCPUs(info.nrVirtCpu); stats.setEntityType("vm"); - stats.setMemoryKBs(info.maxMem); - stats.setTargetMemoryKBs(info.memory); - stats.setIntFreeMemoryKBs((double) mems[0].getValue()); /* get cpu utilization */ VmStats oldStats = null; @@ -3125,9 +3115,6 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li newStat._bytesRead = bytes_rd; newStat._bytesWrote = bytes_wr; newStat._timestamp = now; - newStat._intmemfree = mems[0].getValue(); - newStat._memory = info.memory; - newStat._maxmemory = info.maxMem; _vmStats.put(vmName, newStat); return stats; } finally { diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 47b9c40b88..04a27f3d8c 100644 --- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -66,8 +66,6 @@ import org.libvirt.LibvirtException; import org.libvirt.NodeInfo; import org.libvirt.StorageVol; -import org.libvirt.MemoryStatistic; - import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.Mockito; @@ -419,10 +417,7 @@ public void testGetVmStat() throws LibvirtException { final Connect connect = Mockito.mock(Connect.class); final Domain domain = Mockito.mock(Domain.class); final DomainInfo domainInfo = new DomainInfo(); - final MemoryStatistic[] domainMem = new MemoryStatistic[2]; - domainMem[0] = Mockito.mock(MemoryStatistic.class); Mockito.when(domain.getInfo()).thenReturn(domainInfo); - Mockito.when(domain.memoryStats(2)).thenReturn(domainMem); Mockito.when(connect.domainLookupByName(VMNAME)).thenReturn(domain); final NodeInfo nodeInfo = new NodeInfo(); nodeInfo.cpus = 8; @@ -489,10 +484,6 @@ public List getDisks(final Connect conn, final String vmName) { // IO traffic as generated by the logic above, must be greater than zero Assert.assertTrue(vmStat.getDiskReadKBs() > 0); Assert.assertTrue(vmStat.getDiskWriteKBs() > 0); - // Memory limit of VM must be greater than zero - Assert.assertTrue(vmStat.getIntFreeMemoryKBs() >= 0); - Assert.assertTrue(vmStat.getMemoryKBs() >= 0); - Assert.assertTrue(vmStat.getTargetMemoryKBs() >= vmStat.getMemoryKBs()); } @Test @@ -5030,4 +5021,4 @@ public void testIsInterface () { } } } -} +} \ No newline at end of file diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java index 9863b22dd8..6602e1f1ad 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java @@ -319,7 +319,7 @@ public Answer getVmStats(final GetVmStatsCommand cmd) { final HashMap vmStatsNameMap = new HashMap(); final List vmNames = cmd.getVmNames(); for (final String vmName : vmNames) { - final VmStatsEntry entry = new VmStatsEntry(0, 0, 0, 0, 0, 0, 0, "vm"); + final VmStatsEntry entry = new VmStatsEntry(0, 0, 0, 0, "vm"); entry.setNetworkReadKBs(32768); // default values 256 KBps entry.setNetworkWriteKBs(16384); entry.setCPUUtilization(10); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 4d04abca4f..184159a94a 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -100,7 +100,6 @@ import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; -import org.apache.commons.lang.math.NumberUtils; import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; @@ -4945,14 +4944,8 @@ private HashMap getVmStats(List vmNames) throws Ex } String instanceNameCustomField = "value[" + key + "]"; - final String numCpuStr = "summary.config.numCpu"; - final String cpuUseStr = "summary.quickStats.overallCpuUsage"; - final String guestMemUseStr = "summary.quickStats.guestMemoryUsage"; - final String memLimitStr = "resourceConfig.memoryAllocation.limit"; - final String memMbStr = "config.hardware.memoryMB"; - ObjectContent[] ocs = - hyperHost.getVmPropertiesOnHyperHost(new String[] {"name", numCpuStr, cpuUseStr ,guestMemUseStr ,memLimitStr ,memMbStr, instanceNameCustomField}); + hyperHost.getVmPropertiesOnHyperHost(new String[] {"name", "summary.config.numCpu", "summary.quickStats.overallCpuUsage", instanceNameCustomField}); if (ocs != null && ocs.length > 0) { for (ObjectContent oc : ocs) { List objProps = oc.getPropSet(); @@ -4960,9 +4953,6 @@ private HashMap getVmStats(List vmNames) throws Ex String name = null; String numberCPUs = null; String maxCpuUsage = null; - String memlimit = null; - String memkb = null; - String guestMemusage = null; String vmNameOnVcenter = null; String vmInternalCSName = null; for (DynamicProperty objProp : objProps) { @@ -4971,16 +4961,10 @@ private HashMap getVmStats(List vmNames) throws Ex } else if (objProp.getName().contains(instanceNameCustomField)) { if (objProp.getVal() != null) vmInternalCSName = ((CustomFieldStringValue)objProp.getVal()).getValue(); - }else if(objProp.getName().equals(guestMemusage)){ - guestMemusage = objProp.getVal().toString(); - }else if (objProp.getName().equals(numCpuStr)) { + } else if (objProp.getName().equals("summary.config.numCpu")) { numberCPUs = objProp.getVal().toString(); - } else if (objProp.getName().equals(cpuUseStr)) { + } else if (objProp.getName().equals("summary.quickStats.overallCpuUsage")) { maxCpuUsage = objProp.getVal().toString(); - } else if (objProp.getName().equals(memLimitStr)) { - memlimit = objProp.getVal().toString(); - } else if (objProp.getName().equals(memMbStr)) { - memkb = objProp.getVal().toString(); } } new VirtualMachineMO(hyperHost.getContext(), oc.getObj()); @@ -5049,7 +5033,7 @@ private HashMap getVmStats(List vmNames) throws Ex } } } - vmResponseMap.put(name, new VmStatsEntry( NumberUtils.toDouble(memkb)*1024,NumberUtils.toDouble(guestMemusage)*1024,NumberUtils.toDouble(memlimit)*1024, NumberUtils.toDouble(maxCpuUsage), networkReadKBs, networkWriteKBs, NumberUtils.toInt(numberCPUs), "vm")); + vmResponseMap.put(name, new VmStatsEntry(Integer.parseInt(maxCpuUsage), networkReadKBs, networkWriteKBs, Integer.parseInt(numberCPUs), "vm")); } } } diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index 665ed77cbb..7c8bca7f1b 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -3278,7 +3278,7 @@ public HashMap getVmStats(final Connection conn, final Get final HashMap vmResponseMap = new HashMap(); for (final String vmUUID : vmUUIDs) { - vmResponseMap.put(vmUUID, new VmStatsEntry(0,0,0,0, 0, 0, 0, "vm")); + vmResponseMap.put(vmUUID, new VmStatsEntry(0, 0, 0, 0, "vm")); } final Object[] rrdData = getRRDData(conn, 2); // call rrddata with 2 for @@ -3332,14 +3332,7 @@ public HashMap getVmStats(final Connection conn, final Get vmStatsAnswer.setDiskReadKBs(vmStatsAnswer.getDiskReadKBs() + getDataAverage(dataNode, col, numRows) / 1000); } else if (param.matches("vbd_.*_write")) { vmStatsAnswer.setDiskWriteKBs(vmStatsAnswer.getDiskWriteKBs() + getDataAverage(dataNode, col, numRows) / 1000); - } else if (param.contains("memory_internal_free")) { - vmStatsAnswer.setIntFreeMemoryKBs(vmStatsAnswer.getIntFreeMemoryKBs() + getDataAverage(dataNode, col, numRows) / 1024); - } else if (param.contains("memory_target")) { - vmStatsAnswer.setTargetMemoryKBs(vmStatsAnswer.getTargetMemoryKBs() + getDataAverage(dataNode, col, numRows) / 1024); - } else if (param.contains("memory")) { - vmStatsAnswer.setMemoryKBs(vmStatsAnswer.getMemoryKBs() + getDataAverage(dataNode, col, numRows) / 1024); } - } } @@ -3355,7 +3348,6 @@ public HashMap getVmStats(final Connection conn, final Get s_logger.debug("Vm cpu utilization " + vmStatsAnswer.getCPUUtilization()); } } - return vmResponseMap; } @@ -5402,4 +5394,4 @@ public boolean attachConfigDriveToMigratedVm(Connection conn, String vmName, Str } -} +} \ No newline at end of file diff --git a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java index a1e3dc911a..7983065f31 100644 --- a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java @@ -207,21 +207,14 @@ public UserVmResponse newUserVmResponse(ResponseView view, String objectName, Us userVmResponse.setNetworkKbsWrite((long)vmStats.getNetworkWriteKBs()); - if ((userVm.getHypervisorType() != null) && (userVm.getHypervisorType().equals(HypervisorType.KVM) || userVm.getHypervisorType().equals(HypervisorType.XenServer) || userVm.getHypervisorType().equals(HypervisorType.VMware))) { // support KVM and XenServer only util 2013.06.25 . supporting Vmware from 2015.09.02 + if ((userVm.getHypervisorType() != null) && (userVm.getHypervisorType().equals(HypervisorType.KVM) || userVm.getHypervisorType().equals(HypervisorType.XenServer))) { // support KVM and XenServer only util 2013.06.25 userVmResponse.setDiskKbsRead((long)vmStats.getDiskReadKBs()); - userVmResponse.setDiskKbsWrite((long) vmStats.getDiskWriteKBs()); + userVmResponse.setDiskKbsWrite((long)vmStats.getDiskWriteKBs()); - userVmResponse.setDiskIORead((long) vmStats.getDiskReadIOs()); - - userVmResponse.setDiskIOWrite((long) vmStats.getDiskWriteIOs()); - - userVmResponse.setMemoryKBs((long) vmStats.getMemoryKBs()); - - userVmResponse.setMemoryIntFreeKBs((long) vmStats.getIntFreeMemoryKBs()); - - userVmResponse.setMemoryTargetKBs((long) vmStats.getTargetMemoryKBs()); + userVmResponse.setDiskIORead((long)vmStats.getDiskReadIOs()); + userVmResponse.setDiskIOWrite((long)vmStats.getDiskWriteIOs()); } } } diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index 387639f4b2..0702335308 100644 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -464,9 +464,6 @@ protected void runInContext() { statsInMemory.setDiskReadIOs(statsInMemory.getDiskReadIOs() + statsForCurrentIteration.getDiskReadIOs()); statsInMemory.setDiskWriteIOs(statsInMemory.getDiskWriteIOs() + statsForCurrentIteration.getDiskWriteIOs()); statsInMemory.setDiskReadKBs(statsInMemory.getDiskReadKBs() + statsForCurrentIteration.getDiskReadKBs()); - statsInMemory.setMemoryKBs(statsForCurrentIteration.getMemoryKBs()); - statsInMemory.setIntFreeMemoryKBs(statsForCurrentIteration.getIntFreeMemoryKBs()); - statsInMemory.setTargetMemoryKBs(statsForCurrentIteration.getTargetMemoryKBs()); _VmStats.put(vmId, statsInMemory); } @@ -487,10 +484,6 @@ protected void runInContext() { metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".disk.read_kbs", statsForCurrentIteration.getDiskReadKBs()); metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".disk.write_iops", statsForCurrentIteration.getDiskWriteIOs()); metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".disk.read_iops", statsForCurrentIteration.getDiskReadIOs()); - metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".memory.total_kbs", statsForCurrentIteration.getMemoryKBs()); - metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".memory.internalfree_kbs", statsForCurrentIteration.getIntFreeMemoryKBs()); - metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".memory.target_kbs", statsForCurrentIteration.getTargetMemoryKBs()); - } } From ae0d6b32d8d30f860a53c9c808ca136012609db7 Mon Sep 17 00:00:00 2001 From: Nick Livens Date: Thu, 18 Feb 2016 11:03:34 +0100 Subject: [PATCH 082/203] CLOUDSTACK-9322 : Changes to support InternalLbVm with Nuage VSP plugin --- .../com/cloud/api/commands/VspConstants.java | 1 + .../api/response/NuageVspDeviceResponse.java | 7 ++ .../network/element/NuageVspElement.java | 31 +++++++ .../guru/NuageVspGuestNetworkGuru.java | 9 ++ .../network/manager/NuageVspManagerImpl.java | 91 ++++++++++++++----- .../network/element/NuageVspElementTest.java | 6 ++ .../guru/NuageVspGuestNetworkGuruTest.java | 25 ++++- .../com/cloud/network/vpc/VpcManagerImpl.java | 9 +- .../src/com/cloud/user/DomainManagerImpl.java | 1 + ui/scripts/configuration.js | 5 +- 10 files changed, 153 insertions(+), 32 deletions(-) diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/VspConstants.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/VspConstants.java index 237289064a..7abcdfb8d0 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/VspConstants.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/VspConstants.java @@ -32,4 +32,5 @@ public class VspConstants { public static final String NUAGE_VSP_API_CHILD_RESOURCE = "childresource"; public static final String NUAGE_VSP_API_RESOURCE_FILTER = "resourcefilter"; public static final String NUAGE_VSP_API_RESOURCE_INFO = "resourceinfo"; + public static final String NUAGE_VSP_CMS_ID = "cmsid"; } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/response/NuageVspDeviceResponse.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/response/NuageVspDeviceResponse.java index 136a465e79..346e28823f 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/response/NuageVspDeviceResponse.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/api/response/NuageVspDeviceResponse.java @@ -65,6 +65,10 @@ public class NuageVspDeviceResponse extends BaseResponse { @Param(description = "the time to wait after failure before retrying to communicate to Nuage VSD") private long apiRetryInterval; + @SerializedName(VspConstants.NUAGE_VSP_CMS_ID) + @Param(description = "the CMS ID generated by the Nuage VSD") + private String cmsId; + public void setId(String vspDetailsId) { this.id = vspDetailsId; } @@ -101,4 +105,7 @@ public void setApiRetryInterval(long apiRetryInterval) { this.apiRetryInterval = apiRetryInterval; } + public void setCmsId(String cmsId) { + this.cmsId = cmsId; + } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java index cb0d698c2b..d0d5ad21a6 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java @@ -59,6 +59,7 @@ import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.manager.NuageVspManager; +import com.cloud.network.manager.NuageVspManagerImpl; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.FirewallRuleType; import com.cloud.network.rules.FirewallRuleVO; @@ -69,7 +70,9 @@ import com.cloud.network.vpc.PrivateGateway; import com.cloud.network.vpc.StaticRouteProfile; import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.VpcOfferingServiceMapVO; import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -135,6 +138,8 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider @Inject VpcDao _vpcDao; @Inject + VpcOfferingServiceMapDao _vpcOfferingSrvcDao; + @Inject NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao; @Inject AgentManager _agentMgr; @@ -426,6 +431,16 @@ protected boolean canHandle(Network network, Service service) { } } + if (network.getVpcId() != null) { + NetworkOffering networkOffering = _ntwkOfferingDao.findById(network.getNetworkOfferingId()); + if (!networkOffering.getIsPersistent()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("NuageVsp can't handle VPC tiers which use a network offering which are not persistent"); + } + return false; + } + } + return true; } @@ -586,6 +601,22 @@ public boolean applyNetworkACLs(Network config, List r @Override public boolean implementVpc(Vpc vpc, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + List vpcOfferingServices = _vpcOfferingSrvcDao.listByVpcOffId(vpc.getVpcOfferingId()); + Map> supportedVpcServices = NuageVspManagerImpl.NUAGE_VSP_VPC_SERVICE_MAP; + for (VpcOfferingServiceMapVO vpcOfferingService : vpcOfferingServices) { + Network.Service service = Network.Service.getService(vpcOfferingService.getService()); + if (!supportedVpcServices.containsKey(service)) { + s_logger.warn(String.format("NuageVsp doesn't support service %s for VPCs", service.getName())); + return false; + } + + Network.Provider provider = Network.Provider.getProvider(vpcOfferingService.getProvider()); + if (!supportedVpcServices.get(service).contains(provider)) { + s_logger.warn(String.format("NuageVsp doesn't support provider %s for service %s for VPCs", provider.getName(), service.getName())); + return false; + } + } + return true; } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java index 5f69a2139a..2037d925ed 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java @@ -25,6 +25,7 @@ import com.cloud.agent.api.guru.ImplementNetworkVspCommand; import com.cloud.agent.api.guru.ReserveVmInterfaceVspCommand; import com.cloud.agent.api.guru.TrashNetworkVspCommand; +import com.cloud.configuration.ConfigurationManager; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.VlanVO; @@ -105,6 +106,8 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { AgentManager _agentMgr; @Inject NuageVspManager _nuageVspManager; + @Inject + ConfigurationManager _configMgr; public NuageVspGuestNetworkGuru() { super(); @@ -347,6 +350,12 @@ public void reserve(NicProfile nic, Network network, VirtualMachineProfile vm, D protected boolean canHandle(NetworkOffering offering, final NetworkType networkType, final PhysicalNetwork physicalNetwork) { if (networkType == NetworkType.Advanced && isMyTrafficType(offering.getTrafficType()) && (offering.getGuestType() == Network.GuestType.Isolated || offering.getGuestType() == Network.GuestType.Shared) && isMyIsolationMethod(physicalNetwork)) { + if (_configMgr.isOfferingForVpc(offering) && !offering.getIsPersistent()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("NuageVsp can't handle VPC tiers which use a network offering which are not persistent"); + } + return false; + } return true; } else { if (s_logger.isTraceEnabled()) { diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java index ce2a363631..16fd11de3c 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java @@ -105,6 +105,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import net.nuage.vsp.acs.NuageVspPluginClientLoader; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; @@ -120,7 +121,6 @@ import javax.naming.ConfigurationException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -137,8 +137,7 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager, private static final int ONE_MINUTE_MULTIPLIER = 60 * 1000; - private static final Set NUAGE_VSP_PROVIDERS; - private static final Map> NUAGE_VSP_VPC_SERVICE_MAP; + public static final Map> NUAGE_VSP_VPC_SERVICE_MAP; private static final ConfigKey[] NUAGE_VSP_CONFIG_KEYS = new ConfigKey[] { NuageVspConfigDns, NuageVspDnsExternal, NuageVspConfigGateway, NuageVspSharedNetworkDomainTemplateName, NuageVspVpcDomainTemplateName, NuageVspIsolatedNetworkDomainTemplateName }; @@ -195,13 +194,18 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager, MessageBus _messageBus; static { - NUAGE_VSP_PROVIDERS = ImmutableSet.of(Network.Provider.NuageVsp); + Set nuageVspProviders = ImmutableSet.of(Network.Provider.NuageVsp); + Set userDataProviders = ImmutableSet.of(Network.Provider.VPCVirtualRouter); + Set lbProviders = ImmutableSet.of(Network.Provider.InternalLbVm); NUAGE_VSP_VPC_SERVICE_MAP = ImmutableMap.>builder() - .put(Network.Service.Connectivity, NUAGE_VSP_PROVIDERS) - .put(Network.Service.Dhcp, NUAGE_VSP_PROVIDERS) - .put(Network.Service.StaticNat, NUAGE_VSP_PROVIDERS) - .put(Network.Service.SourceNat, NUAGE_VSP_PROVIDERS) - .put(Network.Service.NetworkACL, NUAGE_VSP_PROVIDERS) + .put(Network.Service.Connectivity, nuageVspProviders) + .put(Network.Service.Gateway, nuageVspProviders) + .put(Network.Service.Dhcp, nuageVspProviders) + .put(Network.Service.StaticNat, nuageVspProviders) + .put(Network.Service.SourceNat, nuageVspProviders) + .put(Network.Service.NetworkACL, nuageVspProviders) + .put(Network.Service.UserData, userDataProviders) + .put(Network.Service.Lb, lbProviders) .build(); } @@ -424,6 +428,7 @@ public NuageVspDeviceResponse createNuageVspDeviceResponse(NuageVspDeviceVO nuag HostVO nuageVspHost = _hostDao.findById(nuageVspDeviceVO.getHostId()); _hostDao.loadDetails(nuageVspHost); + NuageVspResource.Configuration resourceConfiguration = NuageVspResource.Configuration.fromConfiguration(nuageVspHost.getDetails()); NuageVspDeviceResponse response = new NuageVspDeviceResponse(); response.setDeviceName(nuageVspDeviceVO.getDeviceName()); PhysicalNetwork pnw = ApiDBUtils.findPhysicalNetworkById(nuageVspDeviceVO.getPhysicalNetworkId()); @@ -432,12 +437,13 @@ public NuageVspDeviceResponse createNuageVspDeviceResponse(NuageVspDeviceVO nuag } response.setId(nuageVspDeviceVO.getUuid()); response.setProviderName(nuageVspDeviceVO.getProviderName()); - response.setHostName(nuageVspHost.getDetail("hostname")); - response.setPort(Integer.parseInt(nuageVspHost.getDetail("port"))); - String apiRelativePath = nuageVspHost.getDetail("apirelativepath"); + response.setHostName(resourceConfiguration.hostName()); + response.setPort(Integer.parseInt(resourceConfiguration.port())); + String apiRelativePath = resourceConfiguration.apiRelativePath(); response.setApiVersion(apiRelativePath.substring(apiRelativePath.lastIndexOf('/') + 1)); - response.setApiRetryCount(Integer.parseInt(nuageVspHost.getDetail("retrycount"))); - response.setApiRetryInterval(Long.parseLong(nuageVspHost.getDetail("retryinterval"))); + response.setApiRetryCount(Integer.parseInt(resourceConfiguration.retryCount())); + response.setApiRetryInterval(Long.parseLong(resourceConfiguration.retryInterval())); + response.setCmsId(resourceConfiguration.nuageVspCmsId()); response.setObjectName("nuagevspdevice"); return response; } @@ -770,7 +776,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) { defaultNuageVspSharedSGNetworkOffering.setState(NetworkOffering.State.Enabled); defaultNuageVspSharedSGNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultNuageVspSharedSGNetworkOffering); - Map defaultNuageVspSharedSGNetworkOfferingProviders = new HashMap<>(); + Map defaultNuageVspSharedSGNetworkOfferingProviders = new HashMap(); defaultNuageVspSharedSGNetworkOfferingProviders.put(Network.Service.Dhcp, Network.Provider.NuageVsp); defaultNuageVspSharedSGNetworkOfferingProviders.put(Network.Service.SecurityGroup, Network.Provider.NuageVsp); defaultNuageVspSharedSGNetworkOfferingProviders.put(Network.Service.Connectivity, Network.Provider.NuageVsp); @@ -794,16 +800,15 @@ private void initNuageVspVpcOffering() { Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { - if (_vpcOffDao.findByUniqueName(nuageVPCOfferingName) == null) { + VpcOffering offering = _vpcOffDao.findByUniqueName(nuageVPCOfferingName); + if (offering == null) { if (s_logger.isDebugEnabled()) { s_logger.debug("Creating default Nuage VPC offering " + nuageVPCOfferingName); } - Map> svcProviderMap = Maps.newHashMap(NUAGE_VSP_VPC_SERVICE_MAP); - Set userDataProviders = Collections.singleton(Network.Provider.VPCVirtualRouter); - svcProviderMap.put(Network.Service.UserData, userDataProviders); - - createVpcOffering(nuageVPCOfferingName, nuageVPCOfferingDisplayText, svcProviderMap, true, VpcOffering.State.Enabled, null); + createVpcOffering(nuageVPCOfferingName, nuageVPCOfferingDisplayText, NUAGE_VSP_VPC_SERVICE_MAP, true, VpcOffering.State.Enabled, null); + } else { + updateVpcOffering(offering, NUAGE_VSP_VPC_SERVICE_MAP); } } }); @@ -822,7 +827,7 @@ public VpcOffering doInTransaction(TransactionStatus status) { offering.setState(state); } if (s_logger.isDebugEnabled()) { - s_logger.debug("Adding vpc offering " + offering); + s_logger.debug(String.format("Adding vpc offering %s", offering)); } offering = _vpcOffDao.persist(offering); // populate services and providers @@ -834,11 +839,49 @@ public VpcOffering doInTransaction(TransactionStatus status) { VpcOfferingServiceMapVO offService = new VpcOfferingServiceMapVO(offering.getId(), service, provider); _vpcOffSvcMapDao.persist(offService); if (s_logger.isTraceEnabled()) { - s_logger.trace("Added service for the vpc offering: " + offService + " with provider " + provider.getName()); + s_logger.trace(String.format("Added service for the vpc offering: %s with provider %s", offService, provider.getName())); } } } else { - throw new InvalidParameterValueException("Provider is missing for the VPC offering service " + service.getName()); + throw new InvalidParameterValueException(String.format("Provider is missing for the VPC offering service %s", service.getName())); + } + } + } + return offering; + } + }); + } + + @DB + protected void updateVpcOffering(final VpcOffering offering, final Map> svcProviderMap) { + Transaction.execute(new TransactionCallback() { + @Override + public VpcOffering doInTransaction(TransactionStatus status) { + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("Updating vpc offering %s", offering)); + } + + List currentVpcOfferingServices = _vpcOffSvcMapDao.listByVpcOffId(offering.getId()); + Map> currentSvcProviderMap = Maps.newHashMap(); + for (VpcOfferingServiceMapVO vpcOfferingService : currentVpcOfferingServices) { + Network.Service service = Network.Service.getService(vpcOfferingService.getService()); + Network.Provider provider = Network.Provider.getProvider(vpcOfferingService.getProvider()); + + if (!currentSvcProviderMap.containsKey(service)) { + currentSvcProviderMap.put(service, Sets.newHashSet(provider)); + } else if (!currentSvcProviderMap.get(service).contains(provider)) { + currentSvcProviderMap.get(service).add(provider); + } + } + + for (Network.Service service : svcProviderMap.keySet()) { + for (Network.Provider provider : svcProviderMap.get(service)) { + if (currentSvcProviderMap.get(service) == null || !currentSvcProviderMap.get(service).contains(provider)) { + VpcOfferingServiceMapVO offService = new VpcOfferingServiceMapVO(offering.getId(), service, provider); + _vpcOffSvcMapDao.persist(offService); + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("Added service for the vpc offering: %s", offService)); + } } } } diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java index bbdf764ed8..2f5ce7d193 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java @@ -142,6 +142,12 @@ public void testCanHandle() { final Network net = mock(Network.class); when(net.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vsp); when(net.getId()).thenReturn(NETWORK_ID); + when(net.getNetworkOfferingId()).thenReturn(NETWORK_ID); + + final NetworkOfferingVO ntwkoffer = mock(NetworkOfferingVO.class); + when(ntwkoffer.getId()).thenReturn(NETWORK_ID); + when(ntwkoffer.getIsPersistent()).thenReturn(true); + when(ntwkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); when(ntwkSrvcDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true); // Golden path diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java index 18c088f684..c8d23ab047 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java @@ -22,6 +22,7 @@ import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.configuration.ConfigurationManager; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; @@ -78,6 +79,7 @@ import static com.cloud.network.manager.NuageVspManager.NuageVspSharedNetworkDomainTemplateName; import static com.cloud.network.manager.NuageVspManager.NuageVspVpcDomainTemplateName; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; @@ -102,6 +104,7 @@ public class NuageVspGuestNetworkGuruTest { ConfigurationDao configDao = mock(ConfigurationDao.class); IPAddressDao ipAddressDao = mock(IPAddressDao.class); NuageVspManager nuageVspManager = mock(NuageVspManager.class); + ConfigurationManager configurationManager = mock(ConfigurationManager.class); NetworkDao netdao = mock(NetworkDao.class); NuageVspGuestNetworkGuru guru; @@ -126,6 +129,7 @@ public void setUp() { guru._configDao = configDao; guru._ipAddressDao = ipAddressDao; guru._nuageVspManager = nuageVspManager; + guru._configMgr = configurationManager; final DataCenterVO dc = mock(DataCenterVO.class); when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); @@ -144,6 +148,8 @@ public void testCanHandle() { when(offering.getId()).thenReturn(NETWORK_ID); when(offering.getTrafficType()).thenReturn(TrafficType.Guest); when(offering.getGuestType()).thenReturn(GuestType.Isolated); + when(offering.getIsPersistent()).thenReturn(false); + when(configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(false); final PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class); when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] {"VSP"})); @@ -151,25 +157,28 @@ public void testCanHandle() { when(nosd.areServicesSupportedByNetworkOffering(NETWORK_ID, Service.Connectivity)).thenReturn(true); - assertTrue(guru.canHandle(offering, NetworkType.Advanced, physnet) == true); + assertTrue(guru.canHandle(offering, NetworkType.Advanced, physnet)); // Not supported TrafficType != Guest when(offering.getTrafficType()).thenReturn(TrafficType.Management); - assertFalse(guru.canHandle(offering, NetworkType.Advanced, physnet) == true); + assertFalse(guru.canHandle(offering, NetworkType.Advanced, physnet)); // Supported: GuestType Shared when(offering.getTrafficType()).thenReturn(TrafficType.Guest); when(offering.getGuestType()).thenReturn(GuestType.Shared); - assertTrue(guru.canHandle(offering, NetworkType.Advanced, physnet) == true); + assertTrue(guru.canHandle(offering, NetworkType.Advanced, physnet)); // Not supported: Basic networking when(offering.getGuestType()).thenReturn(GuestType.Isolated); - assertFalse(guru.canHandle(offering, NetworkType.Basic, physnet) == true); + assertFalse(guru.canHandle(offering, NetworkType.Basic, physnet)); // Not supported: IsolationMethod != STT when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] {"VLAN"})); - assertFalse(guru.canHandle(offering, NetworkType.Advanced, physnet) == true); + assertFalse(guru.canHandle(offering, NetworkType.Advanced, physnet)); + // Not supported: Non-persistent VPC tier + when(configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(true); + assertFalse(guru.canHandle(offering, NetworkType.Advanced, physnet)); } @Test @@ -187,6 +196,8 @@ public void testDesign() { when(offering.getId()).thenReturn(NETWORK_ID); when(offering.getTrafficType()).thenReturn(TrafficType.Guest); when(offering.getGuestType()).thenReturn(GuestType.Isolated); + when(offering.getIsPersistent()).thenReturn(false); + when(configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(false); when(nosd.areServicesSupportedByNetworkOffering(NETWORK_ID, Service.Connectivity)).thenReturn(true); @@ -197,6 +208,10 @@ public void testDesign() { final Network designednetwork = guru.design(offering, plan, network, account); assertTrue(designednetwork != null); assertTrue(designednetwork.getBroadcastDomainType() == BroadcastDomainType.Vsp); + + // Can't design non-persistent VPC tier + when(configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(true); + assertNull(guru.design(offering, plan, network, account)); } @Test diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 18fbfe2022..706f4c4abf 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -46,6 +46,7 @@ import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import com.cloud.configuration.Config; @@ -402,8 +403,6 @@ public VpcOffering createVpcOffering(final String name, final String displayText svcProviderMap.put(Service.NetworkACL, defaultProviders); } - svcProviderMap.put(Service.Gateway, defaultProviders); - if (serviceProviders != null) { for (final Entry> serviceEntry : serviceProviders.entrySet()) { final Network.Service service = Network.Service.getService(serviceEntry.getKey()); @@ -425,6 +424,12 @@ public VpcOffering createVpcOffering(final String name, final String displayText } } + // add gateway provider (if sourceNat provider is enabled) + final Set sourceNatServiceProviders = svcProviderMap.get(Service.SourceNat); + if (CollectionUtils.isNotEmpty(sourceNatServiceProviders)) { + svcProviderMap.put(Service.Gateway, sourceNatServiceProviders); + } + validateConnectivtyServiceCapabilities(svcProviderMap.get(Service.Connectivity), serviceCapabilitystList); final boolean supportsDistributedRouter = isVpcOfferingSupportsDistributedRouter(serviceCapabilitystList); diff --git a/server/src/com/cloud/user/DomainManagerImpl.java b/server/src/com/cloud/user/DomainManagerImpl.java index 912aa8b73a..e056e2d87e 100644 --- a/server/src/com/cloud/user/DomainManagerImpl.java +++ b/server/src/com/cloud/user/DomainManagerImpl.java @@ -308,6 +308,7 @@ public boolean deleteDomain(DomainVO domain, Boolean cleanup) { cleanupDomainOfferings(domain.getId()); CallContext.current().putContextParameter(Domain.class, domain.getUuid()); + _messageBus.publish(_name, MESSAGE_REMOVE_DOMAIN_EVENT, PublishScope.LOCAL, domain); return true; } catch (Exception ex) { s_logger.error("Exception deleting domain with id " + domain.getId(), ex); diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js index 14b0e156ff..4f7947aadb 100644 --- a/ui/scripts/configuration.js +++ b/ui/scripts/configuration.js @@ -3583,7 +3583,10 @@ }); networkServiceObjs.push({ name: 'Lb', - provider: [{name: 'VpcVirtualRouter'}] + provider: [ + {name: 'VpcVirtualRouter'}, + {name: 'InternalLbVm'} + ] }); networkServiceObjs.push({ name: 'Gateway', From 741e88833f9b0d533f66bc8875675ede51c15922 Mon Sep 17 00:00:00 2001 From: Nick Livens Date: Mon, 21 Mar 2016 14:34:18 +0100 Subject: [PATCH 083/203] CLOUDSTACK-9320 : InternalLBVM is not getting destroyed when the last Internal Load Balancer rule is removed for the corresponding source IP address --- .../element/InternalLoadBalancerElement.java | 84 ++++++++++--------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java index 1e0b2945f1..f3ebeb0bae 100644 --- a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java +++ b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java @@ -302,50 +302,54 @@ public IpDeployer getIpDeployer(Network network) { @Override public boolean applyLBRules(Network network, List rules) throws ResourceUnavailableException { //1) Get Internal LB VMs to destroy - Set vmsToDestroy = getVmsToDestroy(rules); + Set vmsToDestroy = getVmsToDestroy(network, rules); //2) Get rules to apply Map> rulesToApply = getLbRulesToApply(rules); s_logger.debug("Applying " + rulesToApply.size() + " on element " + getName()); - for (Ip sourceIp : rulesToApply.keySet()) { - if (vmsToDestroy.contains(sourceIp)) { - //2.1 Destroy internal lb vm - List vms = _internalLbMgr.findInternalLbVms(network.getId(), sourceIp); - if (vms.size() > 0) { - //only one internal lb per IP exists - try { - s_logger.debug("Destroying internal lb vm for ip " + sourceIp.addr() + " as all the rules for this vm are in Revoke state"); - return _internalLbMgr.destroyInternalLbVm(vms.get(0).getId(), _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM), - _accountMgr.getUserIncludingRemoved(User.UID_SYSTEM).getId()); - } catch (ConcurrentOperationException e) { - s_logger.warn("Failed to apply lb rule(s) for ip " + sourceIp.addr() + " on the element " + getName() + " due to:", e); - return false; - } - } - } else { - //2.2 Start Internal LB vm per IP address - List internalLbVms; + for (Ip sourceIp : vmsToDestroy) { + //2.1 Destroy internal lb vm + List vms = _internalLbMgr.findInternalLbVms(network.getId(), sourceIp); + if (vms.size() > 0) { + //only one internal lb per IP exists try { - DeployDestination dest = new DeployDestination(_entityMgr.findById(DataCenter.class, network.getDataCenterId()), null, null, null); - internalLbVms = _internalLbMgr.deployInternalLbVm(network, sourceIp, dest, _accountMgr.getAccount(network.getAccountId()), null); - } catch (InsufficientCapacityException e) { - s_logger.warn("Failed to apply lb rule(s) for ip " + sourceIp.addr() + "on the element " + getName() + " due to:", e); - return false; + s_logger.debug(String.format("Destroying internal lb vm for ip %s as all the rules for this vm are in Revoke state", sourceIp.addr())); + return _internalLbMgr.destroyInternalLbVm(vms.get(0).getId(), _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM), + _accountMgr.getUserIncludingRemoved(User.UID_SYSTEM).getId()); } catch (ConcurrentOperationException e) { - s_logger.warn("Failed to apply lb rule(s) for ip " + sourceIp.addr() + "on the element " + getName() + " due to:", e); + s_logger.warn(String.format("Failed to apply lb rule(s) for ip %s on the element %s due to: ", sourceIp.addr(), getName()), e); return false; } + } - if (internalLbVms == null || internalLbVms.isEmpty()) { - throw new ResourceUnavailableException("Can't find/deploy internal lb vm to handle LB rules", DataCenter.class, network.getDataCenterId()); - } + rulesToApply.remove(sourceIp); + } - //2.3 Apply Internal LB rules on the VM - if (!_internalLbMgr.applyLoadBalancingRules(network, rulesToApply.get(sourceIp), internalLbVms)) { - throw new CloudRuntimeException("Failed to apply load balancing rules for ip " + sourceIp.addr() + " in network " + network.getId() + " on element " + - getName()); - } + for (Map.Entry> entry : rulesToApply.entrySet()) { + Ip sourceIp = entry.getKey(); + //2.2 Start Internal LB vm per IP address + List internalLbVms; + try { + DeployDestination dest = new DeployDestination(_entityMgr.findById(DataCenter.class, network.getDataCenterId()), null, null, null); + internalLbVms = _internalLbMgr.deployInternalLbVm(network, sourceIp, dest, _accountMgr.getAccount(network.getAccountId()), null); + } catch (InsufficientCapacityException e) { + s_logger.warn(String.format("Failed to apply lb rule(s) for ip %s on the element %s due to: ", sourceIp.addr(), getName()), e); + return false; + } catch (ConcurrentOperationException e) { + s_logger.warn(String.format("Failed to apply lb rule(s) for ip %s on the element %s due to: ", sourceIp.addr(), getName()), e); + return false; + } + + if (internalLbVms == null || internalLbVms.isEmpty()) { + throw new ResourceUnavailableException("Can't find/deploy internal lb vm to handle LB rules", + DataCenter.class, network.getDataCenterId()); + } + + //2.3 Apply Internal LB rules on the VM + if (!_internalLbMgr.applyLoadBalancingRules(network, entry.getValue(), internalLbVms)) { + throw new CloudRuntimeException("Failed to apply load balancing rules for ip " + sourceIp.addr() + + " in network " + network.getId() + " on element " + getName()); } } @@ -359,16 +363,18 @@ protected Map> getLbRulesToApply(List getVmsToDestroy(List rules) { + protected Set getVmsToDestroy(Network network, List rules) { //1) Group rules by the source ip address as NetworkManager always passes the entire network lb config to the element - Map> groupedRules = groupBySourceIp(rules); - + Set lbPublicIps = new HashSet(); Set vmsToDestroy = new HashSet(); - for (Ip sourceIp : groupedRules.keySet()) { + for (LoadBalancingRule rule : rules) { + lbPublicIps.add(rule.getSourceIp()); + } + + for (Ip sourceIp : lbPublicIps) { //2) Check if there are non revoked rules for the source ip address - List rulesToCheck = groupedRules.get(sourceIp); - if (_appLbDao.countBySourceIpAndNotRevoked(sourceIp, rulesToCheck.get(0).getNetworkId()) == 0) { + if (_appLbDao.countBySourceIpAndNotRevoked(sourceIp, network.getId()) == 0) { s_logger.debug("Have to destroy internal lb vm for source ip " + sourceIp + " as it has 0 rules in non-Revoke state"); vmsToDestroy.add(sourceIp); } From de86c0cb170f55bdd2bf27874f1782b7333d71af Mon Sep 17 00:00:00 2001 From: Prashanth Manthena Date: Wed, 23 Mar 2016 15:59:41 +0100 Subject: [PATCH 084/203] CLOUDSTACK-9322 : Marvin tests for Internal Lb with Nuage VSP --- .../plugins/nuagevsp/nuageTestCase.py | 653 +++--- .../nuagevsp/test_nuage_password_reset.py | 98 +- .../nuagevsp/test_nuage_vpc_internal_lb.py | 2076 +++++++++++++++++ .../nuagevsp/test_nuage_vpc_network.py | 49 +- .../plugins/nuagevsp/test_nuage_vsp.py | 53 +- tools/marvin/marvin/config/test_data.py | 128 +- tools/marvin/marvin/lib/base.py | 7 +- 7 files changed, 2565 insertions(+), 499 deletions(-) create mode 100644 test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py diff --git a/test/integration/plugins/nuagevsp/nuageTestCase.py b/test/integration/plugins/nuagevsp/nuageTestCase.py index 55199d5d80..9d0d07743a 100644 --- a/test/integration/plugins/nuagevsp/nuageTestCase.py +++ b/test/integration/plugins/nuagevsp/nuageTestCase.py @@ -15,43 +15,36 @@ # specific language governing permissions and limitations # under the License. -""" Custom base class for NuageVsp SDN Plugin specific Marvin tests +""" Custom base class for Nuage VSP SDN plugin specific Marvin tests """ # Import Local Modules from marvin.cloudstackTestCase import cloudstackTestCase, unittest -from marvin.lib.base import (NetworkServiceProvider, - ServiceOffering, - NetworkOffering, +from marvin.lib.base import (EgressFireWallRule, + FireWallRule, + Hypervisor, Network, - Router, + NetworkACL, + NetworkACLList, + NetworkOffering, + NetworkServiceProvider, Nuage, - VPC, - VpcOffering, + PhysicalNetwork, PublicIPAddress, - VirtualMachine, + Router, + ServiceOffering, StaticNATRule, - NetworkACLList, - NetworkACL, - FireWallRule, - EgressFireWallRule, - Host) -from marvin.lib.common import (get_zone, - get_domain, + VirtualMachine, + VPC, + VpcOffering) +from marvin.lib.common import (get_domain, get_template, - list_templates, - wait_for_cleanup) + get_zone) from marvin.lib.utils import cleanup_resources -from marvin.cloudstackAPI import (listPhysicalNetworks, - updateConfiguration, - updateTemplate, - listConfigurations, - listHypervisors, - stopRouter, - startRouter) +from marvin.cloudstackAPI import restartVPC # Import System Modules -import socket import importlib import logging +import socket class nuageTestCase(cloudstackTestCase): @@ -84,42 +77,36 @@ def setUpClass(cls): ) cls._cleanup = [cls.service_offering] - # Get configured Nuage Vsp device details + # Get configured Nuage VSP device details try: - resp = listPhysicalNetworks.listPhysicalNetworksCmd() - resp.zoneid = cls.zone.id - physical_networks = cls.api_client.listPhysicalNetworks(resp) + physical_networks = PhysicalNetwork.list(cls.api_client, zoneid=cls.zone.id) for pn in physical_networks: - if pn.isolationmethods == 'VSP': + if pn.isolationmethods == "VSP": cls.vsp_physical_network = pn break cls.nuage_vsp_device = Nuage.list(cls.api_client, physicalnetworkid=cls.vsp_physical_network.id )[0] pns = cls.config.zones[0].physical_networks - providers = filter(lambda physical_network: 'VSP' in physical_network.isolationmethods, pns)[0].providers - devices = filter(lambda provider: provider.name == 'NuageVsp', providers)[0].devices + providers = filter(lambda physical_network: "VSP" in physical_network.isolationmethods, pns)[0].providers + devices = filter(lambda provider: provider.name == "NuageVsp", providers)[0].devices cls.nuage_vsp_device.username = devices[0].username cls.nuage_vsp_device.password = devices[0].password - listConfigurationsCmd = listConfigurations.listConfigurationsCmd() - listConfigurationsCmd.name = "nuagevsp.cms.id" - listConfigurationsCmd.scopename = "global" - cs_config_dict = cls.api_client.listConfigurations(listConfigurationsCmd) - cls.cms_id = str(cs_config_dict[0].value).split(":")[1] + cls.cms_id = cls.nuage_vsp_device.cmsid except Exception as e: cls.tearDownClass() - raise unittest.SkipTest("Warning: Couldn't get configured Nuage Vsp device details: %s" % e) + raise unittest.SkipTest("Warning: Couldn't get configured Nuage VSP device details: %s" % e) # Check if the host hypervisor type is simulator - resp = listHypervisors.listHypervisorsCmd() - resp.zoneid = cls.zone.id - cls.isSimulator = cls.api_client.listHypervisors(resp)[0].name == 'Simulator' + cls.isSimulator = Hypervisor.list(cls.api_client, zoneid=cls.zone.id)[0].name == "Simulator" - # VSD is a Python SDK for Nuage Vsp + # VSD is a programmable policy and analytics engine of Nuage VSP SDN platform + # vspk is a Python SDK for Nuage VSP's VSD + # cms_vspk_wrapper is a library that wraps vspk package try: vspk_module = "vspk." + cls.nuage_vsp_device.apiversion if int(cls.nuage_vsp_device.apiversion[1]) >= 4 \ else "vspk.vsdk." + cls.nuage_vsp_device.apiversion - vsdk = importlib.import_module(vspk_module) + cls.vsdk = importlib.import_module(vspk_module) vspk_utils_module = "vspk.utils" if int(cls.nuage_vsp_device.apiversion[1]) >= 4 \ else "vspk.vsdk." + cls.nuage_vsp_device.apiversion + ".utils" vsdk_utils = importlib.import_module(vspk_utils_module) @@ -129,12 +116,12 @@ def setUpClass(cls): raise unittest.SkipTest("vspk (and/or) cms_vspk_wrapper import failure") # Configure VSD session - cls._session = vsdk.NUVSDSession(username=cls.nuage_vsp_device.username, - password=cls.nuage_vsp_device.password, - enterprise="csp", api_url="https://%s:%d" % - (cls.nuage_vsp_device.hostname, - cls.nuage_vsp_device.port) - ) + cls._session = cls.vsdk.NUVSDSession(username=cls.nuage_vsp_device.username, + password=cls.nuage_vsp_device.password, + enterprise="csp", api_url="https://%s:%d" % + (cls.nuage_vsp_device.hostname, + cls.nuage_vsp_device.port) + ) cls._session.start() # Configure cms_vspk_wrapper session @@ -157,7 +144,7 @@ def tearDownClass(cls): # Cleanup resources used cleanup_resources(cls.api_client, cls._cleanup) except Exception as e: - cls.debug("Warning: Exception during cleanup : %s" % e) + cls.debug("Warning: Exception during cleanup: %s" % e) return def tearDown(self): @@ -176,69 +163,51 @@ def tearDown(self): self.debug("Cleanup complete!") return - def getConfigurationValue(self, name, scope="global"): - listConfigurationsCmd = listConfigurations.listConfigurationsCmd() - listConfigurationsCmd.name = name - listConfigurationsCmd.scopename = scope - if scope is "zone": - listConfigurationsCmd.zoneid = self.zone.id - return self.api_client.listConfigurations(listConfigurationsCmd) - - def setConfigurationValue(self, name, value, scope="global"): - cmd = updateConfiguration.updateConfigurationCmd() - cmd.name = name - cmd.scopename = scope - if scope is "zone": - cmd.zoneid = self.zone.id - cmd.value = value - self.api_client.updateConfiguration(cmd) - - def updateTemplate(self, value): - self.debug("UPDATE TEMPLATE") - cmd = updateTemplate.updateTemplateCmd() - cmd.id = self.template.id - cmd.passwordenabled = value - self.api_client.updateTemplate(cmd) - list_template_response = list_templates(self.api_client, - templatefilter="all", - id=self.template.id - ) - self.template = list_template_response[0] - - # Creates the vpc offering + # create_VpcOffering - Creates VPC offering def create_VpcOffering(self, vpc_offering, suffix=None): - self.debug('Create VpcOffering') + self.debug("Creating VPC offering") if suffix: vpc_offering["name"] = "VPC_OFF-" + str(suffix) vpc_off = VpcOffering.create(self.api_client, vpc_offering ) # Enable VPC offering - vpc_off.update(self.api_client, state='Enabled') + vpc_off.update(self.api_client, state="Enabled") self.cleanup.append(vpc_off) - self.debug('Created and Enabled VpcOffering') + self.debug("Created and Enabled VPC offering") return vpc_off - # create_Vpc - Takes the vpc offering as arguments and creates the VPC - def create_Vpc(self, vpc_offering, cidr='10.1.1.1/16', cleanup=True): - self.debug("Creating a VPC network in the account: %s" % self.account.name) + # create_Vpc - Creates VPC with the given VPC offering + def create_Vpc(self, vpc_offering, cidr="10.1.1.1/16", cleanup=True): + self.debug("Creating a VPC in the account - %s" % self.account.name) + self.test_data["vpc"]["name"] = "TestVPC" + self.test_data["vpc"]["displaytext"] = "TestVPC" self.test_data["vpc"]["cidr"] = cidr - vpc = VPC.create( - self.api_client, - self.test_data["vpc"], - vpcofferingid=vpc_offering.id, - zoneid=self.zone.id, - account=self.account.name, - domainid=self.account.domainid - ) - self.debug("Created VPC with ID: %s" % vpc.id) + vpc = VPC.create(self.api_client, + self.test_data["vpc"], + vpcofferingid=vpc_offering.id, + zoneid=self.zone.id, + account=self.account.name, + domainid=self.account.domainid + ) + self.debug("Created VPC with ID - %s" % vpc.id) if cleanup: self.cleanup.append(vpc) return vpc - # create_NetworkOffering - Takes the network offering as argument and creates the Network Offering + # restart_Vpc - Restarts the given VPC with/without cleanup + def restart_Vpc(self, vpc, cleanup=None): + self.debug("Restarting VPC with ID - %s" % vpc.id) + cmd = restartVPC.restartVPCCmd() + cmd.id = vpc.id + cmd.cleanup = cleanup + cmd.makeredundant = False + self.api_client.restartVPC(cmd) + self.debug("Restarted VPC with ID - %s" % vpc.id) + + # create_NetworkOffering - Creates Network offering def create_NetworkOffering(self, net_offering, suffix=None, conserve_mode=False): - self.debug('Create NetworkOffering') + self.debug("Creating Network offering") if suffix: net_offering["name"] = "NET_OFF-" + str(suffix) nw_off = NetworkOffering.create(self.api_client, @@ -246,90 +215,90 @@ def create_NetworkOffering(self, net_offering, suffix=None, conserve_mode=False) conservemode=conserve_mode ) # Enable Network offering - nw_off.update(self.api_client, state='Enabled') + nw_off.update(self.api_client, state="Enabled") self.cleanup.append(nw_off) - self.debug('Created and Enabled NetworkOffering') + self.debug("Created and Enabled Network offering") return nw_off - # create_Network - Takes the network offering as argument and nw_key and creates the network - def create_Network(self, nw_off, nw_key="network", gateway='10.1.1.1', netmask='255.255.255.0', vpc=None, acl_list=None): - if not hasattr(nw_off, "id"): - nw_off = self.create_NetworkOffering(nw_off) - self.debug('Adding Network=%s' % self.test_data[nw_key]) - self.test_data[nw_key]["netmask"] = netmask - obj_network = Network.create(self.api_client, - self.test_data[nw_key], - accountid=self.account.name, - domainid=self.account.domainid, - networkofferingid=nw_off.id, - zoneid=self.zone.id, - gateway=gateway, - vpcid=vpc.id if vpc else self.vpc.id if hasattr(self, "vpc") else None, - aclid=acl_list.id if acl_list else None - ) - self.debug("Created network with ID: %s" % obj_network.id) - self.cleanup.append(obj_network) - return obj_network + # create_Network - Creates network with the given Network offering + def create_Network(self, nw_off, gateway="10.1.1.1", netmask="255.255.255.0", vpc=None, acl_list=None): + self.debug("Creating a network in the account - %s" % self.account.name) + self.test_data["network"]["netmask"] = netmask + network = Network.create(self.api_client, + self.test_data["network"], + accountid=self.account.name, + domainid=self.account.domainid, + networkofferingid=nw_off.id, + zoneid=self.zone.id, + gateway=gateway, + vpcid=vpc.id if vpc else self.vpc.id if hasattr(self, "vpc") else None, + aclid=acl_list.id if acl_list else None + ) + self.debug("Created network with ID - %s" % network.id) + self.cleanup.append(network) + return network # upgrade_Network - Upgrades the given network def upgrade_Network(self, nw_off, network): if not hasattr(nw_off, "id"): nw_off = self.create_NetworkOffering(nw_off, network.gateway) - self.debug('Update Network=%s' % network) - network.update( - self.api_client, - networkofferingid=nw_off.id, - changecidr=False - ) - self.debug("Updated network with ID: %s" % network.id) + self.debug("Updating Network with ID - %s" % network.id) + network.update(self.api_client, + networkofferingid=nw_off.id, + changecidr=False + ) + self.debug("Updated network with ID - %s" % network.id) # delete_Network - Deletes the given network def delete_Network(self, network): - self.debug('Deleting Network - %s' % network.name) - # Wait for network garbage collection before network deletion - wait_for_cleanup(self.api_client, - ["network.gc.interval", "network.gc.wait"] - ) + self.debug("Deleting Network with ID - %s" % network.id) network.delete(self.api_client) if network in self.cleanup: self.cleanup.remove(network) - self.debug('Deleted Network - %s' % network.name) + self.debug("Deleted Network with ID - %s" % network.id) - # create_VM_in_Network - Creates a VM in the given network, the vm_key - is the key for the services on the vm. - def create_VM_in_Network(self, network, vm_key="virtual_machine", host_id=None, start_vm=True): - self.debug('Creating VM in network=%s' % network.name) - self.debug('Passed vm_key=%s' % vm_key) + # create_VM - Creates VM in the given network, vm_key - Key for the services on the VM + def create_VM(self, network, vm_key="virtual_machine", host_id=None, start_vm=True): + self.debug("Creating VM in network with ID - %s" % network.id) + self.debug("Passed vm_key - %s" % vm_key) self.test_data[vm_key]["zoneid"] = self.zone.id self.test_data[vm_key]["template"] = self.template.id - vm = VirtualMachine.create( - self.api_client, - self.test_data[vm_key], - accountid=self.account.name, - domainid=self.account.domainid, - serviceofferingid=self.service_offering.id, - networkids=[str(network.id)], - startvm=start_vm, - hostid=host_id - ) - self.debug('Created VM=%s in network=%s' % (vm.id, network.name)) + vm = VirtualMachine.create(self.api_client, + self.test_data[vm_key], + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + networkids=[str(network.id)], + startvm=start_vm, + hostid=host_id + ) + self.debug("Created VM with ID - %s in network with ID - %s" % (vm.id, network.id)) self.cleanup.append(vm) return vm # delete_VM - Deletes the given VM - def delete_VM(self, vm): - self.debug('Deleting VM - %s' % vm.name) - vm.delete(self.api_client) - # Wait for expunge interval to cleanup VM - wait_for_cleanup(self.api_client, - ["expunge.delay", "expunge.interval"] - ) + def delete_VM(self, vm, expunge=True): + self.debug("Deleting VM with ID - %s" % vm.id) + vm.delete(self.api_client, expunge=expunge) if vm in self.cleanup: self.cleanup.remove(vm) - self.debug('Deleted VM - %s' % vm.name) + self.debug("Deleted VM with ID - %s" % vm.id) + + # get_Router - Returns router for the given network + def get_Router(self, network): + self.debug("Finding the virtual router for network with ID - %s" % network.id) + routers = Router.list(self.api_client, + networkid=network.id, + listall=True + ) + self.assertEqual(isinstance(routers, list), True, + "List routers should return a valid virtual router for network" + ) + return routers[0] - # acquire_Public_IP - Acquires a public IP for the given network - def acquire_Public_IP(self, network, vpc=None): - self.debug("Associating public IP for network: %s" % network.name) + # acquire_PublicIPAddress - Acquires public IP address for the given network/VPC + def acquire_PublicIPAddress(self, network, vpc=None): + self.debug("Associating public IP for network with ID - %s" % network.id) public_ip = PublicIPAddress.create(self.api_client, accountid=self.account.name, zoneid=self.zone.id, @@ -337,41 +306,35 @@ def acquire_Public_IP(self, network, vpc=None): networkid=network.id if vpc is None else None, vpcid=vpc.id if vpc else self.vpc.id if hasattr(self, "vpc") else None ) - self.debug("Associated %s with network %s" % (public_ip.ipaddress.ipaddress, - network.id)) + self.debug("Associated public IP address - %s with network with ID - %s" % + (public_ip.ipaddress.ipaddress, network.id)) return public_ip - # create_StaticNatRule_For_VM - Creates static NAT rule for the given network , VM on the given public ip + # create_StaticNatRule_For_VM - Creates static NAT rule on the given public IP for the given network and VM def create_StaticNatRule_For_VM(self, vm, public_ip, network, vmguestip=None): - self.debug("Enabling static NAT for IP: %s" % - public_ip.ipaddress.ipaddress) - StaticNATRule.enable( - self.api_client, - ipaddressid=public_ip.ipaddress.id, - virtualmachineid=vm.id, - networkid=network.id, - vmguestip=vmguestip - ) - self.debug("Static NAT enabled for IP: %s" % - public_ip.ipaddress.ipaddress) - - # delete_StaticNatRule_For_VM - Deletes the static NAT rule for the given VM + self.debug("Enabling static NAT for public IP - %s" % public_ip.ipaddress.ipaddress) + StaticNATRule.enable(self.api_client, + ipaddressid=public_ip.ipaddress.id, + virtualmachineid=vm.id, + networkid=network.id, + vmguestip=vmguestip + ) + self.debug("Static NAT enabled for public IP - %s" % public_ip.ipaddress.ipaddress) + + # delete_StaticNatRule_For_VM - Deletes static NAT rule on the given public IP for the given VM def delete_StaticNatRule_For_VM(self, vm, public_ip): - self.debug("Disabling static NAT for IP: %s" % - public_ip.ipaddress.ipaddress) - StaticNATRule.disable( - self.api_client, - ipaddressid=public_ip.ipaddress.id, - virtualmachineid=vm.id - ) - self.debug("Static NAT disabled for IP: %s" % - public_ip.ipaddress.ipaddress) - - # create_firewall_rule - Creates the Ingress firewall rule on the given public ip - def create_firewall_rule(self, public_ip, rule=None): + self.debug("Disabling static NAT for public IP - %s" % public_ip.ipaddress.ipaddress) + StaticNATRule.disable(self.api_client, + ipaddressid=public_ip.ipaddress.id, + virtualmachineid=vm.id + ) + self.debug("Static NAT disabled for public IP - %s" % public_ip.ipaddress.ipaddress) + + # create_FirewallRule - Creates Ingress firewall rule on the given public IP + def create_FirewallRule(self, public_ip, rule=None): if not rule: rule = self.test_data["ingress_rule"] - self.debug("Adding an Ingress Firewall rule to make Guest VMs accessible through Static NAT") + self.debug("Adding an Ingress Firewall rule to make Guest VMs accessible through Static NAT - %s" % rule) return FireWallRule.create(self.api_client, ipaddressid=public_ip.ipaddress.id, protocol=rule["protocol"], @@ -380,9 +343,9 @@ def create_firewall_rule(self, public_ip, rule=None): endport=rule["endport"] ) - # create_egress_firewall_rule - Creates the Egress firewall rule on the given public ip - def create_egress_firewall_rule(self, network, rule): - self.debug("Adding an Egress Firewall rule to allow/deny outgoing traffic from Guest VMs") + # create_EgressFirewallRule - Creates Egress firewall rule on the given public IP + def create_EgressFirewallRule(self, network, rule): + self.debug("Adding an Egress Firewall rule to allow/deny outgoing traffic from Guest VMs - %s" % rule) return EgressFireWallRule.create(self.api_client, networkid=network.id, protocol=rule["protocol"], @@ -391,9 +354,9 @@ def create_egress_firewall_rule(self, network, rule): endport=rule["endport"] ) - # create_network_acl_list - Creates network ACL list in the given VPC - def create_network_acl_list(self, name, description, vpc): - self.debug("Adding NetworkACL list in VPC: %s" % vpc.id) + # create_NetworkAclList - Creates network ACL list in the given VPC + def create_NetworkAclList(self, name, description, vpc): + self.debug("Adding NetworkACL list in VPC with ID - %s" % vpc.id) return NetworkACLList.create(self.api_client, services={}, name=name, @@ -401,90 +364,52 @@ def create_network_acl_list(self, name, description, vpc): vpcid=vpc.id ) - # create_network_acl_rule - Creates network ACL rule Ingree/Egress in the given network - def create_network_acl_rule(self, rule, traffic_type="Ingress", network=None, acl_list=None): - self.debug("Adding NetworkACL rule: %s" % rule) - return NetworkACL.create(self.api_client, - networkid=network.id if network else None, - services=rule, - traffictype=traffic_type, - aclid=acl_list.id if acl_list else None - ) - - # migrate_vm - Migrates the VM to a different host if available - def migrate_vm(self, vm): - self.debug("Checking if a host is available for migration?") - hosts = Host.listForMigration(self.api_client) - self.assertEqual(isinstance(hosts, list), True, - "List hosts should return a valid list" - ) - # Remove the host of current VM from the hosts list - hosts[:] = [host for host in hosts if host.id != vm.hostid] - if len(hosts) <= 0: - self.skipTest("No host available for migration. Test requires at-least 2 hosts") - host = hosts[0] - self.debug("Migrating VM-ID: %s to Host: %s" % (vm.id, host.id)) - try: - vm.migrate(self.api_client, hostid=host.id) - except Exception as e: - self.fail("Failed to migrate instance, %s" % e) - - # get_network_router - returns the router for the given network - def get_network_router(self, network): - self.debug("Finding the virtual router for network: %s" % network.name) - routers = Router.list(self.api_client, - networkid=network.id, - listall=True - ) - self.assertEqual(isinstance(routers, list), True, - "List routers should return a valid virtual router for network" - ) - return routers[0] + # create_NetworkAclRule - Creates Ingress/Egress network ACL rule in the given network/acl list + def create_NetworkAclRule(self, rule, traffic_type="Ingress", network=None, acl_list=None): + self.debug("Adding NetworkACL rule - %s" % rule) + if acl_list: + return NetworkACL.create(self.api_client, + networkid=network.id if network else None, + services=rule, + traffictype=traffic_type, + aclid=acl_list.id + ) + else: + return NetworkACL.create(self.api_client, + networkid=network.id if network else None, + services=rule, + traffictype=traffic_type + ) - # stop_network_router - Stops the given network router - def stop_network_router(self, router): - self.debug("Stopping Router with ID: %s" % router.id) - cmd = stopRouter.stopRouterCmd() - cmd.id = router.id - self.api_client.stopRouter(cmd) - - # start_network_router - Starts the given network router - def start_network_router(self, router): - self.debug("Starting Router with ID: %s" % router.id) - cmd = startRouter.startRouterCmd() - cmd.id = router.id - self.api_client.startRouter(cmd) - - # ssh_into_vm - Gets into the shell of the given VM - def ssh_into_vm(self, vm, public_ip): - self.debug("SSH into VM=%s on public_ip=%s" % (vm.name, public_ip.ipaddress.ipaddress)) + # ssh_into_VM - Gets into the shell of the given VM + def ssh_into_VM(self, vm, public_ip): + self.debug("SSH into VM with ID - %s on public IP address - %s" % (vm.id, public_ip.ipaddress.ipaddress)) ssh_client = vm.get_ssh_client(ipaddress=public_ip.ipaddress.ipaddress) return ssh_client # execute_cmd - Executes the given command on the given ssh client def execute_cmd(self, ssh_client, cmd): - self.debug("EXECUTE SSH COMMAND: " + cmd) + self.debug("SSH client executing command - %s" % cmd) ret_data = "" out_list = ssh_client.execute(cmd) if out_list is not None: ret_data = ' '.join(map(str, out_list)).strip() - self.debug("ssh execute cmd result=" + ret_data) + self.debug("SSH client executed command result - %s" % ret_data) else: - self.debug("ssh execute cmd result is None") + self.debug("SSH client executed command result is None") return ret_data - # wget_from_server - fetches the index.html file from the given public Ip + # wget_from_server - Fetches index.html file of web server running with the given public IP def wget_from_server(self, public_ip): import urllib - self.debug("wget from a http server on public_ip=%s" % public_ip.ipaddress.ipaddress) - wget_file = urllib.urlretrieve("http://%s/index.html" % public_ip.ipaddress.ipaddress, - filename="index.html" - ) - return wget_file - - # validate_NetworkServiceProvider - Validates the Network Service Provider - # in the Nuage VSP Physical Network - matches the given provider name - # against the list of providers fetched + self.debug("wget from a http server on public IP address - %s" % public_ip.ipaddress.ipaddress) + filename, headers = urllib.urlretrieve("http://%s/index.html" % public_ip.ipaddress.ipaddress, + filename="index.html" + ) + return filename, headers + + # validate_NetworkServiceProvider - Validates the given Network Service Provider in the Nuage VSP Physical Network, + # matches the given provider name and state against the list of providers fetched def validate_NetworkServiceProvider(self, provider_name, state=None): """Validates the Network Service Provider in the Nuage VSP Physical Network""" self.debug("Check if the Network Service Provider is created successfully ?") @@ -499,12 +424,13 @@ def validate_NetworkServiceProvider(self, provider_name, state=None): ) if state: self.assertEqual(providers[0].state, state, - "Network Service Provider state should be '%s'" % state + "Network Service Provider state should be in state - %s" % state ) - self.debug("Network Service Provider creation successfully validated - %s" % provider_name) + self.debug("Network Service Provider creation successfully validated for %s" % provider_name) - # validate_vpc_offering - Validates the VPC offering, matches the given VPC off name against the list of VPC offerings fetched - def validate_vpc_offering(self, vpc_offering, state=None): + # validate_VpcOffering - Validates the given VPC offering, + # matches the given VPC offering name and state against the list of VPC offerings fetched + def validate_VpcOffering(self, vpc_offering, state=None): """Validates the VPC offering""" self.debug("Check if the VPC offering is created successfully ?") vpc_offs = VpcOffering.list(self.api_client, @@ -518,12 +444,13 @@ def validate_vpc_offering(self, vpc_offering, state=None): ) if state: self.assertEqual(vpc_offs[0].state, state, - "VPC offering state should be '%s'" % state + "VPC offering state should be in state - %s" % state ) - self.debug("VPC offering creation successfully validated - %s" % vpc_offering.name) + self.debug("VPC offering creation successfully validated for %s" % vpc_offering.name) - # validate_vpc - Validates the given VPC matches, the given VPC name against the list of VPCs fetched - def validate_vpc(self, vpc, state=None): + # validate_Vpc - Validates the given VPC, + # matches the given VPC name and state against the list of VPCs fetched + def validate_Vpc(self, vpc, state=None): """Validates the VPC""" self.debug("Check if the VPC is created successfully ?") vpcs = VPC.list(self.api_client, @@ -537,14 +464,13 @@ def validate_vpc(self, vpc, state=None): ) if state: self.assertEqual(vpcs[0].state, state, - "VPC state should be '%s'" % state + "VPC state should be in state - %s" % state ) - self.debug("VPC creation successfully validated - %s" % vpc.name) + self.debug("VPC creation successfully validated for %s" % vpc.name) - # validate_network_offering - Validates the given Network offering - # matches the given network offering name against the list of network - # offerings fetched - def validate_network_offering(self, net_offering, state=None): + # validate_NetworkOffering - Validates the given Network offering, + # matches the given network offering name and state against the list of network offerings fetched + def validate_NetworkOffering(self, net_offering, state=None): """Validates the Network offering""" self.debug("Check if the Network offering is created successfully ?") net_offs = NetworkOffering.list(self.api_client, @@ -558,13 +484,14 @@ def validate_network_offering(self, net_offering, state=None): ) if state: self.assertEqual(net_offs[0].state, state, - "Network offering state should be '%s'" % state + "Network offering state should be in state - %s" % state ) - self.debug("Network offering creation successfully validated - %s" % net_offering.name) + self.debug("Network offering creation successfully validated for %s" % net_offering.name) - # validate_network - Validates the network - matches the given network name against the list of networks fetched - def validate_network(self, network, state=None): - """Validates the network""" + # validate_Network - Validates the given network, + # matches the given network name and state against the list of networks fetched + def validate_Network(self, network, state=None): + """Validates the Network""" self.debug("Check if the network is created successfully ?") networks = Network.list(self.api_client, id=network.id @@ -577,28 +504,13 @@ def validate_network(self, network, state=None): ) if state: self.assertEqual(networks[0].state, state, - "Network state should be '%s'" % state - ) - self.debug("Network creation successfully validated - %s" % network.name) - - # check_router_state - Fetches the list of routers and their states and matches the given router's state - def check_router_state(self, router, state=None): - self.debug("Check if the virtual router is in state - %s" % state) - routers = Router.list(self.api_client, - id=router.id, - listall=True - ) - self.assertEqual(isinstance(routers, list), True, - "List router should return a valid list" - ) - if state: - self.assertEqual(routers[0].state, state, - "Virtual router is not in the expected state" + "Network state should be in state - %s" % state ) - self.debug("Virtual router is in the expected state - %s" % state) + self.debug("Network creation successfully validated for %s" % network.name) - # check_vm_state - Fetches the list of VMs and their states and matches the given VM's state - def check_vm_state(self, vm, state=None): + # check_VM_state - Checks if the given VM is in the expected state form the list of fetched VMs + def check_VM_state(self, vm, state=None): + """Validates the VM state""" self.debug("Check if the VM instance is in state - %s" % state) vms = VirtualMachine.list(self.api_client, id=vm.id, @@ -611,12 +523,30 @@ def check_vm_state(self, vm, state=None): self.assertEqual(vms[0].state, state, "Virtual machine is not in the expected state" ) - self.debug("Virtual machine is in the expected state - %s" % state) + self.debug("Virtual machine instance - %s is in the expected state - %s" % (vm.name, state)) + + # check_Router_state - Checks if the given router is in the expected state form the list of fetched routers + def check_Router_state(self, router, state=None): + """Validates the Router state""" + self.debug("Check if the virtual router instance is in state - %s" % state) + routers = Router.list(self.api_client, + id=router.id, + listall=True + ) + self.assertEqual(isinstance(routers, list), True, + "List router should return a valid list" + ) + if state: + self.assertEqual(routers[0].state, state, + "Virtual router is not in the expected state" + ) + self.debug("Virtual router instance - %s is in the expected state - %s" % (router.name, state)) - # validate_Public_IP - Looks if the given public ip is in the allocated state form the list of fetched public IPs - def validate_Public_IP(self, public_ip, network, static_nat=False, vm=None): - """Validates the Public IP""" - self.debug("Check if the Public IP is successfully assigned to the network ?") + # validate_PublicIPAddress - Validates if the given public IP address is in the expected state form the list of + # fetched public IP addresses + def validate_PublicIPAddress(self, public_ip, network, static_nat=False, vm=None): + """Validates the Public IP Address""" + self.debug("Check if the public IP is successfully assigned to the network ?") public_ips = PublicIPAddress.list(self.api_client, id=public_ip.ipaddress.id, networkid=network.id, @@ -624,24 +554,30 @@ def validate_Public_IP(self, public_ip, network, static_nat=False, vm=None): listall=True ) self.assertEqual(isinstance(public_ips, list), True, - "List public Ip for network should return a valid list" + "List public IP for network should return a valid list" ) self.assertEqual(public_ips[0].ipaddress, public_ip.ipaddress.ipaddress, - "List public Ip for network should list the assigned public Ip address" + "List public IP for network should list the assigned public IP address" ) self.assertEqual(public_ips[0].state, "Allocated", - "Assigned public Ip is not in the allocated state" + "Assigned public IP is not in the allocated state" ) if static_nat and vm: self.assertEqual(public_ips[0].virtualmachineid, vm.id, - "Static NAT Rule not enabled for the VM using the assigned public Ip" + "Static NAT Rule not enabled for the VM using the assigned public IP" ) - self.debug("Assigned Public IP is successfully validated - %s" % public_ip.ipaddress.ipaddress) + self.debug("Assigned Public IP address - %s is successfully validated" % public_ip.ipaddress.ipaddress) # VSD verifications + # VSD is a programmable policy and analytics engine of Nuage VSP SDN platform + + # get_externalID - Returns corresponding external ID of the given object in VSD + def get_externalID(self, object_id): + return object_id + "@" + self.cms_id - def fetch_by_external_id(self, fetcher, *cs_objects): - """ Fetches a child object by external id using the given fetcher, and uuids of the given cloudstack objects. + # fetch_by_externalID - Returns VSD object with the given external ID + def fetch_by_externalID(self, fetcher, *cs_objects): + """ Fetches a child object by external ID using the given fetcher, and uuids of the given cloudstack objects. E.G. - fetch_by_external_id(vsdk.NUSubnet(id="954de425-b860-410b-be09-c560e7dbb474").vms, cs_vm) - fetch_by_external_id(session.user.floating_ips, cs_network, cs_public_ip) @@ -651,12 +587,8 @@ def fetch_by_external_id(self, fetcher, *cs_objects): """ return fetcher.get_first(filter="externalID BEGINSWITH '%s'" % ":".join([o.id for o in cs_objects])) - # VSD verifications using cms_vspk_wrapper - - def get_externalID(self, object_id): - return object_id + "@" + self.cms_id - - # verify_vsp_network - Fetches the vsd domain, vsd zone and vsd subnet and Verifies the given network/VPC values match the fetched values + # verify_vsp_network - Verifies the given domain and network/VPC + # against the corresponding installed enterprise, domain, zone, and subnet in VSD def verify_vsp_network(self, domain_id, network, vpc=None): vsd_enterprise = self.vsd.get_enterprise(name=domain_id) if vpc: @@ -677,24 +609,24 @@ def verify_vsp_network(self, domain_id, network, vpc=None): self.debug(vsd_zone) self.debug(vsd_subnet) if vpc: - self.assertEqual(vsd_domain['description'], "VPC_" + vpc.name, + self.assertEqual(vsd_domain["description"], "VPC_" + vpc.name, "VSD domain description should match VPC name in CloudStack" ) - self.assertEqual(vsd_zone['description'], "VPC_" + vpc.name, + self.assertEqual(vsd_zone["description"], "VPC_" + vpc.name, "VSD zone description should match VPC name in CloudStack" ) else: - self.assertEqual(vsd_domain['description'], network.name, - "VSD domain description should match Isolated Network name in CloudStack" + self.assertEqual(vsd_domain["description"], network.name, + "VSD domain description should match network name in CloudStack" ) - self.assertEqual(vsd_zone['description'], network.name, - "VSD zone description should match Isolated Network name in CloudStack" + self.assertEqual(vsd_zone["description"], network.name, + "VSD zone description should match network name in CloudStack" ) - self.assertEqual(vsd_subnet['description'], network.name, - "VSD subnet description should match Isolated Network name in CloudStack" + self.assertEqual(vsd_subnet["description"], network.name, + "VSD subnet description should match network name in CloudStack" ) - # verify_vsp_vm - Fetches the vsd vport, vsd vm and interface and Verifies the given VM values match the fetched values + # verify_vsp_vm - Verifies the given VM deployment and state in VSD def verify_vsp_vm(self, vm, stopped=None): ext_vm_id = self.get_externalID(vm.id) for nic in vm.nic: @@ -705,10 +637,10 @@ def verify_vsp_vm(self, vm, stopped=None): self.debug("SHOW VPORT and VM INTERFACE DATA FORMAT IN VSD") self.debug(vsd_vport) self.debug(vsd_vm_interface) - self.assertEqual(vsd_vport['active'], True, + self.assertEqual(vsd_vport["active"], True, "VSD VM vport should be active" ) - self.assertEqual(vsd_vm_interface['IPAddress'], nic.ipaddress, + self.assertEqual(vsd_vm_interface["IPAddress"], nic.ipaddress, "VSD VM interface IP address should match VM's NIC IP address in CloudStack" ) vsd_vm = self.vsd.get_vm(externalID=ext_vm_id) @@ -716,15 +648,15 @@ def verify_vsp_vm(self, vm, stopped=None): self.debug(vsd_vm) if not self.isSimulator: if stopped: - self.assertEqual(vsd_vm['status'], "DELETE_PENDING", + self.assertEqual(vsd_vm["status"], "DELETE_PENDING", "VM state in VSD should be DELETE_PENDING" ) else: - self.assertEqual(vsd_vm['status'], vm.state.upper(), + self.assertEqual(vsd_vm["status"], vm.state.upper(), "VM state in VSD should match its state in CloudStack" ) - # verify_vsp_router - Fetches the vsd router and Verifies the given router status match the fetched status + # verify_vsp_router - Verifies the given network router deployment and state in VSD def verify_vsp_router(self, router, stopped=None): ext_router_id = self.get_externalID(router.id) vsd_router = self.vsd.get_vm(externalID=ext_router_id) @@ -732,22 +664,42 @@ def verify_vsp_router(self, router, stopped=None): self.debug(vsd_router) if not self.isSimulator: if stopped: - self.assertEqual(vsd_router['status'], "DELETE_PENDING", + self.assertEqual(vsd_router["status"], "DELETE_PENDING", "Router state in VSD should be DELETE_PENDING" ) else: - self.assertEqual(vsd_router['status'], router.state.upper(), + self.assertEqual(vsd_router["status"], router.state.upper(), "Router state in VSD should match its state in CloudStack" ) - # verify_vsp_floating_ip - Verifies the floating IPs on the given public IP against the VSD FIP + # verify_vsp_LB_device - Verifies the given LB device deployment and state in VSD + def verify_vsp_LB_device(self, lb_device, stopped=None): + ext_lb_device_id = self.get_externalID(lb_device.id) + vsd_lb_device = self.vsd.get_vm(externalID=ext_lb_device_id) + self.debug("SHOW LB Device DATA FORMAT IN VSD") + self.debug(vsd_lb_device) + if not self.isSimulator: + if stopped: + self.assertEqual(vsd_lb_device['status'], "DELETE_PENDING", + "LB device state in VSD should be DELETE_PENDING" + ) + else: + self.assertEqual(vsd_lb_device['status'], lb_device.state.upper(), + "LB device state in VSD should match its state in CloudStack" + ) + + # verify_vsp_floating_ip - Verifies the static nat rule on the given public IP of the given network and VM + # against the corresponding installed FIP in VSD def verify_vsp_floating_ip(self, network, vm, public_ipaddress, vpc=None): - ext_fip_id = self.get_externalID(network.id + ":" + public_ipaddress.id) + if vpc: + ext_fip_id = self.get_externalID(vpc.id + ":" + public_ipaddress.id) + else: + ext_fip_id = self.get_externalID(network.id + ":" + public_ipaddress.id) vsd_fip = self.vsd.get_floating_ip(externalID=ext_fip_id) self.debug("SHOW FLOATING IP DATA FORMAT IN VSD") self.debug(vsd_fip) - self.assertEqual(vsd_fip['address'], public_ipaddress.ipaddress, - "Floating IP address in VSD should match acquired Public IP address in CloudStack" + self.assertEqual(vsd_fip["address"], public_ipaddress.ipaddress, + "Floating IP address in VSD should match acquired public IP address in CloudStack" ) if vpc: ext_network_id = self.get_externalID(vpc.id) @@ -756,28 +708,27 @@ def verify_vsp_floating_ip(self, network, vm, public_ipaddress, vpc=None): vsd_domain = self.vsd.get_domain(externalID=ext_network_id) self.debug("SHOW NETWORK DATA FORMAT IN VSD") self.debug(vsd_domain) - self.assertEqual(vsd_domain['ID'], vsd_fip['parentID'], + self.assertEqual(vsd_domain["ID"], vsd_fip["parentID"], "Floating IP in VSD should be associated with the correct VSD domain, " - "which in turn should correspond to the correct VPC (or) Isolated network in CloudStack" + "which in turn should correspond to the correct VPC (or) network in CloudStack" ) ext_subnet_id = self.get_externalID(network.id) vsd_subnet = self.vsd.get_subnet(externalID=ext_subnet_id) for nic in vm.nic: - if nic.networkname == vsd_subnet['description']: + if nic.networkname == vsd_subnet["description"]: ext_network_id = self.get_externalID(nic.networkid) ext_nic_id = self.get_externalID(nic.id) vsd_vport = self.vsd.get_vport(subnet_externalID=ext_network_id, vport_externalID=ext_nic_id) self.debug("SHOW VM VPORT DATA FORMAT IN VSD") self.debug(vsd_vport) - self.assertEqual(vsd_vport['associatedFloatingIPID'], vsd_fip['ID'], + self.assertEqual(vsd_vport["associatedFloatingIPID"], vsd_fip["ID"], "Floating IP in VSD should be associated to the correct VSD vport, " "which in turn should correspond to the correct Static NAT enabled VM " - "and Isolated Network in CloudStack" + "and network in CloudStack" ) - # verify_vsp_firewall_rule - Verifies the start port, destination port, - # protocol of the given firewall rule Ingress/Egress against the VSD - # firewall rule + # verify_vsp_firewall_rule - Verifies the given Ingress/Egress firewall rule + # against the corresponding installed firewall rule in VSD def verify_vsp_firewall_rule(self, firewall_rule, traffic_type="Ingress"): ext_fw_id = self.get_externalID(firewall_rule.id) if traffic_type is "Ingress": @@ -787,11 +738,11 @@ def verify_vsp_firewall_rule(self, firewall_rule, traffic_type="Ingress"): self.debug("SHOW ACL ENTRY IN VSD") self.debug(vsd_fw_rule) dest_port = str(firewall_rule.startport) + "-" + str(firewall_rule.endport) - self.assertEqual(vsd_fw_rule['destinationPort'], dest_port, - "Destination Port in VSD should match Destination Port in CloudStack" + self.assertEqual(vsd_fw_rule["destinationPort"], dest_port, + "Destination port in VSD should match destination port in CloudStack" ) - vsd_protocol = str(vsd_fw_rule['protocol']) - self.debug("vsd protocol " + vsd_protocol) + vsd_protocol = str(vsd_fw_rule["protocol"]) + self.debug("vsd protocol - %s" % vsd_protocol) protocol = "tcp" if vsd_protocol == 6: protocol = "tcp" @@ -800,5 +751,5 @@ def verify_vsp_firewall_rule(self, firewall_rule, traffic_type="Ingress"): elif vsd_protocol == 17: protocol = "udp" self.assertEqual(protocol, firewall_rule.protocol.lower(), - "Protocol in VSD should match Protocol in CloudStack" + "Protocol in VSD should match protocol in CloudStack" ) diff --git a/test/integration/plugins/nuagevsp/test_nuage_password_reset.py b/test/integration/plugins/nuagevsp/test_nuage_password_reset.py index 5582819d90..ee028c2c54 100644 --- a/test/integration/plugins/nuagevsp/test_nuage_password_reset.py +++ b/test/integration/plugins/nuagevsp/test_nuage_password_reset.py @@ -15,26 +15,29 @@ # specific language governing permissions and limitations # under the License. -""" Component tests for - userdata +""" Component tests for user data and password reset functionality with Nuage VSP SDN plugin """ # Import Local Modules +from nuageTestCase import nuageTestCase from marvin.lib.base import (Account, + Template, VirtualMachine, - Volume, - Template) -from nose.plugins.attrib import attr -from nuageTestCase import nuageTestCase + Volume) +from marvin.lib.common import list_templates from marvin.lib.utils import cleanup_resources -from marvin.cloudstackAPI import startVirtualMachine +from marvin.cloudstackAPI import updateTemplate +# Import System Modules +from nose.plugins.attrib import attr import base64 class TestNuagePasswordReset(nuageTestCase): + """Test user data and password reset functionality with Nuage VSP SDN plugin + """ @classmethod def setUpClass(cls): super(TestNuagePasswordReset, cls).setUpClass() - return def setUp(self): @@ -60,16 +63,15 @@ def tearDown(self): self.vm_1.delete(self.apiclient, expunge=True) if self.remove_vm2: self.vm_2.delete(self.apiclient, expunge=True) - try: cleanup_resources(self.apiclient, self.cleanup) except Exception as e: - self.debug("Warning: Exception during cleanup : %s" % e) + self.debug("Warning: Exception during cleanup: %s" % e) return - # create_template - Takes the VM object as the argument to create the template + # create_template - Creates template with the given VM object def create_template(self, vm): - self.debug("CREATE TEMPLATE") + self.debug("Creating template") list_volume = Volume.list(self.apiclient, virtualmachineid=vm.id, type='ROOT', @@ -77,18 +79,31 @@ def create_template(self, vm): if isinstance(list_volume, list): self.volume = list_volume[0] else: - raise Exception("Exception: Unable to find root volume for VM: %s" % vm.id) - - self.test_data["template_pr"]["ostype"] = self.test_data["ostype_pr"] + raise Exception("Exception: Unable to find root volume for VM with ID - %s" % vm.id) self.pw_enabled_template = Template.create( self.apiclient, - self.test_data["template_pr"], + self.test_data["template"], self.volume.id, account=self.account.name, domainid=self.account.domainid ) self.assertEqual(self.pw_enabled_template.passwordenabled, True, "template is not passwordenabled") self.cleanup.append(self.pw_enabled_template) + self.debug("Created template") + + # updateTemplate - Updates value of template's password enabled setting + def updateTemplate(self, value): + self.debug("Updating value of template's password enabled setting") + cmd = updateTemplate.updateTemplateCmd() + cmd.id = self.template.id + cmd.passwordenabled = value + self.apiclient.updateTemplate(cmd) + list_template_response = list_templates(self.apiclient, + templatefilter="all", + id=self.template.id + ) + self.template = list_template_response[0] + self.debug("Updated template") # VM object is passed as an argument and its interface id is returned def get_vm_interface_id(self, vm): @@ -109,13 +124,13 @@ def get_userdata_url(self, vm): # Creates and verifies the firewall rule def create_and_verify_fw(self, vm, public_ip, network): - self.debug("CREATE AND VERIFY FIREWALL RULE") + self.debug("Create and verify firewall rule") self.create_StaticNatRule_For_VM(vm, public_ip, network) # VSD verification self.verify_vsp_floating_ip(network, vm, public_ip.ipaddress) - fw_rule = self.create_firewall_rule(public_ip, self.test_data["ingress_rule"]) + fw_rule = self.create_FirewallRule(public_ip, self.test_data["ingress_rule"]) self.verify_vsp_firewall_rule(fw_rule) vm_interface_id = self.get_vm_interface_id(vm) pd = self.vsd.get_vm_interface_policydecisions(id=vm_interface_id) @@ -130,7 +145,7 @@ def create_and_verify_fw(self, vm, public_ip, network): raise ValueError('No firewall policy decision in vm interface') def stop_vm(self, vm): - self.debug("STOP VM") + self.debug("Stoping VM") vm.stop(self.apiclient) list_vm_response = VirtualMachine.list(self.apiclient, id=vm.id) @@ -159,8 +174,10 @@ def install_cloud_set_guest_password_script(self, ssh_client): self.debug("get_set_password_file result " + result) @attr(tags=["advanced", "nuagevsp"], required_hardware="true") - def test_01_UserDataPasswordReset(self): - self.debug("START USER DATA PASSWORD RESET ON VM") + def test_nuage_UserDataPasswordReset(self): + """Test user data and password reset functionality with Nuage VSP SDN plugin + """ + """ Validate the following: 1) user data @@ -171,12 +188,12 @@ def test_01_UserDataPasswordReset(self): 2. Create an Isolated network - Test Network (10.1.1.1/24). 3. Deploy VM1 in Test Network 4. Verify domain,zone subnet, vm. - 5. create public ip , Create Static Nat rule firewall rule and verify + 5. create public IP, Create Static Nat rule firewall rule and verify 6. SSH to VM should be successful 7. verify userdata 8. check cloud-set-guest-password exist. 9. if cloud-set-guest-password exist. - 9.1 change template password enabled to true + 9.1 change template password enabled to true 9.2 verify that template is password enbalded 9.3 SSH with new password should be successful 10. else cloud-set-guest-password does not exist. @@ -185,27 +202,30 @@ def test_01_UserDataPasswordReset(self): 10.3 create a new template with password enabled. Verify that template is password enabled. 10.4 create vm 2 with new template in Test Network 10.5 Verify vm. - 10.6 create public ip , Create Static Nat rule firewall rule and verify + 10.6 create public IP, Create Static Nat rule firewall rule and verify 10.7 SSH to VM 2 should be successful 11. Reset VM password (VM_1 if guest password file exist. else it is VM2) 12 Starting VM and SSH to VM to verify new password """ + self.debug("TEST USER DATA & PASSWORD RESET ON VM") + self.defaultTemplateVal = self.template.passwordenabled if self.template.passwordenabled: self.updateTemplate(False) self.debug("CREATE AN ISOLATED NETWORK") - self.network_1 = self.create_Network(self.test_data["network_offering_pr"]) + net_off = self.create_NetworkOffering(self.test_data["nuagevsp"]["isolated_network_offering"]) + self.network_1 = self.create_Network(net_off) self.cleanup.append(self.network_1) expUserData = "hello world vm1" userdata = base64.b64encode(expUserData) - self.test_data["virtual_machine_pr"]["userdata"] = userdata + self.test_data["virtual_machine_userdata"]["userdata"] = userdata self.debug("DEPLOY VM 1 IN TEST NETWORK") # Pass the network and name of the vm type from the testdata with the configuration for the vm - self.vm_1 = self.create_VM_in_Network(self.network_1, "virtual_machine_pr") + self.vm_1 = self.create_VM(self.network_1, vm_key="virtual_machine_userdata") - self.vm_1.password = self.test_data["virtual_machine_pr"]["password"] + self.vm_1.password = self.test_data["virtual_machine_userdata"]["password"] user_data_cmd = self.get_userdata_url(self.vm_1) # VSD verification @@ -214,11 +234,11 @@ def test_01_UserDataPasswordReset(self): self.verify_vsp_vm(self.vm_1) self.debug("CREATE PUBLIC IP, STATIC NAT RULE, FLOATING IP, FIREWALL AND VERIFY") - public_ip_1 = self.acquire_Public_IP(self.network_1) + public_ip_1 = self.acquire_PublicIPAddress(self.network_1) self.create_and_verify_fw(self.vm_1, public_ip_1, self.network_1) self.debug("SSH TO VM") - ssh = self.ssh_into_vm(self.vm_1, public_ip_1) + ssh = self.ssh_into_VM(self.vm_1, public_ip_1) self.debug("VERIFY USER DATA") self.debug("Get User Data with command: " + user_data_cmd) @@ -238,25 +258,23 @@ def test_01_UserDataPasswordReset(self): self.stop_vm(self.vm_1) self.create_template(self.vm_1) self.debug("DEPLOY VM 2 IN TEST NETWORK WITH NEW TEMPLATE") - self.vm_2 = self.create_VM_in_Network(self.network_1, "virtual_machine_pr") + self.vm_2 = self.create_VM(self.network_1, vm_key="virtual_machine_userdata") self.remove_vm2 = True self.debug("STARTING VM_2 ") - startCmd = startVirtualMachine.startVirtualMachineCmd() - startCmd.id = self.vm_2.id - vm_2a = self.apiclient.startVirtualMachine(startCmd) + vm_2a = self.vm_2.start(self.apiclient) self.vm_2.password = vm_2a.password.strip() self.vm_2.nic = vm_2a.nic - self.debug("VM - %s password %s !" % (self.vm_2.name, self.vm_2.password)) + self.debug("VM - %s password - %s !" % (self.vm_2.name, self.vm_2.password)) self.assertNotEqual(self.vm_2.password, - self.test_data["virtual_machine_pr"]["password"], + self.test_data["virtual_machine_userdata"]["password"], "Password enabled not working. Password same as virtual_machine password " ) self.verify_vsp_vm(vm_2a) self.debug("GET PUBLIC IP. CREATE AND VERIFIED FIREWALL RULES") - public_ip_2 = self.acquire_Public_IP(self.network_1) + public_ip_2 = self.acquire_PublicIPAddress(self.network_1) self.create_and_verify_fw(self.vm_2, public_ip_2, self.network_1) - ssh = self.ssh_into_vm(self.vm_2, public_ip_2) + self.ssh_into_VM(self.vm_2, public_ip_2) vm_test = self.vm_2 vm_test_public_ip = public_ip_2 @@ -267,10 +285,10 @@ def test_01_UserDataPasswordReset(self): vm_test = self.vm_1 vm_test_public_ip = public_ip_1 - self.debug("RESETTING VM PASSWORD for VM: %s" % vm_test.name) + self.debug("RESETTING VM PASSWORD for VM - %s" % vm_test.name) vm_test.password = vm_test.resetPassword(self.apiclient) - self.debug("Password reset to: %s" % vm_test.password) + self.debug("Password reset to - %s" % vm_test.password) self.debug("STARTING VM AND SSH TO VM TO VERIFY NEW PASSWORD") vm_test.start(self.apiclient) self.debug("VM - %s started!" % vm_test.name) - self.ssh_into_vm(vm_test, vm_test_public_ip) + self.ssh_into_VM(vm_test, vm_test_public_ip) diff --git a/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py b/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py new file mode 100644 index 0000000000..5a0d759fdd --- /dev/null +++ b/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py @@ -0,0 +1,2076 @@ +# 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. + +""" Component tests for VPC Internal Load Balancer functionality with Nuage VSP SDN plugin +""" +# Import Local Modules +from nuageTestCase import nuageTestCase +from marvin.lib.base import (Account, + ApplicationLoadBalancer, + Network, + Router) +from marvin.cloudstackAPI import (listInternalLoadBalancerVMs, + stopInternalLoadBalancerVM, + startInternalLoadBalancerVM) +# Import System Modules +from nose.plugins.attrib import attr +import copy +import time + + +class TestNuageInternalLb(nuageTestCase): + """Test VPC Internal LB functionality with Nuage VSP SDN plugin + """ + + @classmethod + def setUpClass(cls): + super(TestNuageInternalLb, cls).setUpClass() + return + + def setUp(self): + # Create an account + self.account = Account.create(self.api_client, + self.test_data["account"], + admin=True, + domainid=self.domain.id + ) + self.cleanup = [self.account] + return + + # create_Internal_LB_Rule - Creates Internal LB rule in the given VPC network + def create_Internal_LB_Rule(self, network, vm_array=None, services=None, source_ip=None): + self.debug("Creating Internal LB rule in VPC network with ID - %s" % network.id) + if not services: + services = self.test_data["internal_lbrule"] + int_lb_rule = ApplicationLoadBalancer.create(self.api_client, + services=services, + sourcenetworkid=network.id, + networkid=network.id, + sourceipaddress=source_ip + ) + self.debug("Created Internal LB rule") + # Assigning VMs to the created Internal Load Balancer rule + if vm_array: + self.debug("Assigning virtual machines - %s to the created Internal LB rule" % vm_array) + int_lb_rule.assign(self.api_client, vms=vm_array) + self.debug("Assigned VMs to the created Internal LB rule") + return int_lb_rule + + # validate_Internal_LB_Rule - Validates the given Internal LB rule, + # matches the given Internal LB rule name and state against the list of Internal LB rules fetched + def validate_Internal_LB_Rule(self, int_lb_rule, state=None, vm_array=None): + """Validates the Internal LB Rule""" + self.debug("Check if the Internal LB Rule is created successfully ?") + int_lb_rules = ApplicationLoadBalancer.list(self.api_client, + id=int_lb_rule.id + ) + self.assertEqual(isinstance(int_lb_rules, list), True, + "List Internal LB Rule should return a valid list" + ) + self.assertEqual(int_lb_rule.name, int_lb_rules[0].name, + "Name of the Internal LB Rule should match with the returned list data" + ) + if state: + self.assertEqual(int_lb_rules[0].loadbalancerrule[0].state, state, + "Internal LB Rule state should be '%s'" % state + ) + if vm_array: + instance_ids = [instance.id for instance in int_lb_rules[0].loadbalancerinstance] + for vm in vm_array: + self.assertEqual(vm.id in instance_ids, True, + "Internal LB instance list should have the VM with ID - %s" % vm.id + ) + self.debug("Internal LB Rule creation successfully validated for %s" % int_lb_rule.name) + + # list_InternalLbVms - Lists deployed Internal LB VM instances + def list_InternalLbVms(self, network_id=None, source_ip=None): + listInternalLoadBalancerVMsCmd = listInternalLoadBalancerVMs.listInternalLoadBalancerVMsCmd() + listInternalLoadBalancerVMsCmd.account = self.account.name + listInternalLoadBalancerVMsCmd.domainid = self.account.domainid + if network_id: + listInternalLoadBalancerVMsCmd.networkid = network_id + internal_lb_vms = self.api_client.listInternalLoadBalancerVMs(listInternalLoadBalancerVMsCmd) + if source_ip: + return [internal_lb_vm for internal_lb_vm in internal_lb_vms + if str(internal_lb_vm.guestipaddress) == source_ip] + else: + return internal_lb_vms + + # get_InternalLbVm - Returns Internal LB VM instance for the given VPC network and source ip + def get_InternalLbVm(self, network, source_ip): + self.debug("Finding the InternalLbVm for network with ID - %s and source IP address - %s" % + (network.id, source_ip)) + internal_lb_vms = self.list_InternalLbVms(network.id, source_ip) + self.assertEqual(isinstance(internal_lb_vms, list), True, + "List InternalLbVms should return a valid list" + ) + return internal_lb_vms[0] + + # stop_InternalLbVm - Stops the given Internal LB VM instance + def stop_InternalLbVm(self, int_lb_vm, force=None): + self.debug("Stopping InternalLbVm with ID - %s" % int_lb_vm.id) + cmd = stopInternalLoadBalancerVM.stopInternalLoadBalancerVMCmd() + cmd.id = int_lb_vm.id + if force: + cmd.forced = force + self.api_client.stopInternalLoadBalancerVM(cmd) + + # start_InternalLbVm - Starts the given Internal LB VM instance + def start_InternalLbVm(self, int_lb_vm): + self.debug("Starting InternalLbVm with ID - %s" % int_lb_vm.id) + cmd = startInternalLoadBalancerVM.startInternalLoadBalancerVMCmd() + cmd.id = int_lb_vm.id + self.api_client.startInternalLoadBalancerVM(cmd) + + # check_InternalLbVm_state - Checks if the Internal LB VM instance of the given VPC network and source ip is in the + # expected state form the list of fetched Internal LB VM instances + def check_InternalLbVm_state(self, network, source_ip, state=None): + self.debug("Check if the InternalLbVm is in state - %s" % state) + internal_lb_vms = self.list_InternalLbVms(network.id, source_ip) + self.assertEqual(isinstance(internal_lb_vms, list), True, + "List InternalLbVm should return a valid list" + ) + if state: + self.assertEqual(internal_lb_vms[0].state, state, + "InternalLbVm is not in the expected state" + ) + self.debug("InternalLbVm instance - %s is in the expected state - %s" % (internal_lb_vms[0].name, state)) + + # wget_from_vm_cmd - From within the given VM (ssh client), + # fetches index.html file of web server running with the given public IP + def wget_from_vm_cmd(self, ssh_client, ip_address, port): + cmd = "wget --no-cache -t 1 http://" + ip_address + ":" + str(port) + "/" + response = self.execute_cmd(ssh_client, cmd) + if "200 OK" not in response: + self.fail("Failed to wget from a VM with http server IP address - %s" % ip_address) + # Reading the wget file + cmd = "cat index.html" + wget_file = self.execute_cmd(ssh_client, cmd) + # Removing the wget file + cmd = "rm -r index.html" + self.execute_cmd(ssh_client, cmd) + return wget_file + + # verify_lb_wget_file - Verifies that the given wget file (index.html) belongs to the given Internal LB rule + # assigned VMs (vm array) + def verify_lb_wget_file(self, wget_file, vm_array): + wget_server_ip = None + for vm in vm_array: + for nic in vm.nic: + if str(nic.ipaddress) in str(wget_file): + wget_server_ip = str(nic.ipaddress) + if wget_server_ip: + self.debug("Verified wget file from an Internal Load Balanced VM with http server IP address - %s" + % wget_server_ip) + else: + self.fail("Did not wget file from the Internal Load Balanced VMs - %s" % vm_array) + return wget_server_ip + + # validate_internallb_algorithm_traffic - Validates Internal LB algorithms by performing multiple wget traffic tests + # against the given Internal LB VM instance (source port) + def validate_internallb_algorithm_traffic(self, ssh_client, source_ip, port, vm_array, algorithm): + # Internal LB (wget) traffic tests + iterations = 2 * len(vm_array) + wget_files = [] + for i in range(iterations): + wget_files.append(self.wget_from_vm_cmd(ssh_client, source_ip, port)) + # Verifying Internal LB (wget) traffic tests + wget_servers_ip_list = [] + for i in range(iterations): + wget_servers_ip_list.append(self.verify_lb_wget_file(wget_files[i], vm_array)) + # Validating Internal LB algorithm + if algorithm == "roundrobin" or algorithm == "leastconn": + for i in range(iterations): + if wget_servers_ip_list.count(wget_servers_ip_list[i]) is not 2: + self.fail("Round Robin Internal LB algorithm validation failed - %s" % wget_servers_ip_list) + self.debug("Successfully validated Round Robin/Least connections Internal LB algorithm - %s" % + wget_servers_ip_list) + if algorithm == "source": + for i in range(iterations): + if wget_servers_ip_list.count(wget_servers_ip_list[i]) is not iterations: + self.fail("Source Internal LB algorithm validation failed - %s" % wget_servers_ip_list) + self.debug("Successfully validated Source Internal LB algorithm - %s" % wget_servers_ip_list) + + @attr(tags=["advanced", "nuagevsp"], required_hardware="false") + def test_01_nuage_internallb_vpc_Offering(self): + """Test Nuage VSP VPC Offering with different combinations of LB service providers + """ + + # 1. Verify that the network service providers supported by Nuage VSP for VPC Internal LB functionality are all + # successfully created and enabled. + # 2. Create Nuage VSP VPC offering with LB service provider as "InternalLbVm", check if it is successfully + # created and enabled. Verify that the VPC creation succeeds with this VPC offering. + # 3. Create Nuage VSP VPC offering with LB service provider as "VpcVirtualRouter", check if it is successfully + # created and enabled. Verify that the VPC creation fails with this VPC offering as Nuage VSP does not + # support provider "VpcVirtualRouter" for service LB. + # 4. Create Nuage VSP VPC offering with LB service provider as "Netscaler", check if it is successfully + # created and enabled. Verify that the VPC creation fails with this VPC offering as Nuage VSP does not + # support provider "Netscaler" for service LB. + # 5. Delete the created VPC offerings (cleanup). + + self.debug("Validating network service providers supported by Nuage VSP for VPC Internal LB functionality") + providers = ["NuageVsp", "VpcVirtualRouter", "InternalLbVm"] + for provider in providers: + self.validate_NetworkServiceProvider(provider, state="Enabled") + + # Creating VPC offerings + self.debug("Creating Nuage VSP VPC offering with LB service provider as InternalLbVm...") + vpc_off_1 = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"]) + self.validate_VpcOffering(vpc_off_1, state="Enabled") + + self.debug("Creating Nuage VSP VPC offering with LB service provider as VpcVirtualRouter...") + vpc_offering_lb = copy.deepcopy(self.test_data["nuagevsp"]["vpc_offering_lb"]) + vpc_offering_lb["serviceProviderList"]["Lb"] = "VpcVirtualRouter" + vpc_off_2 = self.create_VpcOffering(vpc_offering_lb) + self.validate_VpcOffering(vpc_off_2, state="Enabled") + + self.debug("Creating Nuage VSP VPC offering with LB service provider as Netscaler...") + vpc_offering_lb["serviceProviderList"]["Lb"] = "Netscaler" + vpc_off_3 = self.create_VpcOffering(vpc_offering_lb) + self.validate_VpcOffering(vpc_off_3, state="Enabled") + + self.debug("Creating Nuage VSP VPC offering without LB service...") + vpc_off_4 = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering"]) + self.validate_VpcOffering(vpc_off_4, state="Enabled") + + # Creating VPCs + self.debug("Creating a VPC with LB service provider as InternalLbVm...") + vpc_1 = self.create_Vpc(vpc_off_1, cidr='10.1.0.0/16') + self.validate_Vpc(vpc_1, state="Enabled") + + self.debug("Creating a VPC with LB service provider as VpcVirtualRouter...") + with self.assertRaises(Exception): + self.create_Vpc(vpc_off_2, cidr='10.1.0.0/16') + self.debug("Nuage VSP does not support provider VpcVirtualRouter for service LB for VPCs") + + self.debug("Creating a VPC with LB service provider as Netscaler...") + with self.assertRaises(Exception): + self.create_Vpc(vpc_off_3, cidr='10.1.0.0/16') + self.debug("Nuage VSP does not support provider Netscaler for service LB for VPCs") + + self.debug("Creating a VPC without LB service...") + vpc_2 = self.create_Vpc(vpc_off_4, cidr='10.1.0.0/16') + self.validate_Vpc(vpc_2, state="Enabled") + + @attr(tags=["advanced", "nuagevsp"], required_hardware="false") + def test_02_nuage_internallb_vpc_network_offering(self): + """Test Nuage VSP VPC Network Offering with and without Internal LB service + """ + + # 1. Create Nuage Vsp VPC Network offering with LB Service Provider as "InternalLbVm" and LB Service Capability + # "lbSchemes" as "internal", check if it is successfully created and enabled. Verify that the VPC network + # creation succeeds with this Network offering. + # 2. Recreate above Network offering with ispersistent False, check if it is successfully created and enabled. + # Verify that the VPC network creation fails with this Network offering as Nuage VSP does not support non + # persistent VPC networks. + # 3. Recreate above Network offering with conserve mode On, check if the network offering creation failed + # as only networks with conserve mode Off can belong to VPC. + # 4. Create Nuage Vsp VPC Network offering with LB Service Provider as "InternalLbVm" and LB Service Capability + # "lbSchemes" as "public", check if the network offering creation failed as "public" lbScheme is not + # supported for LB Service Provider "InternalLbVm". + # 5. Create Nuage Vsp VPC Network offering without Internal LB Service, check if it is successfully created and + # enabled. Verify that the VPC network creation succeeds with this Network offering. + # 6. Recreate above Network offering with ispersistent False, check if it is successfully created and enabled. + # Verify that the VPC network creation fails with this Network offering as Nuage VSP does not support non + # persistent VPC networks. + # 7. Recreate the above Network offering with conserve mode On, check if the network offering creation failed + # as only networks with conserve mode Off can belong to VPC. + # 8. Delete the created Network offerings (cleanup). + + # Creating VPC offering + self.debug("Creating Nuage VSP VPC offering with Internal LB service...") + vpc_off = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"]) + self.validate_VpcOffering(vpc_off, state="Enabled") + + # Creating VPC + self.debug("Creating a VPC with Internal LB service...") + vpc = self.create_Vpc(vpc_off, cidr='10.1.0.0/16') + self.validate_Vpc(vpc, state="Enabled") + + # Creating network offerings + self.debug("Creating Nuage VSP VPC Network offering with LB Service Provider as InternalLbVm and LB Service " + "Capability lbSchemes as internal...") + net_off_1 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"]) + self.validate_NetworkOffering(net_off_1, state="Enabled") + + self.debug("Recreating above Network offering with ispersistent False...") + vpc_net_off_lb_non_persistent = copy.deepcopy(self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"]) + vpc_net_off_lb_non_persistent["ispersistent"] = "False" + net_off_2 = self.create_NetworkOffering(vpc_net_off_lb_non_persistent) + self.validate_NetworkOffering(net_off_2, state="Enabled") + + self.debug("Recreating above Network offering with conserve mode On...") + with self.assertRaises(Exception): + self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"], + conserve_mode=True) + self.debug("Network offering creation failed as only networks with conserve mode Off can belong to VPC") + + self.debug("Creating Nuage VSP VPC Network offering with LB Service Provider as InternalLbVm and LB Service " + "Capability lbSchemes as public...") + network_offering_internal_lb = copy.deepcopy(self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"]) + network_offering_internal_lb["serviceCapabilityList"]["Lb"]["lbSchemes"] = "public" + with self.assertRaises(Exception): + self.create_NetworkOffering(network_offering_internal_lb) + self.debug("Network offering creation failed as public lbScheme is not supported for LB Service Provider " + "InternalLbVm") + + self.debug("Creating Nuage Vsp VPC Network offering without Internal LB service...") + net_off_3 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"]) + self.validate_NetworkOffering(net_off_3, state="Enabled") + + self.debug("Recreating above Network offering with ispersistent False...") + vpc_net_off_non_persistent = copy.deepcopy(self.test_data["nuagevsp"]["vpc_network_offering"]) + vpc_net_off_non_persistent["ispersistent"] = "False" + net_off_4 = self.create_NetworkOffering(vpc_net_off_non_persistent) + self.validate_NetworkOffering(net_off_4, state="Enabled") + + self.debug("Recreating above Network offering with conserve mode On...") + with self.assertRaises(Exception): + self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"], conserve_mode=True) + self.debug("Network offering creation failed as only networks with conserve mode Off can belong to VPC") + + # Creating VPC networks in the VPC + self.debug("Creating a persistent VPC network with Internal LB service...") + internal_tier = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc) + self.validate_Network(internal_tier, state="Implemented") + vr = self.get_Router(internal_tier) + self.check_Router_state(vr, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier, vpc) + self.verify_vsp_router(vr) + + self.debug("Creating a non persistent VPC network with Internal LB service...") + with self.assertRaises(Exception): + self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc) + self.debug("Nuage VSP does not support non persistent VPC networks") + + self.debug("Creating a persistent VPC network without Internal LB service...") + public_tier = self.create_Network(net_off_3, gateway='10.1.3.1', vpc=vpc) + self.validate_Network(public_tier, state="Implemented") + vr = self.get_Router(public_tier) + self.check_Router_state(vr, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, public_tier, vpc) + self.verify_vsp_router(vr) + + self.debug("Creating a non persistent VPC network without Internal LB service...") + with self.assertRaises(Exception): + self.create_Network(net_off_4, gateway='10.1.4.1', vpc=vpc) + self.debug("Nuage VSP does not support non persistent VPC networks") + + @attr(tags=["advanced", "nuagevsp"], required_hardware="false") + def test_03_nuage_internallb_vpc_networks(self): + """Test Nuage VSP VPC Networks with and without Internal LB service + """ + + # 1. Create Nuage VSP VPC offering with Internal LB service, check if it is successfully created and enabled. + # 2. Create Nuage VSP VPC offering without Internal LB service, check if it is successfully created and enabled. + # 3. Create a VPC "vpc_1" with Internal LB service, check if it is successfully created and enabled. + # 4. Create a VPC "vpc_2" without Internal LB service, check if it is successfully created and enabled. + # 5. Create Nuage VSP VPC Network offering with Internal LB service, check if it is successfully created and + # enabled. + # 6. Create Nuage VSP VPC Network offering without Internal LB service, check if it is successfully created and + # enabled. + # 7. Create a VPC network in vpc_1 with Internal LB service and spawn a VM, check if the tier is added to the + # VPC VR, and the VM is deployed successfully in the tier. + # 8. Create one more VPC network in vpc_1 with Internal LB service and spawn a VM, check if the tier is added + # to the VPC VR, and the VM is deployed successfully in the tier. + # 9. Create a VPC network in vpc_2 with Internal LB service, check if the tier creation failed. + # 10. Create a VPC network in vpc_1 without Internal LB service and spawn a VM, check if the tier is added to + # the VPC VR, and the VM is deployed successfully in the tier. + # 11. Create a VPC network in vpc_2 without Internal LB service and spawn a VM, check if the tier is added to + # the VPC VR, and the VM is deployed successfully in the tier. + # 12. Upgrade the VPC network with Internal LB service to one with no Internal LB service and vice-versa, check + # if the VPC Network offering upgrade passed in both directions. + # 13. Delete the VPC network with Internal LB service, check if the tier is successfully deleted. + # 14. Recreate the VPC network with Internal LB service, check if the tier is successfully re-created. + # 15. Delete all the created objects (cleanup). + + # Creating VPC offerings + self.debug("Creating Nuage VSP VPC offering with Internal LB service...") + vpc_off_1 = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"]) + self.validate_VpcOffering(vpc_off_1, state="Enabled") + + self.debug("Creating Nuage VSP VPC offering without Internal LB service...") + vpc_off_2 = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering"]) + self.validate_VpcOffering(vpc_off_2, state="Enabled") + + # Creating VPCs + self.debug("Creating a VPC with Internal LB service...") + vpc_1 = self.create_Vpc(vpc_off_1, cidr='10.1.0.0/16') + self.validate_Vpc(vpc_1, state="Enabled") + + self.debug("Creating a VPC without Internal LB service...") + vpc_2 = self.create_Vpc(vpc_off_2, cidr='10.1.0.0/16') + self.validate_Vpc(vpc_2, state="Enabled") + + # Creating network offerings + self.debug("Creating Nuage VSP VPC Network offering with Internal LB service...") + net_off_1 = self.create_NetworkOffering( + self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"]) + self.validate_NetworkOffering(net_off_1, state="Enabled") + + self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...") + net_off_2 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"]) + self.validate_NetworkOffering(net_off_2, state="Enabled") + + # Creating VPC networks in VPCs, and deploying VMs + self.debug("Creating a VPC network in vpc_1 with Internal LB service...") + internal_tier_1 = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc_1) + self.validate_Network(internal_tier_1, state="Implemented") + vr_1 = self.get_Router(internal_tier_1) + self.check_Router_state(vr_1, state="Running") + + self.debug("Deploying a VM in network - %s" % internal_tier_1.name) + internal_vm_1 = self.create_VM(internal_tier_1) + self.check_VM_state(internal_vm_1, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier_1, vpc_1) + self.verify_vsp_router(vr_1) + self.verify_vsp_vm(internal_vm_1) + + self.debug("Creating one more VPC network in vpc_1 with Internal LB service...") + internal_tier_2 = self.create_Network(net_off_1, gateway='10.1.2.1', vpc=vpc_1) + self.validate_Network(internal_tier_2, state="Implemented") + vr_1 = self.get_Router(internal_tier_2) + self.check_Router_state(vr_1, state="Running") + + self.debug("Deploying a VM in network - %s" % internal_tier_2.name) + internal_vm_2 = self.create_VM(internal_tier_2) + self.check_VM_state(internal_vm_2, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier_2, vpc_1) + self.verify_vsp_router(vr_1) + self.verify_vsp_vm(internal_vm_2) + + self.debug("Creating a VPC network in vpc_2 with Internal LB service...") + with self.assertRaises(Exception): + self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc_2) + self.debug("VPC Network creation failed as vpc_2 does not support Internal Lb service") + + self.debug("Creating a VPC network in vpc_1 without Internal LB service...") + public_tier_1 = self.create_Network(net_off_2, gateway='10.1.3.1', vpc=vpc_1) + self.validate_Network(public_tier_1, state="Implemented") + vr_1 = self.get_Router(public_tier_1) + self.check_Router_state(vr_1, state="Running") + + self.debug("Deploying a VM in network - %s" % public_tier_1.name) + public_vm_1 = self.create_VM(public_tier_1) + self.check_VM_state(public_vm_1, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, public_tier_1, vpc_1) + self.verify_vsp_router(vr_1) + self.verify_vsp_vm(public_vm_1) + + self.debug("Creating a VPC network in vpc_2 without Internal LB service...") + public_tier_2 = self.create_Network(net_off_2, gateway='10.1.1.1', vpc=vpc_2) + self.validate_Network(public_tier_2, state="Implemented") + vr_2 = self.get_Router(public_tier_2) + self.check_Router_state(vr_2, state="Running") + + self.debug("Deploying a VM in network - %s" % public_tier_2.name) + public_vm_2 = self.create_VM(public_tier_2) + self.check_VM_state(public_vm_2, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, public_tier_2, vpc_2) + self.verify_vsp_router(vr_2) + self.verify_vsp_vm(public_vm_2) + + # Upgrading a VPC network + self.debug("Upgrading a VPC network with Internal LB Service to one without Internal LB Service...") + self.upgrade_Network(net_off_2, internal_tier_2) + self.validate_Network(internal_tier_2, state="Implemented") + vr_1 = self.get_Router(internal_tier_2) + self.check_Router_state(vr_1, state="Running") + self.check_VM_state(internal_vm_2, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier_2, vpc_1) + self.verify_vsp_router(vr_1) + self.verify_vsp_vm(internal_vm_2) + + self.debug("Upgrading a VPC network without Internal LB Service to one with Internal LB Service...") + self.upgrade_Network(net_off_1, internal_tier_2) + self.validate_Network(internal_tier_2, state="Implemented") + vr_1 = self.get_Router(internal_tier_2) + self.check_Router_state(vr_1, state="Running") + self.check_VM_state(internal_vm_2, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier_2, vpc_1) + self.verify_vsp_router(vr_1) + self.verify_vsp_vm(internal_vm_2) + + # Deleting and re-creating a VPC network + self.debug("Deleting a VPC network with Internal LB Service...") + self.delete_VM(internal_vm_2) + self.delete_Network(internal_tier_2) + with self.assertRaises(Exception): + self.validate_Network(internal_tier_2) + self.debug("VPC network successfully deleted in CloudStack") + + # VSD verification + with self.assertRaises(Exception): + self.verify_vsp_network(self.domain.id, internal_tier_2, vpc_1) + self.debug("VPC network successfully deleted in VSD") + + self.debug("Recreating a VPC network with Internal LB Service...") + internal_tier_2 = self.create_Network(net_off_1, gateway='10.1.2.1', vpc=vpc_1) + internal_vm_2 = self.create_VM(internal_tier_2) + self.validate_Network(internal_tier_2, state="Implemented") + vr_1 = self.get_Router(internal_tier_2) + self.check_Router_state(vr_1, state="Running") + self.check_VM_state(internal_vm_2, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier_2, vpc_1) + self.verify_vsp_router(vr_1) + self.verify_vsp_vm(internal_vm_2) + + @attr(tags=["advanced", "nuagevsp"], required_hardware="false") + def test_04_nuage_internallb_rules(self): + """Test Nuage VSP VPC Internal LB functionality with different combinations of Internal LB rules + """ + + # 1. Create an Internal LB Rule with source IP Address specified, check if the Internal LB Rule is successfully + # created. + # 2. Create an Internal LB Rule without source IP Address specified, check if the Internal LB Rule is + # successfully created. + # 3. Create an Internal LB Rule when the specified source IP Address is outside the VPC network (tier) CIDR + # range, check if the Internal LB Rule creation failed as the requested source IP is not in the network's + # CIDR subnet. + # 4. Create an Internal LB Rule when the specified source IP Address is outside the VPC super CIDR range, + # check if the Internal LB Rule creation failed as the requested source IP is not in the network's CIDR + # subnet. + # 5. Create an Internal LB Rule in the tier with LB service provider as VpcInlineLbVm, check if the Internal LB + # Rule creation failed as Scheme Internal is not supported by this network offering. + # 6. Create multiple Internal LB Rules using different Load Balancing source IP Addresses, check if the Internal + # LB Rules are successfully created. + # 7. Create multiple Internal LB Rules with different ports but using the same Load Balancing source IP Address, + # check if the Internal LB Rules are successfully created. + # 8. Create multiple Internal LB Rules with same ports and using the same Load Balancing source IP Address, + # check if the second Internal LB Rule creation failed as it conflicts with the first Internal LB rule. + # 9. Attach a VM to the above created Internal LB Rules, check if the VM is successfully attached to the + # Internal LB Rules. + # 10. Verify the InternalLbVm deployment after successfully creating the first Internal LB Rule and attaching a + # VM to it. + # 11. Verify the failure of attaching a VM from a different tier to an Internal LB Rule created on a tier. + # 12. Delete the above created Internal LB Rules, check if the Internal LB Rules are successfully deleted. + + # Creating a VPC offering + self.debug("Creating Nuage VSP VPC offering with Internal LB service...") + vpc_off = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"]) + self.validate_VpcOffering(vpc_off, state="Enabled") + + # Creating a VPC + self.debug("Creating a VPC with Internal LB service...") + vpc = self.create_Vpc(vpc_off, cidr='10.1.0.0/16') + self.validate_Vpc(vpc, state="Enabled") + + # Creating network offerings + self.debug("Creating Nuage VSP VPC Network offering with Internal LB service...") + net_off_1 = self.create_NetworkOffering( + self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"]) + self.validate_NetworkOffering(net_off_1, state="Enabled") + + self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...") + net_off_2 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"]) + self.validate_NetworkOffering(net_off_2, state="Enabled") + + # Creating VPC networks in the VPC, and deploying VMs + self.debug("Creating a VPC network with Internal LB service...") + internal_tier = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc) + self.validate_Network(internal_tier, state="Implemented") + vr = self.get_Router(internal_tier) + self.check_Router_state(vr, state="Running") + + self.debug("Deploying a VM in network - %s" % internal_tier.name) + internal_vm = self.create_VM(internal_tier) + self.check_VM_state(internal_vm, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(internal_vm) + + self.debug("Creating a VPC network without Internal LB service...") + public_tier = self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc) + self.validate_Network(public_tier, state="Implemented") + vr = self.get_Router(public_tier) + self.check_Router_state(vr, state="Running") + + self.debug("Deploying a VM in network - %s" % public_tier.name) + public_vm = self.create_VM(public_tier) + self.check_VM_state(public_vm, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, public_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(public_vm) + + # Creating Internal LB Rules + self.debug("Creating an Internal LB Rule without source IP Address specified...") + int_lb_rule = self.create_Internal_LB_Rule(internal_tier) + self.validate_Internal_LB_Rule(int_lb_rule, state="Add") + + # Validating InternalLbVm deployment + with self.assertRaises(Exception): + self.check_InternalLbVm_state(internal_tier, int_lb_rule.sourceipaddress) + self.debug("InternalLbVm is not deployed in the network as there are no VMs assigned to this Internal LB Rule") + + self.debug('Deleting the Internal LB Rule - %s' % int_lb_rule.name) + int_lb_rule.delete(self.api_client) + with self.assertRaises(Exception): + self.validate_Internal_LB_Rule(int_lb_rule) + self.debug("Internal LB Rule successfully deleted in CloudStack") + + free_source_ip = int_lb_rule.sourceipaddress + + self.debug("Creating an Internal LB Rule with source IP Address specified...") + int_lb_rule = self.create_Internal_LB_Rule(internal_tier, source_ip=free_source_ip) + self.validate_Internal_LB_Rule(int_lb_rule, state="Add") + + # Validating InternalLbVm deployment + with self.assertRaises(Exception): + self.check_InternalLbVm_state(internal_tier, int_lb_rule.sourceipaddress) + self.debug("InternalLbVm is not deployed in the network as there are no VMs assigned to this Internal LB Rule") + + self.debug('Deleting the Internal LB Rule - %s' % int_lb_rule.name) + int_lb_rule.delete(self.api_client) + with self.assertRaises(Exception): + self.validate_Internal_LB_Rule(int_lb_rule) + self.debug("Internal LB Rule successfully deleted in CloudStack") + + self.debug("Creating an Internal LB Rule when the specified source IP Address is outside the VPC network CIDR " + "range...") + with self.assertRaises(Exception): + self.create_Internal_LB_Rule(internal_tier, source_ip="10.1.1.256") + self.debug("Internal LB Rule creation failed as the requested IP is not in the network's CIDR subnet") + + self.debug("Creating an Internal LB Rule when the specified source IP Address is outside the VPC super CIDR " + "range...") + with self.assertRaises(Exception): + self.create_Internal_LB_Rule(internal_tier, source_ip="10.2.1.256") + self.debug("Internal LB Rule creation failed as the requested IP is not in the network's CIDR subnet") + + self.debug("Creating an Internal LB Rule in a VPC network without Internal Lb service...") + with self.assertRaises(Exception): + self.create_Internal_LB_Rule(public_tier) + self.debug("Internal LB Rule creation failed as Scheme Internal is not supported by this network offering") + + self.debug("Creating multiple Internal LB Rules using different Load Balancing source IP Addresses...") + int_lb_rule_1 = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm]) + self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", vm_array=[internal_vm]) + int_lb_rule_2 = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm]) + self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", vm_array=[internal_vm]) + + # Validating InternalLbVms deployment and state + int_lb_vm_1 = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + int_lb_vm_2 = self.get_InternalLbVm(internal_tier, int_lb_rule_2.sourceipaddress) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_2.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm_1) + self.verify_vsp_LB_device(int_lb_vm_2) + + self.debug('Removing VMs from the Internal LB Rules - %s, %s' % (int_lb_rule_1.name, int_lb_rule_2.name)) + int_lb_rule_1.remove(self.api_client, vms=[internal_vm]) + with self.assertRaises(Exception): + self.validate_Internal_LB_Rule(int_lb_rule_1, vm_array=[internal_vm]) + self.debug("VMs successfully removed from the Internal LB Rule in CloudStack") + int_lb_rule_2.remove(self.api_client, vms=[internal_vm]) + with self.assertRaises(Exception): + self.validate_Internal_LB_Rule(int_lb_rule_2, vm_array=[internal_vm]) + self.debug("VMs successfully removed from the Internal LB Rule in CloudStack") + + # Validating InternalLbVms state + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + self.check_InternalLbVm_state(internal_tier, int_lb_rule_2.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm_1) + self.verify_vsp_LB_device(int_lb_vm_2) + + self.debug('Deleting the Internal LB Rules - %s, %s' % (int_lb_rule_1.name, int_lb_rule_2.name)) + int_lb_rule_1.delete(self.api_client) + with self.assertRaises(Exception): + self.validate_Internal_LB_Rule(int_lb_rule_1) + self.debug("Internal LB Rule successfully deleted in CloudStack") + int_lb_rule_2.delete(self.api_client) + with self.assertRaises(Exception): + self.validate_Internal_LB_Rule(int_lb_rule_2) + self.debug("Internal LB Rule successfully deleted in CloudStack") + + # Validating InternalLbVms un-deployment + with self.assertRaises(Exception): + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress) + self.debug("InternalLbVm successfully destroyed in CloudStack") + with self.assertRaises(Exception): + self.check_InternalLbVm_state(internal_tier, int_lb_rule_2.sourceipaddress) + self.debug("InternalLbVm successfully destroyed in CloudStack") + + # VSD Verification + with self.assertRaises(Exception): + self.verify_vsp_LB_device(int_lb_vm_1) + self.debug("InternalLbVm successfully destroyed in VSD") + with self.assertRaises(Exception): + self.verify_vsp_LB_device(int_lb_vm_2) + self.debug("InternalLbVm successfully destroyed in VSD") + + self.debug("Creating multiple Internal LB Rules with different ports but using the same Load Balancing source " + "IP Address...") + int_lb_rule_1 = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm]) + self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", vm_array=[internal_vm]) + int_lb_rule_2 = self.create_Internal_LB_Rule(internal_tier, + vm_array=[internal_vm], + services=self.test_data["internal_lbrule_http"], + source_ip=int_lb_rule_1.sourceipaddress + ) + self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", vm_array=[internal_vm]) + + # Validating InternalLbVm deployment and state + int_lb_vm = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + self.debug('Removing VMs from the Internal LB Rules - %s, %s' % (int_lb_rule_1.name, int_lb_rule_2.name)) + int_lb_rule_1.remove(self.api_client, vms=[internal_vm]) + with self.assertRaises(Exception): + self.validate_Internal_LB_Rule(int_lb_rule_1, vm_array=[internal_vm]) + self.debug("VMs successfully removed from the Internal LB Rule in CloudStack") + int_lb_rule_2.remove(self.api_client, vms=[internal_vm]) + with self.assertRaises(Exception): + self.validate_Internal_LB_Rule(int_lb_rule_2, vm_array=[internal_vm]) + self.debug("VMs successfully removed from the Internal LB Rule in CloudStack") + + # Validating InternalLbVm state + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + self.debug('Deleting the Internal LB Rules - %s, %s' % (int_lb_rule_1.name, int_lb_rule_2.name)) + int_lb_rule_1.delete(self.api_client) + with self.assertRaises(Exception): + self.validate_Internal_LB_Rule(int_lb_rule_1) + self.debug("Internal LB Rule successfully deleted in CloudStack") + int_lb_rule_2.delete(self.api_client) + with self.assertRaises(Exception): + self.validate_Internal_LB_Rule(int_lb_rule_2) + self.debug("Internal LB Rule successfully deleted in CloudStack") + + # Validating InternalLbVm un-deployment + with self.assertRaises(Exception): + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress) + self.debug("InternalLbVm successfully destroyed in CloudStack") + + # VSD Verification + with self.assertRaises(Exception): + self.verify_vsp_LB_device(int_lb_vm) + self.debug("InternalLbVm successfully destroyed in VSD") + + self.debug("Creating multiple Internal LB Rules with same ports and using the same Load Balacing source IP " + "Address...") + int_lb_rule = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm]) + self.validate_Internal_LB_Rule(int_lb_rule, state="Active", vm_array=[internal_vm]) + with self.assertRaises(Exception): + self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm], source_ip=int_lb_rule.sourceipaddress) + self.debug("Internal LB Rule creation failed as it conflicts with the existing rule") + + # Validating InternalLbVm deployment and state + int_lb_vm = self.get_InternalLbVm(internal_tier, int_lb_rule.sourceipaddress) + self.check_InternalLbVm_state(internal_tier, int_lb_rule.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + self.debug('Removing VMs from the Internal LB Rule - %s' % int_lb_rule.name) + int_lb_rule.remove(self.api_client, vms=[internal_vm]) + with self.assertRaises(Exception): + self.validate_Internal_LB_Rule(int_lb_rule, vm_array=[internal_vm]) + self.debug("VMs successfully removed from the Internal LB Rule in CloudStack") + + # Validating InternalLbVm state + self.check_InternalLbVm_state(internal_tier, int_lb_rule.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + self.debug('Deleting the Internal LB Rule - %s' % int_lb_rule.name) + int_lb_rule.delete(self.api_client) + with self.assertRaises(Exception): + self.validate_Internal_LB_Rule(int_lb_rule) + self.debug("Internal LB Rule successfully deleted in CloudStack") + + # Validating InternalLbVm un-deployment + with self.assertRaises(Exception): + self.check_InternalLbVm_state(internal_tier, int_lb_rule.sourceipaddress) + self.debug("InternalLbVm successfully destroyed in CloudStack") + + # VSD Verification + with self.assertRaises(Exception): + self.verify_vsp_LB_device(int_lb_vm) + self.debug("InternalLbVm successfully destroyed in VSD") + + self.debug("Attaching a VM from a different tier to an Internal LB Rule created on a tier...") + with self.assertRaises(Exception): + self.create_Internal_LB_Rule(internal_tier, vm_array=[public_vm]) + self.debug("Internal LB Rule creation failed as the VM belongs to a different network") + + @attr(tags=["advanced", "nuagevsp"], required_hardware="true") + def test_05_nuage_internallb_traffic(self): + """Test Nuage VSP VPC Internal LB functionality by performing (wget) traffic tests within a VPC + """ + + # 1. Create an Internal LB Rule "internal_lbrule" with source IP Address specified on the Internal tier, check + # if the Internal LB Rule is successfully created. + # 2. Create an Internal LB Rule "internal_lbrule_http" with source IP Address (same as above) specified on the + # Internal tier, check if the Internal LB Rule is successfully created. + # 3. Attach a VM to the above created Internal LB Rules, check if the InternalLbVm is successfully deployed in + # the Internal tier. + # 4. Deploy two more VMs in the Internal tier, check if the VMs are successfully deployed. + # 5. Attach the newly deployed VMs to the above created Internal LB Rules, verify the validity of the above + # created Internal LB Rules over three Load Balanced VMs in the Internal tier. + # 6. Create the corresponding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible, + # check if the Network ACL rules are successfully added to the internal tier. + # 7. Validate the Internal LB functionality by performing (wget) traffic tests from a VM in the Public tier to + # the Internal load balanced guest VMs in the Internal tier, using Static NAT functionality to access (ssh) + # the VM on the Public tier. + # 8. Verify that the InternalLbVm gets destroyed when the last Internal LB rule is removed from the Internal + # tier. + # 9. Repeat the above steps for one more Internal tier as well, validate the Internal LB functionality. + + # Creating a VPC offering + self.debug("Creating Nuage VSP VPC offering with Internal LB service...") + vpc_off = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"]) + self.validate_VpcOffering(vpc_off, state="Enabled") + + # Creating a VPC + self.debug("Creating a VPC with Internal LB service...") + vpc = self.create_Vpc(vpc_off, cidr='10.1.0.0/16') + self.validate_Vpc(vpc, state="Enabled") + + # Creating network offerings + self.debug("Creating Nuage VSP VPC Network offering with Internal LB service...") + net_off_1 = self.create_NetworkOffering( + self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"]) + self.validate_NetworkOffering(net_off_1, state="Enabled") + + self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...") + net_off_2 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"]) + self.validate_NetworkOffering(net_off_2, state="Enabled") + + # Creating VPC networks in the VPC, and deploying VMs + self.debug("Creating a VPC network with Internal LB service...") + internal_tier_1 = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc) + self.validate_Network(internal_tier_1, state="Implemented") + vr = self.get_Router(internal_tier_1) + self.check_Router_state(vr, state="Running") + + self.debug("Deploying a VM in network - %s" % internal_tier_1.name) + internal_vm_1 = self.create_VM(internal_tier_1) + self.check_VM_state(internal_vm_1, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier_1, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(internal_vm_1) + + self.debug("Creating one more VPC network with Internal LB service...") + internal_tier_2 = self.create_Network(net_off_1, gateway='10.1.2.1', vpc=vpc) + self.validate_Network(internal_tier_2, state="Implemented") + vr = self.get_Router(internal_tier_2) + self.check_Router_state(vr, state="Running") + + self.debug("Deploying a VM in network - %s" % internal_tier_2.name) + internal_vm_2 = self.create_VM(internal_tier_2) + self.check_VM_state(internal_vm_2, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier_2, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(internal_vm_2) + + self.debug("Creating a VPC network without Internal LB service...") + public_tier = self.create_Network(net_off_2, gateway='10.1.3.1', vpc=vpc) + self.validate_Network(public_tier, state="Implemented") + vr = self.get_Router(public_tier) + self.check_Router_state(vr, state="Running") + + self.debug("Deploying a VM in network - %s" % public_tier.name) + public_vm = self.create_VM(public_tier) + self.check_VM_state(public_vm, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, public_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(public_vm) + + # Creating Internal LB Rules in the Internal tiers + self.debug("Creating two Internal LB Rules (SSH & HTTP) using the same Load Balancing source IP Address...") + int_lb_rule_1 = self.create_Internal_LB_Rule(internal_tier_1, vm_array=[internal_vm_1]) + self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", vm_array=[internal_vm_1]) + int_lb_rule_2 = self.create_Internal_LB_Rule(internal_tier_1, + vm_array=[internal_vm_1], + services=self.test_data["internal_lbrule_http"], + source_ip=int_lb_rule_1.sourceipaddress + ) + self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", vm_array=[internal_vm_1]) + + # Validating InternalLbVm deployment and state + int_lb_vm_1 = self.get_InternalLbVm(internal_tier_1, int_lb_rule_1.sourceipaddress) + self.check_InternalLbVm_state(internal_tier_1, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm_1) + + # Deploying more VMs in the Internal tier + self.debug("Deploying two more VMs in network - %s" % internal_tier_1.name) + internal_vm_1_1 = self.create_VM(internal_tier_1) + internal_vm_1_2 = self.create_VM(internal_tier_1) + + # VSD verification + self.verify_vsp_vm(internal_vm_1_1) + self.verify_vsp_vm(internal_vm_1_2) + + # Adding newly deployed VMs to the created Internal LB rules + self.debug("Adding two more virtual machines to the created Internal LB rules...") + int_lb_rule_1.assign(self.api_client, [internal_vm_1_1, internal_vm_1_2]) + self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", + vm_array=[internal_vm_1, internal_vm_1_1, internal_vm_1_2]) + int_lb_rule_2.assign(self.api_client, [internal_vm_1_1, internal_vm_1_2]) + self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", + vm_array=[internal_vm_1, internal_vm_1_1, internal_vm_1_2]) + + # Validating InternalLbVm state + self.check_InternalLbVm_state(internal_tier_1, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm_1) + + # Adding Network ACL rules in the Internal tier + self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...") + ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=internal_tier_1) + http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier_1) + + # VSD verification + self.verify_vsp_firewall_rule(ssh_rule) + self.verify_vsp_firewall_rule(http_rule) + + # Creating Internal LB Rules in the Internal tier + self.debug("Creating two Internal LB Rules (SSH & HTTP) using the same Load Balancing source IP Address...") + int_lb_rule_3 = self.create_Internal_LB_Rule(internal_tier_2, vm_array=[internal_vm_2]) + self.validate_Internal_LB_Rule(int_lb_rule_3, state="Active", vm_array=[internal_vm_2]) + int_lb_rule_4 = self.create_Internal_LB_Rule(internal_tier_2, + vm_array=[internal_vm_2], + services=self.test_data["internal_lbrule_http"], + source_ip=int_lb_rule_3.sourceipaddress + ) + self.validate_Internal_LB_Rule(int_lb_rule_4, state="Active", vm_array=[internal_vm_2]) + + # Validating InternalLbVm deployment and state + int_lb_vm_2 = self.get_InternalLbVm(internal_tier_2, int_lb_rule_3.sourceipaddress) + self.check_InternalLbVm_state(internal_tier_2, int_lb_rule_3.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm_2) + + # Deploying more VMs in the Internal tier + self.debug("Deploying two more VMs in network - %s" % internal_tier_2.name) + internal_vm_2_1 = self.create_VM(internal_tier_2) + internal_vm_2_2 = self.create_VM(internal_tier_2) + + # VSD verification + self.verify_vsp_vm(internal_vm_2_1) + self.verify_vsp_vm(internal_vm_2_2) + + # Adding newly deployed VMs to the created Internal LB rules + self.debug("Adding two more virtual machines to the created Internal LB rules...") + int_lb_rule_3.assign(self.api_client, [internal_vm_2_1, internal_vm_2_2]) + self.validate_Internal_LB_Rule(int_lb_rule_3, state="Active", + vm_array=[internal_vm_2, internal_vm_2_1, internal_vm_2_2]) + int_lb_rule_4.assign(self.api_client, [internal_vm_2_1, internal_vm_2_2]) + self.validate_Internal_LB_Rule(int_lb_rule_4, state="Active", + vm_array=[internal_vm_2, internal_vm_2_1, internal_vm_2_2]) + + # Validating InternalLbVm state + self.check_InternalLbVm_state(internal_tier_2, int_lb_rule_3.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm_2) + + # Adding Network ACL rules in the Internal tier + self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...") + ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=internal_tier_2) + http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier_2) + + # VSD verification + self.verify_vsp_firewall_rule(ssh_rule) + self.verify_vsp_firewall_rule(http_rule) + + # Creating Static NAT Rule for the VM in the Public tier + public_ip = self.acquire_PublicIPAddress(public_tier, vpc) + self.validate_PublicIPAddress(public_ip, public_tier) + self.create_StaticNatRule_For_VM(public_vm, public_ip, public_tier) + self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) + + # VSD verification + self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + + # Adding Network ACL rule in the Public tier + self.debug("Adding Network ACL rule to make the created NAT rule (SSH) accessible...") + public_ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=public_tier) + + # VSD verification + self.verify_vsp_firewall_rule(public_ssh_rule) + + # Internal LB (wget) traffic tests + ssh_client = self.ssh_into_VM(public_vm, public_ip) + wget_file_1 = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + ssh_client = self.ssh_into_VM(public_vm, public_ip) + wget_file_2 = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_3.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + + # Verifying Internal LB (wget) traffic tests + self.verify_lb_wget_file(wget_file_1, [internal_vm_1, internal_vm_1_1, internal_vm_1_2]) + self.verify_lb_wget_file(wget_file_2, [internal_vm_2, internal_vm_2_1, internal_vm_2_2]) + + @attr(tags=["advanced", "nuagevsp"], required_hardware="true") + def test_06_nuage_internallb_algorithms_traffic(self): + """Test Nuage VSP VPC Internal LB functionality with different LB algorithms by performing (wget) traffic tests + within a VPC + """ + + # Repeat the tests in the testcase "test_05_nuage_internallb_traffic" with different Internal LB algorithms: + # 1. Round Robin + # 2. Least connections + # 3. Source + # Verify the above Internal LB algorithms by performing multiple (wget) traffic tests within a VPC. + + # Creating a VPC offering + self.debug("Creating Nuage VSP VPC offering with Internal LB service...") + vpc_off = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"]) + self.validate_VpcOffering(vpc_off, state="Enabled") + + # Creating a VPC + self.debug("Creating a VPC with Internal LB service...") + vpc = self.create_Vpc(vpc_off, cidr='10.1.0.0/16') + self.validate_Vpc(vpc, state="Enabled") + + # Creating network offerings + self.debug("Creating Nuage VSP VPC Network offering with Internal LB service...") + net_off_1 = self.create_NetworkOffering( + self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"]) + self.validate_NetworkOffering(net_off_1, state="Enabled") + + self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...") + net_off_2 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"]) + self.validate_NetworkOffering(net_off_2, state="Enabled") + + # Creating VPC networks in the VPC, and deploying VMs + self.debug("Creating a VPC network with Internal LB service...") + internal_tier = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc) + self.validate_Network(internal_tier, state="Implemented") + vr = self.get_Router(internal_tier) + self.check_Router_state(vr, state="Running") + + self.debug("Deploying a VM in network - %s" % internal_tier.name) + internal_vm = self.create_VM(internal_tier) + self.check_VM_state(internal_vm, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(internal_vm) + + self.debug("Creating a VPC network without Internal LB service...") + public_tier = self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc) + self.validate_Network(public_tier, state="Implemented") + vr = self.get_Router(public_tier) + self.check_Router_state(vr, state="Running") + + self.debug("Deploying a VM in network - %s" % public_tier.name) + public_vm = self.create_VM(public_tier) + self.check_VM_state(public_vm, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, public_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(public_vm) + + # Creating Internal LB Rules in the Internal tier with Round Robin Algorithm + self.debug("Creating two Internal LB Rules (SSH & HTTP) with Round Robin Algorithm...") + int_lb_rule_1 = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm]) + self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", vm_array=[internal_vm]) + int_lb_rule_2 = self.create_Internal_LB_Rule(internal_tier, + vm_array=[internal_vm], + services=self.test_data["internal_lbrule_http"], + source_ip=int_lb_rule_1.sourceipaddress + ) + self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", vm_array=[internal_vm]) + + # Validating InternalLbVm deployment and state + int_lb_vm_1 = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm_1) + + # Deploying more VMs in the Internal tier + self.debug("Deploying two more VMs in network - %s" % internal_tier.name) + internal_vm_1 = self.create_VM(internal_tier) + internal_vm_2 = self.create_VM(internal_tier) + + # VSD verification + self.verify_vsp_vm(internal_vm_1) + self.verify_vsp_vm(internal_vm_2) + + # Adding newly deployed VMs to the created Internal LB rules + self.debug("Adding two more virtual machines to the created Internal LB rules...") + int_lb_rule_1.assign(self.api_client, [internal_vm_1, internal_vm_2]) + self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", + vm_array=[internal_vm, internal_vm_1, internal_vm_2]) + int_lb_rule_2.assign(self.api_client, [internal_vm_1, internal_vm_2]) + self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", + vm_array=[internal_vm, internal_vm_1, internal_vm_2]) + + # Validating InternalLbVm state + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm_1) + + # Creating Internal LB Rules in the Internal tier with Least connections Algorithm + self.debug("Creating two Internal LB Rules (SSH & HTTP) with Least connections Algorithm...") + self.test_data["internal_lbrule"]["algorithm"] = "leastconn" + int_lb_rule_3 = self.create_Internal_LB_Rule(internal_tier, + vm_array=[internal_vm, internal_vm_1, internal_vm_2], + services=self.test_data["internal_lbrule"] + ) + self.validate_Internal_LB_Rule(int_lb_rule_3, state="Active", + vm_array=[internal_vm, internal_vm_1, internal_vm_2]) + self.test_data["internal_lbrule_http"]["algorithm"] = "leastconn" + int_lb_rule_4 = self.create_Internal_LB_Rule(internal_tier, + vm_array=[internal_vm, internal_vm_1, internal_vm_2], + services=self.test_data["internal_lbrule_http"], + source_ip=int_lb_rule_3.sourceipaddress + ) + self.validate_Internal_LB_Rule(int_lb_rule_4, state="Active", + vm_array=[internal_vm, internal_vm_1, internal_vm_2]) + + # Validating InternalLbVm deployment and state + int_lb_vm_2 = self.get_InternalLbVm(internal_tier, int_lb_rule_3.sourceipaddress) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_3.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm_2) + + # Creating Internal LB Rules in the Internal tier with Source Algorithm + self.debug("Creating two Internal LB Rules (SSH & HTTP) with Source Algorithm...") + self.test_data["internal_lbrule"]["algorithm"] = "source" + int_lb_rule_5 = self.create_Internal_LB_Rule(internal_tier, + vm_array=[internal_vm, internal_vm_1, internal_vm_2], + services=self.test_data["internal_lbrule"] + ) + self.validate_Internal_LB_Rule(int_lb_rule_5, state="Active", + vm_array=[internal_vm, internal_vm_1, internal_vm_2]) + self.test_data["internal_lbrule_http"]["algorithm"] = "source" + int_lb_rule_6 = self.create_Internal_LB_Rule(internal_tier, + vm_array=[internal_vm, internal_vm_1, internal_vm_2], + services=self.test_data["internal_lbrule_http"], + source_ip=int_lb_rule_5.sourceipaddress + ) + self.validate_Internal_LB_Rule(int_lb_rule_6, state="Active", + vm_array=[internal_vm, internal_vm_1, internal_vm_2]) + + # Validating InternalLbVm deployment and state + int_lb_vm_3 = self.get_InternalLbVm(internal_tier, int_lb_rule_5.sourceipaddress) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_5.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm_3) + + # Adding Network ACL rules in the Internal tier + self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...") + ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=internal_tier) + http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier) + + # VSD verification + self.verify_vsp_firewall_rule(ssh_rule) + self.verify_vsp_firewall_rule(http_rule) + + # Creating Static NAT Rule for the VM in the Public tier + public_ip = self.acquire_PublicIPAddress(public_tier, vpc) + self.validate_PublicIPAddress(public_ip, public_tier) + self.create_StaticNatRule_For_VM(public_vm, public_ip, public_tier) + self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) + + # VSD verification + self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + + # Adding Network ACL rule in the Public tier + self.debug("Adding Network ACL rule to make the created NAT rule (SSH) accessible...") + public_ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=public_tier) + + # VSD verification + self.verify_vsp_firewall_rule(public_ssh_rule) + + # Internal LB (wget) traffic tests with Round Robin Algorithm + ssh_client = self.ssh_into_VM(public_vm, public_ip) + self.validate_internallb_algorithm_traffic(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"], + [internal_vm, internal_vm_1, internal_vm_2], + "roundrobin" + ) + + # Internal LB (wget) traffic tests with Least connections Algorithm + ssh_client = self.ssh_into_VM(public_vm, public_ip) + self.validate_internallb_algorithm_traffic(ssh_client, + int_lb_rule_3.sourceipaddress, + self.test_data["http_rule"]["publicport"], + [internal_vm, internal_vm_1, internal_vm_2], + "leastconn" + ) + + # Internal LB (wget) traffic tests with Source Algorithm + ssh_client = self.ssh_into_VM(public_vm, public_ip) + self.validate_internallb_algorithm_traffic(ssh_client, + int_lb_rule_5.sourceipaddress, + self.test_data["http_rule"]["publicport"], + [internal_vm, internal_vm_1, internal_vm_2], + "source" + ) + + @attr(tags=["advanced", "nuagevsp"], required_hardware="true") + def test_07_nuage_internallb_vpc_network_restarts_traffic(self): + """Test Nuage VSP VPC Internal LB functionality with restarts of VPC network components by performing (wget) + traffic tests within a VPC + """ + + # Repeat the tests in the testcase "test_05_nuage_internallb_traffic" with restarts of VPC networks (tiers): + # 1. Restart tier with InternalLbVm (cleanup = false), verify that the InternalLbVm gets destroyed and deployed + # again in the Internal tier. + # 2. Restart tier with InternalLbVm (cleanup = true), verify that the InternalLbVm gets destroyed and deployed + # again in the Internal tier. + # 3. Restart tier without InternalLbVm (cleanup = false), verify that this restart has no effect on the + # InternalLbVm functionality. + # 4. Restart tier without InternalLbVm (cleanup = true), verify that this restart has no effect on the + # InternalLbVm functionality. + # 5. Stop all the VMs configured with InternalLbVm, verify that the InternalLbVm gets destroyed in the Internal + # tier. + # 6. Start all the VMs configured with InternalLbVm, verify that the InternalLbVm gets deployed again in the + # Internal tier. + # 7. Restart VPC, verify that the VPC VR gets rebooted and this restart has no effect on the InternalLbVm + # functionality. + # Verify the above restarts of VPC networks (tiers) by performing (wget) traffic tests within a VPC. + + # Creating a VPC offering + self.debug("Creating Nuage VSP VPC offering with Internal LB service...") + vpc_off = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"]) + self.validate_VpcOffering(vpc_off, state="Enabled") + + # Creating a VPC + self.debug("Creating a VPC with Internal LB service...") + vpc = self.create_Vpc(vpc_off, cidr='10.1.0.0/16') + self.validate_Vpc(vpc, state="Enabled") + + # Creating network offerings + self.debug("Creating Nuage VSP VPC Network offering with Internal LB service...") + net_off_1 = self.create_NetworkOffering( + self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"]) + self.validate_NetworkOffering(net_off_1, state="Enabled") + + self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...") + net_off_2 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"]) + self.validate_NetworkOffering(net_off_2, state="Enabled") + + # Creating VPC networks in the VPC, and deploying VMs + self.debug("Creating a VPC network with Internal LB service...") + internal_tier = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc) + self.validate_Network(internal_tier, state="Implemented") + vr = self.get_Router(internal_tier) + self.check_Router_state(vr, state="Running") + + self.debug("Deploying a VM in network - %s" % internal_tier.name) + internal_vm = self.create_VM(internal_tier) + self.check_VM_state(internal_vm, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(internal_vm) + + self.debug("Creating a VPC network without Internal LB service...") + public_tier = self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc) + self.validate_Network(public_tier, state="Implemented") + vr = self.get_Router(public_tier) + self.check_Router_state(vr, state="Running") + + self.debug("Deploying a VM in network - %s" % public_tier.name) + public_vm = self.create_VM(public_tier) + self.check_VM_state(public_vm, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, public_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(public_vm) + + # Creating Internal LB Rules in the Internal tier + self.debug("Creating two Internal LB Rules (SSH & HTTP) using the same Load Balancing source IP Address...") + int_lb_rule_1 = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm]) + self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", vm_array=[internal_vm]) + int_lb_rule_2 = self.create_Internal_LB_Rule(internal_tier, + vm_array=[internal_vm], + services=self.test_data["internal_lbrule_http"], + source_ip=int_lb_rule_1.sourceipaddress + ) + self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", vm_array=[internal_vm]) + + # Validating InternalLbVm deployment and state + int_lb_vm = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Deploying more VMs in the Internal tier + self.debug("Deploying two more VMs in network - %s" % internal_tier.name) + internal_vm_1 = self.create_VM(internal_tier) + internal_vm_2 = self.create_VM(internal_tier) + + # VSD verification + self.verify_vsp_vm(internal_vm_1) + self.verify_vsp_vm(internal_vm_2) + + # Adding newly deployed VMs to the created Internal LB rules + self.debug("Adding two more virtual machines to the created Internal LB rules...") + int_lb_rule_1.assign(self.api_client, [internal_vm_1, internal_vm_2]) + self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", + vm_array=[internal_vm, internal_vm_1, internal_vm_2]) + int_lb_rule_2.assign(self.api_client, [internal_vm_1, internal_vm_2]) + self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", + vm_array=[internal_vm, internal_vm_1, internal_vm_2]) + + # Validating InternalLbVm state + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Adding Network ACL rules in the Internal tier + self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...") + ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=internal_tier) + http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier) + + # VSD verification + self.verify_vsp_firewall_rule(ssh_rule) + self.verify_vsp_firewall_rule(http_rule) + + # Creating Static NAT Rule for the VM in the Public tier + public_ip = self.acquire_PublicIPAddress(public_tier, vpc) + self.validate_PublicIPAddress(public_ip, public_tier) + self.create_StaticNatRule_For_VM(public_vm, public_ip, public_tier) + self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) + + # VSD verification + self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + + # Adding Network ACL rule in the Public tier + self.debug("Adding Network ACL rule to make the created NAT rule (SSH) accessible...") + public_ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=public_tier) + + # VSD verification + self.verify_vsp_firewall_rule(public_ssh_rule) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + wget_file = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + + # Verifying Internal LB (wget) traffic test + self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2]) + + # Restart Internal tier (cleanup = false) + # InternalLbVm gets destroyed and deployed again in the Internal tier + self.debug("Restarting the Internal tier without cleanup...") + Network.restart(internal_tier, self.api_client, cleanup=False) + self.validate_Network(internal_tier, state="Implemented") + self.check_Router_state(vr, state="Running") + self.check_VM_state(internal_vm, state="Running") + self.check_VM_state(internal_vm_1, state="Running") + self.check_VM_state(internal_vm_2, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(internal_vm) + self.verify_vsp_vm(internal_vm_1) + self.verify_vsp_vm(internal_vm_2) + self.verify_vsp_firewall_rule(ssh_rule) + self.verify_vsp_firewall_rule(http_rule) + + # Validating InternalLbVm state + # InternalLbVm gets destroyed and deployed again in the Internal tier + int_lb_vm = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + tries = 0 + while True: + try: + wget_file = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + except Exception as e: + self.debug("Failed to wget file via the InternalLbVm after re-starting the Internal tier: %s" % e) + if tries == 10: + break + self.debug("Waiting for the InternalLbVm in the Internal tier to be fully resolved for (wget) traffic " + "test...") + time.sleep(30) + tries += 1 + continue + self.debug("Internal LB (wget) traffic test is successful after re-starting the Internal tier") + break + + # Verifying Internal LB (wget) traffic test + self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2]) + + # Restart Internal tier (cleanup = true) + # InternalLbVm gets destroyed and deployed again in the Internal tier + self.debug("Restarting the Internal tier with cleanup...") + Network.restart(internal_tier, self.api_client, cleanup=True) + self.validate_Network(internal_tier, state="Implemented") + self.check_Router_state(vr, state="Running") + self.check_VM_state(internal_vm, state="Running") + self.check_VM_state(internal_vm_1, state="Running") + self.check_VM_state(internal_vm_2, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(internal_vm) + self.verify_vsp_vm(internal_vm_1) + self.verify_vsp_vm(internal_vm_2) + self.verify_vsp_firewall_rule(ssh_rule) + self.verify_vsp_firewall_rule(http_rule) + + # Validating InternalLbVm state + # InternalLbVm gets destroyed and deployed again in the Internal tier + int_lb_vm = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + tries = 0 + while True: + try: + wget_file = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + except Exception as e: + self.debug("Failed to wget file via the InternalLbVm after re-starting the Internal tier with cleanup: " + "%s" % e) + if tries == 10: + break + self.debug("Waiting for the InternalLbVm in the Internal tier to be fully resolved for (wget) traffic " + "test...") + time.sleep(30) + tries += 1 + continue + self.debug("Internal LB (wget) traffic test is successful after re-starting the Internal tier with cleanup") + break + + # Verifying Internal LB (wget) traffic test + self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2]) + + # Restart Public tier (cleanup = false) + # This restart has no effect on the InternalLbVm functionality + self.debug("Restarting the Public tier without cleanup...") + Network.restart(public_tier, self.api_client, cleanup=False) + self.validate_Network(public_tier, state="Implemented") + self.check_Router_state(vr, state="Running") + self.check_VM_state(public_vm, state="Running") + self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) + + # VSD verification + self.verify_vsp_network(self.domain.id, public_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(public_vm) + self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + self.verify_vsp_firewall_rule(public_ssh_rule) + + # Validating InternalLbVm state + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + wget_file = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + + # Verifying Internal LB (wget) traffic test + self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2]) + + # Restart Public tier (cleanup = true) + # This restart has no effect on the InternalLbVm functionality + self.debug("Restarting the Public tier with cleanup...") + Network.restart(public_tier, self.api_client, cleanup=True) + self.validate_Network(public_tier, state="Implemented") + self.check_Router_state(vr, state="Running") + self.check_VM_state(public_vm, state="Running") + self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) + + # VSD verification + self.verify_vsp_network(self.domain.id, public_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(public_vm) + self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + self.verify_vsp_firewall_rule(public_ssh_rule) + + # Validating InternalLbVm state + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + wget_file = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + + # Verifying Internal LB (wget) traffic test + self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2]) + + # Stopping VMs in the Internal tier + # wget traffic test fails as all the VMs in the Internal tier are in stopped state + self.debug("Stopping all the VMs in the Internal tier...") + internal_vm.stop(self.api_client) + internal_vm_1.stop(self.api_client) + internal_vm_2.stop(self.api_client) + self.validate_Network(internal_tier, state="Implemented") + self.check_Router_state(vr, state="Running") + self.check_VM_state(internal_vm, state="Stopped") + self.check_VM_state(internal_vm_1, state="Stopped") + self.check_VM_state(internal_vm_2, state="Stopped") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(internal_vm, stopped=True) + self.verify_vsp_vm(internal_vm_1, stopped=True) + self.verify_vsp_vm(internal_vm_2, stopped=True) + self.verify_vsp_firewall_rule(ssh_rule) + self.verify_vsp_firewall_rule(http_rule) + + # Validating InternalLbVm state + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + with self.assertRaises(Exception): + self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + self.debug("Failed to wget file as all the VMs in the Internal tier are in stopped state") + + # Starting VMs in the Internal tier + # wget traffic test succeeds as all the VMs in the Internal tier are back in running state + self.debug("Starting all the VMs in the Internal tier...") + internal_vm.start(self.api_client) + internal_vm_1.start(self.api_client) + internal_vm_2.start(self.api_client) + self.validate_Network(internal_tier, state="Implemented") + self.check_Router_state(vr, state="Running") + self.check_VM_state(internal_vm, state="Running") + self.check_VM_state(internal_vm_1, state="Running") + self.check_VM_state(internal_vm_2, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(internal_vm) + self.verify_vsp_vm(internal_vm_1) + self.verify_vsp_vm(internal_vm_2) + self.verify_vsp_firewall_rule(ssh_rule) + self.verify_vsp_firewall_rule(http_rule) + + # Validating InternalLbVm state + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + tries = 0 + while True: + try: + wget_file = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + except Exception as e: + self.debug("Failed to wget file via the InternalLbVm after re-starting all the VMs in the Internal tier" + ": %s" % e) + if tries == 10: + break + self.debug("Waiting for the InternalLbVm and all the VMs in the Internal tier to be fully resolved for " + "(wget) traffic test...") + time.sleep(30) + tries += 1 + continue + self.debug("Internal LB (wget) traffic test is successful after re-starting all the VMs in the Internal " + "tier") + break + + # Verifying Internal LB (wget) traffic test + self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2]) + + # Restarting VPC (cleanup = false) + # VPC VR gets destroyed and deployed again in the VPC + # This restart has no effect on the InternalLbVm functionality + self.debug("Restarting the VPC without cleanup...") + self.restart_Vpc(vpc, cleanup=False) + self.validate_Network(public_tier, state="Implemented") + self.validate_Network(internal_tier, state="Implemented") + vr = self.get_Router(public_tier) + self.check_Router_state(vr, state="Running") + self.check_VM_state(public_vm, state="Running") + self.check_VM_state(internal_vm, state="Running") + self.check_VM_state(internal_vm_1, state="Running") + self.check_VM_state(internal_vm_2, state="Running") + self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) + + # VSD verification + self.verify_vsp_network(self.domain.id, public_tier, vpc) + self.verify_vsp_network(self.domain.id, internal_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(public_vm) + self.verify_vsp_vm(internal_vm) + self.verify_vsp_vm(internal_vm_1) + self.verify_vsp_vm(internal_vm_2) + self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + self.verify_vsp_firewall_rule(public_ssh_rule) + self.verify_vsp_firewall_rule(ssh_rule) + self.verify_vsp_firewall_rule(http_rule) + + # Validating InternalLbVm state + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + wget_file = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + + # Verifying Internal LB (wget) traffic test + self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2]) + + # Restarting VPC (cleanup = true) + # VPC VR gets destroyed and deployed again in the VPC + # This restart has no effect on the InternalLbVm functionality + self.debug("Restarting the VPC with cleanup...") + self.restart_Vpc(vpc, cleanup=True) + self.validate_Network(public_tier, state="Implemented") + self.validate_Network(internal_tier, state="Implemented") + vr = self.get_Router(public_tier) + self.check_Router_state(vr, state="Running") + self.check_VM_state(public_vm, state="Running") + self.check_VM_state(internal_vm, state="Running") + self.check_VM_state(internal_vm_1, state="Running") + self.check_VM_state(internal_vm_2, state="Running") + self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) + + # VSD verification + self.verify_vsp_network(self.domain.id, public_tier, vpc) + self.verify_vsp_network(self.domain.id, internal_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(public_vm) + self.verify_vsp_vm(internal_vm) + self.verify_vsp_vm(internal_vm_1) + self.verify_vsp_vm(internal_vm_2) + self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + self.verify_vsp_firewall_rule(public_ssh_rule) + self.verify_vsp_firewall_rule(ssh_rule) + self.verify_vsp_firewall_rule(http_rule) + + # Validating InternalLbVm state + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + wget_file = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + + # Verifying Internal LB (wget) traffic test + self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2]) + + @attr(tags=["advanced", "nuagevsp"], required_hardware="true") + def test_08_nuage_internallb_appliance_operations_traffic(self): + """Test Nuage VSP VPC Internal LB functionality with InternalLbVm appliance operations by performing (wget) + traffic tests within a VPC + """ + + # Repeat the tests in the testcase "test_05_nuage_internallb_traffic" with InternalLbVm appliance operations: + # 1. Verify the InternalLbVm deployment by creating the Internal LB Rules when the VPC VR is in Stopped state, + # VPC VR has no effect on the InternalLbVm functionality. + # 2. Stop the InternalLbVm when the VPC VR is in Stopped State + # 3. Start the InternalLbVm when the VPC VR is in Stopped state + # 4. Stop the InternalLbVm when the VPC VR is in Running State + # 5. Start the InternalLbVm when the VPC VR is in Running state + # 6. Force stop the InternalLbVm when the VPC VR is in Running State + # 7. Start the InternalLbVm when the VPC VR is in Running state + # Verify the above restarts of VPC networks by performing (wget) traffic tests within a VPC. + + # Creating a VPC offering + self.debug("Creating Nuage VSP VPC offering with Internal LB service...") + vpc_off = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"]) + self.validate_VpcOffering(vpc_off, state="Enabled") + + # Creating a VPC + self.debug("Creating a VPC with Internal LB service...") + vpc = self.create_Vpc(vpc_off, cidr='10.1.0.0/16') + self.validate_Vpc(vpc, state="Enabled") + + # Creating network offerings + self.debug("Creating Nuage VSP VPC Network offering with Internal LB service...") + net_off_1 = self.create_NetworkOffering( + self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"]) + self.validate_NetworkOffering(net_off_1, state="Enabled") + + self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...") + net_off_2 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"]) + self.validate_NetworkOffering(net_off_2, state="Enabled") + + # Creating VPC networks in the VPC, and deploying VMs + self.debug("Creating a VPC network with Internal LB service...") + internal_tier = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc) + self.validate_Network(internal_tier, state="Implemented") + vr = self.get_Router(internal_tier) + self.check_Router_state(vr, state="Running") + + self.debug("Deploying a VM in network - %s" % internal_tier.name) + internal_vm = self.create_VM(internal_tier) + self.check_VM_state(internal_vm, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, internal_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(internal_vm) + + self.debug("Creating a VPC network without Internal LB service...") + public_tier = self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc) + self.validate_Network(public_tier, state="Implemented") + vr = self.get_Router(public_tier) + self.check_Router_state(vr, state="Running") + + self.debug("Deploying a VM in network - %s" % public_tier.name) + public_vm = self.create_VM(public_tier) + self.check_VM_state(public_vm, state="Running") + + # VSD verification + self.verify_vsp_network(self.domain.id, public_tier, vpc) + self.verify_vsp_router(vr) + self.verify_vsp_vm(public_vm) + + # Stopping the VPC VR + # VPC VR has no effect on the InternalLbVm functionality + Router.stop(self.api_client, id=vr.id) + self.check_Router_state(vr, state="Stopped") + self.validate_Network(public_tier, state="Implemented") + self.validate_Network(internal_tier, state="Implemented") + + # VSD verification + self.verify_vsp_router(vr, stopped=True) + self.verify_vsp_network(self.domain.id, public_tier, vpc) + self.verify_vsp_network(self.domain.id, internal_tier, vpc) + + # Creating Internal LB Rules in the Internal tier + self.debug("Creating two Internal LB Rules (SSH & HTTP) using the same Load Balancing source IP Address...") + int_lb_rule_1 = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm]) + self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", vm_array=[internal_vm]) + int_lb_rule_2 = self.create_Internal_LB_Rule(internal_tier, + vm_array=[internal_vm], + services=self.test_data["internal_lbrule_http"], + source_ip=int_lb_rule_1.sourceipaddress + ) + self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", vm_array=[internal_vm]) + + # Validating InternalLbVm deployment and state + int_lb_vm = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Deploying more VMs in the Internal tier + self.debug("Deploying two more VMs in network - %s" % internal_tier.name) + internal_vm_1 = self.create_VM(internal_tier) + internal_vm_2 = self.create_VM(internal_tier) + + # VSD verification + self.verify_vsp_vm(internal_vm_1) + self.verify_vsp_vm(internal_vm_2) + + # Adding newly deployed VMs to the created Internal LB rules + self.debug("Adding two more virtual machines to the created Internal LB rules...") + int_lb_rule_1.assign(self.api_client, [internal_vm_1, internal_vm_2]) + self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", + vm_array=[internal_vm, internal_vm_1, internal_vm_2]) + int_lb_rule_2.assign(self.api_client, [internal_vm_1, internal_vm_2]) + self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", + vm_array=[internal_vm, internal_vm_1, internal_vm_2]) + + # Validating InternalLbVm state + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Adding Network ACL rules in the Internal tier + self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...") + ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=internal_tier) + http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier) + + # VSD verification + self.verify_vsp_firewall_rule(ssh_rule) + self.verify_vsp_firewall_rule(http_rule) + + # Creating Static NAT Rule for the VM in the Public tier + public_ip = self.acquire_PublicIPAddress(public_tier, vpc) + self.validate_PublicIPAddress(public_ip, public_tier) + self.create_StaticNatRule_For_VM(public_vm, public_ip, public_tier) + self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) + + # VSD verification + self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + + # Adding Network ACL rule in the Public tier + self.debug("Adding Network ACL rule to make the created NAT rule (SSH) accessible...") + public_ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=public_tier) + + # VSD verification + self.verify_vsp_firewall_rule(public_ssh_rule) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + wget_file = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + + # Verifying Internal LB (wget) traffic test + self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2]) + + # # Stopping the InternalLbVm when the VPC VR is in Stopped state + self.stop_InternalLbVm(int_lb_vm) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Stopped") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm, stopped=True) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + with self.assertRaises(Exception): + self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + self.debug("Failed to wget file as the InternalLbVm is in stopped state") + + # # Starting the InternalLbVm when the VPC VR is in Stopped state + self.start_InternalLbVm(int_lb_vm) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + tries = 0 + while True: + try: + wget_file = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + except Exception as e: + self.debug("Failed to wget file via the InternalLbVm after re-starting the InternalLbVm appliance: %s" + % e) + if tries == 10: + break + self.debug("Waiting for the InternalLbVm to be fully resolved for (wget) traffic test...") + time.sleep(30) + tries += 1 + continue + self.debug("Internal LB (wget) traffic test is successful after re-starting the InternalLbVm appliance") + break + + # Verifying Internal LB (wget) traffic test + self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2]) + + # Starting the VPC VR + # VPC VR has no effect on the InternalLbVm functionality + Router.start(self.api_client, id=vr.id) + self.check_Router_state(vr) + self.validate_Network(public_tier, state="Implemented") + self.validate_Network(internal_tier, state="Implemented") + + # VSD verification + self.verify_vsp_router(vr) + self.verify_vsp_network(self.domain.id, public_tier, vpc) + self.verify_vsp_network(self.domain.id, internal_tier, vpc) + + # # Stopping the InternalLbVm when the VPC VR is in Running state + self.stop_InternalLbVm(int_lb_vm) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Stopped") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm, stopped=True) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + with self.assertRaises(Exception): + self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + self.debug("Failed to wget file as the InternalLbVm is in stopped state") + + # # Starting the InternalLbVm when the VPC VR is in Running state + self.start_InternalLbVm(int_lb_vm) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + tries = 0 + while True: + try: + wget_file = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + except Exception as e: + self.debug("Failed to wget file via the InternalLbVm after re-starting the InternalLbVm appliance: %s" + % e) + if tries == 10: + break + self.debug("Waiting for the InternalLbVm to be fully resolved for (wget) traffic test...") + time.sleep(30) + tries += 1 + continue + self.debug("Internal LB (wget) traffic test is successful after re-starting the InternalLbVm appliance") + break + + # Verifying Internal LB (wget) traffic test + self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2]) + + # # Force Stopping the InternalLbVm when the VPC VR is in Running state + self.stop_InternalLbVm(int_lb_vm, force=True) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Stopped") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm, stopped=True) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + with self.assertRaises(Exception): + self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + self.debug("Failed to wget file as the InternalLbVm is in stopped state") + + # # Starting the InternalLbVm when the VPC VR is in Running state + self.start_InternalLbVm(int_lb_vm) + self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") + + # VSD Verification + self.verify_vsp_LB_device(int_lb_vm) + + # Internal LB (wget) traffic test + ssh_client = self.ssh_into_VM(public_vm, public_ip) + tries = 0 + while True: + try: + wget_file = self.wget_from_vm_cmd(ssh_client, + int_lb_rule_1.sourceipaddress, + self.test_data["http_rule"]["publicport"] + ) + except Exception as e: + self.debug("Failed to wget file via the InternalLbVm after re-starting the InternalLbVm appliance: %s" + % e) + if tries == 10: + break + self.debug("Waiting for the InternalLbVm to be fully resolved for (wget) traffic test...") + time.sleep(30) + tries += 1 + continue + self.debug("Internal LB (wget) traffic test is successful after re-starting the InternalLbVm appliance") + break + + # Verifying Internal LB (wget) traffic test + self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2]) diff --git a/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py b/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py index 3fc9c32cfe..a8361d0e0b 100644 --- a/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py +++ b/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py @@ -15,16 +15,17 @@ # specific language governing permissions and limitations # under the License. -""" Tests for Basic VPC Network Functionality with NuageVsp network Plugin +""" Tests for basic VPC Network functionality with Nuage VSP SDN plugin """ # Import Local Modules +from nuageTestCase import nuageTestCase from marvin.lib.base import Account +# Import System Modules from nose.plugins.attrib import attr -from nuageTestCase import nuageTestCase class TestVpcNetworkNuage(nuageTestCase): - """ Test Basic VPC Network Functionality with NuageVsp network Plugin + """ Test basic VPC Network functionality with Nuage VSP SDN plugin """ @classmethod @@ -44,55 +45,55 @@ def setUp(self): @attr(tags=["advanced", "nuagevsp"], required_hardware="false") def test_nuage_vpc_network(self): - """ Test Basic VPC Network Functionality with NuageVsp network Plugin + """ Test Basic VPC Network Functionality with Nuage VSP SDN plugin """ # 1. Create Nuage VSP VPC offering, check if it is successfully created and enabled. # 2. Create a VPC with Nuage VSP VPC offering, check if it is successfully created and enabled. - # 3. Create Nuage Vsp VPC Network offering, check if it is successfully created and enabled. + # 3. Create Nuage VSP VPC Network offering, check if it is successfully created and enabled. # 4. Create an ACL list in the created VPC, and add an ACL item to it. - # 5. Create a VPC Network with Nuage Vsp VPC Network offering and the created ACL list, check if it is + # 5. Create a VPC Network with Nuage VSP VPC Network offering and the created ACL list, check if it is # successfully created, is in the "Implemented" state, and is added to the VPC VR. # 6. Deploy a VM in the created VPC network, check if the VM is successfully deployed and is in the "Running" # state. - # 7. Verify that the created ACL item is successfully implemented in Nuage Vsp. + # 7. Verify that the created ACL item is successfully implemented in Nuage VSP. # Creating a VPC offering self.debug("Creating Nuage VSP VPC offering...") - vpc_offering = self.create_VpcOffering(self.test_data["nuage_vsp_services"]["vpc_offering"]) - self.validate_vpc_offering(vpc_offering, state="Enabled") + vpc_offering = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering"]) + self.validate_VpcOffering(vpc_offering, state="Enabled") # Creating a VPC self.debug("Creating a VPC with Nuage VSP VPC offering...") vpc = self.create_Vpc(vpc_offering, cidr='10.1.0.0/16') - self.validate_vpc(vpc, state="Enabled") + self.validate_Vpc(vpc, state="Enabled") # Creating a network offering - self.debug("Creating Nuage Vsp VPC Network offering...") - network_offering = self.create_NetworkOffering(self.test_data["nuage_vsp_services"]["vpc_network_offering"]) - self.validate_network_offering(network_offering, state="Enabled") + self.debug("Creating Nuage VSP VPC Network offering...") + network_offering = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"]) + self.validate_NetworkOffering(network_offering, state="Enabled") # Creating an ACL list - acl_list = self.create_network_acl_list(name="acl", description="acl", vpc=vpc) + acl_list = self.create_NetworkAclList(name="acl", description="acl", vpc=vpc) # Creating an ACL item - acl_item = self.create_network_acl_rule(self.test_data["ingress_rule"], acl_list=acl_list) + acl_item = self.create_NetworkAclRule(self.test_data["ingress_rule"], acl_list=acl_list) # Creating a VPC network in the VPC - self.debug("Creating a VPC network with Nuage Vsp VPC Network offering...") - vpc_network = self.create_Network(network_offering, gateway='10.1.1.1', vpc=vpc, acl_list=acl_list) - self.validate_network(vpc_network, state="Implemented") - vr = self.get_network_router(vpc_network) - self.check_router_state(vr, state="Running") + self.debug("Creating a VPC network with Nuage VSP VPC Network offering...") + vpc_network = self.create_Network(network_offering, vpc=vpc, acl_list=acl_list) + self.validate_Network(vpc_network, state="Implemented") + vr = self.get_Router(vpc_network) + self.check_Router_state(vr, state="Running") # Deploying a VM in the VPC network - vm = self.create_VM_in_Network(vpc_network) - self.check_vm_state(vm, state="Running") + vm = self.create_VM(vpc_network) + self.check_VM_state(vm, state="Running") - # VSPK verification + # VSD verification self.verify_vsp_network(self.domain.id, vpc_network, vpc) self.verify_vsp_router(vr) self.verify_vsp_vm(vm) - # VSPK verification for ACL item + # VSD verification for ACL item self.verify_vsp_firewall_rule(acl_item) diff --git a/test/integration/plugins/nuagevsp/test_nuage_vsp.py b/test/integration/plugins/nuagevsp/test_nuage_vsp.py index a6ec7e1fee..ca2a28e276 100644 --- a/test/integration/plugins/nuagevsp/test_nuage_vsp.py +++ b/test/integration/plugins/nuagevsp/test_nuage_vsp.py @@ -15,16 +15,17 @@ # specific language governing permissions and limitations # under the License. -""" P1 tests for NuageVsp network Plugin +""" P1 tests for Nuage VSP SDN plugin """ # Import Local Modules +from nuageTestCase import nuageTestCase from marvin.lib.base import Account +# Import System Modules from nose.plugins.attrib import attr -from nuageTestCase import nuageTestCase class TestNuageVsp(nuageTestCase): - """ Test NuageVsp network plugin + """ Test Nuage VSP SDN plugin """ @classmethod @@ -44,12 +45,12 @@ def setUp(self): @attr(tags=["advanced", "nuagevsp"], required_hardware="false") def test_nuage_vsp(self): - """ Test NuageVsp network plugin with basic Isolated Network functionality + """ Test Nuage VSP SDN plugin with basic Isolated Network functionality """ - # 1. Verify that the NuageVsp network service provider is successfully created and enabled. - # 2. Create and enable Nuage Vsp Isolated Network offering, check if it is successfully created and enabled. - # 3. Create an Isolated Network with Nuage Vsp Isolated Network offering, check if it is successfully created + # 1. Verify that the Nuage VSP network service provider is successfully created and enabled. + # 2. Create and enable Nuage VSP Isolated Network offering, check if it is successfully created and enabled. + # 3. Create an Isolated Network with Nuage VSP Isolated Network offering, check if it is successfully created # and is in the "Allocated" state. # 4. Deploy a VM in the created Isolated network, check if the Isolated network state is changed to # "Implemented", and both the VM & VR are successfully deployed and are in the "Running" state. @@ -58,49 +59,49 @@ def test_nuage_vsp(self): # 6. Delete the created Isolated Network after destroying its VMs, check if the Isolated network is successfully # deleted. - self.debug("Validating the NuageVsp network service provider...") + self.debug("Validating the Nuage VSP network service provider...") self.validate_NetworkServiceProvider("NuageVsp", state="Enabled") # Creating a network offering - self.debug("Creating and enabling Nuage Vsp Isolated Network offering...") + self.debug("Creating and enabling Nuage VSP Isolated Network offering...") network_offering = self.create_NetworkOffering( - self.test_data["nuage_vsp_services"]["isolated_network_offering"]) - self.validate_network_offering(network_offering, state="Enabled") + self.test_data["nuagevsp"]["isolated_network_offering"]) + self.validate_NetworkOffering(network_offering, state="Enabled") # Creating a network - self.debug("Creating an Isolated Network with Nuage Vsp Isolated Network offering...") - network = self.create_Network(network_offering, gateway='10.1.1.1') - self.validate_network(network, state="Allocated") + self.debug("Creating an Isolated Network with Nuage VSP Isolated Network offering...") + network = self.create_Network(network_offering) + self.validate_Network(network, state="Allocated") # Deploying a VM in the network - vm_1 = self.create_VM_in_Network(network) - self.validate_network(network, state="Implemented") - vr = self.get_network_router(network) - self.check_router_state(vr, state="Running") - self.check_vm_state(vm_1, state="Running") + vm_1 = self.create_VM(network) + self.validate_Network(network, state="Implemented") + vr = self.get_Router(network) + self.check_Router_state(vr, state="Running") + self.check_VM_state(vm_1, state="Running") - # VSPK verification + # VSD verification self.verify_vsp_network(self.domain.id, network) self.verify_vsp_router(vr) self.verify_vsp_vm(vm_1) # Deploying one more VM in the network - vm_2 = self.create_VM_in_Network(network) - self.check_vm_state(vm_2, state="Running") + vm_2 = self.create_VM(network) + self.check_VM_state(vm_2, state="Running") - # VSPK verification + # VSD verification self.verify_vsp_vm(vm_2) # Deleting the network - self.debug("Deleting the Isolated Network with Nuage Vsp Isolated Network offering...") + self.debug("Deleting the Isolated Network with Nuage VSP Isolated Network offering...") self.delete_VM(vm_1) self.delete_VM(vm_2) self.delete_Network(network) with self.assertRaises(Exception): - self.validate_network(network) + self.validate_Network(network) self.debug("Isolated Network successfully deleted in CloudStack") - # VSPK verification + # VSD verification with self.assertRaises(Exception): self.verify_vsp_network(self.domain.id, network) self.debug("Isolated Network successfully deleted in VSD") diff --git a/tools/marvin/marvin/config/test_data.py b/tools/marvin/marvin/config/test_data.py index 352f8a2307..c9bb7c603d 100644 --- a/tools/marvin/marvin/config/test_data.py +++ b/tools/marvin/marvin/config/test_data.py @@ -735,6 +735,34 @@ "publicport": 22, "protocol": 'TCP' }, + "internal_lbrule": { + "name": "SSH", + "algorithm": "roundrobin", + # Algorithm used for load balancing + "sourceport": 22, + "instanceport": 22, + "scheme": "internal", + "protocol": "TCP", + "cidrlist": '0.0.0.0/0', + }, + "internal_lbrule_http": { + "name": "HTTP", + "algorithm": "roundrobin", + # Algorithm used for load balancing + "sourceport": 80, + "instanceport": 80, + "scheme": "internal", + "protocol": "TCP", + "cidrlist": '0.0.0.0/0', + }, + "http_rule": { + "privateport": 80, + "publicport": 80, + "startport": 80, + "endport": 80, + "protocol": "TCP", + "cidrlist": '0.0.0.0/0', + }, "icmprule": { "icmptype": -1, "icmpcode": -1, @@ -1696,9 +1724,9 @@ "mode": 'HTTP_DOWNLOAD' } }, - # Nuage Vsp supported services - "nuage_vsp_services": { - # Services supported by Nuage Vsp for Isolated networks + # Nuage VSP SDN plugin specific test data + "nuagevsp": { + # Services supported by the Nuage VSP plugin for Isolated networks "isolated_network_offering": { "name": 'nuage_marvin', "displaytext": 'nuage_marvin', @@ -1718,7 +1746,7 @@ "SourceNat": {"SupportedSourceNatTypes": "perzone"} } }, - # Services supported by Nuage Vsp for VPC networks + # Services supported by the Nuage VSP plugin for VPC networks "vpc_network_offering": { "name": 'nuage_vpc_marvin', "displaytext": 'nuage_vpc_marvin', @@ -1740,7 +1768,30 @@ "SourceNat": {"SupportedSourceNatTypes": "perzone"} } }, - # Nuage Vsp supports only pre-defined and custom VPC offerings + "vpc_network_offering_internal_lb": { + "name": "nuage_vpc_marvin_internal_lb", + "displaytext": "nuage_vpc_marvin_internal_lb", + "guestiptype": 'Isolated', + "supportedservices": 'Dhcp,Lb,StaticNat,SourceNat,NetworkACL,Connectivity,UserData', + "traffictype": 'GUEST', + "availability": 'Optional', + "useVpc": 'on', + "ispersistent": 'True', + "serviceProviderList": { + "Dhcp": "NuageVsp", + "Lb": "InternalLbVm", + "StaticNat": "NuageVsp", + "SourceNat": "NuageVsp", + "NetworkACL": "NuageVsp", + "Connectivity": "NuageVsp", + "UserData": "VpcVirtualRouter" + }, + "serviceCapabilityList": { + "SourceNat": {"SupportedSourceNatTypes": "perzone"}, + "Lb": {"lbSchemes": "internal", "SupportedLbIsolation": "dedicated"} + } + }, + # Services supported by the Nuage VSP plugin for VPCs "vpc_offering": { "name": 'Nuage VSP VPC offering', "displaytext": 'Nuage VSP VPC offering', @@ -1753,57 +1804,20 @@ "Connectivity": "NuageVsp", "UserData": "VpcVirtualRouter" } - } - }, - - #_pr -_ passwordreset - below services used in test_nuage_password_reset - "network_offering_pr": { - "name": 'nuage_marvin', - "displaytext": 'nuage_marvin', - "guestiptype": 'Isolated', - "supportedservices": - 'Dhcp,SourceNat,Connectivity,StaticNat,UserData,Firewall', - "traffictype": 'GUEST', - "availability": 'Optional', - "serviceProviderList": { - "UserData": 'VirtualRouter', - "Dhcp": 'NuageVsp', - "Connectivity": 'NuageVsp', - "StaticNat": 'NuageVsp', - "SourceNat": 'NuageVsp', - "Firewall": 'NuageVsp' }, - }, - "network_pr": { - "name": "Test Network", - "displaytext": "Test Network", - "netmask": '255.255.255.0' - }, - "fw_rule_pr": { - "startport": 1, - "endport": 6000, - "cidr": '0.0.0.0/0', - # Any network (For creating FW rule) - "protocol": "TCP" - }, - "virtual_machine_pr": { - "displayname": "Test VM", - "username": "root", - "password": "password", - "ssh_port": 22, - "hypervisor": 'kvm', - # Hypervisor type should be same as - # hypervisor type of cluster - "privateport": 22, - "publicport": 22, - "protocol": 'TCP', - "userdata": "This is sample data", - }, - "template_pr": { - "displaytext": "Cent OS Template", - "name": "Cent OS Template", - "passwordenabled": True, - }, - "ostype_pr": 'CentOS 5.5 (64-bit)', - + "vpc_offering_lb": { + "name": 'Nuage VSP VPC offering with Lb', + "displaytext": 'Nuage VSP VPC offering with Lb', + "supportedservices": 'Dhcp,Lb,StaticNat,SourceNat,NetworkACL,Connectivity,UserData', + "serviceProviderList": { + "Dhcp": "NuageVsp", + "Lb": "InternalLbVm", + "StaticNat": "NuageVsp", + "SourceNat": "NuageVsp", + "NetworkACL": "NuageVsp", + "Connectivity": "NuageVsp", + "UserData": "VpcVirtualRouter" + } + } + } } diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index e2f4a2c864..4ceb7ace9d 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -4673,7 +4673,7 @@ def __init__(self, items): @classmethod def create(cls, apiclient, services, name=None, sourceport=None, instanceport=22, algorithm="roundrobin", scheme="internal", - sourcenetworkid=None, networkid=None): + sourcenetworkid=None, networkid=None, sourceipaddress=None): """Create Application Load Balancer""" cmd = createLoadBalancer.createLoadBalancerCmd() @@ -4712,6 +4712,11 @@ def create(cls, apiclient, services, name=None, sourceport=None, elif networkid: cmd.networkid = networkid + if "sourceipaddress" in services: + cmd.sourceipaddress = services["sourceipaddress"] + elif sourceipaddress: + cmd.sourceipaddress = sourceipaddress + return LoadBalancerRule(apiclient.createLoadBalancer(cmd).__dict__) def delete(self, apiclient): From 3e2c18a4bb52f0c588469bedf2cb1b171bff760d Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 22 Jan 2016 10:04:57 +0000 Subject: [PATCH 085/203] Refactor console proxy default network retrieval. It is now broken into separate methods for more readability and flexibility. Each zone type (basic, advanced) has its own method for getting the default network when creating the VM. --- .../consoleproxy/ConsoleProxyManagerImpl.java | 90 ++++++++-- .../consoleproxy/ConsoleProxyManagerTest.java | 159 ++++++++++++++++++ 2 files changed, 231 insertions(+), 18 deletions(-) diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index f3766c339c..af5f85d8bb 100644 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -41,6 +41,7 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; @@ -666,35 +667,88 @@ public ConsoleProxyVO startNew(long dataCenterId) throws ConcurrentOperationExce return null; } - protected Map createProxyInstance(long dataCenterId, VMTemplateVO template) throws ConcurrentOperationException { - - long id = _consoleProxyDao.getNextInSequence(Long.class, "id"); - String name = VirtualMachineName.getConsoleProxyName(id, _instance); - DataCenterVO dc = _dcDao.findById(dataCenterId); - Account systemAcct = _accountMgr.getSystemAccount(); + /** + * Get the default network for the console proxy VM, based on the zone it is in. Delegates to + * either {@link #getDefaultNetworkForZone(DataCenter)} or {@link #getDefaultNetworkForAdvancedSGZone(DataCenter)}, + * depending on the zone network type and whether or not security groups are enabled in the zone. + * @param dc - The zone (DataCenter) of the console proxy VM. + * @return The default network for use with the console proxy VM. + */ + protected NetworkVO getDefaultNetworkForCreation(DataCenter dc) { + if (dc.getNetworkType() == NetworkType.Advanced) { + return getDefaultNetworkForAdvancedZone(dc); + } else { + return getDefaultNetworkForBasicZone(dc); + } + } - DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); + /** + * Get default network for a console proxy VM starting up in an advanced zone. If the zone + * is security group-enabled, the first network found that supports SG services is returned. + * If the zone is not SG-enabled, the Public network is returned. + * @param dc - The zone. + * @return The selected default network. + * @throws CloudRuntimeException - If the zone is not a valid choice or a network couldn't be found. + */ + protected NetworkVO getDefaultNetworkForAdvancedZone(DataCenter dc) { + if (dc.getNetworkType() != NetworkType.Advanced) { + throw new CloudRuntimeException("Zone " + dc + " is not advanced."); + } - NetworkVO defaultNetwork = null; - if (dc.getNetworkType() == NetworkType.Advanced && dc.isSecurityGroupEnabled()) { - List networks = _networkDao.listByZoneSecurityGroup(dataCenterId); - if (networks == null || networks.size() == 0) { + if (dc.isSecurityGroupEnabled()) { + List networks = _networkDao.listByZoneSecurityGroup(dc.getId()); + if (CollectionUtils.isEmpty(networks)) { throw new CloudRuntimeException("Can not found security enabled network in SG Zone " + dc); } - defaultNetwork = networks.get(0); - } else { + + return networks.get(0); + } + else { TrafficType defaultTrafficType = TrafficType.Public; - if (dc.getNetworkType() == NetworkType.Basic || dc.isSecurityGroupEnabled()) { - defaultTrafficType = TrafficType.Guest; - } - List defaultNetworks = _networkDao.listByZoneAndTrafficType(dataCenterId, defaultTrafficType); + List defaultNetworks = _networkDao.listByZoneAndTrafficType(dc.getId(), defaultTrafficType); // api should never allow this situation to happen if (defaultNetworks.size() != 1) { throw new CloudRuntimeException("Found " + defaultNetworks.size() + " networks of type " + defaultTrafficType + " when expect to find 1"); } - defaultNetwork = defaultNetworks.get(0); + + return defaultNetworks.get(0); } + } + + /** + * Get default network for console proxy VM for starting up in a basic zone. Basic zones select + * the Guest network whether or not the zone is SG-enabled. + * @param dc - The zone. + * @return The default network according to the zone's network selection rules. + * @throws CloudRuntimeException - If the zone is not a valid choice or a network couldn't be found. + */ + protected NetworkVO getDefaultNetworkForBasicZone(DataCenter dc) { + if (dc.getNetworkType() != NetworkType.Basic) { + throw new CloudRuntimeException("Zone " + dc + "is not basic."); + } + + TrafficType defaultTrafficType = TrafficType.Guest; + List defaultNetworks = _networkDao.listByZoneAndTrafficType(dc.getId(), defaultTrafficType); + + // api should never allow this situation to happen + if (defaultNetworks.size() != 1) { + throw new CloudRuntimeException("Found " + defaultNetworks.size() + " networks of type " + defaultTrafficType + " when expect to find 1"); + } + + return defaultNetworks.get(0); + } + + protected Map createProxyInstance(long dataCenterId, VMTemplateVO template) throws ConcurrentOperationException { + + long id = _consoleProxyDao.getNextInSequence(Long.class, "id"); + String name = VirtualMachineName.getConsoleProxyName(id, _instance); + DataCenterVO dc = _dcDao.findById(dataCenterId); + Account systemAcct = _accountMgr.getSystemAccount(); + + DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); + + NetworkVO defaultNetwork = getDefaultNetworkForCreation(dc); List offerings = _networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemControlNetwork, NetworkOffering.SystemManagementNetwork); diff --git a/server/test/com/cloud/consoleproxy/ConsoleProxyManagerTest.java b/server/test/com/cloud/consoleproxy/ConsoleProxyManagerTest.java index fd12d23a52..76a3f42766 100644 --- a/server/test/com/cloud/consoleproxy/ConsoleProxyManagerTest.java +++ b/server/test/com/cloud/consoleproxy/ConsoleProxyManagerTest.java @@ -17,7 +17,17 @@ package com.cloud.consoleproxy; +import static org.mockito.AdditionalMatchers.not; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Collections; + import org.apache.log4j.Logger; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -25,7 +35,15 @@ import org.mockito.MockitoAnnotations; import org.springframework.test.util.ReflectionTestUtils; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.ConsoleProxyVO; public class ConsoleProxyManagerTest { @@ -37,13 +55,22 @@ public class ConsoleProxyManagerTest { @Mock ConsoleProxyVO proxyVO; @Mock + DataCenterDao _dcDao; + @Mock + NetworkDao _networkDao; + @Mock ConsoleProxyManagerImpl cpvmManager; @Before public void setup() throws Exception { MockitoAnnotations.initMocks(this); ReflectionTestUtils.setField(cpvmManager, "_allocProxyLock", globalLock); + ReflectionTestUtils.setField(cpvmManager, "_dcDao", _dcDao); + ReflectionTestUtils.setField(cpvmManager, "_networkDao", _networkDao); Mockito.doCallRealMethod().when(cpvmManager).expandPool(Mockito.anyLong(), Mockito.anyObject()); + Mockito.doCallRealMethod().when(cpvmManager).getDefaultNetworkForCreation(Mockito.any(DataCenter.class)); + Mockito.doCallRealMethod().when(cpvmManager).getDefaultNetworkForAdvancedZone(Mockito.any(DataCenter.class)); + Mockito.doCallRealMethod().when(cpvmManager).getDefaultNetworkForBasicZone(Mockito.any(DataCenter.class)); } @Test @@ -87,4 +114,136 @@ public void testExisingCPVMStartFailure() throws Exception { cpvmManager.expandPool(new Long(1), new Object()); } + + @Test + public void getDefaultNetworkForAdvancedNonSG() { + DataCenterVO dc = mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); + when(dc.isSecurityGroupEnabled()).thenReturn(false); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Public))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Public)))) + .thenReturn(Collections.singletonList(badNetwork)); + + when(_networkDao.listByZoneSecurityGroup(anyLong())) + .thenReturn(Collections.singletonList(badNetwork)); + + NetworkVO returnedNetwork = cpvmManager.getDefaultNetworkForAdvancedZone(dc); + + Assert.assertNotNull(returnedNetwork); + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + @Test + public void getDefaultNetworkForAdvancedSG() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), any(TrafficType.class))) + .thenReturn(Collections.singletonList(badNetwork)); + + when(_networkDao.listByZoneSecurityGroup(anyLong())) + .thenReturn(Collections.singletonList(network)); + + NetworkVO returnedNetwork = cpvmManager.getDefaultNetworkForAdvancedZone(dc); + + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + @Test + public void getDefaultNetworkForBasicNonSG() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Basic); + when(dc.isSecurityGroupEnabled()).thenReturn(false); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Guest))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Guest)))) + .thenReturn(Collections.singletonList(badNetwork)); + + NetworkVO returnedNetwork = cpvmManager.getDefaultNetworkForBasicZone(dc); + Assert.assertNotNull(returnedNetwork); + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + @Test + public void getDefaultNetworkForBasicSG() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Basic); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Guest))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Guest)))) + .thenReturn(Collections.singletonList(badNetwork)); + + NetworkVO returnedNetwork = cpvmManager.getDefaultNetworkForBasicZone(dc); + + Assert.assertNotNull(returnedNetwork); + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + //also test invalid input + @Test(expected=CloudRuntimeException.class) + public void getDefaultNetworkForBasicSGWrongZoneType() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Guest))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Guest)))) + .thenReturn(Collections.singletonList(badNetwork)); + + cpvmManager.getDefaultNetworkForBasicZone(dc); + } + + @Test(expected=CloudRuntimeException.class) + public void getDefaultNetworkForAdvancedWrongZoneType() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Basic); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), any(TrafficType.class))) + .thenReturn(Collections.singletonList(badNetwork)); + + when(_networkDao.listByZoneSecurityGroup(anyLong())) + .thenReturn(Collections.singletonList(network)); + + cpvmManager.getDefaultNetworkForAdvancedZone(dc); + } } From 897187515bd2186a535561e2c78f227e600eaec6 Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 22 Jan 2016 10:07:01 +0000 Subject: [PATCH 086/203] Refactor ssvm default network retrieval. It is now broken into separate methods based on zone. Each zone type (basic, advanced) has its own method to select the default network when starting the VM. --- .../SecondaryStorageManagerImpl.java | 92 +++++++-- .../SecondaryStorageManagerTest.java | 192 ++++++++++++++++++ 2 files changed, 264 insertions(+), 20 deletions(-) create mode 100644 services/secondary-storage/controller/test/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerTest.java diff --git a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java index 2ff54c8dc9..d127a0e6bb 100644 --- a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java @@ -43,6 +43,7 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; import org.apache.cloudstack.utils.identity.ManagementServerNode; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; @@ -521,6 +522,76 @@ public SecondaryStorageVmVO startNew(long dataCenterId, SecondaryStorageVm.Role return null; } + /** + * Get the default network for the secondary storage VM, based on the zone it is in. Delegates to + * either {@link #getDefaultNetworkForZone(DataCenter)} or {@link #getDefaultNetworkForAdvancedSGZone(DataCenter)}, + * depending on the zone network type and whether or not security groups are enabled in the zone. + * @param dc - The zone (DataCenter) of the secondary storage VM. + * @return The default network for use with the secondary storage VM. + */ + protected NetworkVO getDefaultNetworkForCreation(DataCenter dc) { + if (dc.getNetworkType() == NetworkType.Advanced) { + return getDefaultNetworkForAdvancedZone(dc); + } else { + return getDefaultNetworkForBasicZone(dc); + } + } + + /** + * Get default network for a secondary storage VM starting up in an advanced zone. If the zone + * is security group-enabled, the first network found that supports SG services is returned. + * If the zone is not SG-enabled, the Public network is returned. + * @param dc - The zone. + * @return The selected default network. + * @throws CloudRuntimeException - If the zone is not a valid choice or a network couldn't be found. + */ + protected NetworkVO getDefaultNetworkForAdvancedZone(DataCenter dc) { + if (dc.getNetworkType() != NetworkType.Advanced) { + throw new CloudRuntimeException("Zone " + dc + " is not advanced."); + } + + if (dc.isSecurityGroupEnabled()) { + List networks = _networkDao.listByZoneSecurityGroup(dc.getId()); + if (CollectionUtils.isEmpty(networks)) { + throw new CloudRuntimeException("Can not found security enabled network in SG Zone " + dc); + } + + return networks.get(0); + } + else { + TrafficType defaultTrafficType = TrafficType.Public; + List defaultNetworks = _networkDao.listByZoneAndTrafficType(dc.getId(), defaultTrafficType); + // api should never allow this situation to happen + if (defaultNetworks.size() != 1) { + throw new CloudRuntimeException("Found " + defaultNetworks.size() + " networks of type " + defaultTrafficType + " when expect to find 1"); + } + + return defaultNetworks.get(0); + } + } + + /** + * Get default network for secondary storage VM for starting up in a basic zone. Basic zones select + * the Guest network whether or not the zone is SG-enabled. + * @param dc - The zone. + * @return The default network according to the zone's network selection rules. + * @throws CloudRuntimeException - If the zone is not a valid choice or a network couldn't be found. + */ + protected NetworkVO getDefaultNetworkForBasicZone(DataCenter dc) { + if (dc.getNetworkType() != NetworkType.Basic) { + throw new CloudRuntimeException("Zone " + dc + "is not basic."); + } + + TrafficType defaultTrafficType = TrafficType.Guest; + List defaultNetworks = _networkDao.listByZoneAndTrafficType(dc.getId(), defaultTrafficType); + // api should never allow this situation to happen + if (defaultNetworks.size() != 1) { + throw new CloudRuntimeException("Found " + defaultNetworks.size() + " networks of type " + defaultTrafficType + " when expect to find 1"); + } + + return defaultNetworks.get(0); + } + protected Map createSecStorageVmInstance(long dataCenterId, SecondaryStorageVm.Role role) { DataStore secStore = _dataStoreMgr.getImageStore(dataCenterId); if (secStore == null) { @@ -536,26 +607,7 @@ protected Map createSecStorageVmInstance(long dataCenterId, Seco DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); DataCenter dc = _dcDao.findById(plan.getDataCenterId()); - NetworkVO defaultNetwork = null; - if (dc.getNetworkType() == NetworkType.Advanced && dc.isSecurityGroupEnabled()) { - List networks = _networkDao.listByZoneSecurityGroup(dataCenterId); - if (networks == null || networks.size() == 0) { - throw new CloudRuntimeException("Can not found security enabled network in SG Zone " + dc); - } - defaultNetwork = networks.get(0); - } else { - TrafficType defaultTrafficType = TrafficType.Public; - - if (dc.getNetworkType() == NetworkType.Basic || dc.isSecurityGroupEnabled()) { - defaultTrafficType = TrafficType.Guest; - } - List defaultNetworks = _networkDao.listByZoneAndTrafficType(dataCenterId, defaultTrafficType); - // api should never allow this situation to happen - if (defaultNetworks.size() != 1) { - throw new CloudRuntimeException("Found " + defaultNetworks.size() + " networks of type " + defaultTrafficType + " when expect to find 1"); - } - defaultNetwork = defaultNetworks.get(0); - } + NetworkVO defaultNetwork = getDefaultNetworkForCreation(dc); List offerings = null; if (_sNwMgr.isStorageIpRangeAvailable(dataCenterId)) { diff --git a/services/secondary-storage/controller/test/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerTest.java b/services/secondary-storage/controller/test/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerTest.java new file mode 100644 index 0000000000..c42f2b130c --- /dev/null +++ b/services/secondary-storage/controller/test/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerTest.java @@ -0,0 +1,192 @@ +// 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.secondarystorage; + +import java.util.Collections; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.utils.exception.CloudRuntimeException; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.when; +import static org.mockito.AdditionalMatchers.not; +import static org.mockito.Mockito.eq; + +public class SecondaryStorageManagerTest { + @Mock + DataCenterDao _dcDao; + + @Mock + NetworkDao _networkDao; + + @InjectMocks + SecondaryStorageManagerImpl _ssMgr = new SecondaryStorageManagerImpl(); + + @Before + public void initMocks() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void getDefaultNetworkForAdvancedNonSG() { + DataCenterVO dc = mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); + when(dc.isSecurityGroupEnabled()).thenReturn(false); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Public))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Public)))) + .thenReturn(Collections.singletonList(badNetwork)); + + when(_networkDao.listByZoneSecurityGroup(anyLong())) + .thenReturn(Collections.singletonList(badNetwork)); + + NetworkVO returnedNetwork = _ssMgr.getDefaultNetworkForAdvancedZone(dc); + + Assert.assertNotNull(returnedNetwork); + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + @Test + public void getDefaultNetworkForAdvancedSG() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), any(TrafficType.class))) + .thenReturn(Collections.singletonList(badNetwork)); + + when(_networkDao.listByZoneSecurityGroup(anyLong())) + .thenReturn(Collections.singletonList(network)); + + NetworkVO returnedNetwork = _ssMgr.getDefaultNetworkForAdvancedZone(dc); + + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + @Test + public void getDefaultNetworkForBasicNonSG() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Basic); + when(dc.isSecurityGroupEnabled()).thenReturn(false); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Guest))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Guest)))) + .thenReturn(Collections.singletonList(badNetwork)); + + NetworkVO returnedNetwork = _ssMgr.getDefaultNetworkForBasicZone(dc); + + Assert.assertNotNull(returnedNetwork); + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + @Test + public void getDefaultNetworkForBasicSG() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Basic); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Guest))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Guest)))) + .thenReturn(Collections.singletonList(badNetwork)); + + NetworkVO returnedNetwork = _ssMgr.getDefaultNetworkForBasicZone(dc); + + Assert.assertNotNull(returnedNetwork); + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + //also test invalid input + @Test(expected=CloudRuntimeException.class) + public void getDefaultNetworkForBasicSGWrongZoneType() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Guest))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Guest)))) + .thenReturn(Collections.singletonList(badNetwork)); + + _ssMgr.getDefaultNetworkForBasicZone(dc); + } + + @Test(expected=CloudRuntimeException.class) + public void getDefaultNetworkForAdvancedWrongZoneType() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Basic); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), any(TrafficType.class))) + .thenReturn(Collections.singletonList(badNetwork)); + + when(_networkDao.listByZoneSecurityGroup(anyLong())) + .thenReturn(Collections.singletonList(network)); + + _ssMgr.getDefaultNetworkForAdvancedZone(dc); + } +} From 2a88b11132780a2adba63de519e4c459ee7c3cea Mon Sep 17 00:00:00 2001 From: dahn Date: Tue, 5 Apr 2016 13:28:39 +0200 Subject: [PATCH 087/203] CLOUDSTACK-9336 surround the execution of baremetal-vr.py with condition --- systemvm/patches/debian/config/etc/rc.local | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/systemvm/patches/debian/config/etc/rc.local b/systemvm/patches/debian/config/etc/rc.local index 18e7cd1d43..3b19218cdc 100755 --- a/systemvm/patches/debian/config/etc/rc.local +++ b/systemvm/patches/debian/config/etc/rc.local @@ -42,7 +42,10 @@ then echo 1000000 > /proc/sys/net/nf_conntrack_max fi -python /opt/cloud/bin/baremetal-vr.py & +if [ "$router" != "" ] +then + python /opt/cloud/bin/baremetal-vr.py & +fi date > /var/cache/cloud/boot_up_done logger -t cloud "Boot up process done" From 4aae0515588eafe880d33c33e875e257fdb9403f Mon Sep 17 00:00:00 2001 From: nvazquez Date: Thu, 31 Mar 2016 09:12:07 -0700 Subject: [PATCH 088/203] CLOUDSTACK-9333: Exclude clusters for OVF operations --- .../src/com/cloud/capacity/CapacityManager.java | 10 ++++++++++ .../storage/endpoint/DefaultEndPointSelector.java | 12 +++++++++--- .../src/com/cloud/capacity/CapacityManagerImpl.java | 2 +- setup/db/db/schema-481to490.sql | 3 +++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/engine/components-api/src/com/cloud/capacity/CapacityManager.java b/engine/components-api/src/com/cloud/capacity/CapacityManager.java index 51f73326d5..3db6e57815 100644 --- a/engine/components-api/src/com/cloud/capacity/CapacityManager.java +++ b/engine/components-api/src/com/cloud/capacity/CapacityManager.java @@ -53,6 +53,16 @@ public interface CapacityManager { "0.85", "Percentage (as a value between 0 and 1) of allocated storage utilization above which allocators will disable using the pool for low allocated storage available.", true, ConfigKey.Scope.Zone); + static final ConfigKey StorageOperationsExcludeCluster = + new ConfigKey( + Boolean.class, + "cluster.storage.operations.exclude", + "Advanced", + "false", + "Exclude cluster from storage operations", + true, + ConfigKey.Scope.Cluster, + null); public boolean releaseVmCapacity(VirtualMachine vm, boolean moveFromReserved, boolean moveToReservered, Long hostId); diff --git a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java index d38aaed80e..012d6b3fc3 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java +++ b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java @@ -44,6 +44,7 @@ import org.apache.cloudstack.storage.LocalHostEndpoint; import org.apache.cloudstack.storage.RemoteHostEndPoint; +import com.cloud.capacity.CapacityManager; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; @@ -64,9 +65,13 @@ public class DefaultEndPointSelector implements EndPointSelector { private static final Logger s_logger = Logger.getLogger(DefaultEndPointSelector.class); @Inject HostDao hostDao; - private final String findOneHostOnPrimaryStorage = - "select h.id from host h, storage_pool_host_ref s where h.status = 'Up' and h.type = 'Routing' and h.resource_state = 'Enabled' and" - + " h.id = s.host_id and s.pool_id = ? "; + private final String findOneHostOnPrimaryStorage = "select t.id from " + + "(select h.id, cd.value " + + "from host h join storage_pool_host_ref s on h.id = s.host_id " + + "join cluster c on c.id=h.cluster_id " + + "left join cluster_details cd on c.id=cd.cluster_id and cd.name='" + CapacityManager.StorageOperationsExcludeCluster.key() + "' " + + "where h.status = 'Up' and h.type = 'Routing' and h.resource_state = 'Enabled' and s.pool_id = ? "; + private String findOneHypervisorHostInScope = "select h.id from host h where h.status = 'Up' and h.hypervisor_type is not null "; protected boolean moveBetweenPrimaryImage(DataStore srcStore, DataStore destStore) { @@ -115,6 +120,7 @@ protected EndPoint findEndPointInScope(Scope scope, String sqlBase, Long poolId) sbuilder.append(scope.getScopeId()); } // TODO: order by rand() is slow if there are lot of hosts + sbuilder.append(") t where t.value<>'true' or t.value is null"); //Added for exclude cluster's subquery sbuilder.append(" ORDER by rand() limit 1"); String sql = sbuilder.toString(); HostVO host = null; diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index 55ed9171c9..ac97bc96ab 100644 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -1082,6 +1082,6 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { return new ConfigKey[] {CpuOverprovisioningFactor, MemOverprovisioningFactor, StorageCapacityDisableThreshold, StorageOverprovisioningFactor, - StorageAllocatedCapacityDisableThreshold}; + StorageAllocatedCapacityDisableThreshold, StorageOperationsExcludeCluster}; } } diff --git a/setup/db/db/schema-481to490.sql b/setup/db/db/schema-481to490.sql index 75df7d0eb2..b9a8b2fb93 100644 --- a/setup/db/db/schema-481to490.sql +++ b/setup/db/db/schema-481to490.sql @@ -410,3 +410,6 @@ VIEW `user_vm_view` AS AND (`custom_speed`.`name` = 'CpuSpeed')))) LEFT JOIN `user_vm_details` `custom_ram_size` ON (((`custom_ram_size`.`vm_id` = `vm_instance`.`id`) AND (`custom_ram_size`.`name` = 'memory')))); + +-- Add cluster.storage.operations.exclude property +INSERT INTO `cloud`.`configuration` (`category`, `instance`, `component`, `name`, `description`, `default_value`, `updated`, `scope`, `is_dynamic`) VALUES ('Advanced', 'DEFAULT', 'CapacityManager', 'cluster.storage.operations.exclude', 'Exclude cluster from storage operations', 'false', now(), 'Cluster', '1'); From 28b289d9c080269074d907d94da56517dbd5cd11 Mon Sep 17 00:00:00 2001 From: sanjeevn Date: Fri, 8 Jan 2016 18:49:27 +0530 Subject: [PATCH 089/203] New test to validate starting vm after nic removal and attach Bug-Id: CLOUDSTACK-9219 Incorporated review comments from GabrielBrascher --- .../component/test_add_remove_network.py | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/test/integration/component/test_add_remove_network.py b/test/integration/component/test_add_remove_network.py index 55d0b0ed97..b76197dac7 100644 --- a/test/integration/component/test_add_remove_network.py +++ b/test/integration/component/test_add_remove_network.py @@ -1021,6 +1021,103 @@ def test_29_remove_nic_CS22503(self): self.fail("Failed to delete the nic from vm") return + @attr(tags=["advanced"], required_hardware="true") + def test_30_remove_nic_reattach(self): + """ + Test to verify vm start after NIC removal and reattach + + # 1.Create vm which has 3 nics(e.g. #0,#1,#2) + # 2.Stop the vm + # 3.Remove second nic(#1) + # 4.Add/Reattach same network(#1) + # 5.Start the instance + """ + self.ntwk2 = Network.create( + self.apiclient, + self.services["isolated_network"], + self.account.name, + self.account.domainid, + networkofferingid=self.isolated_network_offering.id + ) + self.ntwk3 = Network.create( + self.apiclient, + self.services["isolated_network"], + self.account.name, + self.account.domainid, + networkofferingid=self.isolated_network_offering.id + ) + self.test_vm = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + mode=self.zone.networktype, + networkids=[self.isolated_network.id, self.ntwk2.id, self.ntwk3.id] + ) + self.assertIsNotNone(self.test_vm, "Failed to create vm with 3 nics") + map(lambda x: self.cleanup.append(x), [self.test_vm, self.ntwk2, self.ntwk3]) + vm_res = VirtualMachine.list( + self.apiclient, + id=self.test_vm.id + ) + self.assertEqual(validateList(vm_res)[0], PASS, "Invalid list vm response") + self.nics = vm_res[0].nic + self.assertEqual( + validateList(self.nics)[0], + PASS, + "vm response does not contain nics info" + ) + self.assertEqual(len(self.nics), 3, "Not all nics found in vm response") + self.test_vm.stop(self.apiclient) + vm_res2 = VirtualMachine.list( + self.apiclient, + id=self.test_vm.id + ) + self.assertEqual(validateList(vm_res2)[0], PASS, "Invalid response") + self.assertEqual( + vm_res2[0].state, + "Stopped", + "VM did not stop properly" + ) + + """ + get the network id of the nic which we are remove from the nic, so that we can + use that network id for reattach + """ + nic_to_attach = [x for x in [self.isolated_network, self.ntwk2, self.ntwk3]\ + if x.id == self.nics[1].networkid] + self.assertEqual(validateList(nic_to_attach)[0], PASS, "No matching nics") + self.assertEqual(len(nic_to_attach), 1, "More than one nic in same network") + try: + self.test_vm.remove_nic(self.apiclient, nicId=self.nics[1].id) + self.test_vm.add_nic( + self.apiclient, + nic_to_attach[0].id + ) + self.test_vm.start(self.apiclient) + except Exception as e: + self.fail("Failed to start vm after nic removal and attachment") + vm_res3 = VirtualMachine.list(self.apiclient, id=self.test_vm.id) + self.assertEqual( + validateList(vm_res3)[0], + PASS, + "Invalid listvm response after nic detach and attach" + ) + self.assertEqual( + vm_res3[0].state, + "Running", + "VM didn't come to running state after nic detach and attach" + ) + vm_nics = vm_res3[0].nic + self.assertEqual(validateList(vm_nics)[0], PASS, "Invalid nics after vm stop/start") + self.assertEqual( + len(vm_nics), + 3, + "Nic is not attached/detected" + ) + return + class TestUpdateVirtualMachineNIC(cloudstackTestCase): @classmethod From 34ec3c31972bf8301c8af72995cd7569891c5979 Mon Sep 17 00:00:00 2001 From: sanjeevn Date: Wed, 6 Jan 2016 11:33:58 +0530 Subject: [PATCH 090/203] New marvin test to validate CLOUDSTACK-9215 Bug-Id: CLOUDSTACK-9215 Adding few validations as per the review comments in PR#1316 Bug-Id: CLOUDSTACK-9215 --- test/integration/component/maint/test_vpc.py | 400 +++++++++++++++++++ 1 file changed, 400 insertions(+) create mode 100644 test/integration/component/maint/test_vpc.py diff --git a/test/integration/component/maint/test_vpc.py b/test/integration/component/maint/test_vpc.py new file mode 100644 index 0000000000..5973f85dd8 --- /dev/null +++ b/test/integration/component/maint/test_vpc.py @@ -0,0 +1,400 @@ +# 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. + +""" Component tests for VPC functionality +""" +# Import Local Modules +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.lib.utils import cleanup_resources, validateList, get_process_status +from marvin.lib.base import (Account, + VPC, + VpcOffering, + VirtualMachine, + ServiceOffering, + Network, + NetworkOffering, + Configurations, + Router) +from marvin.lib.common import (get_domain, + get_zone, + get_template) +from marvin.sshClient import SshClient +from marvin.codes import PASS +import re +import time + +class Services: + + """Test VPC services + """ + + def __init__(self): + self.services = { + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended for unique + # username + "password": "password", + }, + "domain_admin": { + "email": "domain@admin.com", + "firstname": "Domain", + "lastname": "Admin", + "username": "DoA", + # Random characters are appended for unique + # username + "password": "password", + }, + "service_offering": { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 128, + }, + "network_offering": { + "name": 'VPC Network offering', + "displaytext": 'VPC Network off', + "guestiptype": 'Isolated', + "supportedservices": 'Vpn,Dhcp,Dns,SourceNat,PortForwarding,Lb,UserData,StaticNat,NetworkACL', + "traffictype": 'GUEST', + "availability": 'Optional', + "useVpc": 'on', + "serviceProviderList": { + "Vpn": 'VpcVirtualRouter', + "Dhcp": 'VpcVirtualRouter', + "Dns": 'VpcVirtualRouter', + "SourceNat": 'VpcVirtualRouter', + "PortForwarding": 'VpcVirtualRouter', + "Lb": 'VpcVirtualRouter', + "UserData": 'VpcVirtualRouter', + "StaticNat": 'VpcVirtualRouter', + "NetworkACL": 'VpcVirtualRouter' + }, + }, + "network_offering_no_lb": { + "name": 'VPC Network offering', + "displaytext": 'VPC Network off', + "guestiptype": 'Isolated', + "supportedservices": 'Vpn,Dhcp,Dns,SourceNat,PortForwarding,UserData,StaticNat,NetworkACL', + "traffictype": 'GUEST', + "availability": 'Optional', + "useVpc": 'on', + "serviceProviderList": { + "Vpn": 'VpcVirtualRouter', + "Dhcp": 'VpcVirtualRouter', + "Dns": 'VpcVirtualRouter', + "SourceNat": 'VpcVirtualRouter', + "PortForwarding": 'VpcVirtualRouter', + "UserData": 'VpcVirtualRouter', + "StaticNat": 'VpcVirtualRouter', + "NetworkACL": 'VpcVirtualRouter' + }, + }, + "vpc_offering": { + "name": 'VPC off', + "displaytext": 'VPC off', + "supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding,Vpn,Lb,UserData,StaticNat,NetworkACL', + }, + "vpc": { + "name": "TestVPC", + "displaytext": "TestVPC", + "cidr": '10.0.0.1/24' + }, + "vpc_no_name": { + "displaytext": "TestVPC", + "cidr": '10.0.0.1/24' + }, + "network": { + "name": "Test Network", + "displaytext": "Test Network", + "netmask": '255.255.255.0' + }, + "lbrule": { + "name": "SSH", + "alg": "leastconn", + # Algorithm used for load balancing + "privateport": 22, + "publicport": 2222, + "openfirewall": False, + "startport": 22, + "endport": 2222, + "protocol": "TCP", + "cidrlist": '0.0.0.0/0', + }, + "natrule": { + "privateport": 22, + "publicport": 22, + "startport": 22, + "endport": 22, + "protocol": "TCP", + "cidrlist": '0.0.0.0/0', + }, + "fw_rule": { + "startport": 1, + "endport": 6000, + "cidr": '0.0.0.0/0', + # Any network (For creating FW rule) + "protocol": "TCP" + }, + "icmp_rule": { + "icmptype": -1, + "icmpcode": -1, + "cidrlist": '0.0.0.0/0', + "protocol": "ICMP" + }, + "virtual_machine": { + "displayname": "Test VM", + "username": "root", + "password": "password", + "ssh_port": 22, + # Hypervisor type should be same as + # hypervisor type of cluster + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "domain": { + "name": "TestDomain" + }, + "vpn_customer_gw": { + "ipsecpsk": "s2svpn", + "ikepolicy": "3des-md5", + "ikelifetime": "86400", + "esppolicy": "3des-md5", + "esplifetime": "3600", + }, + "ostype": 'CentOS 5.3 (64-bit)', + # Cent OS 5.3 (64 bit) + "sleep": 90, + "timeout": 10, + "mode": 'advanced' + } + + +class TestVPC(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.testClient = super(TestVPC, cls).getClsTestClient() + cls.api_client = cls.testClient.getApiClient() + cls.hypervisor = cls.testClient.getHypervisorInfo() + cls.mgtSvrDetails = cls.config.__dict__["mgtSvr"][0].__dict__ + cls.unsupportedHypervisor = False + if cls.hypervisor.lower() == 'hyperv': + cls._cleanup = [] + cls.unsupportedHypervisor = True + return + cls.services = Services().services + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client) + cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.services["virtual_machine"]["template"] = cls.template.id + + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) + cls.vpc_off = VpcOffering.create( + cls.api_client, + cls.services["vpc_offering"] + ) + cls.vpc_off.update(cls.api_client, state='Enabled') + cls._cleanup = [ + cls.service_offering, + ] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.account = Account.create( + self.apiclient, + self.services["account"], + admin=True, + domainid=self.domain.id + ) + self.cleanup = [] + self.cleanup.insert(0, self.account) + if self.unsupportedHypervisor: + self.skipTest("not supported on %s" % self.hypervisor) + return + + def tearDown(self): + try: + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + self.debug("Warning: Exception during cleanup : %s" % e) + return + + def updateConfigurAndRestart(self, name, value): + Configurations.update(self.apiclient, name, value) + self.RestartServers() + time.sleep(self.services["sleep"]) + + def RestartServers(self): + """ Restart management + server and usage server """ + sshClient = SshClient( + self.mgtSvrDetails["mgtSvrIp"], + 22, + self.mgtSvrDetails["user"], + self.mgtSvrDetails["passwd"] + ) + command = "service cloudstack-management restart" + sshClient.execute(command) + return + + @attr(tags=["advanced", "intervlan", "dvs", "test"], required_hardware="true") + def test_01_create_tier_Vmxnet3(self): + """ + Test to create vpc tier with nic type as Vmxnet3 + #1.Set global setting parameter "vmware.systemvm.nic.device.type" + to "Vmxnet3" + #2.Create VPC + #3.Create one tier + #4.Deploy one guest vm in the tier created in step3 + """ + if self.hypervisor.lower() not in ['vmware']: + self.skipTest("This test can only run on vmware setup") + + nic_types = Configurations.list( + self.apiclient, + name="vmware.systemvm.nic.device.type" + ) + self.assertEqual(validateList(nic_types)[0], PASS, "Invalid list config") + nic_type = nic_types[0].value + reset = False + if nic_type.lower() != "vmxnet3": + self.updateConfigurAndRestart("vmware.systemvm.nic.device.type", "Vmxnet3") + reset = True + + self.services["vpc"]["cidr"] = "10.1.1.1/16" + self.debug("creating a VPC network in the account: %s" % + self.account.name) + try: + vpc = VPC.create( + self.apiclient, + self.services["vpc"], + vpcofferingid=self.vpc_off.id, + zoneid=self.zone.id, + account=self.account.name, + domainid=self.account.domainid + ) + vpc_res = VPC.list(self.apiclient, id=vpc.id) + self.assertEqual(validateList(vpc_res)[0], PASS, "Invalid response from listvpc") + + self.network_offering = NetworkOffering.create( + self.apiclient, + self.services["network_offering"], + conservemode=False + ) + # Enable Network offering + self.network_offering.update(self.apiclient, state='Enabled') + self.cleanup.append(self.network_offering) + + gateway = vpc.cidr.split('/')[0] + # Split the cidr to retrieve gateway + # for eg. cidr = 10.0.0.1/24 + # Gateway = 10.0.0.1 + # Creating network using the network offering created + self.debug("Creating network with network offering: %s" % + self.network_offering.id) + network = Network.create( + self.apiclient, + self.services["network"], + accountid=self.account.name, + domainid=self.account.domainid, + networkofferingid=self.network_offering.id, + zoneid=self.zone.id, + gateway=gateway, + vpcid=vpc.id + ) + self.debug("Created network with ID: %s" % network.id) + vm = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + networkids=[str(network.id)] + ) + self.assertIsNotNone(vm, "VM creation failed") + self.debug("Deployed VM in network: %s" % network.id) + vm_res = VirtualMachine.list(self.apiclient, id=vm.id) + self.assertEqual( + validateList(vm_res)[0], + PASS, + "list vm returned invalid response" + ) + vr_res = Router.list( + self.apiclient, + vpcid=vpc.id, + listall="true" + ) + self.assertEqual(validateList(vr_res)[0], PASS, "list vrs failed for vpc") + vr_linklocal_ip = vr_res[0].linklocalip + result = get_process_status( + self.apiclient.connection.mgtSvr, + 22, + self.apiclient.connection.user, + self.apiclient.connection.passwd, + vr_linklocal_ip, + 'lspci | grep "Ethernet controller"', + hypervisor=self.hypervisor + ) + self.assertEqual( + validateList(result)[0], + PASS, + "We didn't find NICS with adapter type VMXNET3" + ) + reg = re.compile("VMware VMXNET3") + count = 0 + for line in result: + if reg.search(line): + count += 1 + self.assertEqual( + count, + 3, + "Not all NICs on VR are of type VMXNET3" + ) + except Exception as e: + self.fail("NIC creation failed for vpc tier with systemvm nic \ + adapter type as Vmxnet3: %s" % e) + finally: + if reset: + self.updateConfigurAndRestart("vmware.systemvm.nic.device.type", nic_type) + return From 87b431c0f338b8b1c365eabc335ebd69a55c7e07 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Sat, 26 Mar 2016 02:44:40 +0100 Subject: [PATCH 091/203] travis: Fix simulator tests and optimize default global configs - Migrate to trusty based Travis VMs - Increase tests across five build matrices - Fix xunit-reader output, include time - Fix pip/python usage, pkg installation - Build CloudStack in parallel with -T4 - Deploy database with optimized global settings Signed-off-by: Rohit Yadav --- .travis.yml | 24 ++++++++++++++++-------- developer/developer-prefill.sql | 28 ++++++++++++++++++++++++++++ setup/db/templates.simulator.sql | 4 +++- setup/dev/advanced.cfg | 4 ++-- tools/travis/before_install.sh | 25 ++++++++++++++++++------- tools/travis/before_script.sh | 2 +- tools/travis/install.sh | 19 +++++++------------ tools/travis/script.sh | 5 +++-- tools/travis/xunit-reader.py | 14 ++++++++++++-- 9 files changed, 90 insertions(+), 35 deletions(-) diff --git a/.travis.yml b/.travis.yml index 200f1999ce..1441fa4871 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,27 +15,35 @@ # specific language governing permissions and limitations # under the License. sudo: required +dist: trusty language: java cache: directories: - $HOME/.cache jdk: - oraclejdk7 +python: + - "2.7" +cache: + directories: + - $HOME/.m2 + timeout: 1000 notifications: email: false env: global: - REGRESSION_CYCLE=4 - REGRESSION_INDEX=6 + - PATH=$HOME/.local/bin:$PATH matrix: - - TESTS="smoke/test_affinity_groups smoke/test_primary_storage" - - TESTS="smoke/test_deploy_vms_with_varied_deploymentplanners smoke/test_disk_offerings smoke/test_global_settings smoke/test_multipleips_per_nic" - - TESTS="smoke/test_portable_publicip smoke/test_privategw_acl smoke/test_public_ip_range smoke/test_pvlan smoke/test_regions smoke/test_network" - - TESTS="smoke/test_reset_vm_on_reboot smoke/test_resource_detail smoke/test_routers smoke/test_guest_vlan_range smoke/test_iso smoke/test_non_contigiousvlan" - - TESTS="smoke/test_secondary_storage smoke/test_service_offerings smoke/test_ssvm smoke/test_templates smoke/test_over_provisioning" + - TESTS="smoke/test_affinity_groups smoke/test_affinity_groups_projects smoke/test_deploy_vgpu_enabled_vm smoke/test_deploy_vm_iso smoke/test_deploy_vm_root_resize smoke/test_deploy_vm_with_userdata smoke/test_deploy_vms_with_varied_deploymentplanners smoke/test_disk_offerings smoke/test_global_settings smoke/test_guest_vlan_range" + - TESTS="smoke/test_hosts smoke/test_internal_lb smoke/test_iso smoke/test_loadbalance smoke/test_multipleips_per_nic smoke/test_network smoke/test_network_acl smoke/test_nic smoke/test_nic_adapter_type smoke/test_non_contigiousvlan" + - TESTS="smoke/test_over_provisioning smoke/test_password_server smoke/test_portable_publicip smoke/test_primary_storage smoke/test_privategw_acl smoke/test_public_ip_range smoke/test_pvlan smoke/test_regions smoke/test_reset_vm_on_reboot smoke/test_resource_detail" + - TESTS="smoke/test_router_dhcphosts smoke/test_routers smoke/test_routers_iptables_default_policy smoke/test_routers_network_ops smoke/test_scale_vm smoke/test_secondary_storage smoke/test_service_offerings smoke/test_snapshots smoke/test_ssvm smoke/test_templates" + - TESTS="smoke/test_usage_events smoke/test_vm_life_cycle smoke/test_vm_snapshots smoke/test_volumes smoke/test_vpc_redundant smoke/test_vpc_router_nics smoke/test_vpc_vpn smoke/misc/test_deploy_vm smoke/misc/test_vm_ha smoke/misc/test_escalations_templates smoke/misc/test_vm_sync" - - TESTS="smoke/test_volumes smoke/test_vpc_vpn smoke/misc/test_deploy_vm smoke/test_vm_life_cycle component/test_mm_max_limits" - - TESTS="component/test_acl_isolatednetwork_delete component/test_mm_domain_limits component/test_acl_listsnapshot" + - TESTS="component/test_mm_max_limits component/test_acl_isolatednetwork_delete" + - TESTS="component/test_mm_domain_limits component/test_acl_listsnapshot" - TESTS="component/test_acl_listvm component/test_acl_sharednetwork_deployVM-impersonation component/test_acl_sharednetwork" - TESTS="component/test_snapshots component/test_acl_listvolume" before_install: travis_wait 30 ./tools/travis/before_install.sh @@ -43,7 +51,7 @@ install: ./tools/travis/install.sh before_script: travis_wait 30 ./tools/travis/before_script.sh script: - travis_wait 30 sleep 30 - - ./tools/travis/script.sh $TESTS + - ./tools/travis/script.sh ${TESTS} after_success: ./tools/travis/after_success.sh after_failure: ./tools/travis/after_failure.sh after_script: ./tools/travis/after_script.sh diff --git a/developer/developer-prefill.sql b/developer/developer-prefill.sql index 3097203b41..f874118e19 100644 --- a/developer/developer-prefill.sql +++ b/developer/developer-prefill.sql @@ -62,6 +62,10 @@ INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', 'expunge.interval', '60'); +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'expunge.workers', '3'); + INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', 'cluster.cpu.allocated.capacity.disablethreshold', '0.95'); @@ -78,6 +82,30 @@ INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', 'pool.storage.capacity.disablethreshold', '0.95'); +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'network.gc.wait', '60'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'network.gc.interval', '60'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'storage.cleanup.interval', '150'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'vm.op.wait.interval', '5'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'workers', '10'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'direct.agent.load.size', '1000'); + -- Add developer configuration entry; allows management server to be run as a user other than "cloud" INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', diff --git a/setup/db/templates.simulator.sql b/setup/db/templates.simulator.sql index 25e91bd9c5..ac09c05937 100755 --- a/setup/db/templates.simulator.sql +++ b/setup/db/templates.simulator.sql @@ -19,4 +19,6 @@ INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, state) VALUES (100, UUID(), 'simulator-domR', 'SystemVM Template (simulator)', 0, now(), 'SYSTEM', 0, 64, 1, 'http://nfs1.lab.vmops.com/templates/routing/debian/latest/systemvm.vhd.bz2', '', 0, 'SystemVM Template (simulator)', 'VHD', 15, 0, 1, 'Simulator','Active'); INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type,state) - VALUES (111, UUID(), 'simulator-Centos', 'CentOS 5.3(64-bit) no GUI (Simulator)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://nfs1.lab.vmops.com/templates/centos53-x86_64/latest/f59f18fb-ae94-4f97-afd2-f84755767aca.vhd.bz2', '', 0, 'CentOS 5.3(64-bit) no GUI (Simulator)', 'VHD', 11, 1, 1, 'Simulator','Active'); + VALUES (111, UUID(), 'simulator-Centos', 'CentOS 5.6 (64-bit) no GUI (Simulator)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://nfs1.lab.vmops.com/templates/centos53-x86_64/latest/f59f18fb-ae94-4f97-afd2-f84755767aca.vhd.bz2', '', 0, 'CentOS 5.6 (64-bit) no GUI (Simulator)', 'VHD', 142, 1, 1, 'Simulator','Active'); + +INSERT INTO `cloud`.`template_store_ref` VALUES (1,1,111,NOW(),NOW(),NULL,100,0,'Image',0,'DOWNLOADED',NULL,NULL,'template/tmpl/1/111/','http://fake.cloud/111.vhd.bz2','Ready',0,0,0,0,NULL,NULL,NULL); diff --git a/setup/dev/advanced.cfg b/setup/dev/advanced.cfg index 8109bb1d89..afb9b6a215 100644 --- a/setup/dev/advanced.cfg +++ b/setup/dev/advanced.cfg @@ -154,7 +154,7 @@ }, { "name": "storage.cleanup.interval", - "value": "300" + "value": "150" }, { "name": "vm.op.wait.interval", @@ -178,7 +178,7 @@ }, { "name": "account.cleanup.interval", - "value": "600" + "value": "60" }, { "name": "guest.domain.suffix", diff --git a/tools/travis/before_install.sh b/tools/travis/before_install.sh index b90a0999c4..700ac09d5a 100755 --- a/tools/travis/before_install.sh +++ b/tools/travis/before_install.sh @@ -49,12 +49,21 @@ javac -version echo -e "\nMaven Version: " mvn -v +echo -e "\nPython Version: " +python --version + +echo -e "\nPip Version: " +pip --version + echo -e "\nDisk Status: " df echo -e "\nMemory Status: " free +echo -e "\nTotal CPUs: " +nproc + echo -e "\nCheck Git status" git status @@ -66,18 +75,18 @@ sudo apt-get -q -y update > /dev/null echo -e "\nInstalling MySQL: " -sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password your_password' -sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password your_password' +export DEBIAN_FRONTEND=noninteractive +sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password password' +sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password password' sudo apt-get -q -y install mysql-server > /dev/null -#Restart mysql if running to release deleted file locks on filesystem, if aready running -sudo status mysql | grep start && sudo stop mysql -sudo start mysql +mysql -uroot -ppassword -e "SET PASSWORD = PASSWORD(''); FLUSH PRIVILEGES;" +sudo service mysql restart echo -e "\nInstalling Development tools: " RETRY_COUNT=3 -sudo apt-get -q -y install uuid-runtime genisoimage python-setuptools python-pip netcat > /dev/null +sudo apt-get -q -y install uuid-runtime genisoimage netcat > /dev/null if [[ $? -ne 0 ]]; then echo -e "\napt-get packages failed to install" fi @@ -94,9 +103,11 @@ echo " echo -e "\nInstalling some python packages: " +pip install --user --upgrade pip + for ((i=0;i<$RETRY_COUNT;i++)) do - sudo pip install --upgrade lxml texttable paramiko > /tmp/piplog + pip install --user --upgrade lxml paramiko nose texttable > /tmp/piplog if [[ $? -eq 0 ]]; then echo -e "\npython packages installed successfully" break; diff --git a/tools/travis/before_script.sh b/tools/travis/before_script.sh index 40e67001a2..beb8acc89a 100755 --- a/tools/travis/before_script.sh +++ b/tools/travis/before_script.sh @@ -41,4 +41,4 @@ mvn -Dsimulator -pl :cloud-client-ui jetty:run 2>&1 > /tmp/jetty-log & while ! nc -vzw 5 localhost 8096 2>&1 > /dev/null; do grep Exception /tmp/jetty-log; sleep 10; done echo -e "\nStarting DataCenter deployment" -python -m marvin.deployDataCenter -i setup/dev/advanced.cfg 2>&1 || true +python tools/marvin/marvin/deployDataCenter.py -i setup/dev/advanced.cfg 2>&1 || true diff --git a/tools/travis/install.sh b/tools/travis/install.sh index 28f4ed4fbe..5b6bc5ec1e 100755 --- a/tools/travis/install.sh +++ b/tools/travis/install.sh @@ -34,24 +34,19 @@ if [ $MOD -ne 0 ]; then fi fi -export MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=500m -Djava.security.egd=file:/dev/./urandom" +export MAVEN_OPTS="-Xmx2048m -XX:MaxPermSize=500m -Djava.security.egd=file:/dev/./urandom" if [ $TEST_SEQUENCE_NUMBER -eq 1 ]; then - mvn -q -Pimpatient -Dsimulator clean install + mvn -Pdeveloper,systemvm -Dsimulator clean install -T4 | egrep "Building|SUCCESS" else - mvn -q -Pimpatient -Dsimulator clean install -DskipTests=true + mvn -Pdeveloper -Dsimulator clean install -DskipTests=true -T4 | egrep "Building|SUCCESS" fi -# Compile API Docs -cd tools/apidoc -mvn -q clean install -cd ../../ +# Install mysql-connector-python +pip install --user --upgrade http://cdn.mysql.com/Downloads/Connector-Python/mysql-connector-python-2.0.4.zip#md5=3df394d89300db95163f17c843ef49df 2>&1 > /dev/null -# Compile marvin -cd tools/marvin -mvn -q clean install -sudo python setup.py install 2>&1 > /dev/null -cd ../../ +# Install marvin +pip install --user --upgrade tools/marvin/dist/Marvin-*.tar.gz # Deploy the database mvn -q -Pdeveloper -pl developer -Ddeploydb diff --git a/tools/travis/script.sh b/tools/travis/script.sh index 7e7c497016..dc955b004c 100755 --- a/tools/travis/script.sh +++ b/tools/travis/script.sh @@ -37,10 +37,11 @@ fi mkdir -p integration-test-results/smoke/misc mkdir -p integration-test-results/component +TESTS=($@) +echo "Running tests: " ${TESTS[@]} -for suite in $1; do +for suite in "${TESTS[@]}" ; do nosetests --with-xunit --xunit-file=integration-test-results/$suite.xml --with-marvin --marvin-config=setup/dev/advanced.cfg test/integration/$suite.py -s -a tags=advanced,required_hardware=false --zone=Sandbox-simulator --hypervisor=simulator || true ; done - python ./tools/travis/xunit-reader.py integration-test-results/ diff --git a/tools/travis/xunit-reader.py b/tools/travis/xunit-reader.py index c492c01e44..80e228b382 100755 --- a/tools/travis/xunit-reader.py +++ b/tools/travis/xunit-reader.py @@ -61,6 +61,8 @@ def _generate_args(): def _generate_file_list(args): path = args.pop('path') file_path_list = [] + if path.endswith('.xml') and os.path.isfile(path): + file_path_list.append(path) for (root, dirnames, filenames) in os.walk(path): for filename in filenames: if filename.endswith('.xml'): @@ -71,7 +73,7 @@ def _generate_file_list(args): def parse_reports(file_path_list): table = texttable.Texttable() - table.header(['Test', 'Result']) + table.header(['Test', 'Result', 'Time']) exit_code = 0 @@ -80,16 +82,24 @@ def parse_reports(file_path_list): for event, elem in data: name = '' status = 'Success' + time = '' if 'name' in elem.attrib: name = elem.attrib['name'] + if 'time' in elem.attrib: + time = elem.attrib['time'] for children in elem.getchildren(): if 'skipped' == children.tag: status = 'Skipped' elif 'failure' == children.tag: exit_code = 1 status = 'Failure' + elif 'error' == children.tag: + exit_code = 1 + status = 'Error' + if 'type' in children.attrib: + status = children.attrib['type'] - table.add_row([name, status]) + table.add_row([name, status, time]) print table.draw() From 16be8598b0539bb04ff8457b5f5ad986ede71475 Mon Sep 17 00:00:00 2001 From: sanjeevn Date: Thu, 7 Jan 2016 19:32:22 +0530 Subject: [PATCH 092/203] Added new test to verify restart network after destorying master VR Bug-Id: CLOUDSTACK-9218 Made changes to test name as per the review comments from DaanHoogland --- .../test_redundant_router_cleanups.py | 156 +++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-) diff --git a/test/integration/component/test_redundant_router_cleanups.py b/test/integration/component/test_redundant_router_cleanups.py index 295ce08328..04f24a5564 100644 --- a/test/integration/component/test_redundant_router_cleanups.py +++ b/test/integration/component/test_redundant_router_cleanups.py @@ -23,7 +23,7 @@ VirtualMachine, Router, Configurations) -from marvin.lib.utils import cleanup_resources +from marvin.lib.utils import cleanup_resources, validateList from marvin.lib.common import (get_domain, get_zone, get_template) @@ -31,6 +31,7 @@ #Import Local Modules from marvin.cloudstackTestCase import cloudstackTestCase from marvin.cloudstackAPI import startRouter +from marvin.codes import PASS import time class Services: @@ -666,3 +667,156 @@ def test_network_gc(self): "Router should be in stopped state" ) return + + @attr(tags=["advanced", "advancedns"], required_hardware="false") + def test_restart_network_with_destroyed_masterVR(self): + """Test restarting RvR network without cleanup after destroying master VR + """ + + # Steps to validate + # 1. createNetwork using network offering for redundant virtual router + # 2. listRouters in above network + # 3. deployVM in above user account in the created network + # 4. Destroy master VR + # 5. restartNetwork cleanup=false + # 6. Verify RVR status after network restart + + # Creating network using the network offering created + self.debug("Creating network with network offering: %s" % + self.network_offering.id) + network = Network.create( + self.apiclient, + self.services["network"], + accountid=self.account.name, + domainid=self.account.domainid, + networkofferingid=self.network_offering.id, + zoneid=self.zone.id + ) + self.debug("Created network with ID: %s" % network.id) + networks = Network.list( + self.apiclient, + id=network.id, + listall=True + ) + self.assertEqual( + validateList(networks)[0], + PASS, + "List networks should return a valid response for created network" + ) + + self.debug("Deploying VM in account: %s" % self.account.name) + # Spawn an instance in that network + virtual_machine = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + networkids=[str(network.id)] + ) + self.debug("Deployed VM in network: %s" % network.id) + vms = VirtualMachine.list( + self.apiclient, + id=virtual_machine.id, + listall=True + ) + self.assertEqual( + validateList(vms)[0], + PASS, + "List Vms should return a valid list" + ) + vm = vms[0] + self.assertEqual( + vm.state, + "Running", + "Vm should be in running state after deployment" + ) + + self.debug("Listing routers for network: %s" % network.name) + routers = Router.list( + self.apiclient, + networkid=network.id, + listall=True + ) + self.assertEqual( + validateList(routers)[0], + PASS, + "list router should return Master and backup routers" + ) + self.assertEqual( + len(routers), + 2, + "Length of the list router should be 2 (Backup & master)" + ) + if routers[0].redundantstate == 'MASTER' and\ + routers[1].redundantstate == 'BACKUP': + master_router = routers[0] + backup_router = routers[1] + elif routers[1].redundantstate == 'MASTER' and \ + routers[0].redundantstate == 'BACKUP': + master_router = routers[1] + backup_router = routers[0] + else: + self.fail("Both the routers in RVR are in BackupState") + + Router.stop( + self.apiclient, + id=master_router.id + ) + Router.destroy( + self.apiclient, + id=master_router.id + ) + masterVR = Router.list( + self.apiclient, + id=master_router.id + ) + self.assertIsNone(masterVR, "Router is not destroyed") + new_master = Router.list( + self.apiclient, + id=backup_router.id + ) + self.assertEqual(validateList(new_master)[0], PASS, "Invalid response after vr destroy") + self.assertEqual( + new_master[0].redundantstate, + "MASTER", + "Backup didn't switch to Master after destroying Master VR" + ) + + self.debug("restarting network with cleanup=False") + try: + network.restart(self.apiclient, cleanup=False) + except Exception as e: + self.fail("Failed to cleanup network - %s" % e) + + self.debug("Listing routers for network: %s" % network.name) + routers = Router.list( + self.apiclient, + networkid=network.id, + listall=True + ) + self.assertEqual( + validateList(routers)[0], + PASS, + "list router should return Master and backup routers afrer network restart" + ) + self.assertEqual( + len(routers), + 2, + "Length of the list router should be 2 (Backup & master)" + ) + for router in routers: + self.assertEqual( + router.state, + "Running", + "Router state should be running" + ) + if routers[0].redundantstate == 'MASTER' and\ + routers[1].redundantstate == 'BACKUP': + self.debug("Found master and backup VRs after network restart") + elif routers[0].redundantstate == 'BACKUP' and \ + routers[1].redundantstate == 'MASTER': + self.debug("Found master and backup routers") + else: + self.fail("RVR is not in proper start after network restart") + return From 24abba62abb015f796aad69ea3aba669665c502f Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Mon, 4 Apr 2016 12:53:45 +0530 Subject: [PATCH 093/203] CLOUDSTACK-9335: fix typo in dashboard's fetchlatest usage This fixes a typographical error in UI that did not previously send fetchLatest flag in the listCapacity API request. Signed-off-by: Rohit Yadav --- ui/scripts/dashboard.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/scripts/dashboard.js b/ui/scripts/dashboard.js index f2b5682078..bd328634bb 100644 --- a/ui/scripts/dashboard.js +++ b/ui/scripts/dashboard.js @@ -184,9 +184,9 @@ }, capacity: function(data) { if (window.fetchLatestflag == 1) { - data.fetchLastest = true; + data.fetchLatest = true; } else { - data.fetchLastest = false; + data.fetchLatest = false; } window.fetchLatestflag = 0; dataFns.alerts(data); From 4179606c0bd26bf87786008c2db6ff38b8a4b658 Mon Sep 17 00:00:00 2001 From: weingartner Date: Thu, 7 Apr 2016 15:28:55 -0300 Subject: [PATCH 094/203] Removed classes with no reference - org.apache.cloudstack.framework.jobs.JobCancellationException (removed variable JobCancellationException in com.cloud.utils.SerialVersionUID) - org.apache.cloudstack.ldap.NoSuchLdapUserException (removed test file /cloud-plugin-user-authenticator-ldap/test/groovy/org/apache/cloudstack/ldap/NoSuchLdapUserExceptionSpec.groovy) - com.cloud.agent.api.storage.CreateVolumeOVAAnswer - com.cloud.exception.MissingParameterValueException - org.apache.cloudstack.api.response.StatusResponse - org.apache.cloudstack.api.response.VolumeDetailResponse - org.apache.cloudstack.api.response.UpgradeVmResponse - org.apache.cloudstack.api.response.AddIpToVmNicResponse - org.apache.cloudstack.api.response.TemplateZoneResponse (at org.apache.cloudstack.api.response.TemplateResponse, there is this comment "To avoid breaking backwards compatibility, we still treat a template at different zones as different templates, so not embedding template_zone information in this TemplateZoneResponse set. `private Set zones;`" but right now it is not used) - org.apache.cloudstack.api.response.NicDetailResponse --- .../api/storage/CreateVolumeOVAAnswer.java | 26 -- .../api/storage/PrepareOVAPackingAnswer.java | 26 -- .../MissingParameterValueException.java | 26 -- .../api/response/AddIpToVmNicResponse.java | 88 ----- .../api/response/NicDetailResponse.java | 76 ----- .../api/response/StatusResponse.java | 34 -- .../api/response/TemplateResponse.java | 9 +- .../api/response/TemplateZoneResponse.java | 134 -------- .../api/response/UpgradeVmResponse.java | 323 ------------------ .../api/response/VolumeDetailResponse.java | 76 ----- .../jobs/JobCancellationException.java | 46 --- .../ldap/NoSuchLdapUserException.java | 31 -- .../ldap/NoSuchLdapUserExceptionSpec.groovy | 30 -- .../com/cloud/utils/SerialVersionUID.java | 1 - 14 files changed, 1 insertion(+), 925 deletions(-) delete mode 100644 api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java delete mode 100644 api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java delete mode 100644 api/src/com/cloud/exception/MissingParameterValueException.java delete mode 100644 api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java delete mode 100644 api/src/org/apache/cloudstack/api/response/NicDetailResponse.java delete mode 100644 api/src/org/apache/cloudstack/api/response/StatusResponse.java delete mode 100644 api/src/org/apache/cloudstack/api/response/TemplateZoneResponse.java delete mode 100644 api/src/org/apache/cloudstack/api/response/UpgradeVmResponse.java delete mode 100644 api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java delete mode 100644 framework/jobs/src/org/apache/cloudstack/framework/jobs/JobCancellationException.java delete mode 100644 plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/NoSuchLdapUserException.java delete mode 100644 plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/NoSuchLdapUserExceptionSpec.groovy diff --git a/api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java b/api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java deleted file mode 100644 index 60d74f6c86..0000000000 --- a/api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package com.cloud.agent.api.storage; - -import com.cloud.agent.api.Answer; - -public class CreateVolumeOVAAnswer extends Answer { - public CreateVolumeOVAAnswer(CreateVolumeOVACommand cmd, boolean result, String details) { - super(cmd, result, details); - } - -} diff --git a/api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java b/api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java deleted file mode 100644 index dad660b90f..0000000000 --- a/api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package com.cloud.agent.api.storage; - -import com.cloud.agent.api.Answer; - -public class PrepareOVAPackingAnswer extends Answer { - public PrepareOVAPackingAnswer(PrepareOVAPackingCommand cmd, boolean result, String details) { - super(cmd, result, details); - } - -} diff --git a/api/src/com/cloud/exception/MissingParameterValueException.java b/api/src/com/cloud/exception/MissingParameterValueException.java deleted file mode 100644 index 4bcaa567c5..0000000000 --- a/api/src/com/cloud/exception/MissingParameterValueException.java +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package com.cloud.exception; - -import com.cloud.utils.exception.CloudRuntimeException; - -public class MissingParameterValueException extends CloudRuntimeException { - - public MissingParameterValueException(String message) { - super(message); - } -} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java b/api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java deleted file mode 100644 index 0725d40983..0000000000 --- a/api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java +++ /dev/null @@ -1,88 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.api.response; - -import com.google.gson.annotations.SerializedName; - -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; - -import com.cloud.serializer.Param; - -@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/NicDetailResponse.java b/api/src/org/apache/cloudstack/api/response/NicDetailResponse.java deleted file mode 100644 index 152d101d31..0000000000 --- a/api/src/org/apache/cloudstack/api/response/NicDetailResponse.java +++ /dev/null @@ -1,76 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.api.response; - -import com.google.gson.annotations.SerializedName; - -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; - -import com.cloud.serializer.Param; - -@SuppressWarnings("unused") -public class NicDetailResponse extends BaseResponse { - @SerializedName(ApiConstants.ID) - @Param(description = "ID of the nic") - private String id; - - @SerializedName(ApiConstants.NAME) - @Param(description = "name of the nic detail") - private String name; - - @SerializedName(ApiConstants.VALUE) - @Param(description = "value of the nic detail") - private String value; - - @SerializedName(ApiConstants.DISPLAY_NIC) - @Param(description = "an optional field whether to the display the nic to the end user or not.") - private Boolean displayNic; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public String getName() { - - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Boolean getDisplayNic() { - return displayNic; - } - - public void setDisplayNic(Boolean displayNic) { - this.displayNic = displayNic; - } -} diff --git a/api/src/org/apache/cloudstack/api/response/StatusResponse.java b/api/src/org/apache/cloudstack/api/response/StatusResponse.java deleted file mode 100644 index fa2b4b2020..0000000000 --- a/api/src/org/apache/cloudstack/api/response/StatusResponse.java +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.api.response; - -import com.google.gson.annotations.SerializedName; - -import org.apache.cloudstack.api.BaseResponse; - -public class StatusResponse extends BaseResponse { - @SerializedName("status") - private Boolean status; - - public Boolean getStatus() { - return status; - } - - public void setStatus(Boolean status) { - this.status = status; - } -} diff --git a/api/src/org/apache/cloudstack/api/response/TemplateResponse.java b/api/src/org/apache/cloudstack/api/response/TemplateResponse.java index 4986f2f636..237f181d4d 100644 --- a/api/src/org/apache/cloudstack/api/response/TemplateResponse.java +++ b/api/src/org/apache/cloudstack/api/response/TemplateResponse.java @@ -21,8 +21,6 @@ import java.util.Map; import java.util.Set; -import com.google.gson.annotations.SerializedName; - import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponseWithTagInformation; import org.apache.cloudstack.api.EntityReference; @@ -30,6 +28,7 @@ import com.cloud.serializer.Param; import com.cloud.storage.Storage.ImageFormat; import com.cloud.template.VirtualMachineTemplate; +import com.google.gson.annotations.SerializedName; @EntityReference(value = VirtualMachineTemplate.class) @SuppressWarnings("unused") @@ -170,11 +169,6 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements @Param(description = "additional key/value details tied with template") private Map details; - // To avoid breaking backwards compatibility, we still treat a template at different zones as different templates, so not embedding - // template_zone information in this TemplateZoneResponse set. - // @SerializedName("zones") @Param(description="list of zones associated with tempate", responseObject = TemplateZoneResponse.class) - // private Set zones; - @SerializedName(ApiConstants.SSHKEY_ENABLED) @Param(description = "true if template is sshkey enabled, false otherwise") private Boolean sshKeyEnabled; @@ -184,7 +178,6 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements private Boolean isDynamicallyScalable; public TemplateResponse() { - // zones = new LinkedHashSet(); tags = new LinkedHashSet(); } diff --git a/api/src/org/apache/cloudstack/api/response/TemplateZoneResponse.java b/api/src/org/apache/cloudstack/api/response/TemplateZoneResponse.java deleted file mode 100644 index f2e7725de0..0000000000 --- a/api/src/org/apache/cloudstack/api/response/TemplateZoneResponse.java +++ /dev/null @@ -1,134 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.api.response; - -import java.util.Date; - -import com.google.gson.annotations.SerializedName; - -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; - -import com.cloud.serializer.Param; - -public class TemplateZoneResponse extends BaseResponse { - @SerializedName(ApiConstants.ZONE_ID) - @Param(description = "the ID of the zone for the template") - private String zoneId; - - @SerializedName(ApiConstants.ZONE_NAME) - @Param(description = "the name of the zone for the template") - private String zoneName; - - @SerializedName(ApiConstants.STATUS) - @Param(description = "the status of the template") - private String status; - - @SerializedName(ApiConstants.IS_READY) - // propName="ready" (FIXME: this used to be part of Param annotation, do we need it?) - @Param(description = "true if the template is ready to be deployed from, false otherwise.") - private boolean isReady; - - @SerializedName(ApiConstants.CREATED) - @Param(description = "the date this template was created") - private Date created; - - public TemplateZoneResponse() { - super(); - } - - public TemplateZoneResponse(String zoneId, String zoneName) { - super(); - this.zoneId = zoneId; - this.zoneName = zoneName; - } - - public String getZoneId() { - return zoneId; - } - - public void setZoneId(String zoneId) { - this.zoneId = zoneId; - } - - public String getZoneName() { - return zoneName; - } - - public void setZoneName(String zoneName) { - this.zoneName = zoneName; - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - public boolean isReady() { - return isReady; - } - - public void setReady(boolean isReady) { - this.isReady = isReady; - } - - public Date getCreated() { - return created; - } - - public void setCreated(Date created) { - this.created = created; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - String oid = this.getZoneId(); - result = prime * result + ((oid == null) ? 0 : oid.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - TemplateZoneResponse other = (TemplateZoneResponse)obj; - String oid = this.getZoneId(); - if (oid == null) { - if (other.getZoneId() != null) { - return false; - } - } else if (!oid.equals(other.getZoneId())) { - return false; - } else if (this.getZoneName().equals(other.getZoneName())) { - return false; - } - return true; - } - -} diff --git a/api/src/org/apache/cloudstack/api/response/UpgradeVmResponse.java b/api/src/org/apache/cloudstack/api/response/UpgradeVmResponse.java deleted file mode 100644 index c42b64bc72..0000000000 --- a/api/src/org/apache/cloudstack/api/response/UpgradeVmResponse.java +++ /dev/null @@ -1,323 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.api.response; - -import java.util.Date; - -import com.google.gson.annotations.SerializedName; - -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; - -import com.cloud.serializer.Param; - -public class UpgradeVmResponse extends BaseResponse { - @SerializedName("id") - private String id; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Date getCreated() { - return created; - } - - public void setCreated(Date created) { - this.created = created; - } - - public String getIpAddress() { - return ipAddress; - } - - public void setIpAddress(String ipAddress) { - this.ipAddress = ipAddress; - } - - public String getState() { - return state; - } - - public void setState(String state) { - this.state = state; - } - - public String getAccount() { - return account; - } - - public void setAccount(String account) { - this.account = account; - } - - public String getDomainId() { - return domainId; - } - - public void setDomainId(String domainId) { - this.domainId = domainId; - } - - public String getDomain() { - return domain; - } - - public void setDomain(String domain) { - this.domain = domain; - } - - public boolean isHaEnable() { - return haEnable; - } - - public void setHaEnable(boolean haEnable) { - this.haEnable = haEnable; - } - - public String getZoneId() { - return zoneId; - } - - public void setZoneId(String zoneId) { - this.zoneId = zoneId; - } - - public String getDisplayName() { - return displayName; - } - - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - - public String getZoneName() { - return zoneName; - } - - public void setZoneName(String zoneName) { - this.zoneName = zoneName; - } - - public String getHostId() { - return hostId; - } - - public void setHostId(String hostId) { - this.hostId = hostId; - } - - public String getHostName() { - return hostName; - } - - public void setHostName(String hostName) { - this.hostName = hostName; - } - - public String getTemplateId() { - return templateId; - } - - public void setTemplateId(String templateId) { - this.templateId = templateId; - } - - public String getTemplateName() { - return templateName; - } - - public void setTemplateName(String templateName) { - this.templateName = templateName; - } - - public String getTemplateDisplayText() { - return templateDisplayText; - } - - public void setTemplateDisplayText(String templateDisplayText) { - this.templateDisplayText = templateDisplayText; - } - - public boolean isPasswordEnabled() { - return passwordEnabled; - } - - public void setPasswordEnabled(boolean passwordEnabled) { - this.passwordEnabled = passwordEnabled; - } - - public String getServiceOfferingId() { - return serviceOfferingId; - } - - public void setServiceOfferingId(String serviceOfferingId) { - this.serviceOfferingId = serviceOfferingId; - } - - public String getServiceOfferingName() { - return serviceOfferingName; - } - - public void setServiceOfferingName(String serviceOfferingName) { - this.serviceOfferingName = serviceOfferingName; - } - - public long getCpuSpeed() { - return cpuSpeed; - } - - public void setCpuSpeed(long cpuSpeed) { - this.cpuSpeed = cpuSpeed; - } - - public long getMemory() { - return memory; - } - - public void setMemory(long memory) { - this.memory = memory; - } - - public long getCpuUsed() { - return cpuUsed; - } - - public void setCpuUsed(long cpuUsed) { - this.cpuUsed = cpuUsed; - } - - public long getNetworkKbsRead() { - return networkKbsRead; - } - - public void setNetworkKbsRead(long networkKbsRead) { - this.networkKbsRead = networkKbsRead; - } - - public long getNetworkKbsWrite() { - return networkKbsWrite; - } - - public void setNetworkKbsWrite(long networkKbsWrite) { - this.networkKbsWrite = networkKbsWrite; - } - - public String isId() { - return id; - } - - @SerializedName("name") - @Param(description = "the ID of the virtual machine") - private String name; - - @SerializedName("created") - @Param(description = "the date when this virtual machine was created") - private Date created; - - @SerializedName("ipaddress") - @Param(description = "the ip address of the virtual machine") - private String ipAddress; - - @SerializedName("state") - @Param(description = "the state of the virtual machine") - private String state; - - @SerializedName("account") - @Param(description = "the account associated with the virtual machine") - private String account; - - @SerializedName("domainid") - @Param(description = "the ID of the domain in which the virtual machine exists") - private String domainId; - - @SerializedName("domain") - @Param(description = "the name of the domain in which the virtual machine exists") - private String domain; - - @SerializedName("haenable") - @Param(description = "true if high-availability is enabled, false otherwise") - private boolean haEnable; - - @SerializedName("zoneid") - @Param(description = "the ID of the availablility zone for the virtual machine") - private String zoneId; - - @SerializedName("displayname") - @Param(description = "user generated name. The name of the virtual machine is returned if no displayname exists.") - private String displayName; - - @SerializedName(ApiConstants.ZONE_NAME) - @Param(description = "the name of the availability zone for the virtual machine") - private String zoneName; - - @SerializedName("hostid") - @Param(description = "the ID of the host for the virtual machine") - private String hostId; - - @SerializedName("hostname") - @Param(description = "the name of the host for the virtual machine") - private String hostName; - - @SerializedName("templateid") - @Param(description = "the ID of the template for the virtual machine. A -1 is returned if the virtual machine was created from an ISO file.") - private String templateId; - - @SerializedName("templatename") - @Param(description = "the name of the template for the virtual machine") - private String templateName; - - @SerializedName("templatedisplaytext") - @Param(description = " an alternate display text of the template for the virtual machine") - private String templateDisplayText; - - @SerializedName("passwordenabled") - @Param(description = "true if the password rest feature is enabled, false otherwise") - private boolean passwordEnabled; - - @SerializedName("serviceofferingid") - @Param(description = "the ID of the service offering of the virtual machine") - private String serviceOfferingId; - - @SerializedName("serviceofferingname") - @Param(description = "the name of the service offering of the virtual machine") - private String serviceOfferingName; - - @SerializedName("cpunumber") - @Param(description = "the number of cpu this virtual machine is running with") - private long cpuSpeed; - - @SerializedName("memory") - @Param(description = "the memory allocated for the virtual machine") - private long memory; - - @SerializedName("cpuused") - @Param(description = "the amount of the vm's CPU currently used") - private long cpuUsed; - - @SerializedName("networkkbsread") - @Param(description = "the incoming network traffic on the vm") - private long networkKbsRead; - - @SerializedName("networkkbswrite") - @Param(description = "the outgoing network traffic on the host") - private long networkKbsWrite; -} diff --git a/api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java deleted file mode 100644 index 957fb48708..0000000000 --- a/api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java +++ /dev/null @@ -1,76 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.api.response; - -import com.google.gson.annotations.SerializedName; - -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; - -import com.cloud.serializer.Param; - -@SuppressWarnings("unused") -public class VolumeDetailResponse extends BaseResponse { - @SerializedName(ApiConstants.ID) - @Param(description = "ID of the volume") - private String id; - - @SerializedName(ApiConstants.NAME) - @Param(description = "name of the volume detail") - private String name; - - @SerializedName(ApiConstants.VALUE) - @Param(description = "value of the volume detail") - private String value; - - @SerializedName(ApiConstants.DISPLAY_VOLUME) - @Param(description = "an optional field whether to the display the volume to the end user or not.") - private Boolean displayVm; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public String getName() { - - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Boolean getDisplayVm() { - return displayVm; - } - - public void setDisplayVm(Boolean displayVm) { - this.displayVm = displayVm; - } -} diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/JobCancellationException.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/JobCancellationException.java deleted file mode 100644 index 23540e7a07..0000000000 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/JobCancellationException.java +++ /dev/null @@ -1,46 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.framework.jobs; - -import java.util.concurrent.CancellationException; - -import com.cloud.utils.SerialVersionUID; - -/** - * This exception is fired when the job has been cancelled - * - */ -public class JobCancellationException extends CancellationException { - - private static final long serialVersionUID = SerialVersionUID.AffinityConflictException; - - public enum Reason { - RequestedByUser, RequestedByCaller, TimedOut; - } - - Reason reason; - - public JobCancellationException(Reason reason) { - super("The job was cancelled due to " + reason.toString()); - this.reason = reason; - } - - public Reason getReason() { - return reason; - } - -} diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/NoSuchLdapUserException.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/NoSuchLdapUserException.java deleted file mode 100644 index d9bf13f6e4..0000000000 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/NoSuchLdapUserException.java +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.ldap; - -public class NoSuchLdapUserException extends Exception { - private static final long serialVersionUID = 6782938919658010900L; - private final String username; - - public NoSuchLdapUserException(final String username) { - super("No such user: " + username); - this.username = username; - } - - public String getUsername() { - return username; - } -} diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/NoSuchLdapUserExceptionSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/NoSuchLdapUserExceptionSpec.groovy deleted file mode 100644 index dbdf646721..0000000000 --- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/NoSuchLdapUserExceptionSpec.groovy +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package groovy.org.apache.cloudstack.ldap - -import org.apache.cloudstack.ldap.NoSuchLdapUserException; - -class NoSuchLdapUserExceptionSpec extends spock.lang.Specification { - def "Test that the username is correctly set within the No such LDAP user exception object"() { - given: "You have created an No such LDAP user exception object with the username set" - def exception = new NoSuchLdapUserException(username) - expect: "The username is equal to the given data source" - exception.getUsername() == username - where: "The username is set to " - username << ["", null, "rmurphy"] - } -} diff --git a/utils/src/main/java/com/cloud/utils/SerialVersionUID.java b/utils/src/main/java/com/cloud/utils/SerialVersionUID.java index 0683c8c151..b45e028a55 100644 --- a/utils/src/main/java/com/cloud/utils/SerialVersionUID.java +++ b/utils/src/main/java/com/cloud/utils/SerialVersionUID.java @@ -65,7 +65,6 @@ public interface SerialVersionUID { public static final long CallFailedException = Base | 0x28; public static final long UnableDeleteHostException = Base | 0x29; public static final long AffinityConflictException = Base | 0x2a; - public static final long JobCancellationException = Base | 0x2b; public static final long NioConnectionException = Base | 0x2c; public static final long TaskExecutionException = Base | 0x2d; } From 6089d898d9ab7a6cdf59e2c89a579b1271049ed2 Mon Sep 17 00:00:00 2001 From: Slair1 Date: Wed, 9 Mar 2016 12:06:03 -0600 Subject: [PATCH 095/203] Cloudstack Usage Breaks if DB HA enabled With DB HA enabled in db.properties, the cloudstack-usage service restarts every 10 seconds. Making the suggested change has fixed it for me. Cloudstack 4.8 on Centos7 Update cloudstack-usage.service --- packaging/systemd/cloudstack-usage.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/systemd/cloudstack-usage.service b/packaging/systemd/cloudstack-usage.service index 9a1827da61..c37f32c700 100644 --- a/packaging/systemd/cloudstack-usage.service +++ b/packaging/systemd/cloudstack-usage.service @@ -28,7 +28,7 @@ Environment=JAVA_HEAP_INITIAL=256m Environment=JAVA_HEAP_MAX=2048m Environment=JAVA_CLASS=com.cloud.usage.UsageServer ExecStart=/bin/sh -ec '\ - export UCP=`ls /usr/share/cloudstack-usage/cloud-usage-*.jar /usr/share/cloudstack-usage/lib/*.jar | tr "\\n" ":"`; \ + export UCP=`ls /usr/share/cloudstack-usage/cloud-usage-*.jar /usr/share/cloudstack-usage/lib/*.jar /usr/share/cloudstack-mysql-ha/lib/*.jar | tr "\\n" ":"`; \ export CLASSPATH="$UCP:/etc/cloudstack/usage:/usr/share/java/mysql-connector-java.jar"; \ ${JAVA_HOME}/bin/java -Xms${JAVA_HEAP_INITIAL} -Xmx${JAVA_HEAP_MAX} -cp "$CLASSPATH" $JAVA_CLASS' Restart=always From b56e9c7a224fc2ce34687f818ef8110ab407d640 Mon Sep 17 00:00:00 2001 From: weingartner Date: Fri, 8 Apr 2016 11:07:18 -0300 Subject: [PATCH 096/203] Deletion of method endPointSelector.selectHypervisorHost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As discussed on PR 1056, I am removing the method “endPointSelector.selectHypervisorHost” that is not needed anymore --- .../api/storage/EndPointSelector.java | 2 - .../endpoint/DefaultEndPointSelector.java | 48 ++----------------- .../ovm3/resources/Ovm3HypervisorGuru.java | 45 +---------------- .../com/cloud/hypervisor/XenServerGuru.java | 39 +++++---------- .../cloud/hypervisor/HypervisorGuruBase.java | 26 ++++------ 5 files changed, 26 insertions(+), 134 deletions(-) diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java index 4d6465b806..0613a11572 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java @@ -35,7 +35,5 @@ public interface EndPointSelector { EndPoint select(Scope scope, Long storeId); - EndPoint selectHypervisorHost(Scope scope); - EndPoint select(DataStore store, String downloadUrl); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java index 012d6b3fc3..e414b6c4c3 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java +++ b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java @@ -29,9 +29,6 @@ import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; @@ -43,6 +40,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.storage.LocalHostEndpoint; import org.apache.cloudstack.storage.RemoteHostEndPoint; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.capacity.CapacityManager; import com.cloud.host.Host; @@ -64,7 +63,7 @@ public class DefaultEndPointSelector implements EndPointSelector { private static final Logger s_logger = Logger.getLogger(DefaultEndPointSelector.class); @Inject - HostDao hostDao; + private HostDao hostDao; private final String findOneHostOnPrimaryStorage = "select t.id from " + "(select h.id, cd.value " + "from host h join storage_pool_host_ref s on h.id = s.host_id " @@ -72,8 +71,6 @@ public class DefaultEndPointSelector implements EndPointSelector { + "left join cluster_details cd on c.id=cd.cluster_id and cd.name='" + CapacityManager.StorageOperationsExcludeCluster.key() + "' " + "where h.status = 'Up' and h.type = 'Routing' and h.resource_state = 'Enabled' and s.pool_id = ? "; - private String findOneHypervisorHostInScope = "select h.id from host h where h.status = 'Up' and h.hypervisor_type is not null "; - protected boolean moveBetweenPrimaryImage(DataStore srcStore, DataStore destStore) { DataStoreRole srcRole = srcStore.getRole(); DataStoreRole destRole = destStore.getRole(); @@ -266,8 +263,9 @@ private List listUpAndConnectingSecondaryStorageVmHost(Long dcId) { public EndPoint select(DataObject object) { DataStore store = object.getDataStore(); EndPoint ep = select(store); - if (ep != null) + if (ep != null) { return ep; + } if (object instanceof TemplateInfo) { TemplateInfo tmplInfo = (TemplateInfo)object; if (store.getScope().getScopeType() == ScopeType.ZONE && store.getScope().getScopeId() == null && tmplInfo.getTemplateType() == TemplateType.SYSTEM) { @@ -386,40 +384,4 @@ public List selectAll(DataStore store) { } return endPoints; } - - @Override - public EndPoint selectHypervisorHost(Scope scope) { - StringBuilder sbuilder = new StringBuilder(); - sbuilder.append(findOneHypervisorHostInScope); - if (scope.getScopeType() == ScopeType.ZONE) { - sbuilder.append(" and h.data_center_id = "); - sbuilder.append(scope.getScopeId()); - } else if (scope.getScopeType() == ScopeType.CLUSTER) { - sbuilder.append(" and h.cluster_id = "); - sbuilder.append(scope.getScopeId()); - } - sbuilder.append(" ORDER by rand() limit 1"); - - String sql = sbuilder.toString(); - HostVO host = null; - TransactionLegacy txn = TransactionLegacy.currentTxn(); - - try ( - PreparedStatement pstmt = txn.prepareStatement(sql); - ResultSet rs = pstmt.executeQuery(); - ) { - while (rs.next()) { - long id = rs.getLong(1); - host = hostDao.findById(id); - } - } catch (SQLException e) { - s_logger.warn("can't find endpoint", e); - } - - if (host == null) { - return null; - } - - return RemoteHostEndPoint.getHypervisorHostEndPoint(host); - } } diff --git a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3HypervisorGuru.java b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3HypervisorGuru.java index 0d60a2d39b..432474d043 100755 --- a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3HypervisorGuru.java +++ b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3HypervisorGuru.java @@ -19,21 +19,11 @@ import javax.inject.Inject; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; -import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; -import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.log4j.Logger; import com.cloud.agent.api.Command; -import com.cloud.agent.api.to.DataObjectType; -import com.cloud.agent.api.to.DataStoreTO; -import com.cloud.agent.api.to.DataTO; -import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.VirtualMachineTO; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorGuru; import com.cloud.hypervisor.HypervisorGuruBase; @@ -45,15 +35,7 @@ public class Ovm3HypervisorGuru extends HypervisorGuruBase implements HypervisorGuru { private final Logger LOGGER = Logger.getLogger(Ovm3HypervisorGuru.class); @Inject - GuestOSDao guestOsDao; - @Inject - EndPointSelector endPointSelector; - @Inject - HostDao hostDao; - - protected Ovm3HypervisorGuru() { - super(); - } + private GuestOSDao guestOsDao; @Override public HypervisorType getHypervisorType() { @@ -65,7 +47,6 @@ public VirtualMachineTO implement(VirtualMachineProfile vm) { VirtualMachineTO to = toVirtualMachineTO(vm); to.setBootloader(vm.getBootLoaderType()); - // Determine the VM's OS description GuestOSVO guestOS = guestOsDao.findById(vm.getVirtualMachine() .getGuestOSId()); to.setOs(guestOS.getDisplayName()); @@ -78,35 +59,13 @@ public boolean trackVmHostChange() { return true; } - /* I dislike the notion of having to place this here, and not being able to just override - * - * (non-Javadoc) - * @see com.cloud.hypervisor.HypervisorGuruBase#getCommandHostDelegation(long, com.cloud.agent.api.Command) - */ + @Override public Pair getCommandHostDelegation(long hostId, Command cmd) { LOGGER.debug("getCommandHostDelegation: " + cmd.getClass()); if (cmd instanceof StorageSubSystemCommand) { StorageSubSystemCommand c = (StorageSubSystemCommand)cmd; c.setExecuteInSequence(true); } - if (cmd instanceof CopyCommand) { - CopyCommand cpyCommand = (CopyCommand)cmd; - DataTO srcData = cpyCommand.getSrcTO(); - DataTO destData = cpyCommand.getDestTO(); - - if (HypervisorType.Ovm3.equals(srcData.getHypervisorType()) && srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.TEMPLATE) { - LOGGER.debug("Snapshot to Template: " + cmd); - DataStoreTO srcStore = srcData.getDataStore(); - DataStoreTO destStore = destData.getDataStore(); - if (srcStore instanceof NfsTO && destStore instanceof NfsTO) { - HostVO host = hostDao.findById(hostId); - EndPoint ep = endPointSelector.selectHypervisorHost(new ZoneScope(host.getDataCenterId())); - if (ep != null) { - return new Pair(Boolean.TRUE, Long.valueOf(ep.getId())); - } - } - } - } return new Pair(Boolean.FALSE, Long.valueOf(hostId)); } } diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/XenServerGuru.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/XenServerGuru.java index e6ebe555da..9bfcba2596 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/XenServerGuru.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/XenServerGuru.java @@ -18,14 +18,11 @@ import java.util.ArrayList; import java.util.List; -import java.util.Map; import javax.inject.Inject; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; -import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.hypervisor.xenserver.XenserverConfigs; import org.apache.cloudstack.storage.command.CopyCommand; @@ -33,7 +30,7 @@ import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; -import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.log4j.Logger; import com.cloud.agent.api.Command; import com.cloud.agent.api.to.DataObjectType; @@ -57,34 +54,27 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.UserVmDao; -import org.apache.log4j.Logger; public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru, Configurable { private final Logger LOGGER = Logger.getLogger(XenServerGuru.class); @Inject - GuestOSDao _guestOsDao; - @Inject - GuestOSHypervisorDao _guestOsHypervisorDao; + private GuestOSDao _guestOsDao; @Inject - EndPointSelector endPointSelector; + private GuestOSHypervisorDao _guestOsHypervisorDao; @Inject - HostDao hostDao; + private HostDao hostDao; @Inject - VolumeDao _volumeDao; + private VolumeDao _volumeDao; @Inject - PrimaryDataStoreDao _storagePoolDao; + private PrimaryDataStoreDao _storagePoolDao; @Inject - VolumeDataFactory _volFactory; + private VolumeDataFactory _volFactory; @Inject - UserVmDao _userVmDao; + private UserVmDao _userVmDao; - static final ConfigKey MaxNumberOfVCPUSPerVM = new ConfigKey("Advanced", Integer.class, "xen.vm.vcpu.max", "16", + private static final ConfigKey MaxNumberOfVCPUSPerVM = new ConfigKey("Advanced", Integer.class, "xen.vm.vcpu.max", "16", "Maximum number of VCPUs that VM can get in XenServer.", true, ConfigKey.Scope.Cluster); - protected XenServerGuru() { - super(); - } - @Override public HypervisorType getHypervisorType() { return HypervisorType.XenServer; @@ -129,11 +119,6 @@ public boolean trackVmHostChange() { return true; } - @Override - public Map getClusterSettings(long vmId) { - return null; - } - @Override public List finalizeExpungeVolumes(VirtualMachine vm) { List commands = new ArrayList(); @@ -189,15 +174,13 @@ public Pair getCommandHostDelegation(long hostId, Command cmd) { DataStoreTO destStore = destData.getDataStore(); if (srcStore instanceof NfsTO && destStore instanceof NfsTO) { HostVO host = hostDao.findById(hostId); - EndPoint ep = endPointSelector.selectHypervisorHost(new ZoneScope(host.getDataCenterId())); - host = hostDao.findById(ep.getId()); hostDao.loadDetails(host); String hypervisorVersion = host.getHypervisorVersion(); String snapshotHotFixVersion = host.getDetail(XenserverConfigs.XS620HotFix); if (hypervisorVersion != null && !hypervisorVersion.equalsIgnoreCase("6.1.0")) { if (!(hypervisorVersion.equalsIgnoreCase("6.2.0") && !(snapshotHotFixVersion != null && snapshotHotFixVersion.equalsIgnoreCase(XenserverConfigs.XSHotFix62ESP1004)))) { - return new Pair(Boolean.TRUE, new Long(ep.getId())); + return new Pair(Boolean.TRUE, new Long(host.getId())); } } } diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java index fb14dc4408..e48c1f587a 100644 --- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java @@ -33,11 +33,9 @@ import com.cloud.network.dao.NetworkVO; import com.cloud.offering.ServiceOffering; import com.cloud.resource.ResourceManager; -import com.cloud.server.ConfigurationServer; import com.cloud.service.ServiceOfferingDetailsVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.service.dao.ServiceOfferingDetailsDao; -import com.cloud.storage.dao.VMTemplateDetailsDao; import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; import com.cloud.vm.NicProfile; @@ -55,29 +53,21 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis public static final Logger s_logger = Logger.getLogger(HypervisorGuruBase.class); @Inject - VMTemplateDetailsDao _templateDetailsDao; + private NicDao _nicDao; @Inject - NicDao _nicDao; + private NetworkDao _networkDao; @Inject - NetworkDao _networkDao; + private VMInstanceDao _virtualMachineDao; @Inject - VMInstanceDao _virtualMachineDao; + private UserVmDetailsDao _userVmDetailsDao; @Inject - UserVmDetailsDao _userVmDetailsDao; + private NicSecondaryIpDao _nicSecIpDao; @Inject - NicSecondaryIpDao _nicSecIpDao; + private ResourceManager _resourceMgr; @Inject - ConfigurationServer _configServer; + private ServiceOfferingDetailsDao _serviceOfferingDetailsDao; @Inject - ResourceManager _resourceMgr; - @Inject - ServiceOfferingDetailsDao _serviceOfferingDetailsDao; - @Inject - ServiceOfferingDao _serviceOfferingDao; - - protected HypervisorGuruBase() { - super(); - } + private ServiceOfferingDao _serviceOfferingDao; @Override public NicTO toNicTO(NicProfile profile) { From 41e3b61245c995c04d93475c91f014a87a989b3b Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Sat, 9 Apr 2016 03:11:39 +0530 Subject: [PATCH 097/203] travis: increase build verbosity Outputs for modules that fail or succeed with unit tests results Signed-off-by: Rohit Yadav --- tools/travis/install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/travis/install.sh b/tools/travis/install.sh index 5b6bc5ec1e..bbea5503df 100755 --- a/tools/travis/install.sh +++ b/tools/travis/install.sh @@ -37,9 +37,9 @@ fi export MAVEN_OPTS="-Xmx2048m -XX:MaxPermSize=500m -Djava.security.egd=file:/dev/./urandom" if [ $TEST_SEQUENCE_NUMBER -eq 1 ]; then - mvn -Pdeveloper,systemvm -Dsimulator clean install -T4 | egrep "Building|SUCCESS" + mvn -Pdeveloper,systemvm -Dsimulator clean install -T4 | egrep "Building|Tests|SUCCESS|FAILURE" else - mvn -Pdeveloper -Dsimulator clean install -DskipTests=true -T4 | egrep "Building|SUCCESS" + mvn -Pdeveloper -Dsimulator clean install -DskipTests=true -T4 | egrep "Building|Tests|SUCCESS|FAILURE" fi # Install mysql-connector-python From 16651feca02798f00a55f123c3e119a981576f53 Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Tue, 12 Apr 2016 11:15:09 +0200 Subject: [PATCH 098/203] agent: Enable IPv6 connectivity for KVM Agent to Management Server IPv4 is still preferred, so if the hostname of the Management Server returns a A and AAAA-record the Agent will still connect to the server over IPv4. This situation will however allow to use a hostname which only has a AAAA-record. In that case the Agent will connect to the Management Server over IPv6. --- agent/src/com/cloud/agent/AgentShell.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/agent/src/com/cloud/agent/AgentShell.java b/agent/src/com/cloud/agent/AgentShell.java index 961c106017..5e0da68c6d 100644 --- a/agent/src/com/cloud/agent/AgentShell.java +++ b/agent/src/com/cloud/agent/AgentShell.java @@ -409,12 +409,7 @@ public void start() { /* By default we only search for log4j.xml */ LogUtils.initLog4j("log4j-cloud.xml"); - /* - By default we disable IPv6 for now to maintain backwards - compatibility. At a later point in time we can change this - behavior to prefer IPv6 over IPv4. - */ - boolean ipv6disabled = true; + boolean ipv6disabled = false; String ipv6 = getProperty(null, "ipv6disabled"); if (ipv6 != null) { ipv6disabled = Boolean.parseBoolean(ipv6); From 48888e7405da4306b21cdb1f0159848c8ee57679 Mon Sep 17 00:00:00 2001 From: gabrascher Date: Sun, 20 Dec 2015 09:38:04 -0200 Subject: [PATCH 099/203] The goal of this PR is to review com.cloud.api.ApiServer class, with the following actions: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed “_” in beginning of global variables names: Variables was changed from “_” to “”, as this convension (private veriables with “_”) is common in C++ but not in Java. Removed unused code from ApiServer: - com.cloud.api.ApiServer.getPluggableServices(): Unused method. - com.cloud.api.ApiServer.getApiAccessCheckers(): Unused method. Methods and variables access level reviewed: - com.cloud.api.ApiServer.handleAsyncJobPublishEvent(String, String, Object): This method was private but the annotation @MessageHandler requests public methods, as can be seen in org.apache.cloudstack.framework.messagebus.MessageDispatcher.buildHandlerMethodCache(Class), which searches methods with the @MessageHandler annotation and changes it to accessible (“setAccessible(true)”). Thus, there is no reason for handleAsyncJobPublishEvent be a private method. - Global variables and methods called just by this class (ApiServer) were changed to private. Changed variables and methods from static to non static (if possible): As some variables/methods are used just by one object of this class (instantiated by springer), they were changed to non static. With that, calls from com.cloud.api.ApiServlet.ApiServlet() that used static methods from ApiServer, was changed from ApiServer. to _apiServer. that refers to the org.apache.cloudstack.api.ApiServerService interface. Thus, methods com.cloud.api.ApiServer.getJSONContentType() and com.cloud.api.ApiServer.isSecureSessionCookieEnabled() had to be included in the interface (org.apache.cloudstack.api.ApiServerService, interface implemented by class ApiServer). However, com.cloud.api.ApiServer.isEncodeApiResponse() was keept static, as its call hierarchy would have to be changed (more than planed for this PR). --- .../cloudstack/api/ApiServerService.java | 14 +- server/src/com/cloud/api/ApiServer.java | 312 +++++++++--------- server/src/com/cloud/api/ApiServlet.java | 106 +++--- server/test/com/cloud/api/ApiServletTest.java | 13 +- 4 files changed, 223 insertions(+), 222 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/ApiServerService.java b/api/src/org/apache/cloudstack/api/ApiServerService.java index 61474080d7..aeeb7b613c 100644 --- a/api/src/org/apache/cloudstack/api/ApiServerService.java +++ b/api/src/org/apache/cloudstack/api/ApiServerService.java @@ -16,10 +16,12 @@ // under the License. package org.apache.cloudstack.api; -import com.cloud.exception.CloudAuthenticationException; -import javax.servlet.http.HttpSession; -import java.util.Map; import java.net.InetAddress; +import java.util.Map; + +import javax.servlet.http.HttpSession; + +import com.cloud.exception.CloudAuthenticationException; public interface ApiServerService { public boolean verifyRequest(Map requestParameters, Long userId) throws ServerApiException; @@ -27,7 +29,7 @@ public interface ApiServerService { public Long fetchDomainId(String domainUUID); public ResponseObject loginUser(HttpSession session, String username, String password, Long domainId, String domainPath, InetAddress loginIpAddress, - Map requestParameters) throws CloudAuthenticationException; + Map requestParameters) throws CloudAuthenticationException; public void logoutUser(long userId); @@ -40,4 +42,8 @@ public ResponseObject loginUser(HttpSession session, String username, String pas public String handleRequest(Map params, String responseType, StringBuilder auditTrailSb) throws ServerApiException; public Class getCmdClass(String cmdName); + + public String getJSONContentType(); + + public boolean isSecureSessionCookieEnabled(); } diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index e5ae09725b..f76b851f5d 100644 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -16,45 +16,44 @@ // under the License. package com.cloud.api; -import com.cloud.api.dispatch.DispatchChainFactory; -import com.cloud.api.dispatch.DispatchTask; -import com.cloud.api.response.ApiResponseSerializer; -import com.cloud.configuration.Config; -import com.cloud.domain.Domain; -import com.cloud.domain.DomainVO; -import com.cloud.domain.dao.DomainDao; -import com.cloud.event.ActionEventUtils; -import com.cloud.event.EventCategory; -import com.cloud.event.EventTypes; -import com.cloud.exception.AccountLimitException; -import com.cloud.exception.CloudAuthenticationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.RequestLimitException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.DomainManager; -import com.cloud.user.User; -import com.cloud.user.UserAccount; -import com.cloud.user.UserVO; -import com.cloud.utils.ConstantTimeComparator; -import com.cloud.utils.HttpUtils; -import com.cloud.utils.NumbersUtil; -import com.cloud.utils.Pair; -import com.cloud.utils.StringUtils; -import com.cloud.utils.component.ComponentContext; -import com.cloud.utils.component.ManagerBase; -import com.cloud.utils.component.PluggableService; -import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.db.EntityManager; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.TransactionLegacy; -import com.cloud.utils.db.UUIDManager; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.exception.ExceptionProxyObject; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.security.SecureRandom; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + import org.apache.cloudstack.acl.APIChecker; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -138,83 +137,87 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.stereotype.Component; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.inject.Inject; -import javax.naming.ConfigurationException; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URLEncoder; -import java.security.SecureRandom; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TimeZone; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import com.cloud.api.dispatch.DispatchChainFactory; +import com.cloud.api.dispatch.DispatchTask; +import com.cloud.api.response.ApiResponseSerializer; +import com.cloud.configuration.Config; +import com.cloud.domain.Domain; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.event.ActionEventUtils; +import com.cloud.event.EventCategory; +import com.cloud.event.EventTypes; +import com.cloud.exception.AccountLimitException; +import com.cloud.exception.CloudAuthenticationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.RequestLimitException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.DomainManager; +import com.cloud.user.User; +import com.cloud.user.UserAccount; +import com.cloud.user.UserVO; +import com.cloud.utils.ConstantTimeComparator; +import com.cloud.utils.HttpUtils; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; +import com.cloud.utils.StringUtils; +import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.component.PluggableService; +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.TransactionLegacy; +import com.cloud.utils.db.UUIDManager; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.exception.ExceptionProxyObject; @Component public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiServerService { private static final Logger s_logger = Logger.getLogger(ApiServer.class.getName()); private static final Logger s_accessLogger = Logger.getLogger("apiserver." + ApiServer.class.getName()); - public static boolean encodeApiResponse = false; - public static boolean s_enableSecureCookie = false; - public static String s_jsonContentType = HttpUtils.JSON_CONTENT_TYPE; + private static boolean encodeApiResponse = false; + private boolean enableSecureCookie = false; + private String jsonContentType = HttpUtils.JSON_CONTENT_TYPE; /** * Non-printable ASCII characters - numbers 0 to 31 and 127 decimal */ - public static final String CONTROL_CHARACTERS = "[\000-\011\013-\014\016-\037\177]"; + private static final String CONTROL_CHARACTERS = "[\000-\011\013-\014\016-\037\177]"; @Inject - protected ApiDispatcher _dispatcher; + private ApiDispatcher dispatcher; @Inject - protected DispatchChainFactory dispatchChainFactory; + private DispatchChainFactory dispatchChainFactory; @Inject - private AccountManager _accountMgr; + private AccountManager accountMgr; @Inject - private DomainManager _domainMgr; + private DomainManager domainMgr; @Inject - private DomainDao _domainDao; + private DomainDao domainDao; @Inject - private UUIDManager _uuidMgr; + private UUIDManager uuidMgr; @Inject - private AsyncJobManager _asyncMgr; + private AsyncJobManager asyncMgr; @Inject - private ConfigurationDao _configDao; + private ConfigurationDao configDao; @Inject - private EntityManager _entityMgr; + private EntityManager entityMgr; @Inject - APIAuthenticationManager _authManager; + private APIAuthenticationManager authManager; + + private List pluggableServices; - List _pluggableServices; - List _apiAccessCheckers; + private List apiAccessCheckers; @Inject - protected ApiAsyncJobDispatcher _asyncDispatcher; + private ApiAsyncJobDispatcher asyncDispatcher; private static int s_workerCount = 0; private static final DateFormat DateFormatToUse = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); @@ -223,19 +226,16 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer private static ExecutorService s_executor = new ThreadPoolExecutor(10, 150, 60, TimeUnit.SECONDS, new LinkedBlockingQueue(), new NamedThreadFactory( "ApiServer")); @Inject - MessageBus _messageBus; - - public ApiServer() { - } + private MessageBus messageBus; @Override public boolean configure(final String name, final Map params) throws ConfigurationException { - _messageBus.subscribe(AsyncJob.Topics.JOB_EVENT_PUBLISH, MessageDispatcher.getDispatcher(this)); + messageBus.subscribe(AsyncJob.Topics.JOB_EVENT_PUBLISH, MessageDispatcher.getDispatcher(this)); return true; } @MessageHandler(topic = AsyncJob.Topics.JOB_EVENT_PUBLISH) - private void handleAsyncJobPublishEvent(String subject, String senderAddress, Object args) { + public void handleAsyncJobPublishEvent(String subject, String senderAddress, Object args) { assert (args != null); @SuppressWarnings("unchecked") @@ -257,8 +257,8 @@ private void handleAsyncJobPublishEvent(String subject, String senderAddress, Ob return; } - User userJobOwner = _accountMgr.getUserIncludingRemoved(job.getUserId()); - Account jobOwner = _accountMgr.getAccount(userJobOwner.getAccountId()); + User userJobOwner = accountMgr.getUserIncludingRemoved(job.getUserId()); + Account jobOwner = accountMgr.getAccount(userJobOwner.getAccountId()); // Get the event type from the cmdInfo json string String info = job.getCmdInfo(); @@ -296,9 +296,9 @@ private void handleAsyncJobPublishEvent(String subject, String senderAddress, Ob eventDescription.put("cmdInfo", job.getCmdInfo()); eventDescription.put("status", "" + job.getStatus() ); // If the event.accountinfo boolean value is set, get the human readable value for the username / domainname - Map configs = _configDao.getConfiguration("management-server", new HashMap()); + Map configs = configDao.getConfiguration("management-server", new HashMap()); if (Boolean.valueOf(configs.get("event.accountinfo"))) { - DomainVO domain = _domainDao.findById(jobOwner.getDomainId()); + DomainVO domain = domainDao.findById(jobOwner.getDomainId()); eventDescription.put("username", userJobOwner.getUsername()); eventDescription.put("accountname", jobOwner.getAccountName()); eventDescription.put("domainname", domain.getName()); @@ -316,9 +316,9 @@ private void handleAsyncJobPublishEvent(String subject, String senderAddress, Ob @Override public boolean start() { Integer apiPort = null; // api port, null by default - final SearchCriteria sc = _configDao.createSearchCriteria(); + final SearchCriteria sc = configDao.createSearchCriteria(); sc.addAnd("name", SearchCriteria.Op.EQ, Config.IntegrationAPIPort.key()); - final List values = _configDao.search(sc, null); + final List values = configDao.search(sc, null); if ((values != null) && (values.size() > 0)) { final ConfigurationVO apiPortConfig = values.get(0); if (apiPortConfig.getValue() != null) { @@ -326,19 +326,19 @@ public boolean start() { } } - final Map configs = _configDao.getConfiguration(); + final Map configs = configDao.getConfiguration(); final String strSnapshotLimit = configs.get(Config.ConcurrentSnapshotsThresholdPerHost.key()); if (strSnapshotLimit != null) { final Long snapshotLimit = NumbersUtil.parseLong(strSnapshotLimit, 1L); if (snapshotLimit.longValue() <= 0) { s_logger.debug("Global config parameter " + Config.ConcurrentSnapshotsThresholdPerHost.toString() + " is less or equal 0; defaulting to unlimited"); } else { - _dispatcher.setCreateSnapshotQueueSizeLimit(snapshotLimit); + dispatcher.setCreateSnapshotQueueSizeLimit(snapshotLimit); } } final Set> cmdClasses = new HashSet>(); - for (final PluggableService pluggableService : _pluggableServices) { + for (final PluggableService pluggableService : pluggableServices) { cmdClasses.addAll(pluggableService.getCommands()); if (s_logger.isDebugEnabled()) { s_logger.debug("Discovered plugin " + pluggableService.getClass().getSimpleName()); @@ -361,14 +361,14 @@ public boolean start() { } - setEncodeApiResponse(Boolean.valueOf(_configDao.getValue(Config.EncodeApiResponse.key()))); - final String jsonType = _configDao.getValue(Config.JSONDefaultContentType.key()); + setEncodeApiResponse(Boolean.valueOf(configDao.getValue(Config.EncodeApiResponse.key()))); + final String jsonType = configDao.getValue(Config.JSONDefaultContentType.key()); if (jsonType != null) { - s_jsonContentType = jsonType; + jsonContentType = jsonType; } - final Boolean enableSecureSessionCookie = Boolean.valueOf(_configDao.getValue(Config.EnableSecureSessionCookie.key())); + final Boolean enableSecureSessionCookie = Boolean.valueOf(configDao.getValue(Config.EnableSecureSessionCookie.key())); if (enableSecureSessionCookie != null) { - s_enableSecureCookie = enableSecureSessionCookie; + enableSecureCookie = enableSecureSessionCookie; } if (apiPort != null) { @@ -429,7 +429,7 @@ public void handle(final HttpRequest request, final HttpResponse response, final try { // always trust commands from API port, user context will always be UID_SYSTEM/ACCOUNT_ID_SYSTEM - CallContext.register(_accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); + CallContext.register(accountMgr.getSystemUser(), accountMgr.getSystemAccount()); sb.insert(0, "(userId=" + User.UID_SYSTEM + " accountId=" + Account.ACCOUNT_ID_SYSTEM + " sessionId=" + null + ") "); final String responseText = handleRequest(parameterMap, responseType, sb); sb.append(" 200 " + ((responseText == null) ? 0 : responseText.length())); @@ -494,7 +494,7 @@ public String handleRequest(final Map params, final String responseType, final S throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "Invalid request, no command sent"); } else { // Don't allow Login/Logout APIs to go past this point - if (_authManager.getAPIAuthenticator(command[0]) != null) { + if (authManager.getAPIAuthenticator(command[0]) != null) { return null; } final Map paramMap = new HashMap(); @@ -562,7 +562,7 @@ public String handleRequest(final Map params, final String responseType, final S } catch (final InsufficientCapacityException ex) { s_logger.info(ex.getMessage()); String errorMsg = ex.getMessage(); - if (!_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { + if (!accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { // hide internal details to non-admin user for security reason errorMsg = BaseCmd.USER_ERROR_MESSAGE; } @@ -573,7 +573,7 @@ public String handleRequest(final Map params, final String responseType, final S } catch (final ResourceUnavailableException ex) { s_logger.info(ex.getMessage()); String errorMsg = ex.getMessage(); - if (!_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { + if (!accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { // hide internal details to non-admin user for security reason errorMsg = BaseCmd.USER_ERROR_MESSAGE; } @@ -584,7 +584,7 @@ public String handleRequest(final Map params, final String responseType, final S } catch (final Exception ex) { s_logger.error("unhandled exception executing api command: " + ((command == null) ? "null" : command), ex); String errorMsg = ex.getMessage(); - if (!_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { + if (!accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { // hide internal details to non-admin user for security reason errorMsg = BaseCmd.USER_ERROR_MESSAGE; } @@ -597,7 +597,7 @@ public String handleRequest(final Map params, final String responseType, final S private String getBaseAsyncResponse(final long jobId, final BaseAsyncCmd cmd) { final AsyncJobResponse response = new AsyncJobResponse(); - final AsyncJob job = _entityMgr.findById(AsyncJob.class, jobId); + final AsyncJob job = entityMgr.findById(AsyncJob.class, jobId); response.setJobId(job.getUuid()); response.setResponseName(cmd.getCommandName()); return ApiResponseSerializer.toSerializedString(response, cmd.getResponseType()); @@ -605,7 +605,7 @@ private String getBaseAsyncResponse(final long jobId, final BaseAsyncCmd cmd) { private String getBaseAsyncCreateResponse(final long jobId, final BaseAsyncCreateCmd cmd, final String objectUuid) { final CreateCmdResponse response = new CreateCmdResponse(); - final AsyncJob job = _entityMgr.findById(AsyncJob.class, jobId); + final AsyncJob job = entityMgr.findById(AsyncJob.class, jobId); response.setJobId(job.getUuid()); response.setId(objectUuid); response.setResponseName(cmd.getCommandName()); @@ -626,7 +626,7 @@ private String queueCommand(final BaseCmd cmdObj, final Map para String objectUuid = null; if (cmdObj instanceof BaseAsyncCreateCmd) { final BaseAsyncCreateCmd createCmd = (BaseAsyncCreateCmd)cmdObj; - _dispatcher.dispatchCreateCmd(createCmd, params); + dispatcher.dispatchCreateCmd(createCmd, params); objectId = createCmd.getEntityId(); objectUuid = createCmd.getEntityUuid(); params.put("id", objectId.toString()); @@ -671,15 +671,15 @@ private String queueCommand(final BaseCmd cmdObj, final Map para // users can provide the job id they want to use, so log as it is a uuid and is unique String injectedJobId = asyncCmd.getInjectedJobId(); - _uuidMgr.checkUuidSimple(injectedJobId, AsyncJob.class); + uuidMgr.checkUuidSimple(injectedJobId, AsyncJob.class); AsyncJobVO job = new AsyncJobVO("", callerUserId, caller.getId(), cmdObj.getClass().getName(), ApiGsonHelper.getBuilder().create().toJson(params), instanceId, asyncCmd.getInstanceType() != null ? asyncCmd.getInstanceType().toString() : null, - injectedJobId); - job.setDispatcher(_asyncDispatcher.getName()); + injectedJobId); + job.setDispatcher(asyncDispatcher.getName()); - final long jobId = _asyncMgr.submitAsyncJob(job); + final long jobId = asyncMgr.submitAsyncJob(job); if (jobId == 0L) { final String errorMsg = "Unable to schedule async job for command " + job.getCmd(); @@ -695,7 +695,7 @@ private String queueCommand(final BaseCmd cmdObj, final Map para return getBaseAsyncResponse(jobId, asyncCmd); } } else { - _dispatcher.dispatch(cmdObj, params, false); + dispatcher.dispatch(cmdObj, params, false); // if the command is of the listXXXCommand, we will need to also return the // the job id and status if possible @@ -723,10 +723,10 @@ private void buildAsyncListResponse(final BaseListCmd command, final Account acc List jobs = null; // list all jobs for ROOT admin - if (_accountMgr.isRootAdmin(account.getId())) { - jobs = _asyncMgr.findInstancePendingAsyncJobs(command.getInstanceType().toString(), null); + if (accountMgr.isRootAdmin(account.getId())) { + jobs = asyncMgr.findInstancePendingAsyncJobs(command.getInstanceType().toString(), null); } else { - jobs = _asyncMgr.findInstancePendingAsyncJobs(command.getInstanceType().toString(), account.getId()); + jobs = asyncMgr.findInstancePendingAsyncJobs(command.getInstanceType().toString(), account.getId()); } if (jobs.size() == 0) { @@ -871,7 +871,7 @@ public boolean verifyRequest(final Map requestParameters, fina txn.close(); User user = null; // verify there is a user with this api key - final Pair userAcctPair = _accountMgr.findUserByApiKey(apiKey); + final Pair userAcctPair = accountMgr.findUserByApiKey(apiKey); if (userAcctPair == null) { s_logger.debug("apiKey does not map to a valid user -- ignoring request, apiKey: " + apiKey); return false; @@ -931,7 +931,7 @@ public boolean verifyRequest(final Map requestParameters, fina @Override public Long fetchDomainId(final String domainUUID) { - final Domain domain = _domainMgr.getDomain(domainUUID); + final Domain domain = domainMgr.getDomain(domainUUID); if (domain != null) return domain.getId(); else @@ -997,7 +997,7 @@ public ResponseObject loginUser(final HttpSession session, final String username if (domainPath == null || domainPath.trim().length() == 0) { domainId = Domain.ROOT_DOMAIN; } else { - final Domain domainObj = _domainMgr.findDomainByPath(domainPath); + final Domain domainObj = domainMgr.findDomainByPath(domainPath); if (domainObj != null) { domainId = domainObj.getId(); } else { // if an unknown path is passed in, fail the login call @@ -1006,7 +1006,7 @@ public ResponseObject loginUser(final HttpSession session, final String username } } - final UserAccount userAcct = _accountMgr.authenticateUser(username, password, domainId, loginIpAddress, requestParameters); + final UserAccount userAcct = accountMgr.authenticateUser(username, password, domainId, loginIpAddress, requestParameters); if (userAcct != null) { final String timezone = userAcct.getTimezone(); float offsetInHrs = 0f; @@ -1021,11 +1021,11 @@ public ResponseObject loginUser(final HttpSession session, final String username s_logger.info("Timezone offset from UTC is: " + offsetInHrs); } - final Account account = _accountMgr.getAccount(userAcct.getAccountId()); + final Account account = accountMgr.getAccount(userAcct.getAccountId()); // set the userId and account object for everyone session.setAttribute("userid", userAcct.getId()); - final UserVO user = (UserVO)_accountMgr.getActiveUser(userAcct.getId()); + final UserVO user = (UserVO)accountMgr.getActiveUser(userAcct.getId()); if (user.getUuid() != null) { session.setAttribute("user_UUID", user.getUuid()); } @@ -1037,7 +1037,7 @@ public ResponseObject loginUser(final HttpSession session, final String username session.setAttribute("account", account.getAccountName()); session.setAttribute("domainid", account.getDomainId()); - final DomainVO domain = (DomainVO)_domainMgr.getDomain(account.getDomainId()); + final DomainVO domain = (DomainVO)domainMgr.getDomain(account.getDomainId()); if (domain.getUuid() != null) { session.setAttribute("domain_UUID", domain.getUuid()); } @@ -1066,16 +1066,16 @@ public ResponseObject loginUser(final HttpSession session, final String username @Override public void logoutUser(final long userId) { - _accountMgr.logoutUser(userId); + accountMgr.logoutUser(userId); return; } @Override public boolean verifyUser(final Long userId) { - final User user = _accountMgr.getUserIncludingRemoved(userId); + final User user = accountMgr.getUserIncludingRemoved(userId); Account account = null; if (user != null) { - account = _accountMgr.getAccount(user.getAccountId()); + account = accountMgr.getAccount(user.getAccountId()); } if ((user == null) || (user.getRemoved() != null) || !user.getState().equals(Account.State.enabled) || (account == null) || @@ -1091,7 +1091,7 @@ private void checkCommandAvailable(final User user, final String commandName) th throw new PermissionDeniedException("User is null for role based API access check for command" + commandName); } - for (final APIChecker apiChecker : _apiAccessCheckers) { + for (final APIChecker apiChecker : apiAccessCheckers) { apiChecker.checkAccess(user, commandName); } } @@ -1107,7 +1107,7 @@ else if (cmdList.size() == 1) // determine the cmd class based on calling context ResponseView view = ResponseView.Restricted; if (CallContext.current() != null - && _accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { + && accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { view = ResponseView.Full; } for (Class cmdClass : cmdList) { @@ -1175,10 +1175,10 @@ public ListenerThread(final ApiServer requestHandler, final int port) { _params = new BasicHttpParams(); _params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 30000) - .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) - .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false) - .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) - .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); + .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) + .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false) + .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) + .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); // Set up the HTTP protocol processor final BasicHttpProcessor httpproc = new BasicHttpProcessor(); @@ -1340,37 +1340,31 @@ public String getSerializedApiError(final ServerApiException ex, final Map getPluggableServices() { - return _pluggableServices; - } - @Inject public void setPluggableServices(final List pluggableServices) { - _pluggableServices = pluggableServices; - } - - public List getApiAccessCheckers() { - return _apiAccessCheckers; + this.pluggableServices = pluggableServices; } @Inject public void setApiAccessCheckers(final List apiAccessCheckers) { - _apiAccessCheckers = apiAccessCheckers; + this.apiAccessCheckers = apiAccessCheckers; } public static boolean isEncodeApiResponse() { - return encodeApiResponse; + return ApiServer.encodeApiResponse; } private static void setEncodeApiResponse(final boolean encodeApiResponse) { ApiServer.encodeApiResponse = encodeApiResponse; } - public static boolean isSecureSessionCookieEnabled() { - return s_enableSecureCookie; + @Override + public boolean isSecureSessionCookieEnabled() { + return enableSecureCookie; } - public static String getJSONContentType() { - return s_jsonContentType; + @Override + public String getJSONContentType() { + return jsonContentType; } } diff --git a/server/src/com/cloud/api/ApiServlet.java b/server/src/com/cloud/api/ApiServlet.java index 51827daf1d..6c83698461 100644 --- a/server/src/com/cloud/api/ApiServlet.java +++ b/server/src/com/cloud/api/ApiServlet.java @@ -16,13 +16,23 @@ // under the License. package com.cloud.api; -import com.cloud.user.Account; -import com.cloud.user.AccountService; -import com.cloud.user.User; -import com.cloud.utils.HttpUtils; -import com.cloud.utils.StringUtils; -import com.cloud.utils.db.EntityManager; -import com.cloud.utils.net.NetUtils; +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.net.URLDecoder; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiServerService; @@ -36,22 +46,14 @@ import org.springframework.stereotype.Component; import org.springframework.web.context.support.SpringBeanAutowiringSupport; -import javax.inject.Inject; -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.net.URLDecoder; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import com.cloud.user.Account; +import com.cloud.user.AccountService; +import com.cloud.user.User; + +import com.cloud.utils.HttpUtils; +import com.cloud.utils.StringUtils; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.net.NetUtils; @Component("apiServlet") @SuppressWarnings("serial") @@ -63,15 +65,15 @@ public class ApiServlet extends HttpServlet { "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR", "Remote_Addr")); @Inject - ApiServerService _apiServer; + ApiServerService apiServer; @Inject - AccountService _accountMgr; + AccountService accountMgr; @Inject - EntityManager _entityMgr; + EntityManager entityMgr; @Inject - ManagedContext _managedContext; + ManagedContext managedContext; @Inject - APIAuthenticationManager _authManager; + APIAuthenticationManager authManager; public ApiServlet() { } @@ -121,7 +123,7 @@ private String decodeUtf8(final String value) { } private void processRequest(final HttpServletRequest req, final HttpServletResponse resp) { - _managedContext.runWithContext(new Runnable() { + managedContext.runWithContext(new Runnable() { @Override public void run() { processRequestInContext(req, resp); @@ -156,7 +158,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp try { if (HttpUtils.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) { - resp.setContentType(ApiServer.getJSONContentType()); + resp.setContentType(apiServer.getJSONContentType()); } else if (HttpUtils.RESPONSE_TYPE_XML.equalsIgnoreCase(responseType)){ resp.setContentType(HttpUtils.XML_CONTENT_TYPE); } @@ -171,7 +173,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp if (commandObj != null) { final String command = (String) commandObj[0]; - APIAuthenticator apiAuthenticator = _authManager.getAPIAuthenticator(command); + APIAuthenticator apiAuthenticator = authManager.getAPIAuthenticator(command); if (apiAuthenticator != null) { auditTrailSb.append("command="); auditTrailSb.append(command); @@ -187,7 +189,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp } } session = req.getSession(true); - if (ApiServer.isSecureSessionCookieEnabled()) { + if (apiServer.isSecureSessionCookieEnabled()) { resp.setHeader("SET-COOKIE", String.format("JSESSIONID=%s;Secure;HttpOnly;Path=/client", session.getId())); if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) { @@ -218,7 +220,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp } auditTrailSb.insert(0, "(userId=" + userId + " accountId=" + accountId + " sessionId=" + session.getId() + ")"); if (userId != null) { - _apiServer.logoutUser(userId); + apiServer.logoutUser(userId); } try { session.invalidate(); @@ -229,7 +231,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp sessionKeyCookie.setMaxAge(0); resp.addCookie(sessionKeyCookie); } - HttpUtils.writeHttpResponse(resp, responseString, httpResponseCode, responseType, ApiServer.getJSONContentType()); + HttpUtils.writeHttpResponse(resp, responseString, httpResponseCode, responseType, apiServer.getJSONContentType()); return; } } @@ -253,22 +255,22 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp } auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials"); final String serializedResponse = - _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); - HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, ApiServer.getJSONContentType()); + apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); + HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, apiServer.getJSONContentType()); return; } // Do a sanity check here to make sure the user hasn't already been deleted - if ((userId != null) && (account != null) && (accountObj != null) && _apiServer.verifyUser(userId)) { + if ((userId != null) && (account != null) && (accountObj != null) && apiServer.verifyUser(userId)) { final String[] command = (String[])params.get(ApiConstants.COMMAND); if (command == null) { s_logger.info("missing command, ignoring request..."); auditTrailSb.append(" " + HttpServletResponse.SC_BAD_REQUEST + " " + "no command specified"); - final String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_BAD_REQUEST, "no command specified", params, responseType); - HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_BAD_REQUEST, responseType, ApiServer.getJSONContentType()); + final String serializedResponse = apiServer.getSerializedApiError(HttpServletResponse.SC_BAD_REQUEST, "no command specified", params, responseType); + HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_BAD_REQUEST, responseType, apiServer.getJSONContentType()); return; } - final User user = _entityMgr.findById(User.class, userId); + final User user = entityMgr.findById(User.class, userId); CallContext.register(user, (Account)accountObj); } else { // Invalidate the session to ensure we won't allow a request across management server @@ -280,22 +282,22 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials"); final String serializedResponse = - _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); - HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, ApiServer.getJSONContentType()); + apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); + HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, apiServer.getJSONContentType()); return; } } else { - CallContext.register(_accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); + CallContext.register(accountMgr.getSystemUser(), accountMgr.getSystemAccount()); } - if (_apiServer.verifyRequest(params, userId)) { + if (apiServer.verifyRequest(params, userId)) { auditTrailSb.insert(0, "(userId=" + CallContext.current().getCallingUserId() + " accountId=" + CallContext.current().getCallingAccount().getId() + - " sessionId=" + (session != null ? session.getId() : null) + ")"); + " sessionId=" + (session != null ? session.getId() : null) + ")"); // Add the HTTP method (GET/POST/PUT/DELETE) as well into the params map. params.put("httpmethod", new String[] {req.getMethod()}); - final String response = _apiServer.handleRequest(params, responseType, auditTrailSb); - HttpUtils.writeHttpResponse(resp, response != null ? response : "", HttpServletResponse.SC_OK, responseType, ApiServer.getJSONContentType()); + final String response = apiServer.handleRequest(params, responseType, auditTrailSb); + HttpUtils.writeHttpResponse(resp, response != null ? response : "", HttpServletResponse.SC_OK, responseType, apiServer.getJSONContentType()); } else { if (session != null) { try { @@ -306,15 +308,15 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials and/or request signature"); final String serializedResponse = - _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials and/or request signature", params, - responseType); - HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, ApiServer.getJSONContentType()); + apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials and/or request signature", params, + responseType); + HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, apiServer.getJSONContentType()); } } catch (final ServerApiException se) { - final String serializedResponseText = _apiServer.getSerializedApiError(se, params, responseType); + final String serializedResponseText = apiServer.getSerializedApiError(se, params, responseType); resp.setHeader("X-Description", se.getDescription()); - HttpUtils.writeHttpResponse(resp, serializedResponseText, se.getErrorCode().getHttpCode(), responseType, ApiServer.getJSONContentType()); + HttpUtils.writeHttpResponse(resp, serializedResponseText, se.getErrorCode().getHttpCode(), responseType, apiServer.getJSONContentType()); auditTrailSb.append(" " + se.getErrorCode() + " " + se.getDescription()); } catch (final Exception ex) { s_logger.error("unknown exception writing api response", ex); diff --git a/server/test/com/cloud/api/ApiServletTest.java b/server/test/com/cloud/api/ApiServletTest.java index a0a600409c..e7cdf41a38 100644 --- a/server/test/com/cloud/api/ApiServletTest.java +++ b/server/test/com/cloud/api/ApiServletTest.java @@ -89,7 +89,7 @@ public class ApiServletTest { @SuppressWarnings("unchecked") @Before public void setup() throws SecurityException, NoSuchFieldException, - IllegalArgumentException, IllegalAccessException, IOException, UnknownHostException { + IllegalArgumentException, IllegalAccessException, IOException, UnknownHostException { servlet = new ApiServlet(); responseWriter = new StringWriter(); Mockito.when(response.getWriter()).thenReturn( @@ -98,8 +98,7 @@ public void setup() throws SecurityException, NoSuchFieldException, Mockito.when(accountService.getSystemUser()).thenReturn(user); Mockito.when(accountService.getSystemAccount()).thenReturn(account); - Field accountMgrField = ApiServlet.class - .getDeclaredField("_accountMgr"); + Field accountMgrField = ApiServlet.class.getDeclaredField("accountMgr"); accountMgrField.setAccessible(true); accountMgrField.set(servlet, accountService); @@ -107,11 +106,11 @@ public void setup() throws SecurityException, NoSuchFieldException, Mockito.when(authenticator.authenticate(Mockito.anyString(), Mockito.anyMap(), Mockito.isA(HttpSession.class), Mockito.same(InetAddress.getByName("127.0.0.1")), Mockito.anyString(), Mockito.isA(StringBuilder.class), Mockito.isA(HttpServletRequest.class), Mockito.isA(HttpServletResponse.class))).thenReturn("{\"loginresponse\":{}"); - Field authManagerField = ApiServlet.class.getDeclaredField("_authManager"); + Field authManagerField = ApiServlet.class.getDeclaredField("authManager"); authManagerField.setAccessible(true); authManagerField.set(servlet, authManager); - Field apiServerField = ApiServlet.class.getDeclaredField("_apiServer"); + Field apiServerField = ApiServlet.class.getDeclaredField("apiServer"); apiServerField.setAccessible(true); apiServerField.set(servlet, apiServer); } @@ -176,7 +175,7 @@ public void processRequestInContextUnauthorizedGET() { Mockito.when(request.getMethod()).thenReturn("GET"); Mockito.when( apiServer.verifyRequest(Mockito.anyMap(), Mockito.anyLong())) - .thenReturn(false); + .thenReturn(false); servlet.processRequestInContext(request, response); Mockito.verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED); Mockito.verify(apiServer, Mockito.never()).handleRequest( @@ -190,7 +189,7 @@ public void processRequestInContextAuthorizedGet() { Mockito.when(request.getMethod()).thenReturn("GET"); Mockito.when( apiServer.verifyRequest(Mockito.anyMap(), Mockito.anyLong())) - .thenReturn(true); + .thenReturn(true); servlet.processRequestInContext(request, response); Mockito.verify(response).setStatus(HttpServletResponse.SC_OK); Mockito.verify(apiServer, Mockito.times(1)).handleRequest( From 8355b586a0f420ca183e6f4657305284e68487e3 Mon Sep 17 00:00:00 2001 From: weingartner Date: Sun, 10 Apr 2016 18:06:12 -0300 Subject: [PATCH 100/203] Remove test cases duplicated code. --- .../resource/CitrixResourceBaseTest.java | 26 ++++++++---- .../resource/XcpOssResourceTest.java | 29 ++++---------- .../resource/XcpServerResourceTest.java | 29 ++++---------- .../resource/XenServer56FP1ResourceTest.java | 32 +++++---------- .../resource/XenServer56ResourceTest.java | 30 +++++--------- .../resource/XenServer56SP2ResourceTest.java | 31 +++++--------- .../resource/XenServer600ResourceTest.java | 32 +++++---------- .../resource/XenServer625ResourceTest.java | 40 +++++++------------ .../resource/XenServer650ResourceTest.java | 30 +++++--------- 9 files changed, 100 insertions(+), 179 deletions(-) diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java index 81853d4554..67fce92795 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java @@ -19,14 +19,22 @@ import java.util.List; import org.junit.Assert; +import org.junit.Test; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import com.cloud.utils.script.Script; -public abstract class CitrixResourceBaseTest { +public class CitrixResourceBaseTest { - public void testGetPathFilesExeption(CitrixResourceBase citrixResourceBase) { + protected CitrixResourceBase citrixResourceBase = new CitrixResourceBase() { + @Override + protected String getPatchFilePath() { + return null; + } + }; + + public void testGetPathFilesExeption() { String patch = citrixResourceBase.getPatchFilePath(); PowerMockito.mockStatic(Script.class); @@ -36,7 +44,7 @@ public void testGetPathFilesExeption(CitrixResourceBase citrixResourceBase) { } - public void testGetPathFilesListReturned(CitrixResourceBase citrixResourceBase) { + public void testGetPathFilesListReturned() { String patch = citrixResourceBase.getPatchFilePath(); PowerMockito.mockStatic(Script.class); @@ -50,7 +58,8 @@ public void testGetPathFilesListReturned(CitrixResourceBase citrixResourceBase) Assert.assertEquals(receivedPath, pathExpected); } - public void testGetGuestOsTypeNull(CitrixResourceBase citrixResourceBase) { + @Test + public void testGetGuestOsTypeNull() { String platformEmulator = null; String expected = "Other install media"; @@ -58,7 +67,8 @@ public void testGetGuestOsTypeNull(CitrixResourceBase citrixResourceBase) { Assert.assertEquals(expected, guestOsType); } - public void testGetGuestOsTypeEmpty(CitrixResourceBase citrixResourceBase) { + @Test + public void testGetGuestOsTypeEmpty() { String platformEmulator = ""; String expected = "Other install media"; @@ -66,7 +76,8 @@ public void testGetGuestOsTypeEmpty(CitrixResourceBase citrixResourceBase) { Assert.assertEquals(expected, guestOsType); } - public void testGetGuestOsTypeBlank(CitrixResourceBase citrixResourceBase) { + @Test + public void testGetGuestOsTypeBlank() { String platformEmulator = " "; String expected = "Other install media"; @@ -74,7 +85,8 @@ public void testGetGuestOsTypeBlank(CitrixResourceBase citrixResourceBase) { Assert.assertEquals(expected, guestOsType); } - public void testGetGuestOsTypeOther(CitrixResourceBase citrixResourceBase) { + @Test + public void testGetGuestOsTypeOther() { String platformEmulator = "My Own Linux Distribution Y.M (64-bit)"; String guestOsType = citrixResourceBase.getGuestOsType(platformEmulator); diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java index cd4db0f6d0..9266bf915f 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -26,11 +27,14 @@ @RunWith(PowerMockRunner.class) public class XcpOssResourceTest extends CitrixResourceBaseTest{ - private XcpOssResource xcpOssResource = new XcpOssResource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XcpOssResource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xcpOssResource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xcposs/patch"; Assert.assertEquals(patch, patchFilePath); @@ -39,29 +43,12 @@ public void testPatchFilePath() { @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFiles(){ - testGetPathFilesExeption(xcpOssResource); + testGetPathFilesExeption(); } @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xcpOssResource); - } - - @Test - public void testGetOsTypeNull() { - testGetGuestOsTypeNull(xcpOssResource); - } - @Test - public void testGetOsTypeEmpty() { - testGetGuestOsTypeEmpty(xcpOssResource); - } - @Test - public void testGetOsTypeBlank() { - testGetGuestOsTypeBlank(xcpOssResource); - } - @Test - public void testGetOsTypeOther() { - testGetGuestOsTypeOther(xcpOssResource); + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java index 95ba8f6785..5b80a1dc08 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -27,11 +28,14 @@ @RunWith(PowerMockRunner.class) public class XcpServerResourceTest extends CitrixResourceBaseTest{ - private XcpServerResource xcpServerResource = new XcpServerResource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XcpServerResource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xcpServerResource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xcpserver/patch"; Assert.assertEquals(patch, patchFilePath); @@ -40,29 +44,12 @@ public void testPatchFilePath() { @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFilesExeption(){ - testGetPathFilesExeption(xcpServerResource); + testGetPathFilesExeption(); } @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xcpServerResource); - } - - @Test - public void testGetOsTypeNull() { - testGetGuestOsTypeNull(xcpServerResource); - } - @Test - public void testGetOsTypeEmpty() { - testGetGuestOsTypeEmpty(xcpServerResource); - } - @Test - public void testGetOsTypeBlank() { - testGetGuestOsTypeBlank(xcpServerResource); - } - @Test - public void testGetOsTypeOther() { - testGetGuestOsTypeOther(xcpServerResource); + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java index bba3b6ad04..d2edbd4db9 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -23,43 +24,32 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; + @RunWith(PowerMockRunner.class) public class XenServer56FP1ResourceTest extends CitrixResourceBaseTest{ - private XenServer56FP1Resource xenServer56FP1Resource = new XenServer56FP1Resource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XenServer56FP1Resource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xenServer56FP1Resource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xenserver56fp1/patch"; Assert.assertEquals(patch, patchFilePath); } + @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFiles(){ - testGetPathFilesExeption(xenServer56FP1Resource); + testGetPathFilesExeption(); } + @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xenServer56FP1Resource); - } - - @Test - public void testGetOsTypeNull() { - testGetGuestOsTypeNull(xenServer56FP1Resource); - } - @Test - public void testGetOsTypeEmpty() { - testGetGuestOsTypeEmpty(xenServer56FP1Resource); - } - @Test - public void testGetOsTypeBlank() { - testGetGuestOsTypeBlank(xenServer56FP1Resource); - } - @Test - public void testGetOsTypeOther() { - testGetGuestOsTypeOther(xenServer56FP1Resource); + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java index 4a6ff0bea5..dccdb28175 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -26,11 +27,14 @@ @RunWith(PowerMockRunner.class) public class XenServer56ResourceTest extends CitrixResourceBaseTest { - private XenServer56Resource xenServer56Resource = new XenServer56Resource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XenServer56Resource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xenServer56Resource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xenserver56/patch"; Assert.assertEquals(patch, patchFilePath); @@ -39,28 +43,12 @@ public void testPatchFilePath() { @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFiles(){ - testGetPathFilesExeption(xenServer56Resource); + testGetPathFilesExeption(); } + @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xenServer56Resource); - } - - @Test - public void testGetOsTypeNull() { - testGetGuestOsTypeNull(xenServer56Resource); - } - @Test - public void testGetOsTypeEmpty() { - testGetGuestOsTypeEmpty(xenServer56Resource); - } - @Test - public void testGetOsTypeBlank() { - testGetGuestOsTypeBlank(xenServer56Resource); - } - @Test - public void testGetOsTypeOther() { - testGetGuestOsTypeOther(xenServer56Resource); + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java index defbe9be9d..4cc9470538 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -26,40 +27,28 @@ @RunWith(PowerMockRunner.class) public class XenServer56SP2ResourceTest extends CitrixResourceBaseTest{ - private XenServer56SP2Resource xenServer56SP2Resource = new XenServer56SP2Resource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XenServer56SP2Resource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xenServer56SP2Resource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xenserver56fp1/patch"; Assert.assertEquals(patch, patchFilePath); } + @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFiles(){ - testGetPathFilesExeption(xenServer56SP2Resource); + testGetPathFilesExeption(); } + @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xenServer56SP2Resource); - } - - @Test - public void testGetOsTypeNull() { - testGetGuestOsTypeNull(xenServer56SP2Resource); - } - @Test - public void testGetOsTypeEmpty() { - testGetGuestOsTypeEmpty(xenServer56SP2Resource); - } - @Test - public void testGetOsTypeBlank() { - testGetGuestOsTypeBlank(xenServer56SP2Resource); - } - @Test - public void testGetOsTypeOther() { - testGetGuestOsTypeOther(xenServer56SP2Resource); + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java index 899f0a7339..d5eba2af38 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -26,40 +27,29 @@ @RunWith(PowerMockRunner.class) public class XenServer600ResourceTest extends CitrixResourceBaseTest{ - private XenServer600Resource xenServer600Resource = new XenServer600Resource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XenServer600Resource(); + } + @Test public void testPatchFilePath() { - String patchFilePath = xenServer600Resource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xenserver60/patch"; Assert.assertEquals(patch, patchFilePath); } + @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFiles(){ - testGetPathFilesExeption(xenServer600Resource); + testGetPathFilesExeption(); } + @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xenServer600Resource); - } - - @Test - public void testGetOsTypeNull() { - testGetGuestOsTypeNull(xenServer600Resource); - } - @Test - public void testGetOsTypeEmpty() { - testGetGuestOsTypeEmpty(xenServer600Resource); - } - @Test - public void testGetOsTypeBlank() { - testGetGuestOsTypeBlank(xenServer600Resource); - } - @Test - public void testGetOsTypeOther() { - testGetGuestOsTypeOther(xenServer600Resource); + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java index 4c6a6ecf62..9998c2f02b 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -23,43 +24,32 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; + @RunWith(PowerMockRunner.class) -public class XenServer625ResourceTest extends CitrixResourceBaseTest{ +public class XenServer625ResourceTest extends CitrixResourceBaseTest { - private Xenserver625Resource xenServer625Resource = new Xenserver625Resource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new Xenserver625Resource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xenServer625Resource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xenserver62/patch"; Assert.assertEquals(patch, patchFilePath); } + @Test(expected = CloudRuntimeException.class) - @PrepareForTest(Script.class ) - public void testGetFiles(){ - testGetPathFilesExeption(xenServer625Resource); - } - @Test - @PrepareForTest(Script.class ) - public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xenServer625Resource); + @PrepareForTest(Script.class) + public void testGetFiles() { + testGetPathFilesExeption(); } @Test - public void testGetOsTypeNull() { - testGetGuestOsTypeNull(xenServer625Resource); - } - @Test - public void testGetOsTypeEmpty() { - testGetGuestOsTypeEmpty(xenServer625Resource); - } - @Test - public void testGetOsTypeBlank() { - testGetGuestOsTypeBlank(xenServer625Resource); - } - @Test - public void testGetOsTypeOther() { - testGetGuestOsTypeOther(xenServer625Resource); + @PrepareForTest(Script.class) + public void testGetFilesListReturned() { + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java index a062c0c99d..5195025de3 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -26,11 +27,14 @@ @RunWith(PowerMockRunner.class) public class XenServer650ResourceTest extends CitrixResourceBaseTest{ - private XenServer650Resource xenServer650Resource = new XenServer650Resource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XenServer650Resource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xenServer650Resource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xenserver65/patch"; Assert.assertEquals(patch, patchFilePath); @@ -39,28 +43,12 @@ public void testPatchFilePath() { @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFiles(){ - testGetPathFilesExeption(xenServer650Resource); + testGetPathFilesExeption(); } + @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xenServer650Resource); - } - - @Test - public void testGetOsTypeNull() { - testGetGuestOsTypeNull(xenServer650Resource); - } - @Test - public void testGetOsTypeEmpty() { - testGetGuestOsTypeEmpty(xenServer650Resource); - } - @Test - public void testGetOsTypeBlank() { - testGetGuestOsTypeBlank(xenServer650Resource); - } - @Test - public void testGetOsTypeOther() { - testGetGuestOsTypeOther(xenServer650Resource); + testGetPathFilesListReturned(); } } From 7add16d3d9c06d3a806c165559601056a6269e0e Mon Sep 17 00:00:00 2001 From: John Burwell Date: Sat, 2 Apr 2016 18:31:08 -0400 Subject: [PATCH 101/203] CLOUDSTACK-9334: Support jenv and pyenv to manage Java and Python versions * Adds .java-version to specify Java 1.7 as the JDK version to use for CloudStack development. * Adds .python-vresion to specify Python 2.7.11 as the Python to use for CloudStack development. * Adds requirements.txt to specify the default dependencies used for CloudStack development. It does not include Marvin's dependencies because it's bundle already defines the dependencies which are installed with Marvin. * Adds .java-version and .python-version to the RAT excludes because neither jenv or pyenv support comments in these files * Updates INSTALL.md to explain how to utilize jenv and pyenv for CloudStack development --- .java-version | 1 + .python-version | 1 + INSTALL.md | 17 +++++++++++++++++ pom.xml | 2 ++ requirements.txt | 21 +++++++++++++++++++++ 5 files changed, 42 insertions(+) create mode 100644 .java-version create mode 100644 .python-version create mode 100644 requirements.txt diff --git a/.java-version b/.java-version new file mode 100644 index 0000000000..d3bdbdf1fd --- /dev/null +++ b/.java-version @@ -0,0 +1 @@ +1.7 diff --git a/.python-version b/.python-version new file mode 100644 index 0000000000..564383308e --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +cloudstack diff --git a/INSTALL.md b/INSTALL.md index 9924ba91f5..8a83fb0f72 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -38,6 +38,23 @@ Start the MySQL service: $ service mysqld start +### Using jenv and/or pyenv for Version Management + +CloudStack is built using Java and Python. To make selection of these tools versions more consistent and ease installation for developers, optional support for [jenv](http://www.jenv.be/) and [pyenv](https://github.com/yyuu/pyenv) with [virtualenv]|(https://github.com/yyuu/pyenv-virtualenv) is provided. jenv installation instructions are available here and pyenv installation instructions are available here. For users of [oh-my-zsh](http://ohmyz.sh/) there is a pyenv plugin available to trigger configuration of pyenv in a shell session. + +Following installation, execute the following commands to configure jenv and pyenv for use with CloudStack development: + +''' + # pyenv install 2.7.11 # Install Python 2.7.11 + # pyenv virtualenv 2.7.11 cloudstack # Create a cloidstack virtualenv using Python 2.7.11 + # pip install -r /requirements.txt # Install cloudstack Python dependencies + # jenv add # Add Java7 to jenv +''' + +*N.B.* If you are running Linux, you may need to install additional packages to allow pyenv to build Python. + +Following these steps, jenv and pyenv will use .java-version and .python-version files in the root of the CloudStack source tree to switch to the correct Java version and the cloudstack Python virtualenv for CloudStack development. + ## Getting the Source Code You may get the source code from the repository hosted on Apache: diff --git a/pom.xml b/pom.xml index c18c377cf2..724aeb1f09 100644 --- a/pom.xml +++ b/pom.xml @@ -756,6 +756,8 @@ CONTRIBUTING.md tools/docker/Dockerfile tools/docker/supervisord.conf + .java-version + .python-version .idea/ **/*.log **/*.patch diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000..f5c7666231 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Install the latest version of cloudmonkey +cloudmonkey + +# Marvin dependencies are installed via its bundle From ba9a61a30291effefc3857789096f04ebd5e5ad4 Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Mon, 18 Apr 2016 11:56:08 -0600 Subject: [PATCH 102/203] =?UTF-8?q?CLOUDSTACK-9354=20-=20Fixing=20an=20iss?= =?UTF-8?q?ue=20in=20Marvin=20around=20creating=20a=20template=20from=20a?= =?UTF-8?q?=20snapshot=20(if=20=E2=80=9Cis=20public=E2=80=9D=20is=20not=20?= =?UTF-8?q?provided,=20there=20was=20a=20problem)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/marvin/marvin/lib/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index e2f4a2c864..ff4513991d 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -1201,8 +1201,8 @@ def create_from_snapshot(cls, apiclient, snapshot, services, random_gen() ]) if random_name else services["name"] - if services["ispublic"]: - cmd.ispublic = services["ispublic"] + if "ispublic" in services: + cmd.ispublic = services["ispublic"] if "ostypeid" in services: cmd.ostypeid = services["ostypeid"] From c3353257efcc249f9d50becdf8f3d0de0238ae92 Mon Sep 17 00:00:00 2001 From: SudharmaJain Date: Thu, 3 Dec 2015 14:11:14 +0530 Subject: [PATCH 103/203] CLOUDSTACK-9100: ISO.CREATE/TEMPLATE.CREATE event missing for usage_event by template sync thread --- .../storage/image/TemplateServiceImpl.java | 75 ++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index a1d10e3280..df2d37f05b 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -27,6 +27,12 @@ import javax.inject.Inject; +import com.cloud.configuration.Resource; +import com.cloud.event.EventTypes; +import com.cloud.event.UsageEventUtils; +import org.apache.cloudstack.engine.subsystem.api.storage.Scope; +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.framework.messagebus.PublishScope; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; @@ -137,6 +143,8 @@ public class TemplateServiceImpl implements TemplateService { @Inject StorageCacheManager _cacheMgr; @Inject + MessageBus _messageBus; + @Inject ImageStoreDetailsUtil imageStoreDetailsUtil; class TemplateOpContext extends AsyncRpcContext { @@ -355,6 +363,16 @@ public void handleTemplateSync(DataStore store) { toBeDownloaded.add(tmplt); } } else { + if(tmpltStore.getDownloadState() != Status.DOWNLOADED) { + String etype = EventTypes.EVENT_TEMPLATE_CREATE; + if (tmplt.getFormat() == ImageFormat.ISO) { + etype = EventTypes.EVENT_ISO_CREATE; + } + + UsageEventUtils.publishUsageEvent(etype, tmplt.getAccountId(), zoneId, tmplt.getId(), tmplt.getName(), null, null, + tmpltInfo.getPhysicalSize(), tmpltInfo.getSize(), VirtualMachineTemplate.class.getName(), tmplt.getUuid()); + } + tmpltStore.setDownloadPercent(100); tmpltStore.setDownloadState(Status.DOWNLOADED); tmpltStore.setState(ObjectInDataStoreStateMachine.State.Ready); @@ -405,6 +423,14 @@ public void handleTemplateSync(DataStore store) { tmlpt.setSize(tmpltInfo.getSize()); _templateDao.update(tmplt.getId(), tmlpt); associateTemplateToZone(tmplt.getId(), zoneId); + + String etype = EventTypes.EVENT_TEMPLATE_CREATE; + if (tmplt.getFormat() == ImageFormat.ISO) { + etype = EventTypes.EVENT_ISO_CREATE; + } + + UsageEventUtils.publishUsageEvent(etype, tmplt.getAccountId(), zoneId, tmplt.getId(), tmplt.getName(), null, null, + tmpltInfo.getPhysicalSize(), tmpltInfo.getSize(), VirtualMachineTemplate.class.getName(), tmplt.getUuid()); } } else if (tmplt.getState() == VirtualMachineTemplate.State.NotUploaded || tmplt.getState() == VirtualMachineTemplate.State.UploadInProgress) { s_logger.info("Template Sync did not find " + uniqueName + " on image store " + storeId + " uploaded using SSVM, marking it as failed"); @@ -474,8 +500,12 @@ public void handleTemplateSync(DataStore store) { if (availHypers.contains(tmplt.getHypervisorType())) { s_logger.info("Downloading template " + tmplt.getUniqueName() + " to image store " + store.getName()); associateTemplateToZone(tmplt.getId(), zoneId); - TemplateInfo tmpl = _templateFactory.getTemplate(tmplt.getId(), DataStoreRole.Image); - createTemplateAsync(tmpl, store, null); + TemplateInfo tmpl = _templateFactory.getTemplate(tmplt.getId(), store); + TemplateOpContext context = new TemplateOpContext<>(null,(TemplateObject)tmpl, null); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().createTemplateAsyncCallBack(null, null)); + caller.setContext(context); + createTemplateAsync(tmpl, store, caller); } else { s_logger.info("Skip downloading template " + tmplt.getUniqueName() + " since current data center does not have hypervisor " + tmplt.getHypervisorType().toString()); @@ -566,6 +596,47 @@ public void associateCrosszoneTemplatesToZone(long dcId) { } } + protected Void createTemplateAsyncCallBack(AsyncCallbackDispatcher callback, + TemplateOpContext context) { + TemplateInfo template = context.template; + TemplateApiResult result = callback.getResult(); + if (result.isSuccess()) { + VMTemplateVO tmplt = _templateDao.findById(template.getId()); + // need to grant permission for public templates + if (tmplt.isPublicTemplate()) { + _messageBus.publish(null, TemplateManager.MESSAGE_REGISTER_PUBLIC_TEMPLATE_EVENT, PublishScope.LOCAL, tmplt.getId()); + } + long accountId = tmplt.getAccountId(); + if (template.getSize() != null) { + // publish usage event + String etype = EventTypes.EVENT_TEMPLATE_CREATE; + if (tmplt.getFormat() == ImageFormat.ISO) { + etype = EventTypes.EVENT_ISO_CREATE; + } + // get physical size from template_store_ref table + long physicalSize = 0; + DataStore ds = template.getDataStore(); + TemplateDataStoreVO tmpltStore = _vmTemplateStoreDao.findByStoreTemplate(ds.getId(), template.getId()); + if (tmpltStore != null) { + physicalSize = tmpltStore.getPhysicalSize(); + } else { + s_logger.warn("No entry found in template_store_ref for template id: " + template.getId() + " and image store id: " + ds.getId() + + " at the end of registering template!"); + } + Scope dsScope = ds.getScope(); + if (dsScope.getScopeId() != null) { + UsageEventUtils.publishUsageEvent(etype, template.getAccountId(), dsScope.getScopeId(), template.getId(), template.getName(), null, null, + physicalSize, template.getSize(), VirtualMachineTemplate.class.getName(), template.getUuid()); + } else { + s_logger.warn("Zone scope image store " + ds.getId() + " has a null scope id"); + } + _resourceLimitMgr.incrementResourceCount(accountId, Resource.ResourceType.secondary_storage, template.getSize()); + } + } + + return null; + } + private Map listTemplate(DataStore ssStore) { ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO(), imageStoreDetailsUtil.getNfsVersion(ssStore.getId())); EndPoint ep = _epSelector.select(ssStore); From abae9086742b4b83c623a0d0ece0a410a4f1bc48 Mon Sep 17 00:00:00 2001 From: gabrascher Date: Tue, 5 Apr 2016 14:05:22 -0300 Subject: [PATCH 104/203] Handle SSH if server "forget" to send exit status Continued the work started by https://github.com/likitha commit (b9181c6) from PR #561. CS waits indefinitely for CheckS2SVpnConnectionsComm and to return. While remote executing commands through ssh, handle channel condition of EOF because we wait for the the condition. The SshHelper of the PR #561 is of another path from the current master, its path was https://github.com/likitha/cloudstack/commits/CLOUDSTACK-8611/utils/src/com/cloud/utils/ssh/SshHelper.java; thus, although this commit brings changes from PR #561, I did not cherry-picked to keep the master file, otherwise it would look that I had changed all the file. by me. --- .../java/com/cloud/utils/ssh/SshHelper.java | 108 ++++++++++--- .../com/cloud/utils/ssh/SshHelperTest.java | 151 ++++++++++++++++++ 2 files changed, 241 insertions(+), 18 deletions(-) create mode 100644 utils/src/test/java/com/cloud/utils/ssh/SshHelperTest.java diff --git a/utils/src/main/java/com/cloud/utils/ssh/SshHelper.java b/utils/src/main/java/com/cloud/utils/ssh/SshHelper.java index d3c88c8367..4d7a852d41 100644 --- a/utils/src/main/java/com/cloud/utils/ssh/SshHelper.java +++ b/utils/src/main/java/com/cloud/utils/ssh/SshHelper.java @@ -20,18 +20,26 @@ package com.cloud.utils.ssh; import java.io.File; +import java.io.IOException; import java.io.InputStream; import org.apache.log4j.Logger; import com.trilead.ssh2.ChannelCondition; - +import com.trilead.ssh2.Connection; +import com.trilead.ssh2.Session; import com.cloud.utils.Pair; public class SshHelper { private static final int DEFAULT_CONNECT_TIMEOUT = 180000; private static final int DEFAULT_KEX_TIMEOUT = 60000; + /** + * Waiting time to check if the SSH session was successfully opened. This value (of 1000 + * milliseconds) represents one (1) second. + */ + private static final long WAITING_OPEN_SSH_SESSION = 1000; + private static final Logger s_logger = Logger.getLogger(SshHelper.class); public static Pair sshExecute(String host, int port, String user, File pemKeyFile, String password, String command) throws Exception { @@ -40,19 +48,19 @@ public static Pair sshExecute(String host, int port, String use } public static void scpTo(String host, int port, String user, File pemKeyFile, String password, String remoteTargetDirectory, String localFile, String fileMode) - throws Exception { + throws Exception { scpTo(host, port, user, pemKeyFile, password, remoteTargetDirectory, localFile, fileMode, DEFAULT_CONNECT_TIMEOUT, DEFAULT_KEX_TIMEOUT); } public static void scpTo(String host, int port, String user, File pemKeyFile, String password, String remoteTargetDirectory, byte[] data, String remoteFileName, - String fileMode) throws Exception { + String fileMode) throws Exception { scpTo(host, port, user, pemKeyFile, password, remoteTargetDirectory, data, remoteFileName, fileMode, DEFAULT_CONNECT_TIMEOUT, DEFAULT_KEX_TIMEOUT); } public static void scpTo(String host, int port, String user, File pemKeyFile, String password, String remoteTargetDirectory, String localFile, String fileMode, - int connectTimeoutInMs, int kexTimeoutInMs) throws Exception { + int connectTimeoutInMs, int kexTimeoutInMs) throws Exception { com.trilead.ssh2.Connection conn = null; com.trilead.ssh2.SCPClient scpClient = null; @@ -88,7 +96,7 @@ public static void scpTo(String host, int port, String user, File pemKeyFile, St } public static void scpTo(String host, int port, String user, File pemKeyFile, String password, String remoteTargetDirectory, byte[] data, String remoteFileName, - String fileMode, int connectTimeoutInMs, int kexTimeoutInMs) throws Exception { + String fileMode, int connectTimeoutInMs, int kexTimeoutInMs) throws Exception { com.trilead.ssh2.Connection conn = null; com.trilead.ssh2.SCPClient scpClient = null; @@ -123,7 +131,8 @@ public static void scpTo(String host, int port, String user, File pemKeyFile, St } public static Pair sshExecute(String host, int port, String user, File pemKeyFile, String password, String command, int connectTimeoutInMs, - int kexTimeoutInMs, int waitResultTimeoutInMs) throws Exception { + int kexTimeoutInMs, + int waitResultTimeoutInMs) throws Exception { com.trilead.ssh2.Connection conn = null; com.trilead.ssh2.Session sess = null; @@ -144,7 +153,7 @@ public static Pair sshExecute(String host, int port, String use throw new Exception(msg); } } - sess = conn.openSession(); + sess = openConnectionSession(conn); sess.execCommand(command); @@ -156,22 +165,22 @@ public static Pair sshExecute(String host, int port, String use int currentReadBytes = 0; while (true) { + throwSshExceptionIfStdoutOrStdeerIsNull(stdout, stderr); + if ((stdout.available() == 0) && (stderr.available() == 0)) { - int conditions = - sess.waitForCondition(ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA | ChannelCondition.EOF | ChannelCondition.EXIT_STATUS, + int conditions = sess.waitForCondition(ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA | ChannelCondition.EOF | ChannelCondition.EXIT_STATUS, waitResultTimeoutInMs); - if ((conditions & ChannelCondition.TIMEOUT) != 0) { - String msg = "Timed out in waiting SSH execution result"; - s_logger.error(msg); - throw new Exception(msg); - } + throwSshExceptionIfConditionsTimeout(conditions); if ((conditions & ChannelCondition.EXIT_STATUS) != 0) { - if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0) { - break; - } + break; + } + + if (canEndTheSshConnection(waitResultTimeoutInMs, sess, conditions)) { + break; } + } while (stdout.available() > 0) { @@ -189,11 +198,12 @@ public static Pair sshExecute(String host, int port, String use if (sess.getExitStatus() == null) { //Exit status is NOT available. Returning failure result. + s_logger.error(String.format("SSH execution of command %s has no exit status set. Result output: %s", command, result)); return new Pair(false, result); } if (sess.getExitStatus() != null && sess.getExitStatus().intValue() != 0) { - s_logger.error("SSH execution of command " + command + " has an error status code in return. result output: " + result); + s_logger.error(String.format("SSH execution of command %s has an error status code in return. Result output: %s", command, result)); return new Pair(false, result); } @@ -206,4 +216,66 @@ public static Pair sshExecute(String host, int port, String use conn.close(); } } + + /** + * It gets a {@link Session} from the given {@link Connection}; then, it waits + * {@value #WAITING_OPEN_SSH_SESSION} milliseconds before returning the session, given a time to + * ensure that the connection is open before proceeding the execution. + */ + protected static Session openConnectionSession(Connection conn) throws IOException, InterruptedException { + Session sess = conn.openSession(); + Thread.sleep(WAITING_OPEN_SSH_SESSION); + return sess; + } + + /** + * Handles the SSH connection in case of timeout or exit. If the session ends with a timeout + * condition, it throws an exception; if the channel reaches an end of file condition, but it + * does not have an exit status, it returns true to break the loop; otherwise, it returns + * false. + */ + protected static boolean canEndTheSshConnection(int waitResultTimeoutInMs, com.trilead.ssh2.Session sess, int conditions) throws SshException { + if (isChannelConditionEof(conditions)) { + int newConditions = sess.waitForCondition(ChannelCondition.EXIT_STATUS, waitResultTimeoutInMs); + throwSshExceptionIfConditionsTimeout(newConditions); + if ((newConditions & ChannelCondition.EXIT_STATUS) != 0) { + return true; + } + } + return false; + } + + /** + * It throws a {@link SshException} if the channel condition is {@link ChannelCondition#TIMEOUT} + */ + protected static void throwSshExceptionIfConditionsTimeout(int conditions) throws SshException { + if ((conditions & ChannelCondition.TIMEOUT) != 0) { + String msg = "Timed out in waiting for SSH execution exit status"; + s_logger.error(msg); + throw new SshException(msg); + } + } + + /** + * Checks if the channel condition mask is of {@link ChannelCondition#EOF} and not + * {@link ChannelCondition#STDERR_DATA} or {@link ChannelCondition#STDOUT_DATA}. + */ + protected static boolean isChannelConditionEof(int conditions) { + if ((conditions & ChannelCondition.EOF) != 0) { + return true; + } + return false; + } + + /** + * Checks if the SSH session {@link com.trilead.ssh2.Session#getStdout()} or + * {@link com.trilead.ssh2.Session#getStderr()} is null. + */ + protected static void throwSshExceptionIfStdoutOrStdeerIsNull(InputStream stdout, InputStream stderr) throws SshException { + if (stdout == null || stderr == null) { + String msg = "Stdout or Stderr of SSH session is null"; + s_logger.error(msg); + throw new SshException(msg); + } + } } diff --git a/utils/src/test/java/com/cloud/utils/ssh/SshHelperTest.java b/utils/src/test/java/com/cloud/utils/ssh/SshHelperTest.java new file mode 100644 index 0000000000..355a51416b --- /dev/null +++ b/utils/src/test/java/com/cloud/utils/ssh/SshHelperTest.java @@ -0,0 +1,151 @@ +// +// 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.utils.ssh; + +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.trilead.ssh2.ChannelCondition; +import com.trilead.ssh2.Connection; +import com.trilead.ssh2.Session; + +@PrepareForTest({ Thread.class, SshHelper.class }) +@RunWith(PowerMockRunner.class) +public class SshHelperTest { + + @Test + public void canEndTheSshConnectionTest() throws Exception { + PowerMockito.spy(SshHelper.class); + Session mockedSession = Mockito.mock(Session.class); + + PowerMockito.doReturn(true).when(SshHelper.class, "isChannelConditionEof", Mockito.anyInt()); + Mockito.when(mockedSession.waitForCondition(ChannelCondition.EXIT_STATUS, 1l)).thenReturn(0); + PowerMockito.doNothing().when(SshHelper.class, "throwSshExceptionIfConditionsTimeout", Mockito.anyInt()); + + SshHelper.canEndTheSshConnection(1, mockedSession, 0); + + PowerMockito.verifyStatic(); + SshHelper.isChannelConditionEof(Mockito.anyInt()); + SshHelper.throwSshExceptionIfConditionsTimeout(Mockito.anyInt()); + + Mockito.verify(mockedSession).waitForCondition(ChannelCondition.EXIT_STATUS, 1l); + } + + @Test(expected = SshException.class) + public void throwSshExceptionIfConditionsTimeout() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.TIMEOUT); + } + + @Test + public void doNotThrowSshExceptionIfConditionsClosed() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.CLOSED); + } + + @Test + public void doNotThrowSshExceptionIfConditionsStdout() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.STDOUT_DATA); + } + + @Test + public void doNotThrowSshExceptionIfConditionsStderr() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.STDERR_DATA); + } + + @Test + public void doNotThrowSshExceptionIfConditionsEof() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.EOF); + } + + @Test + public void doNotThrowSshExceptionIfConditionsExitStatus() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.EXIT_STATUS); + } + + @Test + public void doNotThrowSshExceptionIfConditionsExitSignal() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.EXIT_SIGNAL); + } + + @Test + public void isChannelConditionEofTestTimeout() { + Assert.assertFalse(SshHelper.isChannelConditionEof(ChannelCondition.TIMEOUT)); + } + + @Test + public void isChannelConditionEofTestClosed() { + Assert.assertFalse(SshHelper.isChannelConditionEof(ChannelCondition.CLOSED)); + } + + @Test + public void isChannelConditionEofTestStdout() { + Assert.assertFalse(SshHelper.isChannelConditionEof(ChannelCondition.STDOUT_DATA)); + } + + @Test + public void isChannelConditionEofTestStderr() { + Assert.assertFalse(SshHelper.isChannelConditionEof(ChannelCondition.STDERR_DATA)); + } + + @Test + public void isChannelConditionEofTestEof() { + Assert.assertTrue(SshHelper.isChannelConditionEof(ChannelCondition.EOF)); + } + + @Test + public void isChannelConditionEofTestExitStatus() { + Assert.assertFalse(SshHelper.isChannelConditionEof(ChannelCondition.EXIT_STATUS)); + } + + @Test + public void isChannelConditionEofTestExitSignal() { + Assert.assertFalse(SshHelper.isChannelConditionEof(ChannelCondition.EXIT_SIGNAL)); + } + + @Test(expected = SshException.class) + public void throwSshExceptionIfStdoutOrStdeerIsNullTestNull() throws SshException { + SshHelper.throwSshExceptionIfStdoutOrStdeerIsNull(null, null); + } + + @Test + public void throwSshExceptionIfStdoutOrStdeerIsNullTestNotNull() throws SshException { + InputStream inputStream = Mockito.mock(InputStream.class); + SshHelper.throwSshExceptionIfStdoutOrStdeerIsNull(inputStream, inputStream); + } + + @Test + public void openConnectionSessionTest() throws IOException, InterruptedException { + Connection conn = Mockito.mock(Connection.class); + PowerMockito.mockStatic(Thread.class); + SshHelper.openConnectionSession(conn); + + Mockito.verify(conn).openSession(); + + PowerMockito.verifyStatic(); + Thread.sleep(Mockito.anyLong()); + } +} From 93ce108e0c26da079e8dabb107104dbd76be3799 Mon Sep 17 00:00:00 2001 From: SudharmaJain Date: Thu, 24 Sep 2015 11:41:54 +0530 Subject: [PATCH 105/203] CLOUDSTACK-8901: PrepareTemplate job thread hard-coded to max 8 threads --- .../src/com/cloud/template/TemplateManager.java | 7 +++++++ server/src/com/cloud/template/TemplateManagerImpl.java | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/engine/components-api/src/com/cloud/template/TemplateManager.java b/engine/components-api/src/com/cloud/template/TemplateManager.java index 5987ac0ee5..5b2d64ad5a 100644 --- a/engine/components-api/src/com/cloud/template/TemplateManager.java +++ b/engine/components-api/src/com/cloud/template/TemplateManager.java @@ -38,9 +38,16 @@ */ public interface TemplateManager { static final String AllowPublicUserTemplatesCK = "allow.public.user.templates"; + static final String TemplatePreloaderPoolSizeCK = "template.preloader.pool.size"; + static final ConfigKey AllowPublicUserTemplates = new ConfigKey("Advanced", Boolean.class, AllowPublicUserTemplatesCK, "true", "If false, users will not be able to create public templates.", true, ConfigKey.Scope.Account); + static final ConfigKey TemplatePreloaderPoolSize = new ConfigKey("Advanced", Integer.class, TemplatePreloaderPoolSizeCK, "8", + "Size of the TemplateManager threadpool", false, ConfigKey.Scope.Global); + + + /** * Prepares a template for vm creation for a certain storage pool. * diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index e6141425df..4b27c8b326 100644 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -926,7 +926,7 @@ public boolean configure(String name, Map params) throws Configu String disableExtraction = _configDao.getValue(Config.DisableExtraction.toString()); _disableExtraction = (disableExtraction == null) ? false : Boolean.parseBoolean(disableExtraction); - _preloadExecutor = Executors.newFixedThreadPool(8, new NamedThreadFactory("Template-Preloader")); + _preloadExecutor = Executors.newFixedThreadPool(TemplatePreloaderPoolSize.value(), new NamedThreadFactory("Template-Preloader")); return true; } @@ -1975,7 +1975,7 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {AllowPublicUserTemplates}; + return new ConfigKey[] {AllowPublicUserTemplates, TemplatePreloaderPoolSize}; } public List getTemplateAdapters() { From 456abb0b94d854b932903d63724fec33ebf1a601 Mon Sep 17 00:00:00 2001 From: nitt10prashant Date: Tue, 18 Aug 2015 16:53:54 +0530 Subject: [PATCH 106/203] CLOUDSTACK-8745 : verify usage after root disk migration modified to use maintenance method is base.py and added some more checks CLOUDSTACK-8745: Fail test if list response in empty --- .../maint/test_ha_pool_maintenance.py | 236 ++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 test/integration/component/maint/test_ha_pool_maintenance.py diff --git a/test/integration/component/maint/test_ha_pool_maintenance.py b/test/integration/component/maint/test_ha_pool_maintenance.py new file mode 100644 index 0000000000..e737726d31 --- /dev/null +++ b/test/integration/component/maint/test_ha_pool_maintenance.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# 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. + +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.cloudstackAPI import (enableStorageMaintenance, + cancelStorageMaintenance + ) +from marvin.lib.utils import (cleanup_resources, + validateList) +from marvin.lib.base import (Account, + VirtualMachine, + ServiceOffering, + Cluster, + StoragePool, + Volume) +from marvin.lib.common import (get_zone, + get_domain, + get_template, + list_hosts + ) +from marvin.codes import PASS + + +class testHaPoolMaintenance(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + try: + cls._cleanup = [] + cls.testClient = super( + testHaPoolMaintenance, + cls).getClsTestClient() + cls.api_client = cls.testClient.getApiClient() + cls.services = cls.testClient.getParsedTestDataConfig() + # Get Domain, Zone, Template + cls.domain = get_domain(cls.api_client) + cls.zone = get_zone( + cls.api_client, + cls.testClient.getZoneForTests()) + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls.hypervisor = cls.testClient.getHypervisorInfo() + cls.services['mode'] = cls.zone.networktype + cls.hypervisor = cls.testClient.getHypervisorInfo() + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.services["virtual_machine"]["template"] = cls.template.id + cls.clusterWithSufficientPool = None + cls.listResponse = None + clusters = Cluster.list(cls.api_client, zoneid=cls.zone.id) + + if not validateList(clusters)[0]: + + cls.debug( + "check list cluster response for zone id %s" % + cls.zone.id) + cls.listResponse = True + return + + for cluster in clusters: + cls.pool = StoragePool.list(cls.api_client, + clusterid=cluster.id, + keyword="NetworkFilesystem" + ) + + if not validateList(cls.pool)[0]: + + cls.debug( + "check list cluster response for zone id %s" % + cls.zone.id) + cls.listResponse = True + return + + if len(cls.pool) >= 2: + cls.clusterWithSufficientPool = cluster + break + if not cls.clusterWithSufficientPool: + return + + cls.services["service_offerings"][ + "tiny"]["offerha"] = "True" + + cls.services_off = ServiceOffering.create( + cls.api_client, + cls.services["service_offerings"]["tiny"]) + cls._cleanup.append(cls.services_off) + + except Exception as e: + cls.tearDownClass() + raise Exception("Warning: Exception in setup : %s" % e) + return + + def setUp(self): + + self.apiClient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + if self.listResponse: + self.fail( + "Check list response") + if not self.clusterWithSufficientPool: + self.skipTest( + "sufficient storage not available in any cluster for zone %s" % + self.zone.id) + self.account = Account.create( + self.api_client, + self.services["account"], + domainid=self.domain.id + ) + self.cleanup.append(self.account) + + def tearDown(self): + # Clean up, terminate the created resources + StoragePool.cancelMaintenance(self.api_client, + id=self.storageid[0][0]) + cleanup_resources(self.apiClient, self.cleanup) + return + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + return + + @attr(tags=["advanced", "cl", "advancedns", "sg", + "basic", "eip", "simulator", "multihost"]) + def test_ha_with_storage_maintenance(self): + """put storage in maintenance mode and start ha vm and check usage""" + # Steps + # 1. Create a Compute service offering with the 'Offer HA' option + # selected. + # 2. Create a Guest VM with the compute service offering created above. + # 3. put PS into maintenance mode + # 4. vm should go in stop state + # 5. start vm ,vm should come up on another storage + # 6. check usage events are getting generated for root disk + + host = list_hosts( + self.api_client, + clusterid=self.clusterWithSufficientPool.id) + self.assertEqual(validateList(host)[0], + PASS, + "check list host response for cluster id %s" + % self.clusterWithSufficientPool.id) + + self.virtual_machine_with_ha = VirtualMachine.create( + self.api_client, + self.services["virtual_machine"], + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.services_off.id, + hostid=host[0].id + ) + + vms = VirtualMachine.list( + self.api_client, + id=self.virtual_machine_with_ha.id, + listall=True, + ) + + self.assertEqual( + validateList(vms)[0], + PASS, + "List VMs should return valid response for deployed VM" + ) + + vm = vms[0] + + self.debug("Deployed VM on host: %s" % vm.hostid) + + # Put storage in maintenance mode + + self.list_root_volume = Volume.list(self.api_client, + virtualmachineid=vm.id, + type='ROOT', + account=self.account.name, + domainid=self.account.domainid) + + self.assertEqual(validateList(self.list_root_volume)[0], + PASS, + "check list voume_response for vm id %s" % vm.id) + + self.pool_id = self.dbclient.execute( + "select pool_id from volumes where uuid = '%s';" + % self.list_root_volume[0].id) + self.storageid = self.dbclient.execute( + "select uuid from storage_pool where id = '%s';" + % self.pool_id[0][0]) + + StoragePool.enableMaintenance(self.api_client, + id=self.storageid[0][0]) + + self.virtual_machine_with_ha.start(self.api_client) + self.events = self.dbclient.execute( + "select type from usage_event where resource_name='%s';" + % self.list_root_volume[0].name + ) + self.assertEqual(len(self.events), + 3, + "check the usage event table for root disk %s" + % self.list_root_volume[0].name + ) + + self.assertEqual(str(self.events[0][0]), + "VOLUME.CREATE", + "check volume create events for volume %s" + % self.list_root_volume[0].name) + self.assertEqual(str(self.events[1][0]), + "VOLUME.DELETE", + "check fvolume delete events for volume%s" + % self.list_root_volume[0].name) + self.assertEqual(str(self.events[2][0]), + "VOLUME.CREATE", + "check volume create events for volume %s" + % self.list_root_volume[0].name) From e5e226e549e0224a3f6ddf4cc570e983d1cb9292 Mon Sep 17 00:00:00 2001 From: Kshitij Kansal Date: Tue, 15 Sep 2015 14:42:29 +0530 Subject: [PATCH 107/203] Fixed: Error given when creating VPN user in one network if VR for another network is stopped --- .../cloudstack/network/topology/BasicNetworkTopology.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/src/org/apache/cloudstack/network/topology/BasicNetworkTopology.java b/server/src/org/apache/cloudstack/network/topology/BasicNetworkTopology.java index 2b8873729d..0869b2289c 100644 --- a/server/src/org/apache/cloudstack/network/topology/BasicNetworkTopology.java +++ b/server/src/org/apache/cloudstack/network/topology/BasicNetworkTopology.java @@ -278,7 +278,11 @@ public String[] applyVpnUsers(final Network network, final List Date: Tue, 15 Sep 2015 16:49:22 +0530 Subject: [PATCH 108/203] Fixed Coverity Issue: Unintentional Integer FLow --- server/src/com/cloud/storage/ImageStoreUploadMonitorImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/com/cloud/storage/ImageStoreUploadMonitorImpl.java b/server/src/com/cloud/storage/ImageStoreUploadMonitorImpl.java index 1478910413..ecdbcae255 100755 --- a/server/src/com/cloud/storage/ImageStoreUploadMonitorImpl.java +++ b/server/src/com/cloud/storage/ImageStoreUploadMonitorImpl.java @@ -115,7 +115,7 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto public boolean configure(String name, Map params) throws ConfigurationException { _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Upload-Monitor")); _monitoringInterval = UploadMonitoringInterval.value(); - _uploadOperationTimeout = UploadOperationTimeout.value() * 60 * 1000; + _uploadOperationTimeout = UploadOperationTimeout.value() * 60 * 1000L; _nodeId = ManagementServerNode.getManagementServerId(); return true; } From 4be5c2e56cd99d7d1bf6a129cf26c3cbc1e2e926 Mon Sep 17 00:00:00 2001 From: gabrascher Date: Sat, 16 Apr 2016 15:35:17 -0300 Subject: [PATCH 109/203] Test fails in Widows as the file separator "/" is different from "\" File separator in windows is different from linux (the expected in the test); thus, the test *com.cloud.utils.SwiftUtilTest.testSplitSwiftPath()* will fail in windows. The problem is that the input of the test is *"container/object"* but the tested method uses the *File.separator* (that depends from the OS), in the windows the tested method (*com.cloud.utils.SwiftUtil.splitSwiftPath(String)*) looks for a "\" in windows systems, resulting in an empty string and consequently a failure in the test. Some solutions: - the simple way is to create a string `String input = "container" + File.separator + "object";`, thus independent of the OS, the test will succeed. - a tricky solution is to mock the final static variable *File.separator* and return "/". I picked the easy way. --- utils/src/test/java/com/cloud/utils/SwiftUtilTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/src/test/java/com/cloud/utils/SwiftUtilTest.java b/utils/src/test/java/com/cloud/utils/SwiftUtilTest.java index 55f7a3479e..20c1623d82 100644 --- a/utils/src/test/java/com/cloud/utils/SwiftUtilTest.java +++ b/utils/src/test/java/com/cloud/utils/SwiftUtilTest.java @@ -19,9 +19,11 @@ package com.cloud.utils; + import org.junit.Test; import org.mockito.Mockito; +import java.io.File; import java.net.URL; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -32,7 +34,6 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; - public class SwiftUtilTest { @Test @@ -72,7 +73,7 @@ public void testGenerateTempUrl() { @Test public void testSplitSwiftPath(){ - String input = "container/object"; + String input = "container" + File.separator + "object"; String[] output = SwiftUtil.splitSwiftPath(input); String[] expected = {"container", "object"}; From bb29b1d06389e41c779d94f2d433f3b7c48009b3 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Wed, 27 Jan 2016 01:41:02 +0100 Subject: [PATCH 110/203] maven: Upgrade dependency versions Updated most dependencies to latest minor releases, EXCEPT: - Gson 2.x - Major spring framework version - Servlet version - Embedded jetty version - Mockito version (beta) - Mysql lib minor version upgrade (breaks mysql-ha plugin) Signed-off-by: Rohit Yadav --- engine/api/pom.xml | 2 +- engine/service/pom.xml | 2 +- framework/rest/pom.xml | 12 ++-- plugins/event-bus/kafka/pom.xml | 2 +- plugins/event-bus/rabbitmq/pom.xml | 2 +- plugins/network-elements/globodns/pom.xml | 2 +- .../network-elements/juniper-contrail/pom.xml | 2 +- plugins/storage/volume/cloudbyte/pom.xml | 2 +- plugins/user-authenticators/ldap/pom.xml | 2 +- plugins/user-authenticators/saml2/pom.xml | 2 +- pom.xml | 58 +++++++++---------- services/console-proxy-rdp/rdpconsole/pom.xml | 2 +- services/secondary-storage/server/pom.xml | 2 +- tools/checkstyle/pom.xml | 7 +-- usage/pom.xml | 6 +- utils/pom.xml | 2 +- 16 files changed, 49 insertions(+), 58 deletions(-) diff --git a/engine/api/pom.xml b/engine/api/pom.xml index 01a6051a34..1f539fbd04 100644 --- a/engine/api/pom.xml +++ b/engine/api/pom.xml @@ -38,7 +38,7 @@ org.apache.cxf cxf-bundle-jaxrs - 2.7.13 + 2.7.18 org.eclipse.jetty diff --git a/engine/service/pom.xml b/engine/service/pom.xml index 38b6035e87..b816f2959f 100644 --- a/engine/service/pom.xml +++ b/engine/service/pom.xml @@ -63,7 +63,7 @@ org.apache.cxf cxf-bundle-jaxrs - 2.7.13 + 2.7.18 org.eclipse.jetty diff --git a/framework/rest/pom.xml b/framework/rest/pom.xml index 830b7ec94d..54cc4b6b6e 100644 --- a/framework/rest/pom.xml +++ b/framework/rest/pom.xml @@ -33,32 +33,32 @@ com.fasterxml.jackson.module jackson-module-jaxb-annotations - 2.6.3 + 2.7.1 com.fasterxml.jackson.core jackson-annotations - 2.6.3 + 2.7.1 com.fasterxml.jackson.core jackson-core - 2.6.3 + 2.7.1 com.fasterxml.jackson.core jackson-databind - 2.6.3 + 2.7.1 com.fasterxml.jackson.jaxrs jackson-jaxrs-json-provider - 2.6.3 + 2.7.1 org.apache.cxf cxf-bundle-jaxrs - 2.7.13 + 2.7.18 org.eclipse.jetty diff --git a/plugins/event-bus/kafka/pom.xml b/plugins/event-bus/kafka/pom.xml index b6827a176b..2c79aa8738 100644 --- a/plugins/event-bus/kafka/pom.xml +++ b/plugins/event-bus/kafka/pom.xml @@ -36,7 +36,7 @@ org.apache.kafka kafka-clients - 0.8.2.0 + 0.9.0.0
diff --git a/plugins/event-bus/rabbitmq/pom.xml b/plugins/event-bus/rabbitmq/pom.xml index bc8f78cab5..937d5bb0da 100644 --- a/plugins/event-bus/rabbitmq/pom.xml +++ b/plugins/event-bus/rabbitmq/pom.xml @@ -31,7 +31,7 @@ com.rabbitmq amqp-client - 3.5.4 + 3.6.0 org.apache.cloudstack diff --git a/plugins/network-elements/globodns/pom.xml b/plugins/network-elements/globodns/pom.xml index 9e177a53d6..9d2c354719 100644 --- a/plugins/network-elements/globodns/pom.xml +++ b/plugins/network-elements/globodns/pom.xml @@ -31,7 +31,7 @@ com.globo.globodns globodns-client - 0.0.15 + 0.0.20
diff --git a/plugins/network-elements/juniper-contrail/pom.xml b/plugins/network-elements/juniper-contrail/pom.xml index cac4d593d5..13a3c5b6e8 100644 --- a/plugins/network-elements/juniper-contrail/pom.xml +++ b/plugins/network-elements/juniper-contrail/pom.xml @@ -109,7 +109,7 @@ org.mockito mockito-all - 1.9.5 + 1.10.19
diff --git a/plugins/storage/volume/cloudbyte/pom.xml b/plugins/storage/volume/cloudbyte/pom.xml index 2a4e02dd8e..9cc874e716 100755 --- a/plugins/storage/volume/cloudbyte/pom.xml +++ b/plugins/storage/volume/cloudbyte/pom.xml @@ -54,7 +54,7 @@ com.sun.jersey jersey-bundle - 1.18.3 + 1.19
diff --git a/plugins/user-authenticators/ldap/pom.xml b/plugins/user-authenticators/ldap/pom.xml index a2af718737..32970a790b 100644 --- a/plugins/user-authenticators/ldap/pom.xml +++ b/plugins/user-authenticators/ldap/pom.xml @@ -96,7 +96,7 @@ org.spockframework spock-core - 0.7-groovy-2.0 + 1.0-groovy-2.4 diff --git a/plugins/user-authenticators/saml2/pom.xml b/plugins/user-authenticators/saml2/pom.xml index a978860461..bff081425c 100644 --- a/plugins/user-authenticators/saml2/pom.xml +++ b/plugins/user-authenticators/saml2/pom.xml @@ -30,7 +30,7 @@ org.springframework.security.extensions spring-security-saml2-core - 1.0.0.RELEASE + 1.0.1.RELEASE org.opensaml diff --git a/pom.xml b/pom.xml index c18c377cf2..3f546e9fe8 100644 --- a/pom.xml +++ b/pom.xml @@ -44,10 +44,6 @@ https://issues.apache.org/jira/browse/CLOUDSTACK - - 3.0.4 - - 1.7 UTF-8 @@ -55,7 +51,7 @@ 1.2.17 1.2.17 - 3.1 + 3.2.0 1.4 1.6 1.10 @@ -65,25 +61,25 @@ 0.5 3.0 - 4.11 + 4.12 1.3 1.46 - 0.1.51 - 2.1.0 + 0.1.53 + 2.1.1 1.9.2 - 1.0.0-build217 - 2.6.9 + 1.0.0-build220 + 2.6.11 1.7.2 18.0 - 18.0 + 19.0 6.2.0-3.1 - 4.5 - 4.4 + 4.5.1 + 4.4.4 3.1 5.1.34 - 1.4.7 + 1.4.8 3.1.3 - 1.4.7 + 1.5.0-b01 1.4 1.5.6 1.5.1 @@ -93,27 +89,27 @@ 1.2 1.0-20081010.060147 5.5 - 3.2.12.RELEASE - 1.9.5 - 1.5.3 - 1.10.34 + 3.2.16.RELEASE + 1.10.19 + 1.6.4 + 1.10.50 2.6.3 2.6 3.4 2.4 - 1.4.0 - 0.9.9 - 0.15 + 1.5.0 + 0.9.10 + 0.16 build/replace.properties 0.5.1 0.2.0 target 1.0.15 4.0.0 - 2.11 - 2.7 - 3.0.1 - 2.10.1 + 2.17 + 2.11 + 3.0.3 + 2.10.3 2.6.1 1.4.01 2.8.1 @@ -390,17 +386,17 @@ org.apache.servicemix.bundles org.apache.servicemix.bundles.snmp4j - 2.3.1_1 + 2.3.4_1 org.aspectj aspectjtools - 1.8.4 + 1.8.8 org.aspectj aspectjweaver - 1.8.4 + 1.8.8 org.apache.axis @@ -425,12 +421,12 @@ org.slf4j slf4j-api - 1.7.7 + 1.7.14 org.slf4j slf4j-log4j12 - 1.7.7 + 1.7.14
diff --git a/services/console-proxy-rdp/rdpconsole/pom.xml b/services/console-proxy-rdp/rdpconsole/pom.xml index ba311830af..a27f2eb4ac 100755 --- a/services/console-proxy-rdp/rdpconsole/pom.xml +++ b/services/console-proxy-rdp/rdpconsole/pom.xml @@ -71,7 +71,7 @@ org.apache.tomcat.embed tomcat-embed-core - 8.0.15 + 8.0.30 diff --git a/services/secondary-storage/server/pom.xml b/services/secondary-storage/server/pom.xml index b6bfbf7df7..f3d0176207 100644 --- a/services/secondary-storage/server/pom.xml +++ b/services/secondary-storage/server/pom.xml @@ -57,7 +57,7 @@ io.netty netty-all - 4.0.25.Final + 4.0.33.Final compile
diff --git a/tools/checkstyle/pom.xml b/tools/checkstyle/pom.xml index f4ee2b8e1f..c0c39c956d 100644 --- a/tools/checkstyle/pom.xml +++ b/tools/checkstyle/pom.xml @@ -25,12 +25,7 @@ org.apache.cloudstack checkstyle 4.9.0-SNAPSHOT - - - - 3.0.4 - - + diff --git a/usage/pom.xml b/usage/pom.xml index ff10e819e4..7e9e8c4f90 100644 --- a/usage/pom.xml +++ b/usage/pom.xml @@ -53,17 +53,17 @@ org.slf4j slf4j-api - 1.7.7 + 1.7.14 org.slf4j slf4j-log4j12 - 1.7.7 + 1.7.14 org.dbunit dbunit - 2.4.9 + 2.5.1 test
diff --git a/utils/pom.xml b/utils/pom.xml index 3a23a58774..93d7d01a06 100755 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -157,7 +157,7 @@ commons-net commons-net - 3.3 + 3.4 com.google.code.gson From 770aa0133ee3011239033e2dfe3f6ed41b76761a Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 2 Feb 2016 19:55:06 +0100 Subject: [PATCH 111/203] framework/quota: fix checkstyle issue Fixes enum name to supress checkstyle failure due to the latest checkstyle version Signed-off-by: Rohit Yadav --- .../cloudstack/quota/QuotaStatementImpl.java | 8 +++---- .../cloudstack/quota/QuotaStatementTest.java | 22 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java index 5c12ae6e75..30d2589187 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java @@ -59,11 +59,11 @@ public class QuotaStatementImpl extends ManagerBase implements QuotaStatement { final public static int s_LAST_STATEMENT_SENT_DAYS = 6; //ideally should be less than 7 days - public enum STATEMENT_PERIODS { + public enum QuotaStatementPeriods { BIMONTHLY, MONTHLY, QUATERLY, HALFYEARLY, YEARLY }; - private STATEMENT_PERIODS _period = STATEMENT_PERIODS.MONTHLY; + private QuotaStatementPeriods _period = QuotaStatementPeriods.MONTHLY; public QuotaStatementImpl() { super(); @@ -87,7 +87,7 @@ public boolean configure(String name, Map params) throws Configu String period_str = configs.get(QuotaConfig.QuotaStatementPeriod.key()); int period = period_str == null ? 1 : Integer.parseInt(period_str); - STATEMENT_PERIODS _period = STATEMENT_PERIODS.values()[period]; + QuotaStatementPeriods _period = QuotaStatementPeriods.values()[period]; return true; } @@ -265,7 +265,7 @@ public Calendar[] getCurrentStatementTime() { return null; } - public Calendar[] statementTime(final Calendar today, final STATEMENT_PERIODS period) { + public Calendar[] statementTime(final Calendar today, final QuotaStatementPeriods period) { //check if it is statement time int day_of_month = today.get(Calendar.DAY_OF_MONTH); int month_of_year = today.get(Calendar.MONTH); diff --git a/framework/quota/test/org/apache/cloudstack/quota/QuotaStatementTest.java b/framework/quota/test/org/apache/cloudstack/quota/QuotaStatementTest.java index d1cc7ace29..e2b5a0abe9 100644 --- a/framework/quota/test/org/apache/cloudstack/quota/QuotaStatementTest.java +++ b/framework/quota/test/org/apache/cloudstack/quota/QuotaStatementTest.java @@ -21,7 +21,7 @@ import com.cloud.utils.db.TransactionLegacy; import junit.framework.TestCase; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.quota.QuotaStatementImpl.STATEMENT_PERIODS; +import org.apache.cloudstack.quota.QuotaStatementImpl.QuotaStatementPeriods; import org.apache.cloudstack.quota.dao.QuotaAccountDao; import org.apache.cloudstack.quota.dao.QuotaUsageDao; import org.apache.cloudstack.quota.vo.QuotaAccountVO; @@ -85,12 +85,12 @@ public void testStatementPeriodBIMONTHLY() { //BIMONTHLY - first statement of month date.set(Calendar.DATE, QuotaStatementImpl.s_LAST_STATEMENT_SENT_DAYS + 1); - Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.BIMONTHLY); + Calendar period[] = quotaStatement.statementTime(date, QuotaStatementPeriods.BIMONTHLY); assertTrue(period == null); //1 of this month date.set(Calendar.DATE, 1); - period = quotaStatement.statementTime(date, STATEMENT_PERIODS.BIMONTHLY); + period = quotaStatement.statementTime(date, QuotaStatementPeriods.BIMONTHLY); assertTrue(period != null); assertTrue(period.length == 2); assertTrue(period[0].toString(), period[0].before(period[1])); @@ -100,12 +100,12 @@ public void testStatementPeriodBIMONTHLY() { //BIMONTHLY - second statement of month date = Calendar.getInstance(); date.set(Calendar.DATE, QuotaStatementImpl.s_LAST_STATEMENT_SENT_DAYS + 16); - period = quotaStatement.statementTime(date, STATEMENT_PERIODS.BIMONTHLY); + period = quotaStatement.statementTime(date, QuotaStatementPeriods.BIMONTHLY); assertTrue(period == null); //17 of this month date.set(Calendar.DATE, 17); - period = quotaStatement.statementTime(date, STATEMENT_PERIODS.BIMONTHLY); + period = quotaStatement.statementTime(date, QuotaStatementPeriods.BIMONTHLY); assertTrue(period != null); assertTrue(period.length == 2); assertTrue(period[0].toString(), period[0].before(period[1])); @@ -128,12 +128,12 @@ public void testStatementPeriodMONTHLY() { //MONTHLY date = Calendar.getInstance(); date.set(Calendar.DATE, QuotaStatementImpl.s_LAST_STATEMENT_SENT_DAYS + 1); - Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.MONTHLY); + Calendar period[] = quotaStatement.statementTime(date, QuotaStatementPeriods.MONTHLY); assertTrue(period == null); //1 of this month date.set(Calendar.DATE, QuotaStatementImpl.s_LAST_STATEMENT_SENT_DAYS - 1); - period = quotaStatement.statementTime(date, STATEMENT_PERIODS.MONTHLY); + period = quotaStatement.statementTime(date, QuotaStatementPeriods.MONTHLY); assertTrue(period != null); assertTrue(period.length == 2); assertTrue(period[0].toString(), period[0].before(period[1])); @@ -157,7 +157,7 @@ public void testStatementPeriodQUATERLY() { date = Calendar.getInstance(); date.set(Calendar.MONTH, Calendar.JANUARY); // 1 Jan date.set(Calendar.DATE, 1); - Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.QUATERLY); + Calendar period[] = quotaStatement.statementTime(date, QuotaStatementPeriods.QUATERLY); assertTrue(period != null); assertTrue(period.length == 2); assertTrue("period[0].before(period[1])" + period[0].toString(), period[0].before(period[1])); @@ -182,7 +182,7 @@ public void testStatementPeriodHALFYEARLY() { date = Calendar.getInstance(); date.set(Calendar.MONTH, Calendar.JANUARY); // 1 Jan date.set(Calendar.DATE, 1); - Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.HALFYEARLY); + Calendar period[] = quotaStatement.statementTime(date, QuotaStatementPeriods.HALFYEARLY); assertTrue(period != null); assertTrue(period.length == 2); assertTrue("period[0].before(period[1])" + period[0].toString(), period[0].before(period[1])); @@ -207,7 +207,7 @@ public void testStatementPeriodYEARLY() { date = Calendar.getInstance(); date.set(Calendar.MONTH, Calendar.JANUARY); // 1 Jan date.set(Calendar.DATE, 1); - Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.YEARLY); + Calendar period[] = quotaStatement.statementTime(date, QuotaStatementPeriods.YEARLY); assertTrue("period != null", period != null); assertTrue(period.length == 2); assertTrue("period[0].before(period[1])" + period[0].toString(), period[0].before(period[1])); @@ -244,7 +244,7 @@ public void testSendStatement() throws UnsupportedEncodingException, MessagingEx // call real method on send monthly statement quotaStatement.sendStatement(); - Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.MONTHLY); + Calendar period[] = quotaStatement.statementTime(date, QuotaStatementPeriods.MONTHLY); if (period != null){ Mockito.verify(alertManager, Mockito.times(1)).sendQuotaAlert(Mockito.any(QuotaAlertManagerImpl.DeferredQuotaEmail.class)); } From 101668994dd27e3ca67c09a8118dbcea255805fd Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Fri, 22 Apr 2016 16:25:27 +0530 Subject: [PATCH 112/203] further maven dependency updates from Daan Signed-off-by: Rohit Yadav --- client/pom.xml | 5 +- engine/service/pom.xml | 15 +--- framework/rest/pom.xml | 14 +-- plugins/hypervisors/hyperv/pom.xml | 5 -- plugins/network-elements/netscaler/pom.xml | 4 +- plugins/user-authenticators/ldap/pom.xml | 4 +- plugins/user-authenticators/saml2/pom.xml | 5 -- pom.xml | 86 +++++++++++++++---- server/pom.xml | 5 +- services/console-proxy-rdp/rdpconsole/pom.xml | 1 + tools/whisker/LICENSE | 2 +- tools/whisker/descriptor-for-packaging.xml | 4 +- utils/pom.xml | 2 +- 13 files changed, 95 insertions(+), 57 deletions(-) diff --git a/client/pom.xml b/client/pom.xml index 5cafd832d2..1f3665d61f 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -429,9 +429,8 @@ - org.mortbay.jetty - maven-jetty-plugin - 6.1.26 + org.eclipse.jetty + jetty-maven-plugin diff --git a/engine/service/pom.xml b/engine/service/pom.xml index b816f2959f..7f07323d48 100644 --- a/engine/service/pom.xml +++ b/engine/service/pom.xml @@ -60,17 +60,6 @@ cloud-engine-network ${project.version} - - org.apache.cxf - cxf-bundle-jaxrs - 2.7.18 - - - org.eclipse.jetty - jetty-server - - - org.springframework spring-context @@ -84,9 +73,9 @@ engine - org.mortbay.jetty + org.eclipse.jetty jetty-maven-plugin - 8.1.7.v20120910 + ${cs.jetty.version} 10 diff --git a/framework/rest/pom.xml b/framework/rest/pom.xml index 54cc4b6b6e..03aad768dc 100644 --- a/framework/rest/pom.xml +++ b/framework/rest/pom.xml @@ -33,32 +33,32 @@ com.fasterxml.jackson.module jackson-module-jaxb-annotations - 2.7.1 + ${cs.jackson.version} com.fasterxml.jackson.core jackson-annotations - 2.7.1 + ${cs.jackson.version} com.fasterxml.jackson.core jackson-core - 2.7.1 + ${cs.jackson.version} com.fasterxml.jackson.core jackson-databind - 2.7.1 + ${cs.jackson.version} com.fasterxml.jackson.jaxrs jackson-jaxrs-json-provider - 2.7.1 + ${cs.jackson.version} org.apache.cxf - cxf-bundle-jaxrs - 2.7.18 + cxf-rt-frontend-jaxrs + ${cs.cxf.version} org.eclipse.jetty diff --git a/plugins/hypervisors/hyperv/pom.xml b/plugins/hypervisors/hyperv/pom.xml index d88fd14188..165eaf6cf4 100644 --- a/plugins/hypervisors/hyperv/pom.xml +++ b/plugins/hypervisors/hyperv/pom.xml @@ -41,11 +41,6 @@ cloud-core ${project.version} - - org.mortbay.jetty - jetty - 6.1.26 - org.apache.cloudstack cloud-utils diff --git a/plugins/network-elements/netscaler/pom.xml b/plugins/network-elements/netscaler/pom.xml index 2475c41363..d7b54e92e7 100644 --- a/plugins/network-elements/netscaler/pom.xml +++ b/plugins/network-elements/netscaler/pom.xml @@ -30,12 +30,12 @@ com.citrix.netscaler.nitro nitro - 10.1 + ${cs.nitro.version} com.citrix.netscaler.nitro sdx_nitro - 10.1 + ${cs.nitro.version} diff --git a/plugins/user-authenticators/ldap/pom.xml b/plugins/user-authenticators/ldap/pom.xml index 32970a790b..7b3b8f76e1 100644 --- a/plugins/user-authenticators/ldap/pom.xml +++ b/plugins/user-authenticators/ldap/pom.xml @@ -97,12 +97,14 @@ org.spockframework spock-core 1.0-groovy-2.4 + test cglib cglib-nodep - + test +
diff --git a/plugins/user-authenticators/saml2/pom.xml b/plugins/user-authenticators/saml2/pom.xml index bff081425c..a54190239e 100644 --- a/plugins/user-authenticators/saml2/pom.xml +++ b/plugins/user-authenticators/saml2/pom.xml @@ -27,11 +27,6 @@ ../../pom.xml - - org.springframework.security.extensions - spring-security-saml2-core - 1.0.1.RELEASE - org.opensaml opensaml diff --git a/pom.xml b/pom.xml index 3f546e9fe8..3b78e990c0 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 4.12 1.3 - 1.46 + 1.54 0.1.53 2.1.1 1.9.2 @@ -86,17 +86,19 @@ 1.2.8 2.0.4 2.5 - 1.2 + 1.2.1 1.0-20081010.060147 5.5 3.2.16.RELEASE 1.10.19 1.6.4 1.10.50 - 2.6.3 + 2.7.1 2.6 3.4 2.4 + 1.3.1 + 3.2.2 1.5.0 0.9.10 0.16 @@ -110,9 +112,18 @@ 2.11 3.0.3 2.10.3 - 2.6.1 + 2.6.4 1.4.01 2.8.1 + 1.8 + 2.3.4_1 + 9.3.7.v20160115 + 3.1.4 + 1.0.1.RELEASE + 4.0.3.RELEASE + 2.4.3 + 9.3.7.v20160115 + 10.1
@@ -204,6 +215,51 @@ + + org.eclipse.jetty + apache-jsp + ${cs.apache-jsp.version} + + + org.codehaus.groovy + groovy-all + ${cs.groovy.version} + + + org.springframework.security + spring-security-core + ${cs.spring-security-core.version} + + + org.springframework.security.extensions + spring-security-saml2-core + ${cs.spring-security-saml2-core.version} + + + org.bouncycastle + bcprov-jdk15on + ${cs.bcprov.version} + + + org.apache.xmlgraphics + batik-css + ${cs.batik.version} + + + org.apache.xmlgraphics + batik-ext + ${cs.batik.version} + + + org.apache.xmlgraphics + batik-util + ${cs.batik.version} + + + commons-collections + commons-collections + ${cs.commons-collections.version} + mysql mysql-connector-java @@ -241,26 +297,26 @@ ehcache-core ${cs.ehcache.version} - - commons-pool - commons-pool - ${cs.pool.version} - commons-codec commons-codec ${cs.codec.version} + + commons-fileupload + commons-fileupload + ${cs.commons-fileupload.version} + + + commons-pool + commons-pool + ${cs.pool.version} + commons-validator commons-validator ${cs.commons-validator.version} - - org.bouncycastle - bcprov-jdk16 - ${cs.bcprov.version} - com.jcraft jsch @@ -386,7 +442,7 @@ org.apache.servicemix.bundles org.apache.servicemix.bundles.snmp4j - 2.3.4_1 + ${cs.servicemix.version} org.aspectj diff --git a/server/pom.xml b/server/pom.xml index b8e3598e3e..8461d18a4f 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -70,8 +70,9 @@ mail - jstl - jstl + javax.servlet.jsp.jstl + javax.servlet.jsp.jstl-api + ${cs.jstl.version} commons-codec diff --git a/services/console-proxy-rdp/rdpconsole/pom.xml b/services/console-proxy-rdp/rdpconsole/pom.xml index a27f2eb4ac..628d039a6e 100755 --- a/services/console-proxy-rdp/rdpconsole/pom.xml +++ b/services/console-proxy-rdp/rdpconsole/pom.xml @@ -77,6 +77,7 @@ org.bouncycastle bcprov-jdk16 + 1.46 diff --git a/tools/whisker/LICENSE b/tools/whisker/LICENSE index 61ebc50f10..da8aaedfd9 100644 --- a/tools/whisker/LICENSE +++ b/tools/whisker/LICENSE @@ -2896,7 +2896,7 @@ Within the target/jar directory cloud-axis.jar from http://axis.apache.org/axis/ cloud-cglib.jar from http://cglib.sourceforge.net/ cloud-commons-codec-1.5.jar from http://commons.apache.org/codec/ - cloud-commons-collections-3.2.1.jar from http://commons.apache.org/collections/ + cloud-commons-collections-3.2.2.jar from http://commons.apache.org/collections/ cloud-commons-configuration-1.8.jar from http://commons.apache.org/configuration/ cloud-commons-dbcp-1.4.jar from http://commons.apache.org/dbcp/ cloud-commons-httpclient-3.1.jar from http://hc.apache.org/httpclient-3.x/ diff --git a/tools/whisker/descriptor-for-packaging.xml b/tools/whisker/descriptor-for-packaging.xml index 1a68a0d9c5..01e60269f4 100644 --- a/tools/whisker/descriptor-for-packaging.xml +++ b/tools/whisker/descriptor-for-packaging.xml @@ -2673,7 +2673,7 @@ Copyright (C) 2008 Tóth István <stoty@tvnet.hu> 2009-2011 Bryan Kearney <bkearney@redhat.com> - + @@ -2683,7 +2683,7 @@ Copyright (c) 2012 The Apache Software Foundation - + diff --git a/utils/pom.xml b/utils/pom.xml index 93d7d01a06..206eb1896a 100755 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -69,7 +69,7 @@
org.bouncycastle - bcprov-jdk16 + bcprov-jdk15on com.jcraft From 8af677a0f0b2a74db74223fc3d0e2d3e9549e960 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 28 Jan 2016 13:06:08 +0100 Subject: [PATCH 113/203] maven: fix dependency version support by JDK7 - Fix jetty dependency that is compatible with Java7 - Upgrade minor revisions of dependencies - Upgrade vmware mvn sdk dependency to 6.0 - Downgrade bounty castle version to 1.46 (same as before) Signed-off-by: Rohit Yadav --- client/pom.xml | 1 + plugins/event-bus/kafka/pom.xml | 2 +- plugins/event-bus/rabbitmq/pom.xml | 2 +- plugins/storage/volume/cloudbyte/pom.xml | 2 +- plugins/user-authenticators/saml2/pom.xml | 6 ++++ pom.xml | 40 ++++++++--------------- usage/pom.xml | 6 ++-- 7 files changed, 27 insertions(+), 32 deletions(-) diff --git a/client/pom.xml b/client/pom.xml index 1f3665d61f..a1e4f609f4 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -431,6 +431,7 @@ org.eclipse.jetty jetty-maven-plugin + ${cs.jetty.version} diff --git a/plugins/event-bus/kafka/pom.xml b/plugins/event-bus/kafka/pom.xml index 2c79aa8738..2bae703443 100644 --- a/plugins/event-bus/kafka/pom.xml +++ b/plugins/event-bus/kafka/pom.xml @@ -36,7 +36,7 @@ org.apache.kafka kafka-clients - 0.9.0.0 + 0.9.0.1 diff --git a/plugins/event-bus/rabbitmq/pom.xml b/plugins/event-bus/rabbitmq/pom.xml index 937d5bb0da..7e797099c0 100644 --- a/plugins/event-bus/rabbitmq/pom.xml +++ b/plugins/event-bus/rabbitmq/pom.xml @@ -31,7 +31,7 @@ com.rabbitmq amqp-client - 3.6.0 + 3.6.1 org.apache.cloudstack diff --git a/plugins/storage/volume/cloudbyte/pom.xml b/plugins/storage/volume/cloudbyte/pom.xml index 9cc874e716..5372ab8013 100755 --- a/plugins/storage/volume/cloudbyte/pom.xml +++ b/plugins/storage/volume/cloudbyte/pom.xml @@ -54,7 +54,7 @@ com.sun.jersey jersey-bundle - 1.19 + 1.19.1
diff --git a/plugins/user-authenticators/saml2/pom.xml b/plugins/user-authenticators/saml2/pom.xml index a54190239e..5e24df35c5 100644 --- a/plugins/user-authenticators/saml2/pom.xml +++ b/plugins/user-authenticators/saml2/pom.xml @@ -47,5 +47,11 @@ cloud-framework-config ${project.version}
+ + xerces + xercesImpl + 2.11.0 + test +
diff --git a/pom.xml b/pom.xml index 3b78e990c0..01828d4393 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ 1.2.17 1.2.17 - 3.2.0 + 3.2.1 1.4 1.6 1.10 @@ -63,7 +63,7 @@ 4.12 1.3 - 1.54 + 1.46 0.1.53 2.1.1 1.9.2 @@ -73,11 +73,11 @@ 18.0 19.0 6.2.0-3.1 - 4.5.1 + 4.5.2 4.4.4 3.1 5.1.34 - 1.4.8 + 1.4.9 3.1.3 1.5.0-b01 1.4 @@ -88,11 +88,11 @@ 2.5 1.2.1 1.0-20081010.060147 - 5.5 + 6.0 3.2.16.RELEASE 1.10.19 1.6.4 - 1.10.50 + 1.10.64 2.7.1 2.6 3.4 @@ -117,12 +117,10 @@ 2.8.1 1.8 2.3.4_1 - 9.3.7.v20160115 + 9.2.15.v20160210 3.1.4 - 1.0.1.RELEASE - 4.0.3.RELEASE - 2.4.3 - 9.3.7.v20160115 + 2.4.6 + 9.2.15.v20160210 10.1 @@ -225,16 +223,6 @@ groovy-all ${cs.groovy.version}
- - org.springframework.security - spring-security-core - ${cs.spring-security-core.version} - - - org.springframework.security.extensions - spring-security-saml2-core - ${cs.spring-security-saml2-core.version} - org.bouncycastle bcprov-jdk15on @@ -377,7 +365,7 @@ org.owasp.esapi esapi - 2.1.0 + 2.1.0.1 org.eclipse.persistence @@ -447,12 +435,12 @@ org.aspectj aspectjtools - 1.8.8 + 1.8.9 org.aspectj aspectjweaver - 1.8.8 + 1.8.9 org.apache.axis @@ -477,12 +465,12 @@ org.slf4j slf4j-api - 1.7.14 + 1.7.21 org.slf4j slf4j-log4j12 - 1.7.14 + 1.7.21
diff --git a/usage/pom.xml b/usage/pom.xml index 7e9e8c4f90..dd80e82ce7 100644 --- a/usage/pom.xml +++ b/usage/pom.xml @@ -53,17 +53,17 @@ org.slf4j slf4j-api - 1.7.14 + 1.7.21 org.slf4j slf4j-log4j12 - 1.7.14 + 1.7.21 org.dbunit dbunit - 2.5.1 + 2.5.2 test
From 5f16199813a9371c6cb47977591a1695dc8b4b69 Mon Sep 17 00:00:00 2001 From: sadhu Date: Fri, 1 Apr 2016 11:54:30 +0530 Subject: [PATCH 114/203] BUG-ID:CLOUDSTACK-9331:added code in marvin frame&new config file to support baremetal advanced testcases --- .../config/Baremetal_AdvZone_Vmware.cfg | 208 ++++++++++++++++++ tools/marvin/marvin/deployDataCenter.py | 41 +++- 2 files changed, 245 insertions(+), 4 deletions(-) create mode 100644 tools/marvin/marvin/config/Baremetal_AdvZone_Vmware.cfg diff --git a/tools/marvin/marvin/config/Baremetal_AdvZone_Vmware.cfg b/tools/marvin/marvin/config/Baremetal_AdvZone_Vmware.cfg new file mode 100644 index 0000000000..a382e33b8f --- /dev/null +++ b/tools/marvin/marvin/config/Baremetal_AdvZone_Vmware.cfg @@ -0,0 +1,208 @@ +# 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. +{ + "zones": [ + { + "name": "ZoneBaremetal", + "guestcidraddress": "10.1.1.0/24", + "providers": [ + { + "broadcastdomainrange": "ZONE", + "name": "VirtualRouter" + } + ], + "dns1": "10.x.x.x", + + "physical_networks": [ + { + "broadcastdomainrange": "Zone", + "name": "Sandbox-pnet", + "vlan": "1020-1025", + "traffictypes": [ + { + "typ": "Guest" + }, + { + "typ": "Management" + }, + { + "typ": "Public" + } + ], + "providers": [ + { + "broadcastdomainrange": "ZONE", + "name": "VirtualRouter" + } + ] + } + ], + "ipranges": [ + { + "startip": "10.x.x.x", + "endip": "10.x.x.x", + "netmask": "255.255.255.0", + "vlan": "1220", + "gateway": "10.x.x.1" + } + ], + "networktype": "Advanced", + "pods": [ + { + "endip": "10.x.x.x", + "name": "POD01", + "startip": "10.x.x.x", + "netmask": "255.255.255.192", + "vmwaredc":{"name":"dc-baremetal","vcenter":"10.x.x.x","username":"Administrator@vsphere.local","password":"Password"}, + "clusters": [ + { + "clustername": "10.x.x.x/dc-baremetal/cluster1", + "hypervisor": "VmWare", + "username": "Administrator@vsphere.local", + "clustertype": "ExternalManaged", + "password": "Password", + "url": "http://10.x.x.x/dc-baremetal/cluster1", + "hosts": [ + { + "username": "root", + "url": "http://10.x.x.x", + "password": "password" + }, + { + "username": "root", + "url": "http://10.x.x.x", + "password": "password" + } + ], + "primaryStorages": [ + { + "url": "nfs://10.x.x.x:/export/home/primary", + "name": "PS0" + } + ] + }, + { + "clustername": "C1", + "hypervisor": "BareMetal", + "hosts": [ + { + "username": "root", + "url": "http://10.x.x.x", + "password": "password", + "hostmac": "xx:xx:xx:xx:xx:xx", + "cpunumber": "1", + "cpuspeed": "1000", + "memory": "1024", + "hosttags": "host15" + } + ], + "clustertype": "CloudManaged" + } + ], + "gateway": "10.x.x.x" + } + ], + "internaldns1": "10.x.x.x", + "baremetalrcturl": "http://10.x.x.x/baremetal/baremetalrct.json", + "secondaryStorages": [ + { + "url": "nfs://10.x.x.x:/export/home/secondary", + "provider": "nfs", + "name":"secondary" + } + ] + } + ], + "logger": { + "LogFolderPath": "/tmp/" + }, + "dbSvr": { + "dbSvr": "10.22.13.12", + "passwd": "password", + "db": "cloud", + "port": 3306, + "user": "root" + }, + + "globalConfig": [ + { + "name": "network.gc.wait", + "value": "60" + }, + { + "name": "storage.cleanup.interval", + "value": "30" + }, + { + "name": "account.cleanup.interval", + "value": "60" + }, + { + "name": "secstorage.allowed.internal.sites", + "value": "10.x.x.0/24" + }, + { + "name": "vm.op.wait.interval", + "value": "5" + }, + { + "name": "network.gc.interval", + "value": "60" + }, + { + "name": "guest.domain.suffix", + "value": "auto.advanced" + }, + { + "name": "expunge.delay", + "value": "60" + }, + { + "name": "vm.allocation.algorithm", + "value": "userdispersing" + }, + { + "name": "expunge.interval", + "value": "60" + }, + { + "name": "instance.name", + "value": "QA" + }, + { + "name": "expunge.workers", + "value": "3" + }, + { + "name": "baremetal.internal.storage.server.ip", + "value": "10.2.1.2" + }, + { + "name": "check.pod.cidrs", + "value": "true" + } + ], + "mgtSvr": [ + { + "mgtSvrIp": "10.22.10.12", + "port": 8096, + "user": "root", + "password": "password", + "hypervisor": "vmware" + } + ] +} diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py index 91b30a6587..889aab510b 100644 --- a/tools/marvin/marvin/deployDataCenter.py +++ b/tools/marvin/marvin/deployDataCenter.py @@ -133,6 +133,12 @@ def addHosts(self, hosts, zoneId, podId, clusterId, hypervisor): hostcmd.username = host.username hostcmd.zoneid = zoneId hostcmd.hypervisor = hypervisor + if hostcmd.hypervisor.lower() == "baremetal": + hostcmd.hostmac=host.hostmac + hostcmd.cpunumber=host.cpunumber + hostcmd.cpuspeed=host.cpuspeed + hostcmd.memory=host.memory + hostcmd.hosttags=host.hosttags ret = self.__apiClient.addHost(hostcmd) if ret: self.__tcRunLogger.debug("=== Add Host Successful ===") @@ -164,6 +170,25 @@ def addVmWareDataCenter(self, vmwareDc): self.__tcRunLogger.exception("=== Adding VmWare DC Failed===") self.__cleanAndExit() + def addBaremetalRct(self, config): + networktype= config.zones[0].networktype + baremetalrcturl= config.zones[0].baremetalrcturl + if networktype is None or baremetalrcturl is None: + return + if networktype.lower()=="advanced": + + try: + brctcmd = addBaremetalRct.addBaremetalRctCmd() + brctcmd.baremetalrcturl=baremetalrcturl + ret = self.__apiClient.addBaremetalRct(brctcmd) + if ret.id: + self.__tcRunLogger.debug("=== Adding Baremetal Rct file Successful===") + self.__addToCleanUp("BaremetalRct", ret.id) + except Exception as e: + print "Exception Occurred: %s" % GetDetailExceptionInfo(e) + self.__tcRunLogger.exception("=== Adding Baremetal Rct file Failed===") + self.__cleanAndExit() + def createClusters(self, clusters, zoneId, podId, vmwareDc=None): try: if clusters is None: @@ -193,10 +218,12 @@ def createClusters(self, clusters, zoneId, podId, vmwareDc=None): self.addHosts(cluster.hosts, zoneId, podId, clusterId, cluster.hypervisor) self.waitForHost(zoneId, clusterId) - self.createPrimaryStorages(cluster.primaryStorages, - zoneId, - podId, - clusterId) + if cluster.hypervisor.lower() != "baremetal": + self.createPrimaryStorages(cluster.primaryStorages, + zoneId, + podId, + clusterId) + except Exception as e: print "Exception Occurred %s" % GetDetailExceptionInfo(e) self.__tcRunLogger.exception("====Cluster %s Creation Failed" @@ -888,6 +915,12 @@ def deploy(self): self.__persistDcConfig() print "\n====Deploy DC Successful=====" self.__tcRunLogger.debug("\n====Deploy DC Successful====") + ''' + Upload baremetalSwitch configuration(.rct) file if enabled zone has baremetal isolated network. + ''' + self.addBaremetalRct(self.__config) + self.__tcRunLogger.debug("\n==== AddbaremetalRct Successful====") + return SUCCESS except Exception as e: print "\nException Occurred Under deploy :%s" % \ From 7db5f1833e72d2208b3b085da47b4b0d114300d3 Mon Sep 17 00:00:00 2001 From: Anshul Gangwar Date: Tue, 22 Dec 2015 11:59:09 +0530 Subject: [PATCH 115/203] CLOUDSTACK-9164: Prevent firefox's quick search from opening in VM console --- systemvm/js/ajaxviewer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/systemvm/js/ajaxviewer.js b/systemvm/js/ajaxviewer.js index f5df103964..09fb41a739 100644 --- a/systemvm/js/ajaxviewer.js +++ b/systemvm/js/ajaxviewer.js @@ -649,6 +649,7 @@ AjaxViewer.prototype = { this.sendingEventInProgress = false; ajaxViewer.installMouseHook(); ajaxViewer.installKeyboardHook(); + ajaxViewer.panel.parent().focus(); $(window).bind("resize", function() { ajaxViewer.onWindowResize(); @@ -1259,6 +1260,7 @@ AjaxViewer.prototype = { case 38 : // UP case 39 : // RIGHT case 40 : // DOWN + case 47 : // FORWARD SLASH // Added to stop Firefox's quick search from opening return false; } From c63ea0a240df0c5af2802b424d70083bbfd0e919 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Mon, 25 Apr 2016 14:47:22 +0530 Subject: [PATCH 116/203] engine/schema: fix upgrade path to work with MySQL 5.7 Found this issue when using MySQL 5.7 with Ubuntu 16.04 with following settings: sql-mode="STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,ERROR_FOR_DIVISION_BY_ZERO,NO_ZERO_DATE,NO_ZERO_IN_DATE,NO_ENGINE_SUBSTITUTION" server-id = 1 innodb_rollback_on_timeout=1 innodb_lock_wait_timeout=600 max_connections=350 log-bin=mysql-bin binlog-format = 'ROW' Signed-off-by: Rohit Yadav --- engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java index b816fdc9fc..7d67d2eb6a 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -1297,7 +1297,7 @@ private void addHostDetailsIndex(Connection conn) { s_logger.debug("Index already exists on host_details - not adding new one"); } else { // add the index - try(PreparedStatement pstmtUpdate = conn.prepareStatement("ALTER IGNORE TABLE `cloud`.`host_details` ADD INDEX `fk_host_details__host_id` (`host_id`)");) { + try(PreparedStatement pstmtUpdate = conn.prepareStatement("ALTER TABLE `cloud`.`host_details` ADD INDEX `fk_host_details__host_id` (`host_id`)");) { pstmtUpdate.executeUpdate(); s_logger.debug("Index did not exist on host_details - added new one"); }catch (SQLException e) { From 182ab648b5afae21fddcd69e4cba1c15df721278 Mon Sep 17 00:00:00 2001 From: Abhinandan Prateek Date: Mon, 28 Mar 2016 08:17:43 +0530 Subject: [PATCH 117/203] CLOUDSTACK-9323: Fix Cancel maintenance so that if maintenance is cancelled the host come back to normal state gracefully. Added marvin tests for host maintennace. --- .../cloud/resource/ResourceManagerImpl.java | 10 +- .../component/test_host_maintenance.py | 292 ++++++++++++++++++ tools/marvin/marvin/lib/utils.py | 23 +- 3 files changed, 320 insertions(+), 5 deletions(-) create mode 100644 test/integration/component/test_host_maintenance.py diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 359bccf034..8341075b72 100644 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -2112,11 +2112,13 @@ private boolean doCancelMaintenance(final long hostId) { /* TODO: move to listener */ _haMgr.cancelScheduledMigrations(host); + + boolean vms_migrating = false; final List vms = _haMgr.findTakenMigrationWork(); for (final VMInstanceVO vm : vms) { - if (vm != null && vm.getHostId() != null && vm.getHostId() == hostId) { - s_logger.info("Unable to cancel migration because the vm is being migrated: " + vm); - return false; + if (vm.getHostId() != null && vm.getHostId() == hostId) { + s_logger.warn("Unable to cancel migration because the vm is being migrated: " + vm + ", hostId = " + hostId); + vms_migrating = true; } } @@ -2125,7 +2127,7 @@ private boolean doCancelMaintenance(final long hostId) { _agentMgr.pullAgentOutMaintenance(hostId); // for kvm, need to log into kvm host, restart cloudstack-agent - if (host.getHypervisorType() == HypervisorType.KVM || host.getHypervisorType() == HypervisorType.LXC) { + if ((host.getHypervisorType() == HypervisorType.KVM && !vms_migrating) || host.getHypervisorType() == HypervisorType.LXC) { final boolean sshToAgent = Boolean.parseBoolean(_configDao.getValue(Config.KvmSshToAgentEnabled.key())); if (!sshToAgent) { diff --git a/test/integration/component/test_host_maintenance.py b/test/integration/component/test_host_maintenance.py new file mode 100644 index 0000000000..94f964caf0 --- /dev/null +++ b/test/integration/component/test_host_maintenance.py @@ -0,0 +1,292 @@ +# 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. +""" BVT tests for Hosts Maintenance +""" + +# Import Local Modules +from marvin.codes import FAILED +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.lib.utils import * +from marvin.lib.base import * +from marvin.lib.common import * +from nose.plugins.attrib import attr + +from time import sleep + +_multiprocess_shared_ = False + + +class TestHostMaintenance(cloudstackTestCase): + + def setUp(self): + self.logger = logging.getLogger('TestHM') + self.stream_handler = logging.StreamHandler() + self.logger.setLevel(logging.DEBUG) + self.logger.addHandler(self.stream_handler) + self.apiclient = self.testClient.getApiClient() + self.hypervisor = self.testClient.getHypervisorInfo() + self.dbclient = self.testClient.getDbConnection() + self.services = self.testClient.getParsedTestDataConfig() + self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests()) + self.pod = get_pod(self.apiclient, self.zone.id) + self.cleanup = [] + self.services = { + "service_offering": { + "name": "Ultra Tiny Instance", + "displaytext": "Ultra Tiny Instance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 128, + }, + "vm": { + "username": "root", + "password": "password", + "ssh_port": 22, + # Hypervisor type should be same as + # hypervisor type of cluster + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "natrule": { + "privateport": 22, + "publicport": 22, + "startport": 22, + "endport": 22, + "protocol": "TCP", + "cidrlist": '0.0.0.0/0', + }, + "ostype": 'CentOS 5.3 (64-bit)', + "sleep": 60, + "timeout": 10, + } + + + def tearDown(self): + try: + # Clean up, terminate the created templates + cleanup_resources(self.apiclient, self.cleanup) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + return + + def createVMs(self, hostId, number): + + self.template = get_template( + self.apiclient, + self.zone.id, + self.services["ostype"] + ) + + if self.template == FAILED: + assert False, "get_template() failed to return template with description %s" % self.services["ostype"] + + self.logger.debug("Using template %s " % self.template.id) + + self.service_offering = ServiceOffering.create( + self.apiclient, + self.services["service_offering"] + ) + self.logger.debug("Using service offering %s " % self.service_offering.id) + + vms=[] + for i in range(0, number): + self.services["vm"]["zoneid"] = self.zone.id + self.services["vm"]["template"] = self.template.id + self.services["vm"]["displayname"] = 'vm' + str(i) + self.services["vm"]["hypervisor"] = self.hypervisor + vm = VirtualMachine.create( + self.apiclient, + self.services["vm"], + serviceofferingid=self.service_offering.id, + hostid=hostId + ) + vms.append(vm) + self.cleanup.append(vm) + self.logger.debug("VM create = {}".format(vm.id)) + return vms + + def checkVmMigratingOnHost(self, hostId): + vm_migrating=False + listVms1 = VirtualMachine.list( + self.apiclient, + hostid=hostId + ) + + if (listVms1 is not None): + self.logger.debug('Vms found = {} '.format(len(listVms1))) + for vm in listVms1: + if (vm.state == "Migrating"): + self.logger.debug('VirtualMachine on Hyp id = {} is in {}'.format(vm.id, vm.state)) + vm_migrating=True + break + + return (vm_migrating, None) + + def checkNoVmMigratingOnHost(self, hostId): + no_vm_migrating=True + listVms1 = VirtualMachine.list( + self.apiclient, + hostid=hostId + ) + + if (listVms1 is not None): + self.logger.debug('Vms found = {} '.format(len(listVms1))) + for vm in listVms1: + if (vm.state == "Migrating"): + self.logger.debug('VirtualMachine on Hyp id = {} is in {}'.format(vm.id, vm.state)) + no_vm_migrating=False + break + + return (no_vm_migrating, None) + + def noOfVMsOnHost(self, hostId): + listVms = VirtualMachine.list( + self.apiclient, + hostid=hostId + ) + no_of_vms=0 + if (listVms is not None): + for vm in listVms: + self.logger.debug('VirtualMachine on Hyp 1 = {}'.format(vm.id)) + no_of_vms=no_of_vms+1 + + return no_of_vms + + def hostPrepareAndCancelMaintenance(self, target_host_id, other_host_id, checkVMMigration): + + cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() + cmd.id = target_host_id + response = self.apiclient.prepareHostForMaintenance(cmd) + + self.logger.debug('Host with id {} is in prepareHostForMaintenance'.format(target_host_id)) + + vm_migrating = wait_until(1, 10, checkVMMigration, other_host_id) + + cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() + cmd.id = target_host_id + response = self.apiclient.cancelHostMaintenance(cmd) + + self.logger.debug('Host with id {} is in cancelHostMaintenance'.format(target_host_id) ) + + return vm_migrating + + @attr( + tags=[ + "advanced", + "advancedns", + "smoke", + "basic", + "eip", + "sg"], + required_hardware="true") + def test_01_cancel_host_maintenace_with_no_migration_jobs(self): + listHost = Host.list( + self.apiclient, + type='Routing', + zoneid=self.zone.id, + podid=self.pod.id, + ) + for host in listHost: + self.logger.debug('1 Hypervisor = {}'.format(host.id)) + + + if (len(listHost) < 2): + raise unittest.SkipTest("Cancel host maintenance when VMs are migrating should be tested for 2 or more hosts"); + return + + vm_migrating=False + + try: + + vm_migrating = self.hostPrepareAndCancelMaintenance(listHost[0].id, listHost[1].id, self.checkNoVmMigratingOnHost) + + vm_migrating = self.hostPrepareAndCancelMaintenance(listHost[1].id, listHost[0].id, self.checkNoVmMigratingOnHost) + + except Exception as e: + self.logger.debug("Exception {}".format(e)) + self.fail("Cancel host maintenance failed {}".format(e[0])) + + + if (vm_migrating == True): + raise unittest.SkipTest("VMs are migrating and the test will not be able to check the conditions the test is intended for"); + + + return + + + + + @attr( + tags=[ + "advanced", + "advancedns", + "smoke", + "basic", + "eip", + "sg"], + required_hardware="true") + def test_02_cancel_host_maintenace_with_migration_jobs(self): + + listHost = Host.list( + self.apiclient, + type='Routing', + zoneid=self.zone.id, + podid=self.pod.id, + ) + for host in listHost: + self.logger.debug('2 Hypervisor = {}'.format(host.id)) + + if (len(listHost) != 2): + raise unittest.SkipTest("Cancel host maintenance when VMs are migrating can only be tested with 2 hosts"); + return + + + no_of_vms = self.noOfVMsOnHost(listHost[0].id) + + no_of_vms = no_of_vms + self.noOfVMsOnHost(listHost[1].id) + + if no_of_vms < 5: + self.logger.debug("Create VMs as there are not enough vms to check host maintenance") + no_vm_req = 5 - no_of_vms + if (no_vm_req > 0): + self.logger.debug("Creating vms = {}".format(no_vm_req)) + self.vmlist = self.createVMs(listHost[0].id, no_vm_req) + + vm_migrating=False + + try: + + vm_migrating = self.hostPrepareAndCancelMaintenance(listHost[0].id, listHost[1].id, self.checkVmMigratingOnHost) + + vm_migrating = self.hostPrepareAndCancelMaintenance(listHost[1].id, listHost[0].id, self.checkVmMigratingOnHost) + + except Exception as e: + self.logger.debug("Exception {}".format(e)) + self.fail("Cancel host maintenance failed {}".format(e[0])) + + + if (vm_migrating == False): + raise unittest.SkipTest("No VM is migrating and the test will not be able to check the conditions the test is intended for"); + + + return + + diff --git a/tools/marvin/marvin/lib/utils.py b/tools/marvin/marvin/lib/utils.py index 97b80ac308..aa41e7b401 100644 --- a/tools/marvin/marvin/lib/utils.py +++ b/tools/marvin/marvin/lib/utils.py @@ -520,4 +520,25 @@ def verifyRouterState(apiclient, routerid, allowedstates): if routers[0].state.lower() not in allowedstates: return [FAIL, "state of the router should be in %s but is %s" % (allowedstates, routers[0].state)] - return [PASS, None] \ No newline at end of file + return [PASS, None] + + + +def wait_until(retry_interval=2, no_of_times=2, callback=None, *callback_args): + """ Utility method to try out the callback method at most no_of_times with a interval of retry_interval, + Will return immediately if callback returns True. The callback method should be written to return a list of values first being a boolean """ + + if callback is None: + raise ("Bad value for callback method !") + + wait_result = False + for i in range(0,no_of_times): + time.sleep(retry_interval) + wait_result, return_val = callback(*callback_args) + if not(isinstance(wait_result, bool)): + raise ("Bad parameter returned from callback !") + if wait_result : + break + + return wait_result, return_val + From 10ae2aff28cae69f0199fa2820472bb9cd7f3ebc Mon Sep 17 00:00:00 2001 From: Dmytro Shevchenko Date: Sat, 12 Dec 2015 16:44:09 +0200 Subject: [PATCH 118/203] CLOUDSTACK-8302 - Cleanup snapshot on KVM with RBD Snapshot removing implemented on RBD. 1. On management side: when created new shanpshot we checking if our primary storage is RBD, then do not remove record from cloud.snapshot_store_ref with link to Ceph image via 'install_path' field. 2. On management side: when removing snapshot, also send command to agent 'DeleteCommand'. 3. On agent side: method implemented 'public Answer deleteSnapshot(final DeleteCommand cmd)' --- engine/storage/snapshot/pom.xml | 5 +++ .../snapshot/XenserverSnapshotStrategy.java | 26 +++++++---- .../kvm/storage/KVMStorageProcessor.java | 43 ++++++++++++++++++- 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/engine/storage/snapshot/pom.xml b/engine/storage/snapshot/pom.xml index 97ca7f21e3..eda47be41e 100644 --- a/engine/storage/snapshot/pom.xml +++ b/engine/storage/snapshot/pom.xml @@ -37,6 +37,11 @@ test-jar test
+ + org.apache.cloudstack + cloud-engine-storage-volume + ${project.version} +
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java index edd194e605..99fc1612fa 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java @@ -36,6 +36,7 @@ import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; +import org.apache.cloudstack.storage.datastore.PrimaryDataStoreImpl; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import com.cloud.exception.InvalidParameterValueException; @@ -53,6 +54,7 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; @@ -263,6 +265,10 @@ public boolean deleteSnapshot(Long snapshotId) { //snapshot is deleted on backup storage, need to delete it on primary storage SnapshotDataStoreVO snapshotOnPrimary = snapshotStoreDao.findBySnapshot(snapshotId, DataStoreRole.Primary); if (snapshotOnPrimary != null) { + SnapshotInfo snapshotOnPrimaryInfo = snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary); + if (((PrimaryDataStoreImpl)snapshotOnPrimaryInfo.getDataStore()).getPoolType() == StoragePoolType.RBD) { + snapshotSvr.deleteSnapshot(snapshotOnPrimaryInfo); + } snapshotOnPrimary.setState(State.Destroyed); snapshotStoreDao.update(snapshotOnPrimary.getId(), snapshotOnPrimary); } @@ -371,15 +377,17 @@ public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) { try { SnapshotInfo parent = snapshot.getParent(); - if (backupedSnapshot != null && parent != null) { - Long parentSnapshotId = parent.getId(); - while (parentSnapshotId != null && parentSnapshotId != 0L) { - SnapshotDataStoreVO snapshotDataStoreVO = snapshotStoreDao.findByStoreSnapshot(primaryStore.getRole(), primaryStore.getId(), parentSnapshotId); - if (snapshotDataStoreVO != null) { - parentSnapshotId = snapshotDataStoreVO.getParentSnapshotId(); - snapshotStoreDao.remove(snapshotDataStoreVO.getId()); - } else { - parentSnapshotId = null; + if (backupedSnapshot != null && parent != null && primaryStore instanceof PrimaryDataStoreImpl) { + if (((PrimaryDataStoreImpl)primaryStore).getPoolType() != StoragePoolType.RBD) { + Long parentSnapshotId = parent.getId(); + while (parentSnapshotId != null && parentSnapshotId != 0L) { + SnapshotDataStoreVO snapshotDataStoreVO = snapshotStoreDao.findByStoreSnapshot(primaryStore.getRole(), primaryStore.getId(), parentSnapshotId); + if (snapshotDataStoreVO != null) { + parentSnapshotId = snapshotDataStoreVO.getParentSnapshotId(); + snapshotStoreDao.remove(snapshotDataStoreVO.getId()); + } else { + parentSnapshotId = null; + } } } SnapshotDataStoreVO snapshotDataStoreVO = snapshotStoreDao.findByStoreSnapshot(primaryStore.getRole(), primaryStore.getId(), snapshot.getId()); diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index 51931dbb9a..92e985e023 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -1274,7 +1274,48 @@ public Answer createVolumeFromSnapshot(final CopyCommand cmd) { @Override public Answer deleteSnapshot(final DeleteCommand cmd) { - return new Answer(cmd); + String snap_full_name = ""; + try { + SnapshotObjectTO snapshotTO = (SnapshotObjectTO) cmd.getData(); + PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO) snapshotTO.getDataStore(); + VolumeObjectTO volume = snapshotTO.getVolume(); + KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid()); + KVMPhysicalDisk disk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), volume.getPath()); + String snapshotFullPath = snapshotTO.getPath(); + String snapshotName = snapshotFullPath.substring(snapshotFullPath.lastIndexOf("/") + 1); + snap_full_name = disk.getName() + "@" + snapshotName; + if (primaryPool.getType() == StoragePoolType.RBD) { + Rados r = new Rados(primaryPool.getAuthUserName()); + r.confSet("mon_host", primaryPool.getSourceHost() + ":" + primaryPool.getSourcePort()); + r.confSet("key", primaryPool.getAuthSecret()); + r.confSet("client_mount_timeout", "30"); + r.connect(); + s_logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host")); + IoCTX io = r.ioCtxCreate(primaryPool.getSourceDir()); + Rbd rbd = new Rbd(io); + RbdImage image = rbd.open(disk.getName()); + try { + s_logger.info("Attempting to remove RBD snapshot " + snap_full_name); + if (image.snapIsProtected(snapshotName)) { + s_logger.debug("Unprotecting RBD snapshot " + snap_full_name); + image.snapUnprotect(snapshotName); + } + image.snapRemove(snapshotName); + s_logger.info("Snapshot " + snap_full_name + " successfully removed from " + + primaryPool.getType().toString() + " pool."); + } finally { + rbd.close(image); + r.ioCtxDestroy(io); + } + } else { + s_logger.warn("Operation not implemented for storage pool type of " + primaryPool.getType().toString()); + throw new InternalErrorException("Operation not implemented for storage pool type of " + primaryPool.getType().toString()); + } + return new Answer(cmd, true, "Snapshot " + snap_full_name + " removed successfully."); + } catch (Exception e) { + s_logger.error(e.getMessage()); + return new Answer(cmd, false, "Failed to remove snapshot " + snap_full_name); + } } @Override From 42de1f81ed13145374a5838459ce068881966e8c Mon Sep 17 00:00:00 2001 From: NuxRo Date: Wed, 27 Apr 2016 10:49:53 +0100 Subject: [PATCH 119/203] CPU socket count reporting correction CPU socket count reporting correction From https://github.com/MissionCriticalCloud/cosmic-plugin-hypervisor-kvm/pull/16 --- .../kvm/resource/LibvirtComputingResource.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) 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 883c8c9942..a15071e83b 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 @@ -2625,8 +2625,15 @@ protected List getHostInfo() { final Connect conn = LibvirtConnection.getConnection(); final NodeInfo hosts = conn.nodeInfo(); speed = getCpuSpeed(hosts); - + + /* + * Some CPUs report a single socket and multiple NUMA cells. + * We need to multiply them to get the correct socket count. + */ cpuSockets = hosts.sockets; + if (hosts.nodes > 0) { + cpuSockets = hosts.sockets * hosts.nodes; + } cpus = hosts.cpus; ram = hosts.memory * 1024L; final LibvirtCapXMLParser parser = new LibvirtCapXMLParser(); From 108b3517afc8a5bd5cb1443fb7dc88a8c71ef168 Mon Sep 17 00:00:00 2001 From: NuxRo Date: Wed, 27 Apr 2016 19:15:02 +0100 Subject: [PATCH 120/203] Remove empty spaces causing the build to fail --- .../cloud/hypervisor/kvm/resource/LibvirtComputingResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a15071e83b..d8826d9c68 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 @@ -2625,7 +2625,7 @@ protected List getHostInfo() { final Connect conn = LibvirtConnection.getConnection(); final NodeInfo hosts = conn.nodeInfo(); speed = getCpuSpeed(hosts); - + /* * Some CPUs report a single socket and multiple NUMA cells. * We need to multiply them to get the correct socket count. From 7778e24bf7bb7bd2c1a19fde5fb711b8d8086446 Mon Sep 17 00:00:00 2001 From: Nathan Johnson Date: Wed, 27 Apr 2016 14:49:50 -0500 Subject: [PATCH 121/203] Log responses from asynchronous api commands This is mainly useful so that we can see the job ids in the logs whenever the job is created via the API. --- server/src/com/cloud/api/ApiServer.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index f76b851f5d..6ec2f18e77 100644 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -686,14 +686,21 @@ private String queueCommand(final BaseCmd cmdObj, final Map para s_logger.warn(errorMsg); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMsg); } - + final String response; if (objectId != null) { final String objUuid = (objectUuid == null) ? objectId.toString() : objectUuid; - return getBaseAsyncCreateResponse(jobId, (BaseAsyncCreateCmd)asyncCmd, objUuid); + response = getBaseAsyncCreateResponse(jobId, (BaseAsyncCreateCmd)asyncCmd, objUuid); } else { SerializationContext.current().setUuidTranslation(true); - return getBaseAsyncResponse(jobId, asyncCmd); + response = getBaseAsyncResponse(jobId, asyncCmd); } + // Always log response for async for now, I don't think any sensitive data will be in here. + // It might be nice to send this through scrubbing similar to how + // ApiResponseSerializer.toSerializedStringWithSecureLogs works. For now, this gets jobid's + // in the api logs. + log.append(response); + return response; + } else { dispatcher.dispatch(cmdObj, params, false); From 26becef7227f508415f04f4131f0feded7d74257 Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Tue, 9 Feb 2016 21:20:58 +0100 Subject: [PATCH 122/203] kvm: Aqcuire lock when running security group Python script It could happen that when multiple instances are starting at the same time on a KVM host the Agent spawns multiple instances of security_group.py which both try to modify iptables/ebtables rules. This fails with on of the two processes failing. The instance is still started, but it doesn't have any IP connectivity due to the failed programming of the security groups. This modification lets the script aqcuire a exclusive lock on a file so that only one instance of the scripts talks to iptables/ebtables at once. Other instances of the script which start will poll every 500ms if they can obtain the lock and otherwise execute anyway after 15 seconds. The lock will be released as soon as the script exists, which is usually within a few hundred ms. --- scripts/vm/network/security_group.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/scripts/vm/network/security_group.py b/scripts/vm/network/security_group.py index 915a8afb06..e459a29740 100755 --- a/scripts/vm/network/security_group.py +++ b/scripts/vm/network/security_group.py @@ -26,8 +26,11 @@ from optparse import OptionParser, OptionGroup, OptParseError, BadOptionError, OptionError, OptionConflictError, OptionValueError import re import libvirt +import fcntl +import time logpath = "/var/run/cloud/" # FIXME: Logs should reside in /var/log/cloud +lock_file = "/var/lock/cloudstack_security_group.lock" iptables = Command("iptables") bash = Command("/bin/bash") ebtables = Command("ebtables") @@ -36,6 +39,21 @@ hyper = cfo.getEntry("hypervisor.type") if hyper == "lxc": driver = "lxc:///" + +lock_handle = None + +def obtain_file_lock(path): + global lock_handle + + try: + lock_handle = open(path, 'w') + fcntl.flock(lock_handle, fcntl.LOCK_EX | fcntl.LOCK_NB) + return True + except IOError: + pass + + return False + def execute(cmd): logging.debug(cmd) return bash("-c", cmd).stdout @@ -303,7 +321,7 @@ def default_network_rules_systemvm(vm_name, localbrname): for bridge in bridges: if bridge != localbrname: if not addFWFramework(bridge): - return False + return False brfw = getBrfw(bridge) vifs = getVifsForBridge(vm_name, bridge) for vif in vifs: @@ -1029,6 +1047,14 @@ def addFWFramework(brname): sys.exit(1) cmd = args[0] logging.debug("Executing command: " + str(cmd)) + + for i in range(0, 30): + if obtain_file_lock(lock_file) is False: + logging.warn("Lock on %s is being held by other process. Waiting for release." % lock_file) + time.sleep(0.5) + else: + break + if cmd == "can_bridge_firewall": can_bridge_firewall(args[1]) elif cmd == "default_network_rules": From 3b89cbe73354c9afdc4a55e9556abc6ae70b2f77 Mon Sep 17 00:00:00 2001 From: Abhinandan Prateek Date: Fri, 15 Apr 2016 16:46:30 +0530 Subject: [PATCH 123/203] CLOUDSTACK-9350: KVM-HA- Fix CheckOnHost for Local storage - Also skip HA on VMs that are using local storage --- .../kvm/src/com/cloud/ha/KVMInvestigator.java | 24 +- pom.xml | 1 + .../cloud/ha/HighAvailabilityManagerImpl.java | 8 + .../ha/HighAvailabilityManagerImplTest.java | 2 + test/integration/component/test_host_ha.py | 516 ++++++++++++++++++ test/integration/component/test_host_ha.sh | 40 ++ tools/marvin/marvin/lib/utils.py | 5 +- 7 files changed, 592 insertions(+), 4 deletions(-) create mode 100644 test/integration/component/test_host_ha.py create mode 100755 test/integration/component/test_host_ha.sh diff --git a/plugins/hypervisors/kvm/src/com/cloud/ha/KVMInvestigator.java b/plugins/hypervisors/kvm/src/com/cloud/ha/KVMInvestigator.java index 32388df6a7..8337a7b764 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/ha/KVMInvestigator.java +++ b/plugins/hypervisors/kvm/src/com/cloud/ha/KVMInvestigator.java @@ -27,7 +27,11 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor; import com.cloud.resource.ResourceManager; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.utils.component.AdapterBase; + +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import javax.inject.Inject; @@ -41,6 +45,8 @@ public class KVMInvestigator extends AdapterBase implements Investigator { AgentManager _agentMgr; @Inject ResourceManager _resourceMgr; + @Inject + PrimaryDataStoreDao _storagePoolDao; @Override public boolean isVmAlive(com.cloud.vm.VirtualMachine vm, Host host) throws UnknownVM { @@ -60,6 +66,21 @@ public Status isAgentAlive(Host agent) { if (agent.getHypervisorType() != Hypervisor.HypervisorType.KVM && agent.getHypervisorType() != Hypervisor.HypervisorType.LXC) { return null; } + + List clusterPools = _storagePoolDao.listPoolsByCluster(agent.getClusterId()); + boolean hasNfs = false; + for (StoragePoolVO pool : clusterPools) { + if (pool.getPoolType() == StoragePoolType.NetworkFilesystem) { + hasNfs = true; + break; + } + } + if (!hasNfs) { + s_logger.warn( + "Agent investigation was requested on host " + agent + ", but host does not support investigation because it has no NFS storage. Skipping investigation."); + return Status.Disconnected; + } + Status hostStatus = null; Status neighbourStatus = null; CheckOnHostCommand cmd = new CheckOnHostCommand(agent); @@ -78,7 +99,8 @@ public Status isAgentAlive(Host agent) { List neighbors = _resourceMgr.listHostsInClusterByStatus(agent.getClusterId(), Status.Up); for (HostVO neighbor : neighbors) { - if (neighbor.getId() == agent.getId() || (neighbor.getHypervisorType() != Hypervisor.HypervisorType.KVM && neighbor.getHypervisorType() != Hypervisor.HypervisorType.LXC)) { + if (neighbor.getId() == agent.getId() + || (neighbor.getHypervisorType() != Hypervisor.HypervisorType.KVM && neighbor.getHypervisorType() != Hypervisor.HypervisorType.LXC)) { continue; } s_logger.debug("Investigating host:" + agent.getId() + " via neighbouring host:" + neighbor.getId()); diff --git a/pom.xml b/pom.xml index 01828d4393..30e96a6107 100644 --- a/pom.xml +++ b/pom.xml @@ -921,6 +921,7 @@ **/.checkstyle scripts/installer/windows/acs_license.rtf **/*.md + test/integration/component/test_host_ha.sh diff --git a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java index ac7dbd17b8..53d79f7107 100644 --- a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java +++ b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java @@ -62,6 +62,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.server.ManagementServer; +import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.StorageManager; import com.cloud.storage.dao.GuestOSCategoryDao; @@ -264,6 +265,13 @@ public void scheduleRestartForVmsOnHost(final HostVO host, boolean investigate) "Host [" + hostDesc + "] is down." + ((sb != null) ? sb.toString() : "")); for (VMInstanceVO vm : reorderedVMList) { + ServiceOfferingVO vmOffering = _serviceOfferingDao.findById(vm.getServiceOfferingId()); + if (vmOffering.getUseLocalStorage()) { + if (s_logger.isDebugEnabled()){ + s_logger.debug("Skipping HA on vm " + vm + ", because it uses local storage. Its fate is tied to the host."); + } + continue; + } if (s_logger.isDebugEnabled()) { s_logger.debug("Notifying HA Mgr of to restart vm " + vm.getId() + "-" + vm.getInstanceName()); } diff --git a/server/test/com/cloud/ha/HighAvailabilityManagerImplTest.java b/server/test/com/cloud/ha/HighAvailabilityManagerImplTest.java index f60044e453..898dff2b79 100644 --- a/server/test/com/cloud/ha/HighAvailabilityManagerImplTest.java +++ b/server/test/com/cloud/ha/HighAvailabilityManagerImplTest.java @@ -59,6 +59,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.server.ManagementServer; +import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.StorageManager; import com.cloud.storage.dao.GuestOSCategoryDao; @@ -195,6 +196,7 @@ public void scheduleRestartForVmsOnHostNonEmptyVMList() { Mockito.when(_dcDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(DataCenterVO.class)); Mockito.when(_haDao.findPreviousHA(Mockito.anyLong())).thenReturn(Arrays.asList(Mockito.mock(HaWorkVO.class))); Mockito.when(_haDao.persist((HaWorkVO)Mockito.anyObject())).thenReturn(Mockito.mock(HaWorkVO.class)); + Mockito.when(_serviceOfferingDao.findById(vm1.getServiceOfferingId())).thenReturn(Mockito.mock(ServiceOfferingVO.class)); highAvailabilityManager.scheduleRestartForVmsOnHost(hostVO, true); } diff --git a/test/integration/component/test_host_ha.py b/test/integration/component/test_host_ha.py new file mode 100644 index 0000000000..6361564e81 --- /dev/null +++ b/test/integration/component/test_host_ha.py @@ -0,0 +1,516 @@ +# 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. +from __builtin__ import False +""" BVT tests for Hosts Maintenance +""" + +# Import Local Modules +from marvin.codes import FAILED +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.lib.utils import * +from marvin.lib.base import * +from marvin.lib.common import * +from nose.plugins.attrib import attr + +from time import sleep + +_multiprocess_shared_ = False + + +class TestHostHA(cloudstackTestCase): + + def setUp(self): + self.logger = logging.getLogger('TestHM') + self.stream_handler = logging.StreamHandler() + self.logger.setLevel(logging.DEBUG) + self.logger.addHandler(self.stream_handler) + self.apiclient = self.testClient.getApiClient() + self.hypervisor = self.testClient.getHypervisorInfo() + self.dbclient = self.testClient.getDbConnection() + self.services = self.testClient.getParsedTestDataConfig() + self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests()) + self.pod = get_pod(self.apiclient, self.zone.id) + self.cleanup = [] + self.services = { + "service_offering": { + "name": "Ultra Tiny Instance", + "displaytext": "Ultra Tiny Instance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 128, + }, + "service_offering_local": { + "name": "Ultra Tiny Local Instance", + "displaytext": "Ultra Tiny Local Instance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 128, + "storagetype": "local" + }, + "vm": { + "username": "root", + "password": "password", + "ssh_port": 22, + # Hypervisor type should be same as + # hypervisor type of cluster + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "natrule": { + "privateport": 22, + "publicport": 22, + "startport": 22, + "endport": 22, + "protocol": "TCP", + "cidrlist": '0.0.0.0/0', + }, + "ostype": 'CentOS 5.3 (64-bit)', + "sleep": 60, + "timeout": 10, + } + + + def tearDown(self): + try: + # Clean up, terminate the created templates + cleanup_resources(self.apiclient, self.cleanup) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + return + + def createVMs(self, hostId, number, local): + + self.template = get_template( + self.apiclient, + self.zone.id, + self.services["ostype"] + ) + + if self.template == FAILED: + assert False, "get_template() failed to return template with description %s" % self.services["ostype"] + + self.logger.debug("Using template %s " % self.template.id) + + if local: + self.service_offering = ServiceOffering.create( + self.apiclient, + self.services["service_offering_local"] + ) + else: + self.service_offering = ServiceOffering.create( + self.apiclient, + self.services["service_offering"] + ) + + + self.logger.debug("Using service offering %s " % self.service_offering.id) + + vms = [] + for i in range(0, number): + self.services["vm"]["zoneid"] = self.zone.id + self.services["vm"]["template"] = self.template.id + self.services["vm"]["displayname"] = 'vm' + str(i) + self.services["vm"]["hypervisor"] = self.hypervisor + vm = VirtualMachine.create( + self.apiclient, + self.services["vm"], + serviceofferingid=self.service_offering.id, + hostid=hostId + ) + vms.append(vm) + self.cleanup.append(vm) + self.logger.debug("VM create = {}".format(vm.id)) + return vm + + def noOfVMsOnHost(self, hostId): + listVms = VirtualMachine.list( + self.apiclient, + hostid=hostId + ) + vmnos = 0 + if (listVms is not None): + for vm in listVms: + self.logger.debug('VirtualMachine on Hyp 1 = {}'.format(vm.id)) + vmnos = vmnos + 1 + + return vmnos + + def checkHostDown(self, fromHostIp, testHostIp): + try: + ssh = SshClient(fromHostIp, 22, "root", "password") + res = ssh.execute("ping -c 1 %s" % testHostIp) + result = str(res) + if result.count("100% packet loss") == 1: + return True, 1 + else: + return False, 1 + except Exception as e: + self.logger.debug("Got exception %s" % e) + return False, 1 + + def checkHostUp(self, fromHostIp, testHostIp): + try: + ssh = SshClient(fromHostIp, 22, "root", "password") + res = ssh.execute("ping -c 1 %s" % testHostIp) + result = str(res) + if result.count(" 0% packet loss") == 1: + return True, 1 + else: + return False, 1 + except Exception as e: + self.logger.debug("Got exception %s" % e) + return False, 1 + + + def isOnlyNFSStorageAvailable(self): + if self.zone.localstorageenabled: + return False + storage_pools = StoragePool.list( + self.apiclient, + zoneid=self.zone.id, + listall=True + ) + self.assertEqual( + isinstance(storage_pools, list), + True, + "Check if listStoragePools returns a valid response" + ) + for storage_pool in storage_pools: + if storage_pool.type == u'NetworkFilesystem': + return True + + return False + + def isOnlyLocalStorageAvailable(self): + if not(self.zone.localstorageenabled): + return False + + storage_pools = StoragePool.list( + self.apiclient, + zoneid=self.zone.id, + listall=True + ) + self.assertEqual( + isinstance(storage_pools, list), + True, + "Check if listStoragePools returns a valid response" + ) + for storage_pool in storage_pools: + if storage_pool.type == u'NetworkFilesystem': + return False + + return True + + def isLocalAndNFSStorageAvailable(self): + if not(self.zone.localstorageenabled): + return False + + storage_pools = StoragePool.list( + self.apiclient, + zoneid=self.zone.id, + listall=True + ) + self.assertEqual( + isinstance(storage_pools, list), + True, + "Check if listStoragePools returns a valid response" + ) + for storage_pool in storage_pools: + if storage_pool.type == u'NetworkFilesystem': + return True + + return False + + + def checkHostStateInCloudstack(self, state, hostId): + try: + listHost = Host.list( + self.apiclient, + type='Routing', + zoneid=self.zone.id, + podid=self.pod.id, + id=hostId + ) + self.assertEqual( + isinstance(listHost, list), + True, + "Check if listHost returns a valid response" + ) + + self.assertEqual( + len(listHost), + 1, + "Check if listHost returns a host" + ) + self.logger.debug(" Host state is %s " % listHost[0].state) + if listHost[0].state == state: + return True, 1 + else: + return False, 1 + except Exception as e: + self.logger.debug("Got exception %s" % e) + return False, 1 + + + def disconnectHostfromNetwork(self, hostIp, timeout): + srcFile = os.path.dirname(os.path.realpath(__file__)) + "/test_host_ha.sh" + if not(os.path.isfile(srcFile)): + self.logger.debug("File %s not found" % srcFile) + raise unittest.SkipTest("Script file %s required for HA not found" % srcFile); + + ssh = SshClient(hostIp, 22, "root", "password") + ssh.scp(srcFile, "/root/test_host_ha.sh") + ssh.execute("nohup sh /root/test_host_ha.sh %s > /dev/null 2>&1 &\n" % timeout) + return + + + @attr( + tags=[ + "advanced", + "advancedns", + "smoke", + "basic", + "eip", + "sg"], + required_hardware="true") + def test_01_host_ha_with_nfs_storagepool_with_vm(self): + + if not(self.isOnlyNFSStorageAvailable()): + raise unittest.SkipTest("Skipping this test as this is for NFS store only."); + return + + listHost = Host.list( + self.apiclient, + type='Routing', + zoneid=self.zone.id, + podid=self.pod.id, + ) + for host in listHost: + self.logger.debug('Hypervisor = {}'.format(host.id)) + + + if len(listHost) != 2: + self.logger.debug("Host HA can be tested with two host only %s, found" % len(listHost)); + raise unittest.SkipTest("Host HA can be tested with two host only %s, found" % len(listHost)); + return + + no_of_vms = self.noOfVMsOnHost(listHost[0].id) + + no_of_vms = no_of_vms + self.noOfVMsOnHost(listHost[1].id) + + self.logger.debug("Number of VMS on hosts = %s" % no_of_vms) + + + if no_of_vms < 5: + self.logger.debug("test_01: Create VMs as there are not enough vms to check host ha") + no_vm_req = 5 - no_of_vms + if (no_vm_req > 0): + self.logger.debug("Creating vms = {}".format(no_vm_req)) + self.vmlist = self.createVMs(listHost[0].id, no_vm_req, False) + + ha_host = listHost[1] + other_host = listHost[0] + if self.noOfVMsOnHost(listHost[0].id) > self.noOfVMsOnHost(listHost[1].id): + ha_host = listHost[0] + other_host = listHost[1] + + self.disconnectHostfromNetwork(ha_host.ipaddress, 400) + + hostDown = wait_until(10, 10, self.checkHostDown, other_host.ipaddress, ha_host.ipaddress) + if not(hostDown): + raise unittest.SkipTest("Host %s is not down, cannot proceed with test" % (ha_host.ipaddress)) + + hostDownInCloudstack = wait_until(40, 10, self.checkHostStateInCloudstack, "Down", ha_host.id) + #the test could have failed here but we will try our best to get host back in consistent state + + no_of_vms = self.noOfVMsOnHost(ha_host.id) + no_of_vms = no_of_vms + self.noOfVMsOnHost(other_host.id) + self.logger.debug("Number of VMS on hosts = %s" % no_of_vms) + # + hostUp = wait_until(10, 10, self.checkHostUp, other_host.ipaddress, ha_host.ipaddress) + if not(hostUp): + self.logger.debug("Host is down %s, though HA went fine, the environment is not consistent " % (ha_host.ipaddress)) + + + hostUpInCloudstack = wait_until(40, 10, self.checkHostStateInCloudstack, "Up", ha_host.id) + + if not(hostDownInCloudstack): + raise self.fail("Host is not down %s, in cloudstack so failing test " % (ha_host.ipaddress)) + if not(hostUpInCloudstack): + raise self.fail("Host is not up %s, in cloudstack so failing test " % (ha_host.ipaddress)) + + return + + + @attr( + tags=[ + "advanced", + "advancedns", + "smoke", + "basic", + "eip", + "sg"], + required_hardware="true") + def test_02_host_ha_with_local_storage_and_nfs(self): + + if not(self.isLocalAndNFSStorageAvailable()): + raise unittest.SkipTest("Skipping this test as this is for Local storage and NFS storage only."); + return + + listHost = Host.list( + self.apiclient, + type='Routing', + zoneid=self.zone.id, + podid=self.pod.id, + ) + for host in listHost: + self.logger.debug('Hypervisor = {}'.format(host.id)) + + + if len(listHost) != 2: + self.logger.debug("Host HA can be tested with two host only %s, found" % len(listHost)); + raise unittest.SkipTest("Host HA can be tested with two host only %s, found" % len(listHost)); + return + + no_of_vms = self.noOfVMsOnHost(listHost[0].id) + + no_of_vms = no_of_vms + self.noOfVMsOnHost(listHost[1].id) + + self.logger.debug("Number of VMS on hosts = %s" % no_of_vms) + + + if no_of_vms < 5: + self.logger.debug("test_02: Create VMs as there are not enough vms to check host ha") + no_vm_req = 5 - no_of_vms + if (no_vm_req > 0): + self.logger.debug("Creating vms = {}".format(no_vm_req)) + self.vmlist = self.createVMs(listHost[0].id, no_vm_req, True) + + ha_host = listHost[1] + other_host = listHost[0] + if self.noOfVMsOnHost(listHost[0].id) > self.noOfVMsOnHost(listHost[1].id): + ha_host = listHost[0] + other_host = listHost[1] + + self.disconnectHostfromNetwork(ha_host.ipaddress, 400) + + hostDown = wait_until(10, 10, self.checkHostDown, other_host.ipaddress, ha_host.ipaddress) + if not(hostDown): + raise unittest.SkipTest("Host %s is not down, cannot proceed with test" % (ha_host.ipaddress)) + + hostDownInCloudstack = wait_until(40, 10, self.checkHostStateInCloudstack, "Down", ha_host.id) + #the test could have failed here but we will try our best to get host back in consistent state + + no_of_vms = self.noOfVMsOnHost(ha_host.id) + no_of_vms = no_of_vms + self.noOfVMsOnHost(other_host.id) + self.logger.debug("Number of VMS on hosts = %s" % no_of_vms) + # + hostUp = wait_until(10, 10, self.checkHostUp, other_host.ipaddress, ha_host.ipaddress) + if not(hostUp): + self.logger.debug("Host is down %s, though HA went fine, the environment is not consistent " % (ha_host.ipaddress)) + + + hostUpInCloudstack = wait_until(40, 10, self.checkHostStateInCloudstack, "Up", ha_host.id) + + if not(hostDownInCloudstack): + raise self.fail("Host is not down %s, in cloudstack so failing test " % (ha_host.ipaddress)) + if not(hostUpInCloudstack): + raise self.fail("Host is not up %s, in cloudstack so failing test " % (ha_host.ipaddress)) + + return + + + + @attr( + tags=[ + "advanced", + "advancedns", + "smoke", + "basic", + "eip", + "sg"], + required_hardware="true") + def test_03_host_ha_with_only_local_storage(self): + + if not(self.isOnlyLocalStorageAvailable()): + raise unittest.SkipTest("Skipping this test as this is for Local storage only."); + return + + listHost = Host.list( + self.apiclient, + type='Routing', + zoneid=self.zone.id, + podid=self.pod.id, + ) + for host in listHost: + self.logger.debug('Hypervisor = {}'.format(host.id)) + + + if len(listHost) != 2: + self.logger.debug("Host HA can be tested with two host only %s, found" % len(listHost)); + raise unittest.SkipTest("Host HA can be tested with two host only %s, found" % len(listHost)); + return + + no_of_vms = self.noOfVMsOnHost(listHost[0].id) + + no_of_vms = no_of_vms + self.noOfVMsOnHost(listHost[1].id) + + self.logger.debug("Number of VMS on hosts = %s" % no_of_vms) + + if no_of_vms < 5: + self.logger.debug("test_03: Create VMs as there are not enough vms to check host ha") + no_vm_req = 5 - no_of_vms + if (no_vm_req > 0): + self.logger.debug("Creating vms = {}".format(no_vm_req)) + self.vmlist = self.createVMs(listHost[0].id, no_vm_req, True) + + ha_host = listHost[1] + other_host = listHost[0] + if self.noOfVMsOnHost(listHost[0].id) > self.noOfVMsOnHost(listHost[1].id): + ha_host = listHost[0] + other_host = listHost[1] + + self.disconnectHostfromNetwork(ha_host.ipaddress, 400) + + hostDown = wait_until(10, 10, self.checkHostDown, other_host.ipaddress, ha_host.ipaddress) + if not(hostDown): + raise unittest.SkipTest("Host %s is not down, cannot proceed with test" % (ha_host.ipaddress)) + + hostDownInCloudstack = wait_until(40, 10, self.checkHostStateInCloudstack, "Alert", ha_host.id) + #the test could have failed here but we will try our best to get host back in consistent state + + no_of_vms = self.noOfVMsOnHost(ha_host.id) + no_of_vms = no_of_vms + self.noOfVMsOnHost(other_host.id) + self.logger.debug("Number of VMS on hosts = %s" % no_of_vms) + # + hostUp = wait_until(10, 10, self.checkHostUp, other_host.ipaddress, ha_host.ipaddress) + if not(hostUp): + self.logger.debug("Host is down %s, though HA went fine, the environment is not consistent " % (ha_host.ipaddress)) + + + hostUpInCloudstack = wait_until(40, 10, self.checkHostStateInCloudstack, "Up", ha_host.id) + + if not(hostDownInCloudstack): + raise self.fail("Host is not in alert %s, in cloudstack so failing test " % (ha_host.ipaddress)) + if not(hostUpInCloudstack): + raise self.fail("Host is not up %s, in cloudstack so failing test " % (ha_host.ipaddress)) + + return \ No newline at end of file diff --git a/test/integration/component/test_host_ha.sh b/test/integration/component/test_host_ha.sh new file mode 100755 index 0000000000..85aadb1b68 --- /dev/null +++ b/test/integration/component/test_host_ha.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +#bring down all eth interfaces + +usage() { echo "Usage: $0 "; exit 1; } + +case $1 in + ''|*[!0-9]*) echo "The parameter should be an integer"; exit ;; + *) echo $1 ;; +esac + +if [ -z $1 ]; then + usage +elif [ $1 -lt 1 ]; then + echo "Down time should be at least 1 second" + exit 1 +elif [ $1 -gt 5000 ]; then + echo "Down time should be less than 5000 second" + exit 1 +fi + +for i in `ifconfig -a | sed 's/[ \t].*//;/^\(lo\|\)$/d' | grep eth` +do + ifconfig $i down +done + + +service cloudstack-agent stop +update-rc.d -f cloudstack-agent remove + +sleep $1 + +for i in `ifconfig -a | sed 's/[ \t].*//;/^\(lo\|\)$/d' | grep eth` +do + ifconfig $i up +done + + +update-rc.d -f cloudstack-agent defaults +service cloudstack-agent start \ No newline at end of file diff --git a/tools/marvin/marvin/lib/utils.py b/tools/marvin/marvin/lib/utils.py index aa41e7b401..68fb336901 100644 --- a/tools/marvin/marvin/lib/utils.py +++ b/tools/marvin/marvin/lib/utils.py @@ -523,15 +523,14 @@ def verifyRouterState(apiclient, routerid, allowedstates): return [PASS, None] - def wait_until(retry_interval=2, no_of_times=2, callback=None, *callback_args): """ Utility method to try out the callback method at most no_of_times with a interval of retry_interval, Will return immediately if callback returns True. The callback method should be written to return a list of values first being a boolean """ if callback is None: raise ("Bad value for callback method !") - - wait_result = False + + wait_result = False for i in range(0,no_of_times): time.sleep(retry_interval) wait_result, return_val = callback(*callback_args) From 7ad3c5e83442fefa5c027d173ac08c16f52382c6 Mon Sep 17 00:00:00 2001 From: "Maneesha.P" Date: Fri, 9 Oct 2015 15:46:56 +0530 Subject: [PATCH 124/203] CLOUDSTACK-8800 : Improved the listVirtualMachines API call to include memory utilization information for a VM for xenserver,kvm and for vmware. --- api/src/com/cloud/vm/VmStats.java | 6 ++++ .../api/response/UserVmResponse.java | 36 +++++++++++++++++++ .../src/com/cloud/agent/api/VmStatsEntry.java | 35 +++++++++++++++++- .../resource/LibvirtComputingResource.java | 13 +++++++ .../LibvirtComputingResourceTest.java | 11 +++++- .../agent/manager/MockVmManagerImpl.java | 2 +- .../vmware/resource/VmwareResource.java | 24 ++++++++++--- .../resource/CitrixResourceBase.java | 12 +++++-- .../api/query/dao/UserVmJoinDaoImpl.java | 15 +++++--- .../src/com/cloud/server/StatsCollector.java | 7 ++++ 10 files changed, 148 insertions(+), 13 deletions(-) mode change 100755 => 100644 plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java diff --git a/api/src/com/cloud/vm/VmStats.java b/api/src/com/cloud/vm/VmStats.java index 2b7943883e..1c23c01ed8 100644 --- a/api/src/com/cloud/vm/VmStats.java +++ b/api/src/com/cloud/vm/VmStats.java @@ -32,4 +32,10 @@ public interface VmStats { public double getDiskWriteKBs(); + public double getMemoryKBs(); + + public double getIntFreeMemoryKBs(); + + public double getTargetMemoryKBs(); + } diff --git a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java index d4e612b001..b681d4f70d 100644 --- a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java +++ b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java @@ -196,6 +196,18 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co @Param(description = "the write (bytes) of disk on the vm") private Long diskKbsWrite; + @SerializedName("memorykbs") + @Param(description = "the memory used by the vm") + private Long memoryKBs; + + @SerializedName("memoryintfreekbs") + @Param(description = "the internal memory thats free in vm") + private Long memoryIntFreeKBs; + + @SerializedName("memorytargetkbs") + @Param(description = "the target memory in vm") + private Long memoryTargetKBs; + @SerializedName("diskioread") @Param(description = "the read (io) of disk on the vm") private Long diskIORead; @@ -462,6 +474,18 @@ public Long getDiskKbsWrite() { return diskKbsWrite; } + public Long getMemoryKBs() { + return memoryKBs; + } + + public Long getMemoryIntFreeKBs() { + return memoryIntFreeKBs; + } + + public Long getMemoryTargetKBs() { + return memoryTargetKBs; + } + public Long getDiskIORead() { return diskIORead; } @@ -637,6 +661,18 @@ public void setDiskIORead(Long diskIORead) { this.diskIORead = diskIORead; } + public void setMemoryKBs(Long memoryKBs) { + this.memoryKBs = memoryKBs; + } + + public void setMemoryIntFreeKBs(Long memoryIntFreeKBs) { + this.memoryIntFreeKBs = memoryIntFreeKBs; + } + + public void setMemoryTargetKBs(Long memoryTargetKBs) { + this.memoryTargetKBs = memoryTargetKBs; + } + public void setDiskIOWrite(Long diskIOWrite) { this.diskIOWrite = diskIOWrite; } diff --git a/core/src/com/cloud/agent/api/VmStatsEntry.java b/core/src/com/cloud/agent/api/VmStatsEntry.java index 0f30b6af53..e6063b9ab5 100644 --- a/core/src/com/cloud/agent/api/VmStatsEntry.java +++ b/core/src/com/cloud/agent/api/VmStatsEntry.java @@ -30,13 +30,19 @@ public class VmStatsEntry implements VmStats { double diskWriteIOs; double diskReadKBs; double diskWriteKBs; + double memoryKBs; + double intfreememoryKBs; + double targetmemoryKBs; int numCPUs; String entityType; public VmStatsEntry() { } - public VmStatsEntry(double cpuUtilization, double networkReadKBs, double networkWriteKBs, int numCPUs, String entityType) { + public VmStatsEntry(double memoryKBs,double intfreememoryKBs,double targetmemoryKBs, double cpuUtilization, double networkReadKBs, double networkWriteKBs, int numCPUs, String entityType) { + this.memoryKBs = memoryKBs; + this.intfreememoryKBs = intfreememoryKBs; + this.targetmemoryKBs = targetmemoryKBs; this.cpuUtilization = cpuUtilization; this.networkReadKBs = networkReadKBs; this.networkWriteKBs = networkWriteKBs; @@ -117,6 +123,33 @@ public void setDiskWriteKBs(double diskWriteKBs) { this.diskWriteKBs = diskWriteKBs; } + @Override + public double getMemoryKBs() { + return memoryKBs; + } + + public void setMemoryKBs(double memoryKBs) { + this.memoryKBs = memoryKBs; + } + + @Override + public double getIntFreeMemoryKBs() { + return intfreememoryKBs; + } + + public void setIntFreeMemoryKBs(double intfreememoryKBs) { + this.intfreememoryKBs = intfreememoryKBs; + } + + @Override + public double getTargetMemoryKBs() { + return targetmemoryKBs; + } + + public void setTargetMemoryKBs(double targetmemoryKBs) { + this.targetmemoryKBs = targetmemoryKBs; + } + public int getNumCPUs() { return numCPUs; } 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 old mode 100755 new mode 100644 index 883c8c9942..02cf872d92 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -57,6 +57,7 @@ import org.libvirt.Domain; import org.libvirt.DomainBlockStats; import org.libvirt.DomainInfo; +import org.libvirt.MemoryStatistic; import org.libvirt.DomainInfo.DomainState; import org.libvirt.DomainInterfaceStats; import org.libvirt.LibvirtException; @@ -190,6 +191,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv private long _hvVersion; private long _kernelVersion; private int _timeout; + private static final int NUMMEMSTATS =2; private KVMHAMonitor _monitor; public static final String SSHKEYSPATH = "/root/.ssh"; @@ -3018,6 +3020,9 @@ private class VmStats { long _ioWrote; long _bytesRead; long _bytesWrote; + long _intmemfree; + long _memory; + long _maxmemory; Calendar _timestamp; } @@ -3026,11 +3031,16 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li try { dm = getDomain(conn, vmName); final DomainInfo info = dm.getInfo(); + final MemoryStatistic[] mems = dm.memoryStats(NUMMEMSTATS); //number of memory statistics required. final VmStatsEntry stats = new VmStatsEntry(); + stats.setNumCPUs(info.nrVirtCpu); stats.setEntityType("vm"); + stats.setMemoryKBs(info.maxMem); + stats.setTargetMemoryKBs(info.memory); + stats.setIntFreeMemoryKBs((double) mems[0].getValue()); /* get cpu utilization */ VmStats oldStats = null; @@ -3115,6 +3125,9 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li newStat._bytesRead = bytes_rd; newStat._bytesWrote = bytes_wr; newStat._timestamp = now; + newStat._intmemfree = mems[0].getValue(); + newStat._memory = info.memory; + newStat._maxmemory = info.maxMem; _vmStats.put(vmName, newStat); return stats; } finally { diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 9803785a34..391313e191 100644 --- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -67,6 +67,8 @@ import org.libvirt.LibvirtException; import org.libvirt.NodeInfo; import org.libvirt.StorageVol; +import org.libvirt.MemoryStatistic; + import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.Mockito; @@ -418,7 +420,10 @@ public void testGetVmStat() throws LibvirtException { final Connect connect = Mockito.mock(Connect.class); final Domain domain = Mockito.mock(Domain.class); final DomainInfo domainInfo = new DomainInfo(); + final MemoryStatistic[] domainMem = new MemoryStatistic[2]; + domainMem[0] = Mockito.mock(MemoryStatistic.class); Mockito.when(domain.getInfo()).thenReturn(domainInfo); + Mockito.when(domain.memoryStats(2)).thenReturn(domainMem); Mockito.when(connect.domainLookupByName(VMNAME)).thenReturn(domain); final NodeInfo nodeInfo = new NodeInfo(); nodeInfo.cpus = 8; @@ -485,6 +490,10 @@ public List getDisks(final Connect conn, final String vmName) { // IO traffic as generated by the logic above, must be greater than zero Assert.assertTrue(vmStat.getDiskReadKBs() > 0); Assert.assertTrue(vmStat.getDiskWriteKBs() > 0); + // Memory limit of VM must be greater than zero + Assert.assertTrue(vmStat.getIntFreeMemoryKBs() >= 0); + Assert.assertTrue(vmStat.getMemoryKBs() >= 0); + Assert.assertTrue(vmStat.getTargetMemoryKBs() >= vmStat.getMemoryKBs()); } @Test @@ -5031,4 +5040,4 @@ public void testIsInterface () { } } } -} \ No newline at end of file +} diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java index 5efcd3b57e..6eaf09cad8 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java @@ -319,7 +319,7 @@ public Answer getVmStats(final GetVmStatsCommand cmd) { final HashMap vmStatsNameMap = new HashMap(); final List vmNames = cmd.getVmNames(); for (final String vmName : vmNames) { - final VmStatsEntry entry = new VmStatsEntry(0, 0, 0, 0, "vm"); + final VmStatsEntry entry = new VmStatsEntry(0, 0, 0, 0, 0, 0, 0, "vm"); entry.setNetworkReadKBs(32768); // default values 256 KBps entry.setNetworkWriteKBs(16384); entry.setCPUUtilization(10); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 184159a94a..4d04abca4f 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -100,6 +100,7 @@ import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.commons.lang.math.NumberUtils; import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; @@ -4944,8 +4945,14 @@ private HashMap getVmStats(List vmNames) throws Ex } String instanceNameCustomField = "value[" + key + "]"; + final String numCpuStr = "summary.config.numCpu"; + final String cpuUseStr = "summary.quickStats.overallCpuUsage"; + final String guestMemUseStr = "summary.quickStats.guestMemoryUsage"; + final String memLimitStr = "resourceConfig.memoryAllocation.limit"; + final String memMbStr = "config.hardware.memoryMB"; + ObjectContent[] ocs = - hyperHost.getVmPropertiesOnHyperHost(new String[] {"name", "summary.config.numCpu", "summary.quickStats.overallCpuUsage", instanceNameCustomField}); + hyperHost.getVmPropertiesOnHyperHost(new String[] {"name", numCpuStr, cpuUseStr ,guestMemUseStr ,memLimitStr ,memMbStr, instanceNameCustomField}); if (ocs != null && ocs.length > 0) { for (ObjectContent oc : ocs) { List objProps = oc.getPropSet(); @@ -4953,6 +4960,9 @@ private HashMap getVmStats(List vmNames) throws Ex String name = null; String numberCPUs = null; String maxCpuUsage = null; + String memlimit = null; + String memkb = null; + String guestMemusage = null; String vmNameOnVcenter = null; String vmInternalCSName = null; for (DynamicProperty objProp : objProps) { @@ -4961,10 +4971,16 @@ private HashMap getVmStats(List vmNames) throws Ex } else if (objProp.getName().contains(instanceNameCustomField)) { if (objProp.getVal() != null) vmInternalCSName = ((CustomFieldStringValue)objProp.getVal()).getValue(); - } else if (objProp.getName().equals("summary.config.numCpu")) { + }else if(objProp.getName().equals(guestMemusage)){ + guestMemusage = objProp.getVal().toString(); + }else if (objProp.getName().equals(numCpuStr)) { numberCPUs = objProp.getVal().toString(); - } else if (objProp.getName().equals("summary.quickStats.overallCpuUsage")) { + } else if (objProp.getName().equals(cpuUseStr)) { maxCpuUsage = objProp.getVal().toString(); + } else if (objProp.getName().equals(memLimitStr)) { + memlimit = objProp.getVal().toString(); + } else if (objProp.getName().equals(memMbStr)) { + memkb = objProp.getVal().toString(); } } new VirtualMachineMO(hyperHost.getContext(), oc.getObj()); @@ -5033,7 +5049,7 @@ private HashMap getVmStats(List vmNames) throws Ex } } } - vmResponseMap.put(name, new VmStatsEntry(Integer.parseInt(maxCpuUsage), networkReadKBs, networkWriteKBs, Integer.parseInt(numberCPUs), "vm")); + vmResponseMap.put(name, new VmStatsEntry( NumberUtils.toDouble(memkb)*1024,NumberUtils.toDouble(guestMemusage)*1024,NumberUtils.toDouble(memlimit)*1024, NumberUtils.toDouble(maxCpuUsage), networkReadKBs, networkWriteKBs, NumberUtils.toInt(numberCPUs), "vm")); } } } diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index 155c84bbad..6da2c7b02a 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -3276,7 +3276,7 @@ public HashMap getVmStats(final Connection conn, final Get final HashMap vmResponseMap = new HashMap(); for (final String vmUUID : vmUUIDs) { - vmResponseMap.put(vmUUID, new VmStatsEntry(0, 0, 0, 0, "vm")); + vmResponseMap.put(vmUUID, new VmStatsEntry(0,0,0,0, 0, 0, 0, "vm")); } final Object[] rrdData = getRRDData(conn, 2); // call rrddata with 2 for @@ -3330,7 +3330,14 @@ public HashMap getVmStats(final Connection conn, final Get vmStatsAnswer.setDiskReadKBs(vmStatsAnswer.getDiskReadKBs() + getDataAverage(dataNode, col, numRows) / 1000); } else if (param.matches("vbd_.*_write")) { vmStatsAnswer.setDiskWriteKBs(vmStatsAnswer.getDiskWriteKBs() + getDataAverage(dataNode, col, numRows) / 1000); + } else if (param.contains("memory_internal_free")) { + vmStatsAnswer.setIntFreeMemoryKBs(vmStatsAnswer.getIntFreeMemoryKBs() + getDataAverage(dataNode, col, numRows) / 1024); + } else if (param.contains("memory_target")) { + vmStatsAnswer.setTargetMemoryKBs(vmStatsAnswer.getTargetMemoryKBs() + getDataAverage(dataNode, col, numRows) / 1024); + } else if (param.contains("memory")) { + vmStatsAnswer.setMemoryKBs(vmStatsAnswer.getMemoryKBs() + getDataAverage(dataNode, col, numRows) / 1024); } + } } @@ -3346,6 +3353,7 @@ public HashMap getVmStats(final Connection conn, final Get s_logger.debug("Vm cpu utilization " + vmStatsAnswer.getCPUUtilization()); } } + return vmResponseMap; } @@ -5392,4 +5400,4 @@ public boolean attachConfigDriveToMigratedVm(Connection conn, String vmName, Str } -} \ No newline at end of file +} diff --git a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java index 079da57047..552200bc29 100644 --- a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java @@ -205,14 +205,21 @@ public UserVmResponse newUserVmResponse(ResponseView view, String objectName, Us userVmResponse.setNetworkKbsWrite((long)vmStats.getNetworkWriteKBs()); - if ((userVm.getHypervisorType() != null) && (userVm.getHypervisorType().equals(HypervisorType.KVM) || userVm.getHypervisorType().equals(HypervisorType.XenServer))) { // support KVM and XenServer only util 2013.06.25 + if ((userVm.getHypervisorType() != null) && (userVm.getHypervisorType().equals(HypervisorType.KVM) || userVm.getHypervisorType().equals(HypervisorType.XenServer) || userVm.getHypervisorType().equals(HypervisorType.VMware))) { // support KVM and XenServer only util 2013.06.25 . supporting Vmware from 2015.09.02 userVmResponse.setDiskKbsRead((long)vmStats.getDiskReadKBs()); - userVmResponse.setDiskKbsWrite((long)vmStats.getDiskWriteKBs()); + userVmResponse.setDiskKbsWrite((long) vmStats.getDiskWriteKBs()); - userVmResponse.setDiskIORead((long)vmStats.getDiskReadIOs()); + userVmResponse.setDiskIORead((long) vmStats.getDiskReadIOs()); + + userVmResponse.setDiskIOWrite((long) vmStats.getDiskWriteIOs()); + + userVmResponse.setMemoryKBs((long) vmStats.getMemoryKBs()); + + userVmResponse.setMemoryIntFreeKBs((long) vmStats.getIntFreeMemoryKBs()); + + userVmResponse.setMemoryTargetKBs((long) vmStats.getTargetMemoryKBs()); - userVmResponse.setDiskIOWrite((long)vmStats.getDiskWriteIOs()); } } } diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index 0702335308..387639f4b2 100644 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -464,6 +464,9 @@ protected void runInContext() { statsInMemory.setDiskReadIOs(statsInMemory.getDiskReadIOs() + statsForCurrentIteration.getDiskReadIOs()); statsInMemory.setDiskWriteIOs(statsInMemory.getDiskWriteIOs() + statsForCurrentIteration.getDiskWriteIOs()); statsInMemory.setDiskReadKBs(statsInMemory.getDiskReadKBs() + statsForCurrentIteration.getDiskReadKBs()); + statsInMemory.setMemoryKBs(statsForCurrentIteration.getMemoryKBs()); + statsInMemory.setIntFreeMemoryKBs(statsForCurrentIteration.getIntFreeMemoryKBs()); + statsInMemory.setTargetMemoryKBs(statsForCurrentIteration.getTargetMemoryKBs()); _VmStats.put(vmId, statsInMemory); } @@ -484,6 +487,10 @@ protected void runInContext() { metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".disk.read_kbs", statsForCurrentIteration.getDiskReadKBs()); metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".disk.write_iops", statsForCurrentIteration.getDiskWriteIOs()); metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".disk.read_iops", statsForCurrentIteration.getDiskReadIOs()); + metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".memory.total_kbs", statsForCurrentIteration.getMemoryKBs()); + metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".memory.internalfree_kbs", statsForCurrentIteration.getIntFreeMemoryKBs()); + metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".memory.target_kbs", statsForCurrentIteration.getTargetMemoryKBs()); + } } From cb85b7e8beeedd338676fedead3249f27759fa40 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Sat, 30 Jan 2016 00:15:24 +0100 Subject: [PATCH 125/203] CLOUDSTACK-9265 cleanup around httpclient versions --- .../cloudstack/storage/test/TestHttp.java | 27 ++-- .../ClusterServiceServletHttpHandler.java | 56 +++++---- .../cloud/network/brocade/BrocadeVcsApi.java | 117 +++++++++--------- .../network/brocade/BrocadeVcsApiTest.java | 6 +- .../network/nicira/NiciraNvpApiTest.java | 2 +- 5 files changed, 103 insertions(+), 105 deletions(-) diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/TestHttp.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/TestHttp.java index b1524f37ef..43a2476891 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/TestHttp.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/TestHttp.java @@ -24,11 +24,9 @@ import java.io.IOException; import java.io.OutputStream; -import junit.framework.Assert; - -import org.apache.commons.httpclient.HttpException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpHead; import org.apache.http.impl.client.DefaultHttpClient; @@ -37,13 +35,15 @@ import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; import org.testng.annotations.Parameters; +import junit.framework.Assert; + @ContextConfiguration(locations = "classpath:/storageContext.xml") public class TestHttp extends AbstractTestNGSpringContextTests { @Test @Parameters("template-url") public void testHttpclient(String templateUrl) { - HttpHead method = new HttpHead(templateUrl); - DefaultHttpClient client = new DefaultHttpClient(); + final HttpHead method = new HttpHead(templateUrl); + final DefaultHttpClient client = new DefaultHttpClient(); OutputStream output = null; long length = 0; @@ -51,34 +51,35 @@ public void testHttpclient(String templateUrl) { HttpResponse response = client.execute(method); length = Long.parseLong(response.getFirstHeader("Content-Length").getValue()); System.out.println(response.getFirstHeader("Content-Length").getValue()); - File localFile = new File("/tmp/test"); + final File localFile = new File("/tmp/test"); if (!localFile.exists()) { localFile.createNewFile(); } - HttpGet getMethod = new HttpGet(templateUrl); + final HttpGet getMethod = new HttpGet(templateUrl); response = client.execute(getMethod); - HttpEntity entity = response.getEntity(); + final HttpEntity entity = response.getEntity(); output = new BufferedOutputStream(new FileOutputStream(localFile)); entity.writeTo(output); - } catch (HttpException e) { + } catch (final ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); - } catch (IOException e) { + } catch (final IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { - if (output != null) + if (output != null) { output.close(); - } catch (IOException e) { + } + } catch (final IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } - File f = new File("/tmp/test"); + final File f = new File("/tmp/test"); Assert.assertEquals(f.length(), length); } } diff --git a/framework/cluster/src/com/cloud/cluster/ClusterServiceServletHttpHandler.java b/framework/cluster/src/com/cloud/cluster/ClusterServiceServletHttpHandler.java index 3a85302c4a..e12e0fe5ae 100644 --- a/framework/cluster/src/com/cloud/cluster/ClusterServiceServletHttpHandler.java +++ b/framework/cluster/src/com/cloud/cluster/ClusterServiceServletHttpHandler.java @@ -20,11 +20,11 @@ import java.io.IOException; import java.net.URLDecoder; -import org.apache.commons.httpclient.HttpStatus; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpException; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; import org.apache.http.entity.BasicHttpEntity; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpRequestHandler; @@ -55,14 +55,14 @@ public void handle(HttpRequest request, HttpResponse response, HttpContext conte s_logger.trace("Handle cluster HTTP request done"); } - } catch (Throwable e) { + } catch (final Throwable e) { if (s_logger.isDebugEnabled()) { s_logger.debug("Exception " + e.toString()); } try { writeResponse(response, HttpStatus.SC_INTERNAL_SERVER_ERROR, null); - } catch (Throwable e2) { + } catch (final Throwable e2) { if (s_logger.isDebugEnabled()) { s_logger.debug("Exception " + e2.toString()); } @@ -73,20 +73,20 @@ public void handle(HttpRequest request, HttpResponse response, HttpContext conte @SuppressWarnings("deprecation") private void parseRequest(HttpRequest request) throws IOException { if (request instanceof HttpEntityEnclosingRequest) { - HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest)request; + final HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest)request; - String body = EntityUtils.toString(entityRequest.getEntity()); + final String body = EntityUtils.toString(entityRequest.getEntity()); if (body != null) { - String[] paramArray = body.split("&"); + final String[] paramArray = body.split("&"); if (paramArray != null) { - for (String paramEntry : paramArray) { - String[] paramValue = paramEntry.split("="); + for (final String paramEntry : paramArray) { + final String[] paramValue = paramEntry.split("="); if (paramValue.length != 2) { continue; } - String name = URLDecoder.decode(paramValue[0]); - String value = URLDecoder.decode(paramValue[1]); + final String name = URLDecoder.decode(paramValue[0]); + final String value = URLDecoder.decode(paramValue[1]); if (s_logger.isTraceEnabled()) { s_logger.trace("Parsed request parameter " + name + "=" + value); @@ -103,17 +103,17 @@ private void writeResponse(HttpResponse response, int statusCode, String content content = ""; } response.setStatusCode(statusCode); - BasicHttpEntity body = new BasicHttpEntity(); + final BasicHttpEntity body = new BasicHttpEntity(); body.setContentType("text/html; charset=UTF-8"); - byte[] bodyData = content.getBytes(); + final byte[] bodyData = content.getBytes(); body.setContent(new ByteArrayInputStream(bodyData)); body.setContentLength(bodyData.length); response.setEntity(body); } protected void handleRequest(HttpRequest req, HttpResponse response) { - String method = (String)req.getParams().getParameter("method"); + final String method = (String)req.getParams().getParameter("method"); int nMethod = RemoteMethodConstants.METHOD_UNKNOWN; String responseContent = null; @@ -133,22 +133,24 @@ protected void handleRequest(HttpRequest req, HttpResponse response) { case RemoteMethodConstants.METHOD_UNKNOWN: default: - assert (false); + assert false; s_logger.error("unrecognized method " + nMethod); break; } - } catch (Throwable e) { + } catch (final Throwable e) { s_logger.error("Unexpected exception when processing cluster service request : ", e); } if (responseContent != null) { - if (s_logger.isTraceEnabled()) + if (s_logger.isTraceEnabled()) { s_logger.trace("Write reponse with HTTP OK " + responseContent); + } writeResponse(response, HttpStatus.SC_OK, responseContent); } else { - if (s_logger.isTraceEnabled()) + if (s_logger.isTraceEnabled()) { s_logger.trace("Write reponse with HTTP Bad request"); + } writeResponse(response, HttpStatus.SC_BAD_REQUEST, null); } @@ -156,16 +158,16 @@ protected void handleRequest(HttpRequest req, HttpResponse response) { private String handleDeliverPduMethodCall(HttpRequest req) { - String pduSeq = (String)req.getParams().getParameter("pduSeq"); - String pduAckSeq = (String)req.getParams().getParameter("pduAckSeq"); - String sourcePeer = (String)req.getParams().getParameter("sourcePeer"); - String destPeer = (String)req.getParams().getParameter("destPeer"); - String agentId = (String)req.getParams().getParameter("agentId"); - String gsonPackage = (String)req.getParams().getParameter("gsonPackage"); - String stopOnError = (String)req.getParams().getParameter("stopOnError"); - String pduType = (String)req.getParams().getParameter("pduType"); + final String pduSeq = (String)req.getParams().getParameter("pduSeq"); + final String pduAckSeq = (String)req.getParams().getParameter("pduAckSeq"); + final String sourcePeer = (String)req.getParams().getParameter("sourcePeer"); + final String destPeer = (String)req.getParams().getParameter("destPeer"); + final String agentId = (String)req.getParams().getParameter("agentId"); + final String gsonPackage = (String)req.getParams().getParameter("gsonPackage"); + final String stopOnError = (String)req.getParams().getParameter("stopOnError"); + final String pduType = (String)req.getParams().getParameter("pduType"); - ClusterServicePdu pdu = new ClusterServicePdu(); + final ClusterServicePdu pdu = new ClusterServicePdu(); pdu.setSourcePeer(sourcePeer); pdu.setDestPeer(destPeer); pdu.setAgentId(Long.parseLong(agentId)); @@ -180,7 +182,7 @@ private String handleDeliverPduMethodCall(HttpRequest req) { } private String handlePingMethodCall(HttpRequest req) { - String callingPeer = (String)req.getParams().getParameter("callingPeer"); + final String callingPeer = (String)req.getParams().getParameter("callingPeer"); if (s_logger.isDebugEnabled()) { s_logger.debug("Handle ping request from " + callingPeer); diff --git a/plugins/network-elements/brocade-vcs/src/com/cloud/network/brocade/BrocadeVcsApi.java b/plugins/network-elements/brocade-vcs/src/com/cloud/network/brocade/BrocadeVcsApi.java index dc111fd898..eb03515b5d 100644 --- a/plugins/network-elements/brocade-vcs/src/com/cloud/network/brocade/BrocadeVcsApi.java +++ b/plugins/network-elements/brocade-vcs/src/com/cloud/network/brocade/BrocadeVcsApi.java @@ -30,9 +30,8 @@ import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.HttpStatus; import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.methods.HttpDelete; @@ -64,9 +63,9 @@ public class BrocadeVcsApi { private static final Logger s_logger = Logger.getLogger(BrocadeVcsApi.class); - private String _host; - private String _adminuser; - private String _adminpass; + private final String _host; + private final String _adminuser; + private final String _adminpass; protected DefaultHttpClient _client; @@ -74,7 +73,7 @@ protected HttpRequestBase createMethod(String type, String uri) throws BrocadeVc String url; try { url = new URL(Constants.PROTOCOL, _host, Constants.PORT, uri).toString(); - } catch (MalformedURLException e) { + } catch (final MalformedURLException e) { s_logger.error("Unable to build Brocade Switch API URL", e); throw new BrocadeVcsApiException("Unable to build Brocade Switch API URL", e); } @@ -116,7 +115,7 @@ public boolean createNetwork(int vlanId, long networkId) throws BrocadeVcsApiExc if (createInterfaceVlan(vlanId)) { - PortProfile portProfile = createPortProfile(vlanId, networkId); + final PortProfile portProfile = createPortProfile(vlanId, networkId); if (portProfile != null) { return activatePortProfile(portProfile); @@ -129,9 +128,9 @@ public boolean createNetwork(int vlanId, long networkId) throws BrocadeVcsApiExc * Activates a port-profile. */ private boolean activatePortProfile(PortProfile portProfile) throws BrocadeVcsApiException { - PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); + final PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); portProfile.setVlanProfile(null); - Activate activate = new Activate(); + final Activate activate = new Activate(); portProfile.setActivate(activate); portProfileGlobal.setPortProfile(portProfile); @@ -144,7 +143,7 @@ private boolean activatePortProfile(PortProfile portProfile) throws BrocadeVcsAp */ private PortProfile createPortProfile(int vlanId, long networkId) throws BrocadeVcsApiException { - PortProfile portProfile = new PortProfile(); + final PortProfile portProfile = new PortProfile(); portProfile.setName(Constants.PORT_PROFILE_NAME_PREFIX + networkId); if (executeCreateObject(portProfile, Constants.URI)) { if (createVlanSubProfile(vlanId, portProfile)) { @@ -158,7 +157,7 @@ private PortProfile createPortProfile(int vlanId, long networkId) throws Brocade * Create vlan sub-profile for port-profile */ private boolean createVlanSubProfile(int vlanId, PortProfile portProfile) throws BrocadeVcsApiException { - VlanProfile vlanProfile = new VlanProfile(); + final VlanProfile vlanProfile = new VlanProfile(); portProfile.setVlanProfile(vlanProfile); if (executeUpdateObject(portProfile, Constants.URI)) { return configureVlanSubProfile(vlanId, portProfile); @@ -173,15 +172,15 @@ private boolean createVlanSubProfile(int vlanId, PortProfile portProfile) throws * - configure allowed VLANs for vlan sub-profile */ private boolean configureVlanSubProfile(int vlanId, PortProfile portProfile) throws BrocadeVcsApiException { - SwitchportBasic switchPortBasic = new SwitchportBasic(); - Basic basic = new Basic(); + final SwitchportBasic switchPortBasic = new SwitchportBasic(); + final Basic basic = new Basic(); switchPortBasic.setBasic(basic); portProfile.getVlanProfile().setSwitchportBasic(switchPortBasic); // configure L2 mode for vlan sub-profile if (executeUpdateObject(portProfile, Constants.URI)) { VlanProfile vlanProfile = new VlanProfile(); Switchport switchPort = new Switchport(); - Mode mode = new Mode(); + final Mode mode = new Mode(); mode.setVlanMode("trunk"); switchPort.setMode(mode); vlanProfile.setSwitchport(switchPort); @@ -191,9 +190,9 @@ private boolean configureVlanSubProfile(int vlanId, PortProfile portProfile) thr if (executeUpdateObject(portProfile, Constants.URI)) { vlanProfile = new VlanProfile(); switchPort = new Switchport(); - Trunk trunk = new Trunk(); - Allowed allowed = new Allowed(); - Allowed.Vlan allowedVlan = new Allowed.Vlan(); + final Trunk trunk = new Trunk(); + final Allowed allowed = new Allowed(); + final Allowed.Vlan allowedVlan = new Allowed.Vlan(); allowedVlan.setAdd(vlanId); allowed.setVlan(allowedVlan); trunk.setAllowed(allowed); @@ -214,9 +213,9 @@ private boolean configureVlanSubProfile(int vlanId, PortProfile portProfile) thr * Creates a vlan interface. */ private boolean createInterfaceVlan(int vlanId) throws BrocadeVcsApiException { - InterfaceVlan interfaceVlan = new InterfaceVlan(); - Interface interfaceObj = new Interface(); - Vlan vlan = new Vlan(); + final InterfaceVlan interfaceVlan = new InterfaceVlan(); + final Interface interfaceObj = new Interface(); + final Vlan vlan = new Vlan(); vlan.setName(vlanId); interfaceObj.setVlan(vlan); interfaceVlan.setInterface(interfaceObj); @@ -230,10 +229,10 @@ private boolean createInterfaceVlan(int vlanId) throws BrocadeVcsApiException { */ public boolean associateMacToNetwork(long networkId, String macAddress) throws BrocadeVcsApiException { - PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); - PortProfile portProfile = new PortProfile(); + final PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); + final PortProfile portProfile = new PortProfile(); portProfile.setName(Constants.PORT_PROFILE_NAME_PREFIX + networkId); - Static staticObj = new Static(); + final Static staticObj = new Static(); staticObj.setMacAddress(macAddress); portProfile.setStatic(staticObj); portProfileGlobal.setPortProfile(portProfile); @@ -247,10 +246,10 @@ public boolean associateMacToNetwork(long networkId, String macAddress) throws B */ public boolean disassociateMacFromNetwork(long networkId, String macAddress) throws BrocadeVcsApiException { - PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); - PortProfile portProfile = new PortProfile(); + final PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); + final PortProfile portProfile = new PortProfile(); portProfile.setName(Constants.PORT_PROFILE_NAME_PREFIX + networkId); - Static staticObj = new Static(); + final Static staticObj = new Static(); staticObj.setOperation("delete"); staticObj.setMacAddress(macAddress); portProfile.setStatic(staticObj); @@ -278,9 +277,9 @@ public boolean deleteNetwork(int vlanId, long networkId) throws BrocadeVcsApiExc * Deletes a vlan interface. */ private boolean deleteInterfaceVlan(int vlanId) throws BrocadeVcsApiException { - InterfaceVlan interfaceVlan = new InterfaceVlan(); - Interface interfaceObj = new Interface(); - Vlan vlan = new Vlan(); + final InterfaceVlan interfaceVlan = new InterfaceVlan(); + final Interface interfaceObj = new Interface(); + final Vlan vlan = new Vlan(); vlan.setOperation("delete"); vlan.setName(vlanId); interfaceObj.setVlan(vlan); @@ -294,10 +293,10 @@ private boolean deleteInterfaceVlan(int vlanId) throws BrocadeVcsApiException { * Deactivates a port-profile. */ private boolean deactivatePortProfile(long networkId) throws BrocadeVcsApiException { - PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); - PortProfile portProfile = new PortProfile(); + final PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); + final PortProfile portProfile = new PortProfile(); portProfile.setName(Constants.PORT_PROFILE_NAME_PREFIX + networkId); - Activate activate = new Activate(); + final Activate activate = new Activate(); activate.setOperation("delete"); portProfile.setActivate(activate); portProfileGlobal.setPortProfile(portProfile); @@ -311,7 +310,7 @@ private boolean deactivatePortProfile(long networkId) throws BrocadeVcsApiExcept */ private boolean deletePortProfile(long networkId) throws BrocadeVcsApiException { - PortProfile portProfile = new PortProfile(); + final PortProfile portProfile = new PortProfile(); portProfile.setName(Constants.PORT_PROFILE_NAME_PREFIX + networkId); portProfile.setOperation("delete"); //deletes port-profile @@ -320,25 +319,25 @@ private boolean deletePortProfile(long networkId) throws BrocadeVcsApiException protected boolean executeUpdateObject(T newObject, String uri) throws BrocadeVcsApiException { - boolean result = true; + final boolean result = true; if (_host == null || _host.isEmpty() || _adminuser == null || _adminuser.isEmpty() || _adminpass == null || _adminpass.isEmpty()) { throw new BrocadeVcsApiException("Hostname/credentials are null or empty"); } - HttpPatch pm = (HttpPatch)createMethod("patch", uri); + final HttpPatch pm = (HttpPatch)createMethod("patch", uri); pm.setHeader("Accept", "application/vnd.configuration.resource+xml"); pm.setEntity(new StringEntity(convertToString(newObject), ContentType.APPLICATION_XML)); - HttpResponse response = executeMethod(pm); + final HttpResponse response = executeMethod(pm); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_NO_CONTENT) { String errorMessage; try { errorMessage = responseToErrorMessage(response); - } catch (IOException e) { + } catch (final IOException e) { s_logger.error("Failed to update object : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to update object : " + e.getMessage()); } @@ -363,12 +362,12 @@ protected String convertToString(T object) throws BrocadeVcsApiException { marshaller.marshal(object, stringWriter); - } catch (JAXBException e) { + } catch (final JAXBException e) { s_logger.error("Failed to convert object to string : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to convert object to string : " + e.getMessage()); } - String str = stringWriter.toString(); + final String str = stringWriter.toString(); s_logger.info(str); return str; @@ -379,19 +378,19 @@ protected Output convertToXML(String object) throws BrocadeVcsApiException { Output output = null; try { - JAXBContext context = JAXBContext.newInstance(Output.class); + final JAXBContext context = JAXBContext.newInstance(Output.class); - StringReader reader = new StringReader(object); + final StringReader reader = new StringReader(object); final Unmarshaller unmarshaller = context.createUnmarshaller(); - Object result = unmarshaller.unmarshal(reader); + final Object result = unmarshaller.unmarshal(reader); if (result instanceof Output) { output = (Output)result; s_logger.info(output); } - } catch (JAXBException e) { + } catch (final JAXBException e) { s_logger.error("Failed to convert string to object : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to convert string to object : " + e.getMessage()); } @@ -405,19 +404,19 @@ protected boolean executeCreateObject(T newObject, String uri) throws Brocad throw new BrocadeVcsApiException("Hostname/credentials are null or empty"); } - boolean result = true; - HttpPost pm = (HttpPost)createMethod("post", uri); + final boolean result = true; + final HttpPost pm = (HttpPost)createMethod("post", uri); pm.setHeader("Accept", "application/vnd.configuration.resource+xml"); pm.setEntity(new StringEntity(convertToString(newObject), ContentType.APPLICATION_XML)); - HttpResponse response = executeMethod(pm); + final HttpResponse response = executeMethod(pm); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) { String errorMessage; try { errorMessage = responseToErrorMessage(response); - } catch (IOException e) { + } catch (final IOException e) { s_logger.error("Failed to create object : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to create object : " + e.getMessage()); } @@ -440,18 +439,18 @@ protected Output executeRetreiveStatus(String uri) throws BrocadeVcsApiException String readLine = null; StringBuffer sb = null; - HttpPost pm = (HttpPost)createMethod("post", uri); + final HttpPost pm = (HttpPost)createMethod("post", uri); pm.setHeader("Accept", "application/vnd.operational-state.resource+xml"); pm.setEntity(new StringEntity("", ContentType.APPLICATION_XML)); - HttpResponse response = executeMethod(pm); + final HttpResponse response = executeMethod(pm); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { String errorMessage; try { errorMessage = responseToErrorMessage(response); - } catch (IOException e) { + } catch (final IOException e) { s_logger.error("Failed to retreive status : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to retreive status : " + e.getMessage()); } @@ -464,12 +463,12 @@ protected Output executeRetreiveStatus(String uri) throws BrocadeVcsApiException try (BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), Charset.forName("UTF-8")))) { sb = new StringBuffer(); - while (((readLine = br.readLine()) != null)) { + while ((readLine = br.readLine()) != null) { s_logger.debug(readLine); sb.append(readLine); } - } catch (Exception e) { + } catch (final Exception e) { s_logger.error("Failed to retreive status : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to retreive status : " + e.getMessage()); } @@ -484,17 +483,17 @@ protected void executeDeleteObject(String uri) throws BrocadeVcsApiException { throw new BrocadeVcsApiException("Hostname/credentials are null or empty"); } - HttpDelete dm = (HttpDelete)createMethod("delete", uri); + final HttpDelete dm = (HttpDelete)createMethod("delete", uri); dm.setHeader("Accept", "application/vnd.configuration.resource+xml"); - HttpResponse response = executeMethod(dm); + final HttpResponse response = executeMethod(dm); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_NO_CONTENT) { String errorMessage; try { errorMessage = responseToErrorMessage(response); - } catch (IOException e) { + } catch (final IOException e) { s_logger.error("Failed to delete object : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to delete object : " + e.getMessage()); } @@ -514,11 +513,7 @@ protected HttpResponse executeMethod(HttpRequestBase method) throws BrocadeVcsAp method.releaseConnection(); response = _client.execute(method); } - } catch (HttpException e) { - s_logger.error("HttpException caught while trying to connect to the Brocade Switch", e); - method.releaseConnection(); - throw new BrocadeVcsApiException("API call to Brocade Switch Failed", e); - } catch (IOException e) { + } catch (final IOException e) { s_logger.error("IOException caught while trying to connect to the Brocade Switch", e); method.releaseConnection(); throw new BrocadeVcsApiException("API call to Brocade Switch Failed", e); @@ -533,7 +528,7 @@ private String responseToErrorMessage(HttpResponse response) throws IOException try (BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), Charset.forName("UTF-8")))) { - StringBuffer result = new StringBuffer(); + final StringBuffer result = new StringBuffer(); String line = ""; while ((line = rd.readLine()) != null) { result.append(line); diff --git a/plugins/network-elements/brocade-vcs/test/com/cloud/network/brocade/BrocadeVcsApiTest.java b/plugins/network-elements/brocade-vcs/test/com/cloud/network/brocade/BrocadeVcsApiTest.java index 4223d4cc7b..e84b7caf26 100644 --- a/plugins/network-elements/brocade-vcs/test/com/cloud/network/brocade/BrocadeVcsApiTest.java +++ b/plugins/network-elements/brocade-vcs/test/com/cloud/network/brocade/BrocadeVcsApiTest.java @@ -26,9 +26,9 @@ import static org.mockito.Mockito.when; import java.io.IOException; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.http.StatusLine; import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.StatusLine; import org.apache.http.client.methods.HttpPatch; import org.apache.http.client.methods.HttpPost; @@ -93,7 +93,7 @@ public void testGetSwitchStatus() throws BrocadeVcsApiException, IOException { when(response.getEntity()).thenReturn(new StringEntity(OUTPUT_XML_RESPONSE)); // Execute - Output result = api.getSwitchStatus(); + final Output result = api.getSwitchStatus(); // Assert verify(method, times(1)).releaseConnection(); diff --git a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraNvpApiTest.java b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraNvpApiTest.java index 79546a6847..34518cedad 100644 --- a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraNvpApiTest.java +++ b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraNvpApiTest.java @@ -33,9 +33,9 @@ import java.util.List; -import org.apache.commons.httpclient.HttpStatus; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; +import org.apache.http.HttpStatus; import org.apache.http.ProtocolVersion; import org.apache.http.StatusLine; import org.apache.http.client.methods.CloseableHttpResponse; From 0154da6417ab1dc0fa9719df4543e72ca5f2c178 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Fri, 15 Apr 2016 00:24:53 +0530 Subject: [PATCH 126/203] CLOUDSTACK-9348: Unit test to demonstrate denial of service attack The NioConnection uses blocking handlers for various events such as connect, accept, read, write. In case a client connects NioServer (used by agent mgr to service agents on port 8250) but fails to participate in SSL handshake or just sits idle, this would block the main IO/selector loop in NioConnection. Such a client could be either malicious or aggresive. This unit test demonstrates such a malicious client that can perform a denial-of-service attack on NioServer that blocks it to serve any other client. Signed-off-by: Rohit Yadav --- utils/pom.xml | 1 - .../com/cloud/utils/testcase/NioTest.java | 243 +++++++++++------- 2 files changed, 150 insertions(+), 94 deletions(-) diff --git a/utils/pom.xml b/utils/pom.xml index 206eb1896a..9e2358680f 100755 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -208,7 +208,6 @@ com/cloud/utils/testcase/*TestCase* com/cloud/utils/db/*Test* - com/cloud/utils/testcase/NioTest.java diff --git a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java index d8510cfcac..7516cfc42e 100644 --- a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java +++ b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java @@ -19,14 +19,7 @@ package com.cloud.utils.testcase; -import java.nio.channels.ClosedChannelException; -import java.util.Random; - -import junit.framework.TestCase; - -import org.apache.log4j.Logger; -import org.junit.Assert; - +import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.exception.NioConnectionException; import com.cloud.utils.nio.HandlerFactory; import com.cloud.utils.nio.Link; @@ -34,131 +27,190 @@ import com.cloud.utils.nio.NioServer; import com.cloud.utils.nio.Task; import com.cloud.utils.nio.Task.Type; +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; -/** - * - * - * - * - */ +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class NioTest { -public class NioTest extends TestCase { + private static final Logger LOGGER = Logger.getLogger(NioTest.class); - private static final Logger s_logger = Logger.getLogger(NioTest.class); + final private int totalTestCount = 10; + private int completedTestCount = 0; - private NioServer _server; - private NioClient _client; + private NioServer server; + private List clients = new ArrayList<>(); + private List maliciousClients = new ArrayList<>(); - private Link _clientLink; + private ExecutorService clientExecutor = Executors.newFixedThreadPool(totalTestCount, new NamedThreadFactory("NioClientHandler"));; + private ExecutorService maliciousExecutor = Executors.newFixedThreadPool(5*totalTestCount, new NamedThreadFactory("MaliciousNioClientHandler"));; - private int _testCount; - private int _completedCount; + private Random randomGenerator = new Random(); + private byte[] testBytes; private boolean isTestsDone() { boolean result; synchronized (this) { - result = _testCount == _completedCount; + result = totalTestCount == completedTestCount; } return result; } - private void getOneMoreTest() { - synchronized (this) { - _testCount++; - } - } - private void oneMoreTestDone() { synchronized (this) { - _completedCount++; + completedTestCount++; } } - @Override + @Before public void setUp() { - s_logger.info("Test"); + LOGGER.info("Setting up Benchmark Test"); - _testCount = 0; - _completedCount = 0; - - _server = new NioServer("NioTestServer", 7777, 5, new NioTestServer()); - try { - _server.start(); - } catch (final NioConnectionException e) { - fail(e.getMessage()); - } + completedTestCount = 0; + testBytes = new byte[1000000]; + randomGenerator.nextBytes(testBytes); - _client = new NioClient("NioTestServer", "127.0.0.1", 7777, 5, new NioTestClient()); + // Server configured with one worker + server = new NioServer("NioTestServer", 7777, 1, new NioTestServer()); try { - _client.start(); + server.start(); } catch (final NioConnectionException e) { - fail(e.getMessage()); + Assert.fail(e.getMessage()); } - while (_clientLink == null) { - try { - s_logger.debug("Link is not up! Waiting ..."); - Thread.sleep(1000); - } catch (final InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + // 5 malicious clients per valid client + for (int i = 0; i < totalTestCount; i++) { + for (int j = 0; j < 5; j++) { + final NioClient maliciousClient = new NioMaliciousClient("NioMaliciousTestClient-" + i, "127.0.0.1", 7777, 1, new NioMaliciousTestClient()); + maliciousClients.add(maliciousClient); + maliciousExecutor.submit(new ThreadedNioClient(maliciousClient)); } + final NioClient client = new NioClient("NioTestClient-" + i, "127.0.0.1", 7777, 1, new NioTestClient()); + clients.add(client); + clientExecutor.submit(new ThreadedNioClient(client)); } } - @Override + @After public void tearDown() { + stopClient(); + stopServer(); + } + + protected void stopClient() { + for (NioClient client : clients) { + client.stop(); + } + for (NioClient maliciousClient : maliciousClients) { + maliciousClient.stop(); + } + LOGGER.info("Clients stopped."); + } + + protected void stopServer() { + server.stop(); + LOGGER.info("Server stopped."); + } + + @Test + public void testConnection() { + final long currentTime = System.currentTimeMillis(); while (!isTestsDone()) { + if (System.currentTimeMillis() - currentTime > 600000) { + Assert.fail("Failed to complete test within 600s"); + } try { - s_logger.debug(_completedCount + "/" + _testCount + " tests done. Waiting for completion"); + LOGGER.debug(completedTestCount + "/" + totalTestCount + " tests done. Waiting for completion"); Thread.sleep(1000); } catch (final InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Assert.fail(e.getMessage()); } } - stopClient(); - stopServer(); + LOGGER.debug(completedTestCount + "/" + totalTestCount + " tests done."); } - protected void stopClient() { - _client.stop(); - s_logger.info("Client stopped."); + protected void doServerProcess(final byte[] data) { + oneMoreTestDone(); + Assert.assertArrayEquals(testBytes, data); + LOGGER.info("Verify data received by server done."); } - protected void stopServer() { - _server.stop(); - s_logger.info("Server stopped."); + public byte[] getTestBytes() { + return testBytes; } - protected void setClientLink(final Link link) { - _clientLink = link; + public class ThreadedNioClient implements Runnable { + final private NioClient client; + ThreadedNioClient(final NioClient client) { + this.client = client; + } + + @Override + public void run() { + try { + client.start(); + } catch (NioConnectionException e) { + Assert.fail(e.getMessage()); + } + } } - Random randomGenerator = new Random(); + public class NioMaliciousClient extends NioClient { - byte[] _testBytes; + public NioMaliciousClient(String name, String host, int port, int workers, HandlerFactory factory) { + super(name, host, port, workers, factory); + } - public void testConnection() { - _testBytes = new byte[1000000]; - randomGenerator.nextBytes(_testBytes); - try { - getOneMoreTest(); - _clientLink.send(_testBytes); - s_logger.info("Client: Data sent"); - getOneMoreTest(); - _clientLink.send(_testBytes); - s_logger.info("Client: Data sent"); - } catch (final ClosedChannelException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + @Override + protected void init() throws IOException { + _selector = Selector.open(); + try { + _clientConnection = SocketChannel.open(); + LOGGER.info("Connecting to " + _host + ":" + _port); + final InetSocketAddress peerAddr = new InetSocketAddress(_host, _port); + _clientConnection.connect(peerAddr); + // Hang in there don't do anything + Thread.sleep(3600000); + } catch (final IOException e) { + _selector.close(); + throw e; + } catch (InterruptedException e) { + LOGGER.debug(e.getMessage()); + } } } - protected void doServerProcess(final byte[] data) { - oneMoreTestDone(); - Assert.assertArrayEquals(_testBytes, data); - s_logger.info("Verify done."); + public class NioMaliciousTestClient implements HandlerFactory { + + @Override + public Task create(final Type type, final Link link, final byte[] data) { + return new NioMaliciousTestClientHandler(type, link, data); + } + + public class NioMaliciousTestClientHandler extends Task { + + public NioMaliciousTestClientHandler(final Type type, final Link link, final byte[] data) { + super(type, link, data); + } + + @Override + public void doTask(final Task task) { + LOGGER.info("Malicious Client: Received task " + task.getType().toString()); + } + } } public class NioTestClient implements HandlerFactory { @@ -177,18 +229,23 @@ public NioTestClientHandler(final Type type, final Link link, final byte[] data) @Override public void doTask(final Task task) { if (task.getType() == Task.Type.CONNECT) { - s_logger.info("Client: Received CONNECT task"); - setClientLink(task.getLink()); + LOGGER.info("Client: Received CONNECT task"); + try { + LOGGER.info("Sending data to server"); + task.getLink().send(getTestBytes()); + } catch (ClosedChannelException e) { + LOGGER.error(e.getMessage()); + e.printStackTrace(); + } } else if (task.getType() == Task.Type.DATA) { - s_logger.info("Client: Received DATA task"); + LOGGER.info("Client: Received DATA task"); } else if (task.getType() == Task.Type.DISCONNECT) { - s_logger.info("Client: Received DISCONNECT task"); + LOGGER.info("Client: Received DISCONNECT task"); stopClient(); } else if (task.getType() == Task.Type.OTHER) { - s_logger.info("Client: Received OTHER task"); + LOGGER.info("Client: Received OTHER task"); } } - } } @@ -208,15 +265,15 @@ public NioTestServerHandler(final Type type, final Link link, final byte[] data) @Override public void doTask(final Task task) { if (task.getType() == Task.Type.CONNECT) { - s_logger.info("Server: Received CONNECT task"); + LOGGER.info("Server: Received CONNECT task"); } else if (task.getType() == Task.Type.DATA) { - s_logger.info("Server: Received DATA task"); + LOGGER.info("Server: Received DATA task"); doServerProcess(task.getData()); } else if (task.getType() == Task.Type.DISCONNECT) { - s_logger.info("Server: Received DISCONNECT task"); + LOGGER.info("Server: Received DISCONNECT task"); stopServer(); } else if (task.getType() == Task.Type.OTHER) { - s_logger.info("Server: Received OTHER task"); + LOGGER.info("Server: Received OTHER task"); } } From ba77a692391856df468a141f98687ec71373a3d3 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Fri, 15 Apr 2016 01:59:25 +0530 Subject: [PATCH 127/203] CLOUDSTACK-9348: Use non-blocking SSL handshake - Uses non-blocking socket config in NioClient and NioServer/NioConnection - Scalable connectivity from agents and peer clustered-management server - Removes blocking ssl handshake code with a non-blocking code - Protects from denial-of-service issues that can degrade mgmt server responsiveness due to an aggressive/malicious client - Uses separate executor services for handling ssl handshakes Signed-off-by: Rohit Yadav --- .../manager/ClusteredAgentManagerImpl.java | 9 +- .../main/java/com/cloud/utils/nio/Link.java | 294 +++++++++++------- .../java/com/cloud/utils/nio/NioClient.java | 31 +- .../com/cloud/utils/nio/NioConnection.java | 84 ++--- .../java/com/cloud/utils/nio/NioServer.java | 8 +- .../com/cloud/utils/testcase/NioTest.java | 38 ++- 6 files changed, 272 insertions(+), 192 deletions(-) diff --git a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java index f35a4efe36..91085bf8d1 100644 --- a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java @@ -499,7 +499,7 @@ public SocketChannel connectToPeer(final String peerName, final SocketChannel pr SocketChannel ch1 = null; try { ch1 = SocketChannel.open(new InetSocketAddress(addr, Port.value())); - ch1.configureBlocking(true); // make sure we are working at blocking mode + ch1.configureBlocking(false); ch1.socket().setKeepAlive(true); ch1.socket().setSoTimeout(60 * 1000); try { @@ -507,8 +507,11 @@ public SocketChannel connectToPeer(final String peerName, final SocketChannel pr sslEngine = sslContext.createSSLEngine(ip, Port.value()); sslEngine.setUseClientMode(true); sslEngine.setEnabledProtocols(SSLUtils.getSupportedProtocols(sslEngine.getEnabledProtocols())); - - Link.doHandshake(ch1, sslEngine, true); + sslEngine.beginHandshake(); + if (!Link.doHandshake(ch1, sslEngine, true)) { + ch1.close(); + throw new IOException("SSL handshake failed!"); + } s_logger.info("SSL: Handshake done"); } catch (final Exception e) { ch1.close(); diff --git a/utils/src/main/java/com/cloud/utils/nio/Link.java b/utils/src/main/java/com/cloud/utils/nio/Link.java index 6d6306a53b..f297d52c07 100644 --- a/utils/src/main/java/com/cloud/utils/nio/Link.java +++ b/utils/src/main/java/com/cloud/utils/nio/Link.java @@ -19,37 +19,33 @@ package com.cloud.utils.nio; +import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.db.DbProperties; +import org.apache.cloudstack.utils.security.SSLUtils; +import org.apache.log4j.Logger; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; -import java.net.SocketTimeoutException; import java.nio.ByteBuffer; -import java.nio.channels.Channels; import java.nio.channels.ClosedChannelException; -import java.nio.channels.ReadableByteChannel; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.util.concurrent.ConcurrentLinkedQueue; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLEngineResult.HandshakeStatus; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; - -import org.apache.cloudstack.utils.security.SSLUtils; -import org.apache.log4j.Logger; - -import com.cloud.utils.PropertiesUtil; -import com.cloud.utils.db.DbProperties; - /** */ public class Link { @@ -453,115 +449,185 @@ public static SSLContext initSSLContext(boolean isClient) throws GeneralSecurity return sslContext; } - public static void doHandshake(SocketChannel ch, SSLEngine sslEngine, boolean isClient) throws IOException { - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: begin Handshake, isClient: " + isClient); + public static ByteBuffer enlargeBuffer(ByteBuffer buffer, final int sessionProposedCapacity) { + if (buffer == null || sessionProposedCapacity < 0) { + return buffer; } - - SSLEngineResult engResult; - SSLSession sslSession = sslEngine.getSession(); - HandshakeStatus hsStatus; - ByteBuffer in_pkgBuf = ByteBuffer.allocate(sslSession.getPacketBufferSize() + 40); - ByteBuffer in_appBuf = ByteBuffer.allocate(sslSession.getApplicationBufferSize() + 40); - ByteBuffer out_pkgBuf = ByteBuffer.allocate(sslSession.getPacketBufferSize() + 40); - ByteBuffer out_appBuf = ByteBuffer.allocate(sslSession.getApplicationBufferSize() + 40); - int count; - ch.socket().setSoTimeout(60 * 1000); - InputStream inStream = ch.socket().getInputStream(); - // Use readCh to make sure the timeout on reading is working - ReadableByteChannel readCh = Channels.newChannel(inStream); - - if (isClient) { - hsStatus = SSLEngineResult.HandshakeStatus.NEED_WRAP; + if (sessionProposedCapacity > buffer.capacity()) { + buffer = ByteBuffer.allocate(sessionProposedCapacity); } else { - hsStatus = SSLEngineResult.HandshakeStatus.NEED_UNWRAP; + buffer = ByteBuffer.allocate(buffer.capacity() * 2); } + return buffer; + } - while (hsStatus != SSLEngineResult.HandshakeStatus.FINISHED) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Handshake status " + hsStatus); + public static ByteBuffer handleBufferUnderflow(final SSLEngine engine, ByteBuffer buffer) { + if (engine == null || buffer == null) { + return buffer; + } + if (buffer.position() < buffer.limit()) { + return buffer; + } + ByteBuffer replaceBuffer = enlargeBuffer(buffer, engine.getSession().getPacketBufferSize()); + buffer.flip(); + replaceBuffer.put(buffer); + return replaceBuffer; + } + + private static boolean doHandshakeUnwrap(final SocketChannel socketChannel, final SSLEngine sslEngine, + ByteBuffer peerAppData, ByteBuffer peerNetData, final int appBufferSize) throws IOException { + if (socketChannel == null || sslEngine == null || peerAppData == null || peerNetData == null || appBufferSize < 0) { + return false; + } + if (socketChannel.read(peerNetData) < 0) { + if (sslEngine.isInboundDone() && sslEngine.isOutboundDone()) { + return false; } - engResult = null; - if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP) { - out_pkgBuf.clear(); - out_appBuf.clear(); - out_appBuf.put("Hello".getBytes()); - engResult = sslEngine.wrap(out_appBuf, out_pkgBuf); - out_pkgBuf.flip(); - int remain = out_pkgBuf.limit(); - while (remain != 0) { - remain -= ch.write(out_pkgBuf); - if (remain < 0) { - throw new IOException("Too much bytes sent?"); - } - } - } else if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) { - in_appBuf.clear(); - // One packet may contained multiply operation - if (in_pkgBuf.position() == 0 || !in_pkgBuf.hasRemaining()) { - in_pkgBuf.clear(); - count = 0; - try { - count = readCh.read(in_pkgBuf); - } catch (SocketTimeoutException ex) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("Handshake reading time out! Cut the connection"); - } - count = -1; - } - if (count == -1) { - throw new IOException("Connection closed with -1 on reading size."); - } - in_pkgBuf.flip(); + try { + sslEngine.closeInbound(); + } catch (SSLException e) { + s_logger.warn("This SSL engine was forced to close inbound due to end of stream."); + } + sslEngine.closeOutbound(); + // After closeOutbound the engine will be set to WRAP state, + // in order to try to send a close message to the client. + return true; + } + peerNetData.flip(); + SSLEngineResult result = null; + try { + result = sslEngine.unwrap(peerNetData, peerAppData); + peerNetData.compact(); + } catch (SSLException sslException) { + s_logger.error("SSL error occurred while processing unwrap data: " + sslException.getMessage()); + sslEngine.closeOutbound(); + return true; + } + switch (result.getStatus()) { + case OK: + break; + case BUFFER_OVERFLOW: + // Will occur when peerAppData's capacity is smaller than the data derived from peerNetData's unwrap. + peerAppData = enlargeBuffer(peerAppData, appBufferSize); + break; + case BUFFER_UNDERFLOW: + // Will occur either when no data was read from the peer or when the peerNetData buffer + // was too small to hold all peer's data. + peerNetData = handleBufferUnderflow(sslEngine, peerNetData); + break; + case CLOSED: + if (sslEngine.isOutboundDone()) { + return false; + } else { + sslEngine.closeOutbound(); + break; } - engResult = sslEngine.unwrap(in_pkgBuf, in_appBuf); - ByteBuffer tmp_pkgBuf = ByteBuffer.allocate(sslSession.getPacketBufferSize() + 40); - int loop_count = 0; - while (engResult.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) { - // The client is too slow? Cut it and let it reconnect - if (loop_count > 10) { - throw new IOException("Too many times in SSL BUFFER_UNDERFLOW, disconnect guest."); - } - // We need more packets to complete this operation - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Buffer underflowed, getting more packets"); - } - tmp_pkgBuf.clear(); - count = ch.read(tmp_pkgBuf); - if (count == -1) { - throw new IOException("Connection closed with -1 on reading size."); - } - tmp_pkgBuf.flip(); - - in_pkgBuf.mark(); - in_pkgBuf.position(in_pkgBuf.limit()); - in_pkgBuf.limit(in_pkgBuf.limit() + tmp_pkgBuf.limit()); - in_pkgBuf.put(tmp_pkgBuf); - in_pkgBuf.reset(); + default: + throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + } + return true; + } - in_appBuf.clear(); - engResult = sslEngine.unwrap(in_pkgBuf, in_appBuf); - loop_count++; + private static boolean doHandshakeWrap(final SocketChannel socketChannel, final SSLEngine sslEngine, + ByteBuffer myAppData, ByteBuffer myNetData, ByteBuffer peerNetData, + final int netBufferSize) throws IOException { + if (socketChannel == null || sslEngine == null || myNetData == null || peerNetData == null + || myAppData == null || netBufferSize < 0) { + return false; + } + myNetData.clear(); + SSLEngineResult result = null; + try { + result = sslEngine.wrap(myAppData, myNetData); + } catch (SSLException sslException) { + s_logger.error("SSL error occurred while processing wrap data: " + sslException.getMessage()); + sslEngine.closeOutbound(); + return true; + } + switch (result.getStatus()) { + case OK : + myNetData.flip(); + while (myNetData.hasRemaining()) { + socketChannel.write(myNetData); } - } else if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK) { - Runnable run; - while ((run = sslEngine.getDelegatedTask()) != null) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Running delegated task!"); + break; + case BUFFER_OVERFLOW: + // Will occur if there is not enough space in myNetData buffer to write all the data + // that would be generated by the method wrap. Since myNetData is set to session's packet + // size we should not get to this point because SSLEngine is supposed to produce messages + // smaller or equal to that, but a general handling would be the following: + myNetData = enlargeBuffer(myNetData, netBufferSize); + break; + case BUFFER_UNDERFLOW: + throw new SSLException("Buffer underflow occurred after a wrap. We should not reach here."); + case CLOSED: + try { + myNetData.flip(); + while (myNetData.hasRemaining()) { + socketChannel.write(myNetData); } - run.run(); + // At this point the handshake status will probably be NEED_UNWRAP + // so we make sure that peerNetData is clear to read. + peerNetData.clear(); + } catch (Exception e) { + s_logger.error("Failed to send server's CLOSE message due to socket channel's failure."); } - } else if (hsStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { - throw new IOException("NOT a handshaking!"); + break; + default: + throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + } + return true; + } + + public static boolean doHandshake(final SocketChannel socketChannel, final SSLEngine sslEngine, final boolean isClient) throws IOException { + if (socketChannel == null || sslEngine == null) { + return false; + } + final int appBufferSize = sslEngine.getSession().getApplicationBufferSize(); + final int netBufferSize = sslEngine.getSession().getPacketBufferSize(); + ByteBuffer myAppData = ByteBuffer.allocate(appBufferSize); + ByteBuffer peerAppData = ByteBuffer.allocate(appBufferSize); + ByteBuffer myNetData = ByteBuffer.allocate(netBufferSize); + ByteBuffer peerNetData = ByteBuffer.allocate(netBufferSize); + + final long startTimeMills = System.currentTimeMillis(); + + HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); + while (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED + && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { + final long timeTaken = System.currentTimeMillis() - startTimeMills; + if (timeTaken > 60000L) { + s_logger.warn("SSL Handshake has taken more than 60s to connect to: " + socketChannel.getRemoteAddress() + + ". Please investigate this connection."); + return false; } - if (engResult != null && engResult.getStatus() != SSLEngineResult.Status.OK) { - throw new IOException("Fail to handshake! " + engResult.getStatus()); + switch (handshakeStatus) { + case NEED_UNWRAP: + if (!doHandshakeUnwrap(socketChannel, sslEngine, peerAppData, peerNetData, appBufferSize)) { + return false; + } + break; + case NEED_WRAP: + if (!doHandshakeWrap(socketChannel, sslEngine, myAppData, myNetData, peerNetData, netBufferSize)) { + return false; + } + break; + case NEED_TASK: + Runnable task; + while ((task = sslEngine.getDelegatedTask()) != null) { + new Thread(task).run(); + } + break; + case FINISHED: + break; + case NOT_HANDSHAKING: + break; + default: + throw new IllegalStateException("Invalid SSL status: " + handshakeStatus); } - if (engResult != null) - hsStatus = engResult.getHandshakeStatus(); - else - hsStatus = sslEngine.getHandshakeStatus(); + handshakeStatus = sslEngine.getHandshakeStatus(); } + return true; } } diff --git a/utils/src/main/java/com/cloud/utils/nio/NioClient.java b/utils/src/main/java/com/cloud/utils/nio/NioClient.java index d989f306c5..dc4f670de1 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioClient.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioClient.java @@ -36,7 +36,6 @@ public class NioClient extends NioConnection { private static final Logger s_logger = Logger.getLogger(NioClient.class); protected String _host; - protected String _bindAddress; protected SocketChannel _clientConnection; public NioClient(final String name, final String host, final int port, final int workers, final HandlerFactory factory) { @@ -44,10 +43,6 @@ public NioClient(final String name, final String host, final int port, final int _host = host; } - public void setBindAddress(final String ipAddress) { - _bindAddress = ipAddress; - } - @Override protected void init() throws IOException { _selector = Selector.open(); @@ -55,33 +50,25 @@ protected void init() throws IOException { try { _clientConnection = SocketChannel.open(); - _clientConnection.configureBlocking(true); - s_logger.info("Connecting to " + _host + ":" + _port); - - if (_bindAddress != null) { - s_logger.info("Binding outbound interface at " + _bindAddress); - - final InetSocketAddress bindAddr = new InetSocketAddress(_bindAddress, 0); - _clientConnection.socket().bind(bindAddr); - } + s_logger.info("Connecting to " + _host + ":" + _port); final InetSocketAddress peerAddr = new InetSocketAddress(_host, _port); _clientConnection.connect(peerAddr); - - SSLEngine sslEngine = null; - // Begin SSL handshake in BLOCKING mode - _clientConnection.configureBlocking(true); + _clientConnection.configureBlocking(false); final SSLContext sslContext = Link.initSSLContext(true); - sslEngine = sslContext.createSSLEngine(_host, _port); + SSLEngine sslEngine = sslContext.createSSLEngine(_host, _port); sslEngine.setUseClientMode(true); sslEngine.setEnabledProtocols(SSLUtils.getSupportedProtocols(sslEngine.getEnabledProtocols())); - - Link.doHandshake(_clientConnection, sslEngine, true); + sslEngine.beginHandshake(); + if (!Link.doHandshake(_clientConnection, sslEngine, true)) { + s_logger.error("SSL Handshake failed while connecting to host: " + _host + " port: " + _port); + _selector.close(); + throw new IOException("SSL Handshake failed while connecting to host: " + _host + " port: " + _port); + } s_logger.info("SSL: Handshake done"); s_logger.info("Connected to " + _host + ":" + _port); - _clientConnection.configureBlocking(false); final Link link = new Link(peerAddr, this); link.setSSLEngine(sslEngine); final SelectionKey key = _clientConnection.register(_selector, SelectionKey.OP_READ); diff --git a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java index 249f512d9c..6fdb4736ac 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java @@ -19,8 +19,13 @@ package com.cloud.utils.nio; -import static com.cloud.utils.AutoCloseableUtil.closeAutoCloseable; +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.exception.NioConnectionException; +import org.apache.cloudstack.utils.security.SSLUtils; +import org.apache.log4j.Logger; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; import java.io.IOException; import java.net.ConnectException; import java.net.InetSocketAddress; @@ -44,14 +49,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; - -import org.apache.cloudstack.utils.security.SSLUtils; -import org.apache.log4j.Logger; - -import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.exception.NioConnectionException; +import static com.cloud.utils.AutoCloseableUtil.closeAutoCloseable; /** * NioConnection abstracts the NIO socket operations. The Java implementation @@ -71,6 +69,7 @@ public abstract class NioConnection implements Callable { protected HandlerFactory _factory; protected String _name; protected ExecutorService _executor; + protected ExecutorService _sslHandshakeExecutor; public NioConnection(final String name, final int port, final int workers, final HandlerFactory factory) { _name = name; @@ -79,6 +78,7 @@ public NioConnection(final String name, final int port, final int workers, final _port = port; _factory = factory; _executor = new ThreadPoolExecutor(workers, 5 * workers, 1, TimeUnit.DAYS, new LinkedBlockingQueue(), new NamedThreadFactory(name + "-Handler")); + _sslHandshakeExecutor = Executors.newCachedThreadPool(new NamedThreadFactory(name + "-SSLHandshakeHandler")); } public void start() throws NioConnectionException { @@ -185,8 +185,9 @@ public Boolean call() throws NioConnectionException { protected void accept(final SelectionKey key) throws IOException { final ServerSocketChannel serverSocketChannel = (ServerSocketChannel)key.channel(); - final SocketChannel socketChannel = serverSocketChannel.accept(); + socketChannel.configureBlocking(false); + final Socket socket = socketChannel.socket(); socket.setKeepAlive(true); @@ -194,43 +195,52 @@ protected void accept(final SelectionKey key) throws IOException { s_logger.trace("Connection accepted for " + socket); } - // Begin SSL handshake in BLOCKING mode - socketChannel.configureBlocking(true); - - SSLEngine sslEngine = null; + final SSLEngine sslEngine; try { final SSLContext sslContext = Link.initSSLContext(false); sslEngine = sslContext.createSSLEngine(); sslEngine.setUseClientMode(false); sslEngine.setNeedClientAuth(false); sslEngine.setEnabledProtocols(SSLUtils.getSupportedProtocols(sslEngine.getEnabledProtocols())); - - Link.doHandshake(socketChannel, sslEngine, false); - + final NioConnection nioConnection = this; + _sslHandshakeExecutor.submit(new Runnable() { + @Override + public void run() { + _selector.wakeup(); + try { + sslEngine.beginHandshake(); + if (!Link.doHandshake(socketChannel, sslEngine, false)) { + throw new IOException("SSL handshake timed out with " + socketChannel.getRemoteAddress()); + } + if (s_logger.isTraceEnabled()) { + s_logger.trace("SSL: Handshake done"); + } + final InetSocketAddress saddr = (InetSocketAddress)socket.getRemoteSocketAddress(); + final Link link = new Link(saddr, nioConnection); + link.setSSLEngine(sslEngine); + link.setKey(socketChannel.register(key.selector(), SelectionKey.OP_READ, link)); + final Task task = _factory.create(Task.Type.CONNECT, link, null); + registerLink(saddr, link); + _executor.submit(task); + } catch (IOException e) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Connection closed due to failure: " + e.getMessage()); + } + closeAutoCloseable(socket, "accepting socket"); + closeAutoCloseable(socketChannel, "accepting socketChannel"); + } finally { + _selector.wakeup(); + } + } + }); } catch (final Exception e) { if (s_logger.isTraceEnabled()) { - s_logger.trace("Socket " + socket + " closed on read. Probably -1 returned: " + e.getMessage()); + s_logger.trace("Connection closed due to failure: " + e.getMessage()); } + closeAutoCloseable(socket, "accepting socket"); closeAutoCloseable(socketChannel, "accepting socketChannel"); - closeAutoCloseable(socket, "opened socket"); - return; - } - - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Handshake done"); - } - socketChannel.configureBlocking(false); - final InetSocketAddress saddr = (InetSocketAddress)socket.getRemoteSocketAddress(); - final Link link = new Link(saddr, this); - link.setSSLEngine(sslEngine); - link.setKey(socketChannel.register(key.selector(), SelectionKey.OP_READ, link)); - final Task task = _factory.create(Task.Type.CONNECT, link, null); - registerLink(saddr, link); - - try { - _executor.submit(task); - } catch (final Exception e) { - s_logger.warn("Exception occurred when submitting the task", e); + } finally { + _selector.wakeup(); } } diff --git a/utils/src/main/java/com/cloud/utils/nio/NioServer.java b/utils/src/main/java/com/cloud/utils/nio/NioServer.java index 539c2bb13d..13d5476cba 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioServer.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioServer.java @@ -43,6 +43,10 @@ public NioServer(final String name, final int port, final int workers, final Han _links = new WeakHashMap(1024); } + public int getPort() { + return _serverSocket.socket().getLocalPort(); + } + @Override protected void init() throws IOException { _selector = SelectorProvider.provider().openSelector(); @@ -53,9 +57,9 @@ protected void init() throws IOException { _localAddr = new InetSocketAddress(_port); _serverSocket.socket().bind(_localAddr); - _serverSocket.register(_selector, SelectionKey.OP_ACCEPT, null); + _serverSocket.register(_selector, SelectionKey.OP_ACCEPT); - s_logger.info("NioConnection started and listening on " + _localAddr.toString()); + s_logger.info("NioConnection started and listening on " + _serverSocket.socket().getLocalSocketAddress()); } @Override diff --git a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java index 7516cfc42e..20c31e21b1 100644 --- a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java +++ b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java @@ -44,11 +44,26 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +/** + * NioTest demonstrates that NioServer can function without getting its main IO + * loop blocked when an aggressive or malicious client connects to the server but + * fail to participate in SSL handshake. In this test, we run bunch of clients + * that send a known payload to the server, to which multiple malicious clients + * also try to connect and hang. + * A malicious client could cause denial-of-service if the server's main IO loop + * along with SSL handshake was blocking. A passing tests shows that NioServer + * can still function in case of connection load and that the main IO loop along + * with SSL handshake is non-blocking with some internal timeout mechanism. + */ + public class NioTest { private static final Logger LOGGER = Logger.getLogger(NioTest.class); - final private int totalTestCount = 10; + // Test should fail in due time instead of looping forever + private static final int TESTTIMEOUT = 300000; + + final private int totalTestCount = 5; private int completedTestCount = 0; private NioServer server; @@ -83,22 +98,20 @@ public void setUp() { testBytes = new byte[1000000]; randomGenerator.nextBytes(testBytes); - // Server configured with one worker - server = new NioServer("NioTestServer", 7777, 1, new NioTestServer()); + server = new NioServer("NioTestServer", 0, 1, new NioTestServer()); try { server.start(); } catch (final NioConnectionException e) { Assert.fail(e.getMessage()); } - // 5 malicious clients per valid client for (int i = 0; i < totalTestCount; i++) { - for (int j = 0; j < 5; j++) { - final NioClient maliciousClient = new NioMaliciousClient("NioMaliciousTestClient-" + i, "127.0.0.1", 7777, 1, new NioMaliciousTestClient()); + for (int j = 0; j < 4; j++) { + final NioClient maliciousClient = new NioMaliciousClient("NioMaliciousTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioMaliciousTestClient()); maliciousClients.add(maliciousClient); maliciousExecutor.submit(new ThreadedNioClient(maliciousClient)); } - final NioClient client = new NioClient("NioTestClient-" + i, "127.0.0.1", 7777, 1, new NioTestClient()); + final NioClient client = new NioClient("NioTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioTestClient()); clients.add(client); clientExecutor.submit(new ThreadedNioClient(client)); } @@ -125,13 +138,9 @@ protected void stopServer() { LOGGER.info("Server stopped."); } - @Test + @Test(timeout=TESTTIMEOUT) public void testConnection() { - final long currentTime = System.currentTimeMillis(); while (!isTestsDone()) { - if (System.currentTimeMillis() - currentTime > 600000) { - Assert.fail("Failed to complete test within 600s"); - } try { LOGGER.debug(completedTestCount + "/" + totalTestCount + " tests done. Waiting for completion"); Thread.sleep(1000); @@ -182,8 +191,9 @@ protected void init() throws IOException { LOGGER.info("Connecting to " + _host + ":" + _port); final InetSocketAddress peerAddr = new InetSocketAddress(_host, _port); _clientConnection.connect(peerAddr); - // Hang in there don't do anything - Thread.sleep(3600000); + // This is done on purpose, the malicious client would connect + // to the server and then do nothing, hence using a large sleep value + Thread.sleep(Long.MAX_VALUE); } catch (final IOException e) { _selector.close(); throw e; From 866ac7b6e1808e768c29b2491c8b3bfa174f2f78 Mon Sep 17 00:00:00 2001 From: weingartner Date: Fri, 29 Apr 2016 14:25:29 -0300 Subject: [PATCH 128/203] Fixed issues from CLOUDSTACK-8800 that were introduced in PR 780 It was worked around some possible runtime exceptions introduced by the changes that were added by the PR 780. Basically, the points in which a null pointer exception could happen, we added safety checks to avoid them. It was create a specific method do that, all together test cases were created for this newly method that was added. --- .../resource/LibvirtComputingResource.java | 43 +++++++----- .../LibvirtComputingResourceTest.java | 69 ++++++++++++++----- .../resource/CitrixResourceBase.java | 16 +++-- 3 files changed, 84 insertions(+), 44 deletions(-) diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 02cf872d92..0f8e9edb9f 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -52,15 +52,17 @@ import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.math.NumberUtils; import org.apache.log4j.Logger; import org.libvirt.Connect; import org.libvirt.Domain; import org.libvirt.DomainBlockStats; import org.libvirt.DomainInfo; -import org.libvirt.MemoryStatistic; import org.libvirt.DomainInfo.DomainState; import org.libvirt.DomainInterfaceStats; import org.libvirt.LibvirtException; +import org.libvirt.MemoryStatistic; import org.libvirt.NodeInfo; import com.cloud.agent.api.Answer; @@ -189,7 +191,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv private String _clusterId; private long _hvVersion; - private long _kernelVersion; private int _timeout; private static final int NUMMEMSTATS =2; @@ -958,13 +959,6 @@ public boolean configure(final String name, final Map params) th storageProcessor.configure(name, params); storageHandler = new StorageSubsystemCommandHandlerBase(storageProcessor); - final String unameKernelVersion = Script.runSimpleBashScript("uname -r"); - final String[] kernelVersions = unameKernelVersion.split("[\\.\\-]"); - _kernelVersion = Integer.parseInt(kernelVersions[0]) * 1000 * 1000 + (long)Integer.parseInt(kernelVersions[1]) * 1000 + Integer.parseInt(kernelVersions[2]); - - /* Disable this, the code using this is pretty bad and non portable - * getOsVersion(); - */ return true; } @@ -3020,9 +3014,6 @@ private class VmStats { long _ioWrote; long _bytesRead; long _bytesWrote; - long _intmemfree; - long _memory; - long _maxmemory; Calendar _timestamp; } @@ -3030,9 +3021,10 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li Domain dm = null; try { dm = getDomain(conn, vmName); - final DomainInfo info = dm.getInfo(); - final MemoryStatistic[] mems = dm.memoryStats(NUMMEMSTATS); //number of memory statistics required. - + if (dm == null) { + return null; + } + DomainInfo info = dm.getInfo(); final VmStatsEntry stats = new VmStatsEntry(); stats.setNumCPUs(info.nrVirtCpu); @@ -3040,7 +3032,8 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li stats.setMemoryKBs(info.maxMem); stats.setTargetMemoryKBs(info.memory); - stats.setIntFreeMemoryKBs((double) mems[0].getValue()); + stats.setIntFreeMemoryKBs(getMemoryFreeInKBs(dm)); + /* get cpu utilization */ VmStats oldStats = null; @@ -3125,9 +3118,6 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li newStat._bytesRead = bytes_rd; newStat._bytesWrote = bytes_wr; newStat._timestamp = now; - newStat._intmemfree = mems[0].getValue(); - newStat._memory = info.memory; - newStat._maxmemory = info.maxMem; _vmStats.put(vmName, newStat); return stats; } finally { @@ -3137,6 +3127,21 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li } } + /** + * This method retrieves the memory statistics from the domain given as parameters. + * If no memory statistic is found, it will return {@link NumberUtils#LONG_ZERO} as the value of free memory in the domain. + * If it can retrieve the domain memory statistics, it will return the free memory statistic; that means, it returns the value at the first position of the array returned by {@link Domain#memoryStats(int)}. + * + * @return the amount of free memory in KBs + */ + protected long getMemoryFreeInKBs(Domain dm) throws LibvirtException { + MemoryStatistic[] mems = dm.memoryStats(NUMMEMSTATS); + if (ArrayUtils.isEmpty(mems)) { + return NumberUtils.LONG_ZERO; + } + return mems[0].getValue(); + } + private boolean canBridgeFirewall(final String prvNic) { final Script cmd = new Script(_securityGroupPath, _timeout, s_logger); cmd.add("can_bridge_firewall"); diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 391313e191..488325ea81 100644 --- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -65,10 +65,10 @@ import org.libvirt.DomainInfo.DomainState; import org.libvirt.DomainInterfaceStats; import org.libvirt.LibvirtException; +import org.libvirt.MemoryStatistic; import org.libvirt.NodeInfo; import org.libvirt.StorageVol; -import org.libvirt.MemoryStatistic; - +import org.libvirt.jna.virDomainMemoryStats; import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.Mockito; @@ -182,8 +182,8 @@ public class LibvirtComputingResourceTest { @Mock private LibvirtComputingResource libvirtComputingResource; - String _hyperVisorType = "kvm"; - Random _random = new Random(); + String hyperVisorType = "kvm"; + Random random = new Random(); /** This test tests if the Agent can handle a vmSpec coming @@ -194,10 +194,10 @@ public class LibvirtComputingResourceTest { */ @Test public void testCreateVMFromSpecLegacy() { - final int id = _random.nextInt(65534); + final int id = random.nextInt(65534); final String name = "test-instance-1"; - final int cpus = _random.nextInt(2) + 1; + final int cpus = random.nextInt(2) + 1; final int speed = 1024; final int minRam = 256 * 1024; final int maxRam = 512 * 1024; @@ -213,7 +213,7 @@ public void testCreateVMFromSpecLegacy() { to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); final LibvirtVMDef vm = lcr.createVMFromSpec(to); - vm.setHvsType(_hyperVisorType); + vm.setHvsType(hyperVisorType); verifyVm(to, vm); } @@ -223,7 +223,7 @@ public void testCreateVMFromSpecLegacy() { */ @Test public void testCreateVMFromSpecWithTopology6() { - final int id = _random.nextInt(65534); + final int id = random.nextInt(65534); final String name = "test-instance-1"; final int cpus = 12; @@ -243,7 +243,7 @@ public void testCreateVMFromSpecWithTopology6() { to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); final LibvirtVMDef vm = lcr.createVMFromSpec(to); - vm.setHvsType(_hyperVisorType); + vm.setHvsType(hyperVisorType); verifyVm(to, vm); } @@ -253,7 +253,7 @@ public void testCreateVMFromSpecWithTopology6() { */ @Test public void testCreateVMFromSpecWithTopology4() { - final int id = _random.nextInt(65534); + final int id = random.nextInt(65534); final String name = "test-instance-1"; final int cpus = 8; @@ -273,7 +273,7 @@ public void testCreateVMFromSpecWithTopology4() { to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); final LibvirtVMDef vm = lcr.createVMFromSpec(to); - vm.setHvsType(_hyperVisorType); + vm.setHvsType(hyperVisorType); verifyVm(to, vm); } @@ -287,10 +287,10 @@ public void testCreateVMFromSpecWithTopology4() { */ @Test public void testCreateVMFromSpec() { - final int id = _random.nextInt(65534); + final int id = random.nextInt(65534); final String name = "test-instance-1"; - final int cpus = _random.nextInt(2) + 1; + final int cpus = random.nextInt(2) + 1; final int minSpeed = 1024; final int maxSpeed = 2048; final int minRam = 256 * 1024; @@ -308,7 +308,7 @@ public void testCreateVMFromSpec() { to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); final LibvirtVMDef vm = lcr.createVMFromSpec(to); - vm.setHvsType(_hyperVisorType); + vm.setHvsType(hyperVisorType); verifyVm(to, vm); } @@ -718,10 +718,9 @@ public void testGetVmDiskStatsCommand() { } } - @SuppressWarnings("unchecked") @Test + @SuppressWarnings("unchecked") public void testGetVmDiskStatsCommandException() { - Mockito.mock(Connect.class); final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class); final String vmName = "Test"; @@ -941,7 +940,6 @@ public void testRebootRouterCommandConnect() { public void testGetHostStatsCommand() { // A bit difficult to test due to the logger being passed and the parser itself relying on the connection. // Have to spend some more time afterwards in order to refactor the wrapper itself. - Mockito.mock(LibvirtUtilitiesHelper.class); final CPUStat cpuStat = Mockito.mock(CPUStat.class); final MemStat memStat = Mockito.mock(MemStat.class); @@ -3531,7 +3529,6 @@ public void testNetworkUsageCommandVpcNoOption() { verify(libvirtComputingResource, times(1)).configureVPCNetworkUsage(command.getPrivateIP(), command.getGatewayIP(), command.getOption(), command.getVpcCIDR()); } - @SuppressWarnings("unchecked") @Test public void testCreatePrivateTemplateFromVolumeCommand() { //Simple test used to make sure the flow (LibvirtComputingResource => Request => CommandWrapper) is working. @@ -5040,4 +5037,40 @@ public void testIsInterface () { } } } + + @Test + public void testMemoryFreeInKBsDomainReturningOfSomeMemoryStatistics() throws LibvirtException { + LibvirtComputingResource libvirtComputingResource = new LibvirtComputingResource(); + + MemoryStatistic[] mem = createMemoryStatisticFreeMemory100(); + Domain domainMock = getDomainConfiguredToReturnMemoryStatistic(mem); + long memoryFreeInKBs = libvirtComputingResource.getMemoryFreeInKBs(domainMock); + + Assert.assertEquals(100, memoryFreeInKBs); + } + + @Test + public void testMemoryFreeInKBsDomainReturningNoMemoryStatistics() throws LibvirtException { + LibvirtComputingResource libvirtComputingResource = new LibvirtComputingResource(); + + Domain domainMock = getDomainConfiguredToReturnMemoryStatistic(null); + long memoryFreeInKBs = libvirtComputingResource.getMemoryFreeInKBs(domainMock); + + Assert.assertEquals(0, memoryFreeInKBs); + } + + private MemoryStatistic[] createMemoryStatisticFreeMemory100() { + virDomainMemoryStats stat = new virDomainMemoryStats(); + stat.val = 100; + + MemoryStatistic[] mem = new MemoryStatistic[2]; + mem[0] = new MemoryStatistic(stat); + return mem; + } + + private Domain getDomainConfiguredToReturnMemoryStatistic(MemoryStatistic[] mem) throws LibvirtException { + Domain domainMock = Mockito.mock(Domain.class); + when(domainMock.memoryStats(2)).thenReturn(mem); + return domainMock; + } } diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index 6da2c7b02a..efc3f81ed1 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -184,6 +184,8 @@ public String toString() { } } + private final static int BASE_TO_CONVERT_BYTES_INTO_KILOBYTES = 1024; + protected static final XenServerConnectionPool ConnPool = XenServerConnectionPool.getInstance(); // static min values for guests on xenserver private static final long mem_128m = 134217728L; @@ -3323,19 +3325,19 @@ public HashMap getVmStats(final Connection conn, final Get vmStatsAnswer.setNumCPUs(vmStatsAnswer.getNumCPUs() + 1); vmStatsAnswer.setCPUUtilization(vmStatsAnswer.getCPUUtilization() + getDataAverage(dataNode, col, numRows)); } else if (param.matches("vif_\\d*_rx")) { - vmStatsAnswer.setNetworkReadKBs(vmStatsAnswer.getNetworkReadKBs() + getDataAverage(dataNode, col, numRows) / 1000); + vmStatsAnswer.setNetworkReadKBs(vmStatsAnswer.getNetworkReadKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); } else if (param.matches("vif_\\d*_tx")) { - vmStatsAnswer.setNetworkWriteKBs(vmStatsAnswer.getNetworkWriteKBs() + getDataAverage(dataNode, col, numRows) / 1000); + vmStatsAnswer.setNetworkWriteKBs(vmStatsAnswer.getNetworkWriteKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); } else if (param.matches("vbd_.*_read")) { - vmStatsAnswer.setDiskReadKBs(vmStatsAnswer.getDiskReadKBs() + getDataAverage(dataNode, col, numRows) / 1000); + vmStatsAnswer.setDiskReadKBs(vmStatsAnswer.getDiskReadKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); } else if (param.matches("vbd_.*_write")) { - vmStatsAnswer.setDiskWriteKBs(vmStatsAnswer.getDiskWriteKBs() + getDataAverage(dataNode, col, numRows) / 1000); + vmStatsAnswer.setDiskWriteKBs(vmStatsAnswer.getDiskWriteKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); } else if (param.contains("memory_internal_free")) { - vmStatsAnswer.setIntFreeMemoryKBs(vmStatsAnswer.getIntFreeMemoryKBs() + getDataAverage(dataNode, col, numRows) / 1024); + vmStatsAnswer.setIntFreeMemoryKBs(vmStatsAnswer.getIntFreeMemoryKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); } else if (param.contains("memory_target")) { - vmStatsAnswer.setTargetMemoryKBs(vmStatsAnswer.getTargetMemoryKBs() + getDataAverage(dataNode, col, numRows) / 1024); + vmStatsAnswer.setTargetMemoryKBs(vmStatsAnswer.getTargetMemoryKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); } else if (param.contains("memory")) { - vmStatsAnswer.setMemoryKBs(vmStatsAnswer.getMemoryKBs() + getDataAverage(dataNode, col, numRows) / 1024); + vmStatsAnswer.setMemoryKBs(vmStatsAnswer.getMemoryKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); } } From 1889e399dd7fc6e0e9dbac2595cfce0da7858416 Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Tue, 16 Feb 2016 11:21:30 +0100 Subject: [PATCH 129/203] systemvm, logrotate: remove daily explicitly as it is ignored If the size directive is used, logrotate will ignore the daily, weekly, monthly, and yearly directives. remove cloud-cleanup This script does not do anything because it fails due missing /var/log/cloud directory. Logrotate is used for this functionality. --- .../config/etc/cron.daily/cloud-cleanup | 27 ------------------- .../debian/config/etc/logrotate.d/cloud | 5 ++-- .../debian/config/etc/logrotate.d/conntrackd | 1 - .../debian/config/etc/logrotate.d/dnsmasq | 1 - .../debian/config/etc/logrotate.d/haproxy | 3 +-- .../patches/debian/config/etc/logrotate.d/ppp | 1 - .../debian/config/etc/logrotate.d/rsyslog | 2 -- 7 files changed, 3 insertions(+), 37 deletions(-) delete mode 100755 systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup diff --git a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup b/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup deleted file mode 100755 index 9d254d3fbb..0000000000 --- a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh -# /etc/cron.daily/cloud-cleanup: cleanup old cloudstack logs -# 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. - -cd / -output=$(find /var/log/cloud -mtime +7 -size +1M -exec rm -v '{}' \; ) -logger -t cloud "cloud-cleanup cronjob: cleaning up logfiles in /var/log/cloud older than 7 days and more than 1M in size" - -[ "$output" != "" ] && logger -t cloud $output -[ -z "$output" ] && logger -t cloud "No files removed" - -exit 0 diff --git a/systemvm/patches/debian/config/etc/logrotate.d/cloud b/systemvm/patches/debian/config/etc/logrotate.d/cloud index 420fce23e1..3fedd5e32e 100644 --- a/systemvm/patches/debian/config/etc/logrotate.d/cloud +++ b/systemvm/patches/debian/config/etc/logrotate.d/cloud @@ -5,9 +5,9 @@ # 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 @@ -16,7 +16,6 @@ # under the License. /var/log/cloud.log { rotate 4 - daily size 10M missingok notifempty diff --git a/systemvm/patches/debian/config/etc/logrotate.d/conntrackd b/systemvm/patches/debian/config/etc/logrotate.d/conntrackd index 0229cd7e8c..1c37c4c80d 100644 --- a/systemvm/patches/debian/config/etc/logrotate.d/conntrackd +++ b/systemvm/patches/debian/config/etc/logrotate.d/conntrackd @@ -1,5 +1,4 @@ /var/log/conntrackd-stats.log { - daily size 10M rotate 2 missingok diff --git a/systemvm/patches/debian/config/etc/logrotate.d/dnsmasq b/systemvm/patches/debian/config/etc/logrotate.d/dnsmasq index 2f91785519..99815d856f 100644 --- a/systemvm/patches/debian/config/etc/logrotate.d/dnsmasq +++ b/systemvm/patches/debian/config/etc/logrotate.d/dnsmasq @@ -1,5 +1,4 @@ /var/log/dnsmasq.log { - daily size 10M missingok rotate 5 diff --git a/systemvm/patches/debian/config/etc/logrotate.d/haproxy b/systemvm/patches/debian/config/etc/logrotate.d/haproxy index 858fe2a1c3..28da41c2ed 100644 --- a/systemvm/patches/debian/config/etc/logrotate.d/haproxy +++ b/systemvm/patches/debian/config/etc/logrotate.d/haproxy @@ -1,10 +1,9 @@ /var/log/haproxy.log { - daily rotate 5 missingok notifempty size 10M - postrotate + postrotate /bin/kill -HUP `cat /var/run/rsyslog.pid 2> /dev/null` 2> /dev/null || true endscript } diff --git a/systemvm/patches/debian/config/etc/logrotate.d/ppp b/systemvm/patches/debian/config/etc/logrotate.d/ppp index 2004e77ff0..624b4aed25 100644 --- a/systemvm/patches/debian/config/etc/logrotate.d/ppp +++ b/systemvm/patches/debian/config/etc/logrotate.d/ppp @@ -1,5 +1,4 @@ /var/log/ppp-connect-errors { - daily size 10M rotate 5 missingok diff --git a/systemvm/patches/debian/config/etc/logrotate.d/rsyslog b/systemvm/patches/debian/config/etc/logrotate.d/rsyslog index 5803c43d87..5a104b3e52 100644 --- a/systemvm/patches/debian/config/etc/logrotate.d/rsyslog +++ b/systemvm/patches/debian/config/etc/logrotate.d/rsyslog @@ -1,7 +1,6 @@ /var/log/syslog { rotate 7 - daily size 50M missingok notifempty @@ -26,7 +25,6 @@ /var/log/messages { rotate 10 - daily size 50M missingok notifempty From 61d2692597dd9219862573933957f0da504acb42 Mon Sep 17 00:00:00 2001 From: Olivier Lemasle Date: Wed, 20 Apr 2016 15:25:17 +0200 Subject: [PATCH 130/203] CLOUDSTACK-9358: StringIndexOutOfBoundsException on events Fixes JSON deserialization of cmdInfo (current process fails with StringIndexOutOfBoundsException when cmdEventType is the last parameter in the JSON string. --- server/src/com/cloud/api/ApiServer.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index 6ec2f18e77..ad75d98b24 100644 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -19,6 +19,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InterruptedIOException; +import java.lang.reflect.Type; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; @@ -176,6 +177,7 @@ import com.cloud.utils.db.UUIDManager; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExceptionProxyObject; +import com.google.gson.reflect.TypeToken; @Component public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiServerService { @@ -264,10 +266,11 @@ public void handleAsyncJobPublishEvent(String subject, String senderAddress, Obj String info = job.getCmdInfo(); String cmdEventType = "unknown"; if (info != null) { - String marker = "\"cmdEventType\""; - int begin = info.indexOf(marker); - if (begin >= 0) { - cmdEventType = info.substring(begin + marker.length() + 2, info.indexOf(",", begin) - 1); + Type type = new TypeToken>(){}.getType(); + Map cmdInfo = ApiGsonHelper.getBuilder().create().fromJson(info, type); + String eventTypeObj = cmdInfo.get("cmdEventType"); + if (eventTypeObj != null) { + cmdEventType = eventTypeObj; if (s_logger.isDebugEnabled()) s_logger.debug("Retrieved cmdEventType from job info: " + cmdEventType); From 696440a6754a60888fce7a82e8022ca7278b9be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Aur=C3=A8le=20Brothier?= Date: Wed, 4 May 2016 14:28:44 +0200 Subject: [PATCH 131/203] dao: Hit the cache for entity flagged as removed too since they are put in cache afterwards. --- framework/db/src/com/cloud/utils/db/GenericDaoBase.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/framework/db/src/com/cloud/utils/db/GenericDaoBase.java b/framework/db/src/com/cloud/utils/db/GenericDaoBase.java index 29adbe257a..2de161b457 100644 --- a/framework/db/src/com/cloud/utils/db/GenericDaoBase.java +++ b/framework/db/src/com/cloud/utils/db/GenericDaoBase.java @@ -969,7 +969,12 @@ public T findByUuidIncludingRemoved(final String uuid) { @Override @DB() public T findByIdIncludingRemoved(ID id) { - return findById(id, true, null); + if (_cache != null) { + final Element element = _cache.get(id); + return element == null ? findById(id, true, null) : (T)element.getObjectValue(); + } else { + return findById(id, true, null); + } } @Override From 8b6e6185f53cbdcfc13cced34ad531a6df3e9b09 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Fri, 8 Apr 2016 10:47:50 -0700 Subject: [PATCH 132/203] CLOUDSTACK-9340: General DB Optimization --- setup/db/db/schema-481to490-cleanup.sql | 65 +++++++++++++++++++++++++ setup/db/db/schema-481to490.sql | 23 +++++++++ 2 files changed, 88 insertions(+) diff --git a/setup/db/db/schema-481to490-cleanup.sql b/setup/db/db/schema-481to490-cleanup.sql index c74fa41533..b1bb702727 100644 --- a/setup/db/db/schema-481to490-cleanup.sql +++ b/setup/db/db/schema-481to490-cleanup.sql @@ -18,3 +18,68 @@ --; -- Schema cleanup from 4.8.1 to 4.9.0; --; + +-- Added in CLOUDSTACK-9340: General DB optimization, 4 cases: + +----- 1) Incorrect PRIMARY key +ALTER TABLE `cloud`.`ovs_tunnel_network` +DROP PRIMARY KEY, +ADD PRIMARY KEY (`id`), +DROP INDEX `id` , +ADD UNIQUE INDEX `i_to_from_network_id` (`to` ASC, `from` ASC, `network_id` ASC); + +----- 2) Duplicate PRIMARY KEY +ALTER TABLE `cloud`.`user_vm` DROP INDEX `id_2` ,DROP INDEX `id` ; +ALTER TABLE `cloud`.`domain_router` DROP INDEX `id_2` ,DROP INDEX `id` ; +ALTER TABLE `cloud`.`vm_instance` DROP INDEX `id_2` ,DROP INDEX `id` ; +ALTER TABLE `cloud`.`account_vlan_map` DROP INDEX `id` ; +ALTER TABLE `cloud`.`account_vnet_map` DROP INDEX `id` ; +ALTER TABLE `cloud`.`baremetal_rct` DROP INDEX `id` ; +ALTER TABLE `cloud`.`cluster` DROP INDEX `id` ; +ALTER TABLE `cloud`.`conditions` DROP INDEX `id` ; +ALTER TABLE `cloud`.`counter` DROP INDEX `id` ; +ALTER TABLE `cloud`.`data_center` DROP INDEX `id` ; +ALTER TABLE `cloud`.`dc_storage_network_ip_range` DROP INDEX `id` ; +ALTER TABLE `cloud`.`dedicated_resources` DROP INDEX `id` ; +ALTER TABLE `cloud`.`host_pod_ref` DROP INDEX `id` ; +ALTER TABLE `cloud`.`iam_group` DROP INDEX `id` ; +ALTER TABLE `cloud`.`iam_policy` DROP INDEX `id` ; +ALTER TABLE `cloud`.`iam_policy_permission` DROP INDEX `id` ; +ALTER TABLE `cloud`.`image_store_details` DROP INDEX `id` ; +ALTER TABLE `cloud`.`instance_group` DROP INDEX `id` ; +ALTER TABLE `cloud`.`netapp_lun` DROP INDEX `id` ; +ALTER TABLE `cloud`.`netapp_pool` DROP INDEX `id` ; +ALTER TABLE `cloud`.`netapp_volume` DROP INDEX `id` ; +ALTER TABLE `cloud`.`network_acl_item_cidrs` DROP INDEX `id` ; +ALTER TABLE `cloud`.`network_offerings` DROP INDEX `id` ; +ALTER TABLE `cloud`.`nic_secondary_ips` DROP INDEX `id` ; +ALTER TABLE `cloud`.`nics` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_ha_work` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_host` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_host_transfer` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_networks` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_nwgrp_work` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_vm_ruleset_log` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_vpc_distributed_router_sequence_no` DROP INDEX `id` ; +ALTER TABLE `cloud`.`pod_vlan_map` DROP INDEX `id` ; +ALTER TABLE `cloud`.`portable_ip_address` DROP INDEX `id` ; +ALTER TABLE `cloud`.`portable_ip_range` DROP INDEX `id` ; +ALTER TABLE `cloud`.`region` DROP INDEX `id` ; +ALTER TABLE `cloud`.`remote_access_vpn` DROP INDEX `id` ; +ALTER TABLE `cloud`.`snapshot_details` DROP INDEX `id` ; +ALTER TABLE `cloud`.`snapshots` DROP INDEX `id` ; +ALTER TABLE `cloud`.`storage_pool` DROP INDEX `id` ; +ALTER TABLE `cloud`.`storage_pool_details` DROP INDEX `id` ; +ALTER TABLE `cloud`.`storage_pool_work` DROP INDEX `id` ; +ALTER TABLE `cloud`.`user_ip_address` DROP INDEX `id` ; +ALTER TABLE `cloud`.`user_ipv6_address` DROP INDEX `id` ; +ALTER TABLE `cloud`.`user_statistics` DROP INDEX `id` ; +ALTER TABLE `cloud`.`version` DROP INDEX `id` ; +ALTER TABLE `cloud`.`vlan` DROP INDEX `id` ; +ALTER TABLE `cloud`.`vm_disk_statistics` DROP INDEX `id` ; +ALTER TABLE `cloud`.`vm_snapshot_details` DROP INDEX `id` ; +ALTER TABLE `cloud`.`vm_work_job` DROP INDEX `id` ; +ALTER TABLE `cloud`.`vpc_gateways` DROP INDEX `id` ; +ALTER TABLE `cloud`.`vpn_users` DROP INDEX `id` ; + + diff --git a/setup/db/db/schema-481to490.sql b/setup/db/db/schema-481to490.sql index b9a8b2fb93..a02615ffa7 100644 --- a/setup/db/db/schema-481to490.sql +++ b/setup/db/db/schema-481to490.sql @@ -413,3 +413,26 @@ VIEW `user_vm_view` AS -- Add cluster.storage.operations.exclude property INSERT INTO `cloud`.`configuration` (`category`, `instance`, `component`, `name`, `description`, `default_value`, `updated`, `scope`, `is_dynamic`) VALUES ('Advanced', 'DEFAULT', 'CapacityManager', 'cluster.storage.operations.exclude', 'Exclude cluster from storage operations', 'false', now(), 'Cluster', '1'); + +----- 3) Missing indexes (Add indexes to avoid full table scans) +ALTER TABLE `cloud`.`op_it_work` ADD INDEX `i_type_and_updated` (`type` ASC, `updated_at` ASC); +ALTER TABLE `cloud`.`vm_root_disk_tags` ADD INDEX `i_vm_id` (`vm_id` ASC); +ALTER TABLE `cloud`.`vm_compute_tags` ADD INDEX `i_vm_id` (`vm_id` ASC); +ALTER TABLE `cloud`.`vm_network_map` ADD INDEX `i_vm_id` (`vm_id` ASC); +ALTER TABLE `cloud`.`ssh_keypairs` ADD INDEX `i_public_key` (`public_key` (64) ASC); +ALTER TABLE `cloud`.`user_vm_details` ADD INDEX `i_name_vm_id` (`vm_id` ASC, `name` ASC); +ALTER TABLE `cloud`.`instance_group` ADD INDEX `i_name` (`name` ASC); + +----- 4) Some views query (Change view to improve account retrieval speed) +CREATE OR REPLACE +VIEW `account_vmstats_view` AS + SELECT + `vm_instance`.`account_id` AS `account_id`, + `vm_instance`.`state` AS `state`, + COUNT(0) AS `vmcount` + FROM + `vm_instance` + WHERE + (`vm_instance`.`vm_type` = 'User' and `vm_instance`.`removed` is NULL) + GROUP BY `vm_instance`.`account_id` , `vm_instance`.`state`; +-- End CLOUDSTACK-9340 From 92e3ba2053a6785c8e9c029f5a4f267a592ed380 Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Tue, 10 Nov 2015 09:04:48 +0100 Subject: [PATCH 133/203] CLOUDSTACK-8818: Use MySQL native connector with Python MySQLdb has been deprecated and is also not supported in Python 3. mysql.connector is a connector written in Python which talks the native MySQL protocol without any external code. https://dev.mysql.com/doc/connector-python/en/ --- .../bindir/cloud-update-xenserver-licenses.in | 4 +- debian/control | 4 +- packaging/centos63/cloud.spec | 4 +- packaging/centos7/cloud.spec | 4 +- packaging/fedora20/cloud.spec | 4 +- packaging/fedora21/cloud.spec | 4 +- python/lib/cloudutils/db.py | 45 +++++++++---------- setup/bindir/cloud-migrate-databases.in | 8 ++-- 8 files changed, 38 insertions(+), 39 deletions(-) diff --git a/client/bindir/cloud-update-xenserver-licenses.in b/client/bindir/cloud-update-xenserver-licenses.in index c64bc8f7c0..9db50781c2 100755 --- a/client/bindir/cloud-update-xenserver-licenses.in +++ b/client/bindir/cloud-update-xenserver-licenses.in @@ -24,7 +24,7 @@ import glob from random import choice import string from optparse import OptionParser -import MySQLdb +import mysql.connector import paramiko from threading import Thread @@ -59,7 +59,7 @@ parser.add_option("-a", "--all", action="store_true", dest="all", default=False, def e(msg): parser.error(msg) def getknownhosts(host,username,password): - conn = MySQLdb.connect(host=host,user=username,passwd=password) + conn = mysql.connector.connect(host=host, user=username, password=password) cur = conn.cursor() cur.execute("SELECT h.private_ip_address,d.value FROM cloud.host h inner join cloud.host_details d on (h.id = d.host_id) where d.name = 'username' and setup = 1") usernames = dict(cur.fetchall()) diff --git a/debian/control b/debian/control index 6c101ce137..05058a8dcf 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Section: libs Priority: extra Maintainer: Wido den Hollander Build-Depends: debhelper (>= 9), openjdk-8-jdk | openjdk-7-jdk, genisoimage, - python-mysqldb, maven (>= 3) | maven3, python (>= 2.7) + python-mysql.connector, maven (>= 3) | maven3, python (>= 2.7) Standards-Version: 3.8.1 Homepage: http://www.cloudstack.org/ @@ -15,7 +15,7 @@ Description: A common package which contains files which are shared by several C Package: cloudstack-management Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, cloudstack-common (= ${source:Version}), tomcat6, sudo, jsvc, python-mysqldb, libmysql-java, augeas-tools, mysql-client, adduser, bzip2 +Depends: ${misc:Depends}, ${python:Depends}, cloudstack-common (= ${source:Version}), tomcat6, sudo, jsvc, python-mysql.connector, libmysql-java, augeas-tools, mysql-client, adduser, bzip2 Conflicts: cloud-server, cloud-client, cloud-client-ui Description: CloudStack server library The CloudStack management server diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index b000bd1926..99e37a3325 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -50,7 +50,7 @@ BuildRequires: jpackage-utils BuildRequires: gcc BuildRequires: glibc-devel BuildRequires: /usr/bin/mkisofs -BuildRequires: MySQL-python +BuildRequires: mysql-connector-python #BuildRequires: maven => 3.0.0 %description @@ -79,7 +79,7 @@ Requires: /sbin/service Requires: /sbin/chkconfig Requires: /usr/bin/ssh-keygen Requires: mkisofs -Requires: MySQL-python +Requires: mysql-connector-python Requires: python-paramiko Requires: ipmitool Requires: %{name}-common = %{_ver} diff --git a/packaging/centos7/cloud.spec b/packaging/centos7/cloud.spec index e94ef655c9..ae26c059dd 100644 --- a/packaging/centos7/cloud.spec +++ b/packaging/centos7/cloud.spec @@ -50,7 +50,7 @@ BuildRequires: jpackage-utils BuildRequires: gcc BuildRequires: glibc-devel BuildRequires: /usr/bin/mkisofs -BuildRequires: MySQL-python +BuildRequires: mysql-connector-python BuildRequires: maven => 3.0.0 %description @@ -79,7 +79,7 @@ Requires: /sbin/service Requires: /sbin/chkconfig Requires: /usr/bin/ssh-keygen Requires: mkisofs -Requires: MySQL-python +Requires: mysql-connector-python Requires: ipmitool Requires: %{name}-common = %{_ver} Requires: iptables-services diff --git a/packaging/fedora20/cloud.spec b/packaging/fedora20/cloud.spec index 93cf1863e6..704e4f79c4 100644 --- a/packaging/fedora20/cloud.spec +++ b/packaging/fedora20/cloud.spec @@ -50,7 +50,7 @@ BuildRequires: jpackage-utils BuildRequires: gcc BuildRequires: glibc-devel BuildRequires: /usr/bin/mkisofs -BuildRequires: MySQL-python +BuildRequires: mysql-connector-python #BuildRequires: maven => 3.0.0 %description @@ -79,7 +79,7 @@ Requires: /sbin/service Requires: /sbin/chkconfig Requires: /usr/bin/ssh-keygen Requires: mkisofs -Requires: MySQL-python +Requires: mysql-connector-python Requires: python-paramiko Requires: ipmitool Requires: %{name}-common = %{_ver} diff --git a/packaging/fedora21/cloud.spec b/packaging/fedora21/cloud.spec index e089b120d0..2314ef2fdc 100644 --- a/packaging/fedora21/cloud.spec +++ b/packaging/fedora21/cloud.spec @@ -50,7 +50,7 @@ BuildRequires: jpackage-utils BuildRequires: gcc BuildRequires: glibc-devel BuildRequires: /usr/bin/mkisofs -BuildRequires: MySQL-python +BuildRequires: mysql-connector-python #BuildRequires: maven => 3.0.0 %description @@ -79,7 +79,7 @@ Requires: /sbin/service Requires: /sbin/chkconfig Requires: /usr/bin/ssh-keygen Requires: mkisofs -Requires: MySQL-python +Requires: mysql-connector-python Requires: python-paramiko Requires: ipmitool Requires: %{name}-common = %{_ver} diff --git a/python/lib/cloudutils/db.py b/python/lib/cloudutils/db.py index 8fe3195599..f2ce6f9b50 100644 --- a/python/lib/cloudutils/db.py +++ b/python/lib/cloudutils/db.py @@ -5,21 +5,21 @@ # 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. -import MySQLdb import os from utilities import bash from cloudException import CloudRuntimeException -import sys -class Database: +import mysql.connector + +class Database(object): """Database connection""" def __init__(self, username, password=None, host='localhost', port='3306', db="cloud"): self.host = host @@ -28,15 +28,16 @@ def __init__(self, username, password=None, host='localhost', port='3306', db="c self.port = port self.db = db + def connect(self): + return mysql.connector.connect(host=self.host, + user=self.username, + password=self.password, + database=self.db) + def execute(self, statement): txn = None try: - if self.password is not None: - txn = MySQLdb.Connect(host=self.host, user=self.username, - passwd=self.password, db=self.db) - else: - txn = MySQLdb.Connect(host=self.host, user=self.username, - db=self.db) + txn = self.connect() cursor = txn.cursor() cursor.execute(statement) cursor.close() @@ -47,35 +48,33 @@ def execute(self, statement): except: pass except: + raise CloudRuntimeException("Failed to execute: %s " % statement) + finally: if txn is not None: try: txn.close() except: pass - raise CloudRuntimeException("Failed to execute:%s"%statement) - + def testConnection(self): try: - if self.password is not None: - db = MySQLdb.Connect(host=self.host, user=self.username, - passwd=self.password, db=self.db) - else: - db = MySQLdb.Connect(host=self.host, user=self.username, - db=self.db) + conn = self.connect() + conn.ping() + conn.close() return True except: raise CloudRuntimeException("Failed to Connect to DB") - + def executeFromFile(self, file): if not os.path.exists(file): return False - + cmdLine = "mysql --host=" + self.host + " --port=" + str(self.port) + " --user=" + self.username if self.password is not None: cmdLine += " --password=" + self.password - + cmdLine += " < " + file - + try: bash(cmdLine) except: diff --git a/setup/bindir/cloud-migrate-databases.in b/setup/bindir/cloud-migrate-databases.in index 58a02d5cdf..513e60b75d 100644 --- a/setup/bindir/cloud-migrate-databases.in +++ b/setup/bindir/cloud-migrate-databases.in @@ -20,7 +20,7 @@ import os,logging,sys from optparse import OptionParser -import MySQLdb +import mysql.connector import subprocess import glob @@ -72,10 +72,10 @@ class CloudContext(cloud_utils.MigrationContext): self.database = database self.configdir = configdir self.resourcedir = resourcedir - self.conn = MySQLdb.connect(host=self.host, + self.conn = mysql.connector.connect(host=self.host, user=self.username, - passwd=self.password, - db=self.database, + password=self.password, + database=self.database, port=self.port) self.conn.autocommit(False) self.db = self.conn.cursor() From ea22869593f68a3a34b12aeb23c2bb6c34efd365 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 5 May 2016 23:19:33 +0530 Subject: [PATCH 134/203] CLOUDSTACK-9348: Optimize NioTest and NioConnection main loop - Reduces SSL handshake timeout to 15s, previously this was only 10s in commit debfcdef788ce0d51be06db0ef10f6815f9b563b - Adds an aggresive explicit wakeup to save the Nio main IO loop/handler from getting blocked - Fix NioTest to fail/succeed in about 60s, previously this was 300s - Due to aggresive wakeup usage, NioTest should complete in less than 5s on most systems. On virtualized environment this may slightly increase due to thread, CPU burst/scheduling delays. Signed-off-by: Rohit Yadav --- .../main/java/com/cloud/utils/nio/Link.java | 4 ++-- .../com/cloud/utils/nio/NioConnection.java | 2 ++ .../com/cloud/utils/testcase/NioTest.java | 23 +++++++++++-------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/utils/src/main/java/com/cloud/utils/nio/Link.java b/utils/src/main/java/com/cloud/utils/nio/Link.java index f297d52c07..da2c0d54e8 100644 --- a/utils/src/main/java/com/cloud/utils/nio/Link.java +++ b/utils/src/main/java/com/cloud/utils/nio/Link.java @@ -596,8 +596,8 @@ public static boolean doHandshake(final SocketChannel socketChannel, final SSLEn while (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { final long timeTaken = System.currentTimeMillis() - startTimeMills; - if (timeTaken > 60000L) { - s_logger.warn("SSL Handshake has taken more than 60s to connect to: " + socketChannel.getRemoteAddress() + + if (timeTaken > 15000L) { + s_logger.warn("SSL Handshake has taken more than 15s to connect to: " + socketChannel.getRemoteAddress() + ". Please investigate this connection."); return false; } diff --git a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java index 6fdb4736ac..749e552c2c 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java @@ -171,6 +171,8 @@ public Boolean call() throws NioConnectionException { } catch (final IOException e) { s_logger.error("Agent will die due to this IOException!", e); throw new NioConnectionException(e.getMessage(), e); + } finally { + _selector.wakeup(); } } _isStartup = false; diff --git a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java index 20c31e21b1..446b1e2fbf 100644 --- a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java +++ b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java @@ -61,9 +61,9 @@ public class NioTest { private static final Logger LOGGER = Logger.getLogger(NioTest.class); // Test should fail in due time instead of looping forever - private static final int TESTTIMEOUT = 300000; + private static final int TESTTIMEOUT = 60000; - final private int totalTestCount = 5; + final private int totalTestCount = 4; private int completedTestCount = 0; private NioServer server; @@ -71,7 +71,7 @@ public class NioTest { private List maliciousClients = new ArrayList<>(); private ExecutorService clientExecutor = Executors.newFixedThreadPool(totalTestCount, new NamedThreadFactory("NioClientHandler"));; - private ExecutorService maliciousExecutor = Executors.newFixedThreadPool(5*totalTestCount, new NamedThreadFactory("MaliciousNioClientHandler"));; + private ExecutorService maliciousExecutor = Executors.newFixedThreadPool(totalTestCount, new NamedThreadFactory("MaliciousNioClientHandler"));; private Random randomGenerator = new Random(); private byte[] testBytes; @@ -105,12 +105,18 @@ public void setUp() { Assert.fail(e.getMessage()); } + /** + * The malicious client(s) tries to block NioServer's main IO loop + * thread until SSL handshake timeout value (from Link class, 15s) after + * which the valid NioClient(s) get the opportunity to make connection(s) + */ + for (int i = 0; i < totalTestCount; i++) { + final NioClient maliciousClient = new NioMaliciousClient("NioMaliciousTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioMaliciousTestClient()); + maliciousClients.add(maliciousClient); + maliciousExecutor.submit(new ThreadedNioClient(maliciousClient)); + } + for (int i = 0; i < totalTestCount; i++) { - for (int j = 0; j < 4; j++) { - final NioClient maliciousClient = new NioMaliciousClient("NioMaliciousTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioMaliciousTestClient()); - maliciousClients.add(maliciousClient); - maliciousExecutor.submit(new ThreadedNioClient(maliciousClient)); - } final NioClient client = new NioClient("NioTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioTestClient()); clients.add(client); clientExecutor.submit(new ThreadedNioClient(client)); @@ -286,7 +292,6 @@ public void doTask(final Task task) { LOGGER.info("Server: Received OTHER task"); } } - } } } From baa861006127daf0da7d762a2913cd6b9c458588 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Tue, 12 Apr 2016 10:57:55 -0700 Subject: [PATCH 135/203] CLOUDSTACK-9351: Add ids parameter to resource listing API calls --- .../apache/cloudstack/api/ApiConstants.java | 1 + .../user/snapshot/ListSnapshotsCmd.java | 7 ++ .../user/template/ListTemplatesCmd.java | 8 ++ .../user/vmsnapshot/ListVMSnapshotCmd.java | 7 ++ .../command/user/volume/ListVolumesCmd.java | 8 ++ .../query/MutualExclusiveIdsManagerBase.java | 62 +++++++++++ .../com/cloud/api/query/QueryManagerImpl.java | 21 +++- .../storage/snapshot/SnapshotManagerImpl.java | 9 +- .../vm/snapshot/VMSnapshotManagerImpl.java | 9 +- .../MutualExclusiveIdsManagerBaseTest.java | 102 ++++++++++++++++++ 10 files changed, 225 insertions(+), 9 deletions(-) create mode 100755 server/src/com/cloud/api/query/MutualExclusiveIdsManagerBase.java create mode 100755 server/test/com/cloud/api/query/MutualExclusiveIdsManagerBaseTest.java diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index ef4ff9a0fe..6f3152b75a 100644 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -551,6 +551,7 @@ public class ApiConstants { public static final String VM_SNAPSHOT_DESCRIPTION = "description"; public static final String VM_SNAPSHOT_DISPLAYNAME = "name"; public static final String VM_SNAPSHOT_ID = "vmsnapshotid"; + public static final String VM_SNAPSHOT_IDS = "vmsnapshotids"; public static final String VM_SNAPSHOT_DISK_IDS = "vmsnapshotdiskids"; public static final String VM_SNAPSHOT_MEMORY = "snapshotmemory"; public static final String VM_SNAPSHOT_QUIESCEVM = "quiescevm"; diff --git a/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java b/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java index 47a6876d09..97bb187dd5 100644 --- a/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java @@ -48,6 +48,9 @@ public class ListSnapshotsCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = SnapshotResponse.class, description = "lists snapshot by snapshot ID") private Long id; + @Parameter(name=ApiConstants.IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=SnapshotResponse.class, description="the IDs of the snapshots, mutually exclusive with id", since = "4.9") + private List ids; + @Parameter(name = ApiConstants.INTERVAL_TYPE, type = CommandType.STRING, description = "valid values are HOURLY, DAILY, WEEKLY, and MONTHLY.") private String intervalType; @@ -120,4 +123,8 @@ public void execute() { setResponseObject(response); } + + public List getIds() { + return ids; + } } diff --git a/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java index 7a2a15834a..772ca2749e 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java @@ -18,6 +18,7 @@ import org.apache.log4j.Logger; +import java.util.List; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandJobType; import org.apache.cloudstack.api.ApiConstants; @@ -50,6 +51,9 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = TemplateResponse.class, description = "the template ID") private Long id; + @Parameter(name=ApiConstants.IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=TemplateResponse.class, description="the IDs of the templates, mutually exclusive with id", since = "4.9") + private List ids; + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the template name") private String templateName; @@ -132,4 +136,8 @@ public void execute() { response.setResponseName(getCommandName()); setResponseObject(response); } + + public List getIds() { + return ids; + } } diff --git a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java index c9bc2430d2..ad5126e468 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java @@ -39,6 +39,9 @@ public class ListVMSnapshotCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.VM_SNAPSHOT_ID, type = CommandType.UUID, entityType = VMSnapshotResponse.class, description = "The ID of the VM snapshot") private Long id; + @Parameter(name=ApiConstants.VM_SNAPSHOT_IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=VMSnapshotResponse.class, description="the IDs of the vm snapshots, mutually exclusive with vmsnapshotid", since = "4.9") + private List ids; + @Parameter(name = ApiConstants.STATE, type = CommandType.STRING, description = "state of the virtual machine snapshot") private String state; @@ -84,4 +87,8 @@ public String getCommandName() { return s_name; } + public List getIds() { + return ids; + } + } diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java index cc218f7197..059def7c16 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java @@ -18,6 +18,7 @@ import org.apache.log4j.Logger; +import java.util.List; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandJobType; @@ -53,6 +54,9 @@ public class ListVolumesCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = VolumeResponse.class, description = "the ID of the disk volume") private Long id; + @Parameter(name=ApiConstants.IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=VolumeResponse.class, description="the IDs of the volumes, mutually exclusive with id", since = "4.9") + private List ids; + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the name of the disk volume") private String volumeName; @@ -153,4 +157,8 @@ public void execute() { response.setResponseName(getCommandName()); setResponseObject(response); } + + public List getIds() { + return ids; + } } diff --git a/server/src/com/cloud/api/query/MutualExclusiveIdsManagerBase.java b/server/src/com/cloud/api/query/MutualExclusiveIdsManagerBase.java new file mode 100755 index 0000000000..c7b32225b5 --- /dev/null +++ b/server/src/com/cloud/api/query/MutualExclusiveIdsManagerBase.java @@ -0,0 +1,62 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +package com.cloud.api.query; + +import java.util.ArrayList; +import java.util.List; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.SearchCriteria; + +public class MutualExclusiveIdsManagerBase extends ManagerBase { + + /*** + * Include ids list in query criteria if ids is not null + * @param sc search criteria, class type SearchCriteria + * @param ids ids list, class type List + */ + protected void setIdsListToSearchCriteria(SearchCriteria sc, List ids){ + if (ids != null && !ids.isEmpty()) { + sc.setParameters("idIN", ids.toArray()); + } + } + + /*** + * Mutually exclusive parameters id and ids for API calls.
+ * Retrieve a list of ids or a list containing id depending on which of them is not null, or null if both are null + * @param id entity id, class type T + * @param ids entities ids, class type List + * @return if id is not null return a list containing id else return ids, if both parameters are null -> return null + * @throws InvalidParameterValueException - if id and ids are both not null + */ + protected List getIdsListFromCmd(T id, List ids){ + List idsList = null; + if (id != null) { + if (ids != null && !ids.isEmpty()) { + throw new InvalidParameterValueException("Specify either id or ids but not both parameters"); + } + idsList = new ArrayList(); + idsList.add(id); + } else { + idsList = ids; + } + return idsList; + } +} diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 94929577a3..781b1959ad 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -205,7 +205,6 @@ import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; import com.cloud.utils.Ternary; -import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; @@ -222,7 +221,7 @@ import com.cloud.vm.dao.VMInstanceDao; @Component -public class QueryManagerImpl extends ManagerBase implements QueryService, Configurable { +public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements QueryService, Configurable { public static final Logger s_logger = Logger.getLogger(QueryManagerImpl.class); @@ -1731,6 +1730,8 @@ private Pair, Integer> searchForVolumesInternal(ListVolumesCm Long zoneId = cmd.getZoneId(); Long podId = cmd.getPodId(); + List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); + Ternary domainIdRecursiveListProject = new Ternary( cmd.getDomainId(), cmd.isRecursive(), null); _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, @@ -1754,6 +1755,7 @@ private Pair, Integer> searchForVolumesInternal(ListVolumesCm sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ); sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); sb.and("volumeType", sb.entity().getVolumeType(), SearchCriteria.Op.LIKE); sb.and("instanceId", sb.entity().getVmId(), SearchCriteria.Op.EQ); sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); @@ -1790,6 +1792,8 @@ private Pair, Integer> searchForVolumesInternal(ListVolumesCm sc.setParameters("display", display); } + setIdsListToSearchCriteria(sc, ids); + sc.setParameters("systemUse", 1); if (tags != null && !tags.isEmpty()) { @@ -3077,14 +3081,15 @@ private Pair, Integer> searchForTemplatesInternal(ListTempl return searchForTemplatesInternal(id, cmd.getTemplateName(), cmd.getKeyword(), templateFilter, false, null, cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), hypervisorType, showDomr, - cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedTmpl); + cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedTmpl, + cmd.getIds()); } private Pair, Integer> searchForTemplatesInternal(Long templateId, String name, String keyword, TemplateFilter templateFilter, boolean isIso, Boolean bootable, Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean showDomr, boolean onlyReady, List permittedAccounts, Account caller, ListProjectResourcesCriteria listProjectResourcesCriteria, - Map tags, boolean showRemovedTmpl) { + Map tags, boolean showRemovedTmpl, List ids) { // check if zone is configured, if not, just return empty list List hypers = null; @@ -3104,6 +3109,9 @@ private Pair, Integer> searchForTemplatesInternal(Long temp SearchBuilder sb = _templateJoinDao.createSearchBuilder(); sb.select(null, Func.DISTINCT, sb.entity().getTempZonePair()); // select distinct (templateId, zoneId) pair + if (ids != null && !ids.isEmpty()){ + sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); + } SearchCriteria sc = sb.create(); // verify templateId parameter and specially handle it @@ -3149,6 +3157,8 @@ private Pair, Integer> searchForTemplatesInternal(Long temp // hypers = _resourceMgr.listAvailHypervisorInZone(null, null); // } + setIdsListToSearchCriteria(sc, ids); + // add criteria for project or not if (listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources) { sc.addAnd("accountType", SearchCriteria.Op.NEQ, Account.ACCOUNT_TYPE_PROJECT); @@ -3386,7 +3396,8 @@ private Pair, Integer> searchForIsosInternal(ListIsosCmd cm return searchForTemplatesInternal(cmd.getId(), cmd.getIsoName(), cmd.getKeyword(), isoFilter, true, cmd.isBootable(), cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), hypervisorType, true, - cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedISO); + cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedISO, + null); } @Override diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 65f5140418..757ab6110c 100644 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -58,6 +58,7 @@ import com.cloud.agent.api.DeleteSnapshotsDirCommand; import com.cloud.alert.AlertManager; import com.cloud.api.commands.ListRecurringSnapshotScheduleCmd; +import com.cloud.api.query.MutualExclusiveIdsManagerBase; import com.cloud.configuration.Config; import com.cloud.configuration.Resource.ResourceType; import com.cloud.dc.ClusterVO; @@ -112,7 +113,6 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; -import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; @@ -129,7 +129,7 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Component -public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, SnapshotApiService { +public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implements SnapshotManager, SnapshotApiService { private static final Logger s_logger = Logger.getLogger(SnapshotManagerImpl.class); @Inject VMTemplateDao _templateDao; @@ -512,6 +512,8 @@ public Pair, Integer> listSnapshots(ListSnapshotsCmd cm } } + List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); + Ternary domainIdRecursiveListProject = new Ternary(cmd.getDomainId(), cmd.isRecursive(), null); _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); Long domainId = domainIdRecursiveListProject.first(); @@ -526,6 +528,7 @@ public Pair, Integer> listSnapshots(ListSnapshotsCmd cm sb.and("volumeId", sb.entity().getVolumeId(), SearchCriteria.Op.EQ); sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE); sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); sb.and("snapshotTypeEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.IN); sb.and("snapshotTypeNEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.NEQ); sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); @@ -565,6 +568,8 @@ public Pair, Integer> listSnapshots(ListSnapshotsCmd cm sc.setParameters("dataCenterId", zoneId); } + setIdsListToSearchCriteria(sc, ids); + if (name != null) { sc.setParameters("name", "%" + name + "%"); } diff --git a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java index c113e3c920..d8f459627b 100644 --- a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java +++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@ -46,6 +46,7 @@ import org.apache.cloudstack.jobs.JobInfo; import org.apache.cloudstack.utils.identity.ManagementServerNode; +import com.cloud.api.query.MutualExclusiveIdsManagerBase; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; @@ -77,7 +78,6 @@ import com.cloud.utils.Predicate; import com.cloud.utils.ReflectionUse; import com.cloud.utils.Ternary; -import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.EntityManager; import com.cloud.utils.db.Filter; import com.cloud.utils.db.SearchBuilder; @@ -99,7 +99,7 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Component -public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotManager, VMSnapshotService, VmWorkJobHandler { +public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase implements VMSnapshotManager, VMSnapshotService, VmWorkJobHandler { private static final Logger s_logger = Logger.getLogger(VMSnapshotManagerImpl.class); public static final String VM_WORK_JOB_HANDLER = VMSnapshotManagerImpl.class.getSimpleName(); @@ -176,6 +176,8 @@ public List listVMSnapshots(ListVMSnapshotCmd cmd) { String name = cmd.getVmSnapshotName(); String accountName = cmd.getAccountName(); + List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); + Ternary domainIdRecursiveListProject = new Ternary( cmd.getDomainId(), cmd.isRecursive(), null); _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, listAll, @@ -193,6 +195,7 @@ public List listVMSnapshots(ListVMSnapshotCmd cmd) { sb.and("status", sb.entity().getState(), SearchCriteria.Op.IN); sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ); sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); sb.and("display_name", sb.entity().getDisplayName(), SearchCriteria.Op.EQ); sb.and("account_id", sb.entity().getAccountId(), SearchCriteria.Op.EQ); sb.done(); @@ -209,6 +212,8 @@ public List listVMSnapshots(ListVMSnapshotCmd cmd) { sc.setParameters("vm_id", vmId); } + setIdsListToSearchCriteria(sc, ids); + if (domainId != null) { sc.setParameters("domain_id", domainId); } diff --git a/server/test/com/cloud/api/query/MutualExclusiveIdsManagerBaseTest.java b/server/test/com/cloud/api/query/MutualExclusiveIdsManagerBaseTest.java new file mode 100755 index 0000000000..a4d92614b3 --- /dev/null +++ b/server/test/com/cloud/api/query/MutualExclusiveIdsManagerBaseTest.java @@ -0,0 +1,102 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +package com.cloud.api.query; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.never; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.db.SearchCriteria; + +@RunWith(MockitoJUnitRunner.class) +public class MutualExclusiveIdsManagerBaseTest { + + @Mock + SearchCriteria sc; + + private static Long id1 = 1L; + private static Long id2 = 2L; + + private List idsList; + private List idsEmptyList; + private List expectedListId; + private List expectedListIds; + + private MutualExclusiveIdsManagerBase mgr = new MutualExclusiveIdsManagerBase(); + + @Before + public void setup() { + idsList = Arrays.asList(id1, id2); + idsEmptyList = Arrays.asList(); + expectedListId = Arrays.asList(id1); + expectedListIds = Arrays.asList(id1, id2); + } + + @Test + public void testSetIdsListToSearchCriteria(){ + mgr.setIdsListToSearchCriteria(sc, idsList); + Mockito.verify(sc).setParameters(Mockito.same("idIN"), Mockito.same(id1), Mockito.same(id2)); + } + + @Test + public void testSetIdsListToSearchCriteriaEmptyList(){ + mgr.setIdsListToSearchCriteria(sc, idsEmptyList); + Mockito.verify(sc, never()).setParameters(Mockito.anyString(), Mockito.any()); + } + + @Test + public void testGetIdsListId(){ + List result = mgr.getIdsListFromCmd(id1, idsEmptyList); + assertEquals(expectedListId, result); + } + + @Test + public void testGetIdsListProvideList(){ + List result = mgr.getIdsListFromCmd(null, idsList); + assertEquals(expectedListIds, result); + } + + @Test(expected=InvalidParameterValueException.class) + public void testGetIdsListBothNotNull(){ + mgr.getIdsListFromCmd(id1, idsList); + } + + @Test + public void testGetIdsListBothNull(){ + List result = mgr.getIdsListFromCmd(null, null); + assertNull(result); + } + + @Test + public void testGetIdsEmptyListIdNull(){ + List result = mgr.getIdsListFromCmd(null, idsEmptyList); + assertEquals(idsEmptyList, result); + } +} From 417d9a5d800facc48b6df46ada2e73223a16b5dd Mon Sep 17 00:00:00 2001 From: weingartner Date: Wed, 4 May 2016 15:27:17 -0300 Subject: [PATCH 136/203] =?UTF-8?q?Removed=20unnecessary=20check=20when=20?= =?UTF-8?q?creating=20the=20=E2=80=9CuserVmResponse=E2=80=9D=20object.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/query/dao/UserVmJoinDaoImpl.java | 31 ++++++------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java index 552200bc29..106cd25a5b 100644 --- a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java @@ -27,9 +27,6 @@ import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.ApiConstants.VMDetails; import org.apache.cloudstack.api.ResponseObject.ResponseView; @@ -38,11 +35,12 @@ import org.apache.cloudstack.api.response.SecurityGroupResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.api.ApiDBUtils; import com.cloud.api.query.vo.UserVmJoinVO; import com.cloud.gpu.GPU; -import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.service.ServiceOfferingDetailsVO; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -200,27 +198,16 @@ public UserVmResponse newUserVmResponse(ResponseView view, String objectName, Us VmStats vmStats = ApiDBUtils.getVmStatistics(userVm.getId()); if (vmStats != null) { userVmResponse.setCpuUsed(new DecimalFormat("#.##").format(vmStats.getCPUUtilization()) + "%"); - userVmResponse.setNetworkKbsRead((long)vmStats.getNetworkReadKBs()); - userVmResponse.setNetworkKbsWrite((long)vmStats.getNetworkWriteKBs()); + userVmResponse.setDiskKbsRead((long)vmStats.getDiskReadKBs()); + userVmResponse.setDiskKbsWrite((long)vmStats.getDiskWriteKBs()); + userVmResponse.setDiskIORead((long)vmStats.getDiskReadIOs()); + userVmResponse.setDiskIOWrite((long)vmStats.getDiskWriteIOs()); + userVmResponse.setMemoryKBs((long)vmStats.getMemoryKBs()); + userVmResponse.setMemoryIntFreeKBs((long)vmStats.getIntFreeMemoryKBs()); + userVmResponse.setMemoryTargetKBs((long)vmStats.getTargetMemoryKBs()); - if ((userVm.getHypervisorType() != null) && (userVm.getHypervisorType().equals(HypervisorType.KVM) || userVm.getHypervisorType().equals(HypervisorType.XenServer) || userVm.getHypervisorType().equals(HypervisorType.VMware))) { // support KVM and XenServer only util 2013.06.25 . supporting Vmware from 2015.09.02 - userVmResponse.setDiskKbsRead((long)vmStats.getDiskReadKBs()); - - userVmResponse.setDiskKbsWrite((long) vmStats.getDiskWriteKBs()); - - userVmResponse.setDiskIORead((long) vmStats.getDiskReadIOs()); - - userVmResponse.setDiskIOWrite((long) vmStats.getDiskWriteIOs()); - - userVmResponse.setMemoryKBs((long) vmStats.getMemoryKBs()); - - userVmResponse.setMemoryIntFreeKBs((long) vmStats.getIntFreeMemoryKBs()); - - userVmResponse.setMemoryTargetKBs((long) vmStats.getTargetMemoryKBs()); - - } } } From eeb3373e412ab5cc5464709a01412e5cfc82636e Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Mon, 2 May 2016 22:38:55 -0600 Subject: [PATCH 137/203] Replace a timer.sleep(30) with pulling logic --- tools/marvin/marvin/codes.py | 25 +++++++++++++++++++++++ tools/marvin/marvin/lib/base.py | 36 +++++++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/tools/marvin/marvin/codes.py b/tools/marvin/marvin/codes.py index c81e7e901a..e23069bf94 100644 --- a/tools/marvin/marvin/codes.py +++ b/tools/marvin/marvin/codes.py @@ -115,6 +115,31 @@ ''' ALLOCATED = "Allocated" +''' +Host states +''' +HOST_CREATING = "Creating" +HOST_CONNECTING = "Connecting" +HOST_UP = "Up" +HOST_DOWN = "Down" +HOST_DISCONNECTED = "Disconnected" +HOST_ALERT = "Alert" +HOST_REMOVED = "Removed" +HOST_ERROR = "Error" +HOST_REBALANCING = "Rebalancing" +HOST_UNKNOWN = "Unknown" + +''' +Host resource states +''' +HOST_RS_CREATING = "Creating" +HOST_RS_ENABLED = "Enabled" +HOST_RS_DISABLED = "Disabled" +HOST_RS_PREPARE_FOR_MAINTENANCE = "PrepareForMaintenance" +HOST_RS_ERROR_IN_MAINTENANCE = "ErrorInMaintenance" +HOST_RS_MAINTENANCE = "Maintenance" +HOST_RS_ERROR = "Error" + ''' Storage Tags ''' diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index 906fb57695..93923ad80e 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -23,9 +23,10 @@ from marvin.cloudstackAPI import * from marvin.codes import (FAILED, FAIL, PASS, RUNNING, STOPPED, STARTING, DESTROYED, EXPUNGING, - STOPPING, BACKED_UP, BACKING_UP) + STOPPING, BACKED_UP, BACKING_UP, + HOST_RS_MAINTENANCE) from marvin.cloudstackException import GetDetailExceptionInfo, CloudstackAPIException -from marvin.lib.utils import validateList, is_server_ssh_ready, random_gen +from marvin.lib.utils import validateList, is_server_ssh_ready, random_gen, wait_until # Import System modules import time import hashlib @@ -2459,13 +2460,40 @@ def create(cls, apiclient, cluster, services, zoneid=None, podid=None, hyperviso GetDetailExceptionInfo(e) return FAILED + @staticmethod + def _check_resource_state(apiclient, hostid, resourcestate): + hosts = Host.list(apiclient, id=hostid, listall=True) + + validationresult = validateList(hosts) + + assert validationresult is not None, "'validationresult' should not be equal to 'None'." + + assert isinstance(validationresult, list), "'validationresult' should be a 'list'." + + assert len(validationresult) == 3, "'validationresult' should be a list with three items in it." + + if validationresult[0] == FAIL: + raise Exception("Host list validation failed: %s" % validationresult[2]) + + if str(hosts[0].resourcestate).lower().decode("string_escape") == str(resourcestate).lower(): + return True, None + + return False, "Host is not in the following state: " + str(resourcestate) + def delete(self, apiclient): """Delete Host""" # Host must be in maintenance mode before deletion cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() cmd.id = self.id apiclient.prepareHostForMaintenance(cmd) - time.sleep(30) + + retry_interval = 10 + num_tries = 10 + + wait_result, return_val = wait_until(retry_interval, num_tries, Host._check_resource_state, apiclient, self.id, HOST_RS_MAINTENANCE) + + if not wait_result: + raise Exception(return_val) cmd = deleteHost.deleteHostCmd() cmd.id = self.id @@ -2711,7 +2739,7 @@ def getState(cls, apiclient, poolid, state, timeout=600): id=poolid, listAll=True) validationresult = validateList(pools) if validationresult[0] == FAIL: - raise Exception("Host list validation failed: %s" % validationresult[2]) + raise Exception("Pool list validation failed: %s" % validationresult[2]) elif str(pools[0].state).lower().decode("string_escape") == str(state).lower(): returnValue = [PASS, None] break From 7b5d5648d80a603d68a1232f663127819799c89a Mon Sep 17 00:00:00 2001 From: Syed Date: Thu, 25 Feb 2016 16:29:58 -0500 Subject: [PATCH 138/203] Fix create template from snapshot returning null in case of region store --- .../src/com/cloud/api/ApiResponseHelper.java | 2 +- .../cloud/template/TemplateManagerImpl.java | 14 ++- .../template/TemplateManagerImplTest.java | 85 +++++++++++++++++++ 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 1c256440d4..74649d7546 100644 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -1388,7 +1388,7 @@ public TemplateResponse createTemplateUpdateResponse(ResponseView view, VirtualM @Override public List createTemplateResponses(ResponseView view, VirtualMachineTemplate result, Long zoneId, boolean readyOnly) { List tvo = null; - if (zoneId == null || zoneId == -1) { + if (zoneId == null || zoneId == -1 || result.isCrossZones()) { tvo = ApiDBUtils.newTemplateView(result); } else { tvo = ApiDBUtils.newTemplateView(result, zoneId, readyOnly); diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 6a8c3b6142..17c103d6de 100644 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -40,6 +40,8 @@ import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd; import org.apache.cloudstack.api.response.GetUploadParamsResponse; import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; @@ -262,7 +264,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, private UserVmJoinDao _userVmJoinDao; @Inject private SnapshotDataStoreDao _snapshotStoreDao; - + @Inject + private ImageStoreDao _imgStoreDao; @Inject MessageBus _messageBus; @@ -276,6 +279,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, @Inject private EndPointSelector selector; + private TemplateAdapter getAdapter(HypervisorType type) { TemplateAdapter adapter = null; if (type == HypervisorType.BareMetal) { @@ -1705,6 +1709,14 @@ public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account t s_logger.debug("This template is getting created from other template, setting source template Id to: " + sourceTemplateId); } } + + + // for region wide storage, set cross zones flag + List stores = _imgStoreDao.findRegionImageStores(); + if (!CollectionUtils.isEmpty(stores)) { + privateTemplate.setCrossZones(true); + } + privateTemplate.setSourceTemplateId(sourceTemplateId); VMTemplateVO template = _tmpltDao.persist(privateTemplate); diff --git a/server/test/com/cloud/template/TemplateManagerImplTest.java b/server/test/com/cloud/template/TemplateManagerImplTest.java index ed4ec520a9..6e1693832a 100644 --- a/server/test/com/cloud/template/TemplateManagerImplTest.java +++ b/server/test/com/cloud/template/TemplateManagerImplTest.java @@ -21,13 +21,19 @@ import com.cloud.agent.AgentManager; import com.cloud.api.query.dao.UserVmJoinDao; +import com.cloud.configuration.Resource; import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.dao.DomainDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor; import com.cloud.projects.ProjectManager; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolStatus; @@ -54,6 +60,7 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; @@ -66,6 +73,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; @@ -77,6 +86,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -102,11 +113,13 @@ import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.eq; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class) @@ -133,6 +146,21 @@ public class TemplateManagerImplTest { @Inject PrimaryDataStoreDao primaryDataStoreDao; + @Inject + ResourceLimitService resourceLimitMgr; + + @Inject + ImageStoreDao imgStoreDao; + + @Inject + GuestOSDao guestOSDao; + + @Inject + VMTemplateDao tmpltDao; + + @Inject + SnapshotDao snapshotDao; + public class CustomThreadPoolExecutor extends ThreadPoolExecutor { AtomicInteger ai = new AtomicInteger(0); public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, @@ -357,6 +385,58 @@ public void testTemplateScheduledForDownloadInMultiplePool() { assertTrue("Test template is scheduled for seeding to on pool", ((CustomThreadPoolExecutor) preloadExecutor).getCount() == 2); } + @Test + public void testCreatePrivateTemplateRecordForRegionStore() throws ResourceAllocationException { + + CreateTemplateCmd mockCreateCmd = mock(CreateTemplateCmd.class); + when(mockCreateCmd.getTemplateName()).thenReturn("test"); + when(mockCreateCmd.getTemplateTag()).thenReturn(null); + when(mockCreateCmd.getBits()).thenReturn(64); + when(mockCreateCmd.getRequiresHvm()).thenReturn(true); + when(mockCreateCmd.isPasswordEnabled()).thenReturn(false); + when(mockCreateCmd.isPublic()).thenReturn(false); + when(mockCreateCmd.isFeatured()).thenReturn(false); + when(mockCreateCmd.isDynamicallyScalable()).thenReturn(false); + when(mockCreateCmd.getVolumeId()).thenReturn(null); + when(mockCreateCmd.getSnapshotId()).thenReturn(1L); + when(mockCreateCmd.getOsTypeId()).thenReturn(1L); + when(mockCreateCmd.getEventDescription()).thenReturn("test"); + when(mockCreateCmd.getDetails()).thenReturn(null); + + Account mockTemplateOwner = mock(Account.class); + + SnapshotVO mockSnapshot = mock(SnapshotVO.class); + when(snapshotDao.findById(anyLong())).thenReturn(mockSnapshot); + + when(mockSnapshot.getVolumeId()).thenReturn(1L); + when(mockSnapshot.getState()).thenReturn(Snapshot.State.BackedUp); + when(mockSnapshot.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.XenServer); + + doNothing().when(resourceLimitMgr).checkResourceLimit(any(Account.class), eq(Resource.ResourceType.template)); + doNothing().when(resourceLimitMgr).checkResourceLimit(any(Account.class), eq(Resource.ResourceType.secondary_storage), anyLong()); + + GuestOSVO mockGuestOS = mock(GuestOSVO.class); + when(guestOSDao.findById(anyLong())).thenReturn(mockGuestOS); + + when(tmpltDao.getNextInSequence(eq(Long.class), eq("id"))).thenReturn(1L); + + List mockRegionStores = new ArrayList<>(); + ImageStoreVO mockRegionStore = mock(ImageStoreVO.class); + mockRegionStores.add(mockRegionStore); + when(imgStoreDao.findRegionImageStores()).thenReturn(mockRegionStores); + + when(tmpltDao.persist(any(VMTemplateVO.class))).thenAnswer(new Answer() { + @Override + public VMTemplateVO answer(InvocationOnMock invocationOnMock) throws Throwable { + Object[] args = invocationOnMock.getArguments(); + return (VMTemplateVO)args[0]; + } + }); + + VMTemplateVO template = templateManager.createPrivateTemplateRecord(mockCreateCmd, mockTemplateOwner); + assertTrue("Template in a region store should have cross zones set", template.isCrossZones()); + } + @Configuration @ComponentScan(basePackageClasses = {TemplateManagerImpl.class}, includeFilters = {@ComponentScan.Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM)}, @@ -523,6 +603,11 @@ public SnapshotDataStoreDao snapshotStoreDao() { return Mockito.mock(SnapshotDataStoreDao.class); } + @Bean + public ImageStoreDao imageStoreDao() { + return Mockito.mock(ImageStoreDao.class); + } + @Bean public MessageBus messageBus() { return Mockito.mock(MessageBus.class); From b9d75c6ffaf382468b6a0359ee24bb2915615d9b Mon Sep 17 00:00:00 2001 From: nvazquez Date: Wed, 4 May 2016 16:00:44 -0300 Subject: [PATCH 139/203] CLOUDSTACK-9351: Add marvin test and add it to travis file --- .travis.yml | 2 +- .../smoke/test_list_ids_parameter.py | 295 ++++++++++++++++++ 2 files changed, 296 insertions(+), 1 deletion(-) create mode 100755 test/integration/smoke/test_list_ids_parameter.py diff --git a/.travis.yml b/.travis.yml index 1441fa4871..d160e487aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,7 +37,7 @@ env: - PATH=$HOME/.local/bin:$PATH matrix: - TESTS="smoke/test_affinity_groups smoke/test_affinity_groups_projects smoke/test_deploy_vgpu_enabled_vm smoke/test_deploy_vm_iso smoke/test_deploy_vm_root_resize smoke/test_deploy_vm_with_userdata smoke/test_deploy_vms_with_varied_deploymentplanners smoke/test_disk_offerings smoke/test_global_settings smoke/test_guest_vlan_range" - - TESTS="smoke/test_hosts smoke/test_internal_lb smoke/test_iso smoke/test_loadbalance smoke/test_multipleips_per_nic smoke/test_network smoke/test_network_acl smoke/test_nic smoke/test_nic_adapter_type smoke/test_non_contigiousvlan" + - TESTS="smoke/test_hosts smoke/test_internal_lb smoke/test_iso smoke/test_list_ids_parameter smoke/test_loadbalance smoke/test_multipleips_per_nic smoke/test_network smoke/test_network_acl smoke/test_nic smoke/test_nic_adapter_type smoke/test_non_contigiousvlan" - TESTS="smoke/test_over_provisioning smoke/test_password_server smoke/test_portable_publicip smoke/test_primary_storage smoke/test_privategw_acl smoke/test_public_ip_range smoke/test_pvlan smoke/test_regions smoke/test_reset_vm_on_reboot smoke/test_resource_detail" - TESTS="smoke/test_router_dhcphosts smoke/test_routers smoke/test_routers_iptables_default_policy smoke/test_routers_network_ops smoke/test_scale_vm smoke/test_secondary_storage smoke/test_service_offerings smoke/test_snapshots smoke/test_ssvm smoke/test_templates" - TESTS="smoke/test_usage_events smoke/test_vm_life_cycle smoke/test_vm_snapshots smoke/test_volumes smoke/test_vpc_redundant smoke/test_vpc_router_nics smoke/test_vpc_vpn smoke/misc/test_deploy_vm smoke/misc/test_vm_ha smoke/misc/test_escalations_templates smoke/misc/test_vm_sync" diff --git a/test/integration/smoke/test_list_ids_parameter.py b/test/integration/smoke/test_list_ids_parameter.py new file mode 100755 index 0000000000..be9554bf41 --- /dev/null +++ b/test/integration/smoke/test_list_ids_parameter.py @@ -0,0 +1,295 @@ +# 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. +""" Tests for API listing methods using 'ids' parameter +""" +#Import Local Modules +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.lib.utils import (cleanup_resources, + validateList) +from marvin.lib.base import (Account, + Volume, + DiskOffering, + Template, + ServiceOffering, + Snapshot, + VmSnapshot, + VirtualMachine) +from marvin.lib.common import (get_domain, + get_zone, get_template) +from marvin.codes import FAILED, PASS +from nose.plugins.attrib import attr +#Import System modules +import time + +_multiprocess_shared_ = True +class TestListIdsParams(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + testClient = super(TestListIdsParams, cls).getClsTestClient() + cls.apiclient = testClient.getApiClient() + cls.services = testClient.getParsedTestDataConfig() + cls.hypervisor = testClient.getHypervisorInfo() + cls.domain = get_domain(cls.apiclient) + cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) + + cls.disk_offering = DiskOffering.create( + cls.apiclient, + cls.services["disk_offering"] + ) + + cls.account = Account.create( + cls.apiclient, + cls.services["account"], + domainid=cls.domain.id + ) + cls.service_offering = ServiceOffering.create( + cls.apiclient, + cls.services["service_offerings"]["tiny"] + ) + + template = get_template( + cls.apiclient, + cls.zone.id, + cls.services["ostype"] + ) + if template == FAILED: + assert False, "get_template() failed to return template with description %s" % cls.services["ostype"] + + cls.services["template"]["ostypeid"] = template.ostypeid + cls.services["template_2"]["ostypeid"] = template.ostypeid + cls.services["ostypeid"] = template.ostypeid + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.services["mode"] = cls.zone.networktype + + #Create 3 VMs + cls.virtual_machine_1 = VirtualMachine.create( + cls.apiclient, + cls.services["virtual_machine"], + templateid=template.id, + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering.id, + mode=cls.services["mode"] + ) + cls.virtual_machine_2 = VirtualMachine.create( + cls.apiclient, + cls.services["virtual_machine"], + templateid=template.id, + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering.id, + mode=cls.services["mode"] + ) + cls.virtual_machine_3 = VirtualMachine.create( + cls.apiclient, + cls.services["virtual_machine"], + templateid=template.id, + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering.id, + mode=cls.services["mode"] + ) + + #Take 3 VM1 Snapshots + #PLEASE UNCOMMENT ONCE VM SNAPSHOT DELAY BUG AFTER VM CREATION IS FIXED + """cls.vmsnapshot_1 = VmSnapshot.create( + cls.apiclient, + cls.virtual_machine_1.id + ) + cls.vmsnapshot_2 = VmSnapshot.create( + cls.apiclient, + cls.virtual_machine_1.id + ) + cls.vmsnapshot_3 = VmSnapshot.create( + cls.apiclient, + cls.virtual_machine_1.id + )""" + + #Stop VMs + cls.virtual_machine_1.stop(cls.apiclient) + cls.virtual_machine_2.stop(cls.apiclient) + cls.virtual_machine_3.stop(cls.apiclient) + + #Get ROOT volumes of 3 VMs + vm1RootVolumeResponse = Volume.list( + cls.apiclient, + virtualmachineid=cls.virtual_machine_1.id, + type='ROOT', + listall=True + ) + vm2RootVolumeResponse = Volume.list( + cls.apiclient, + virtualmachineid=cls.virtual_machine_2.id, + type='ROOT', + listall=True + ) + vm3RootVolumeResponse = Volume.list( + cls.apiclient, + virtualmachineid=cls.virtual_machine_3.id, + type='ROOT', + listall=True + ) + cls.vm1_root_volume = vm1RootVolumeResponse[0] + cls.vm2_root_volume = vm2RootVolumeResponse[0] + cls.vm3_root_volume = vm3RootVolumeResponse[0] + + #Take 3 snapshots of VM2's ROOT volume + cls.snapshot_1 = Snapshot.create( + cls.apiclient, + cls.vm2_root_volume.id, + account=cls.account.name, + domainid=cls.account.domainid + ) + cls.snapshot_2 = Snapshot.create( + cls.apiclient, + cls.vm2_root_volume.id, + account=cls.account.name, + domainid=cls.account.domainid + ) + cls.snapshot_3 = Snapshot.create( + cls.apiclient, + cls.vm2_root_volume.id, + account=cls.account.name, + domainid=cls.account.domainid + ) + + #Create 3 templates + cls.template_1 = Template.create( + cls.apiclient, + cls.services["template"], + cls.vm3_root_volume.id, + account=cls.account.name, + domainid=cls.account.domainid + ) + cls.template_2 = Template.create( + cls.apiclient, + cls.services["template_2"], + cls.vm3_root_volume.id, + account=cls.account.name, + domainid=cls.account.domainid + ) + cls.template_3 = Template.create( + cls.apiclient, + cls.services["template_2"], + cls.vm3_root_volume.id, + account=cls.account.name, + domainid=cls.account.domainid + ) + + cls._cleanup = [ + cls.disk_offering, + cls.account, + cls.service_offering, + cls.snapshot_1, + cls.snapshot_2, + cls.snapshot_3 + ] + + @classmethod + def tearDownClass(cls): + cls.apiclient = super(TestListIdsParams, cls).getClsTestClient().getApiClient() + try: + cleanup_resources(cls.apiclient, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + def test_01_list_volumes(self): + """Test listing Volumes using 'ids' parameter + """ + list_volume_response = Volume.list( + self.apiclient, + ids=[self.vm1_root_volume.id, self.vm2_root_volume.id, self.vm3_root_volume.id], + type='ROOT', + listAll=True + ) + self.assertEqual( + isinstance(list_volume_response, list), + True, + "List Volume response was not a valid list" + ) + self.assertEqual( + len(list_volume_response), + 3, + "ListVolumes response expected 3 Volumes, received %s" % len(list_volume_response) + ) + + @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + def test_02_list_templates(self): + """Test listing Templates using 'ids' parameter + """ + list_template_response = Template.list( + self.apiclient, + templatefilter='all', + ids=[self.template_1.id, self.template_2.id, self.template_3.id], + account=self.account.name, + domainid=self.account.domainid, + listAll=True + ) + self.assertEqual( + isinstance(list_template_response, list), + True, + "ListTemplates response was not a valid list" + ) + self.assertEqual( + len(list_template_response), + 3, + "ListTemplates response expected 3 Templates, received %s" % len(list_template_response) + ) + + @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + def test_03_list_snapshots(self): + """Test listing Snapshots using 'ids' parameter + """ + list_snapshot_response = Snapshot.list( + self.apiclient, + ids=[self.snapshot_1.id, self.snapshot_2.id, self.snapshot_3.id], + listAll=True + ) + self.assertEqual( + isinstance(list_snapshot_response, list), + True, + "ListSnapshots response was not a valid list" + ) + self.assertEqual( + len(list_snapshot_response), + 3, + "ListSnapshots response expected 3 Snapshots, received %s" % len(list_snapshot_response) + ) + + #PLEASE UNCOMMENT ONCE VM SNAPSHOT DELAY BUG AFTER VM CREATION IS FIXED + #@attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + #def test_04_list_vm_snapshots(self): + """Test listing VMSnapshots using 'vmsnapshotids' parameter + """ + """list_vm_snapshot_response = VmSnapshot.list( + self.apiclient, + vmsnapshotids=[self.vmsnapshot_1.id, self.vmsnapshot_2.id, self.vmsnapshot_3.id], + listall=True + ) + self.assertEqual( + isinstance(list_vm_snapshot_response, list), + True, + "ListVMSnapshots response was not a valid list" + ) + self.assertEqual( + len(list_vm_snapshot_response), + 3, + "ListVMSnapshots response expected 3 VMSnapshots, received %s" % len(list_vm_snapshot_response) + )""" From 95abb6efc350189cb2be0cfd655c1205ced42155 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 21 Apr 2016 15:43:04 +0530 Subject: [PATCH 140/203] CLOUDSTACK-9361: Centrally handle API validations Validate API arguments based on annotations. Introduces: - NotNullOrEmpty: for doing null and empty string checks - PositiveNumber: number > 0 (natural number) Signed-off-by: Rohit Yadav --- .../cloudstack/api/ApiArgValidator.java | 23 ++++++++ .../org/apache/cloudstack/api/Parameter.java | 2 + .../api/dispatch/ParamProcessWorker.java | 54 +++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 api/src/org/apache/cloudstack/api/ApiArgValidator.java diff --git a/api/src/org/apache/cloudstack/api/ApiArgValidator.java b/api/src/org/apache/cloudstack/api/ApiArgValidator.java new file mode 100644 index 0000000000..bd2294c601 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/ApiArgValidator.java @@ -0,0 +1,23 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api; + +public enum ApiArgValidator { + NotNullOrEmpty, // does Strings.isNullOrEmpty check + PositiveNumber, // does != null and > 0 check +} diff --git a/api/src/org/apache/cloudstack/api/Parameter.java b/api/src/org/apache/cloudstack/api/Parameter.java index 7ee6897af2..fa6075dc97 100644 --- a/api/src/org/apache/cloudstack/api/Parameter.java +++ b/api/src/org/apache/cloudstack/api/Parameter.java @@ -49,4 +49,6 @@ String since() default ""; RoleType[] authorized() default {}; + + ApiArgValidator[] validations() default {}; } diff --git a/server/src/com/cloud/api/dispatch/ParamProcessWorker.java b/server/src/com/cloud/api/dispatch/ParamProcessWorker.java index 099c0c91e6..feefaabc55 100644 --- a/server/src/com/cloud/api/dispatch/ParamProcessWorker.java +++ b/server/src/com/cloud/api/dispatch/ParamProcessWorker.java @@ -34,6 +34,7 @@ import javax.inject.Inject; +import com.google.common.base.Strings; import org.apache.log4j.Logger; import org.apache.cloudstack.acl.ControlledEntity; @@ -49,6 +50,7 @@ import org.apache.cloudstack.api.InternalIdentity; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; import org.apache.cloudstack.api.command.admin.resource.ArchiveAlertsCmd; import org.apache.cloudstack.api.command.admin.resource.DeleteAlertsCmd; import org.apache.cloudstack.api.command.admin.usage.GetUsageRecordsCmd; @@ -92,6 +94,55 @@ public void handle(final DispatchTask task) { processParameters(task.getCmd(), task.getParams()); } + private void validateNonEmptyString(final Object param, final String argName) { + if (param == null || Strings.isNullOrEmpty(param.toString())) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Empty or null value provided for API arg: %s", argName)); + } + } + + private void validateNaturalNumber(final Object param, final String argName) { + Long value = null; + if (param != null && param instanceof Long) { + value = (Long) param; + } else if (param != null) { + value = Long.valueOf(param.toString()); + } + if (value == null || value < 1L) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Invalid value provided for API arg: %s", argName)); + } + } + + private void validateField(final Object paramObj, final Parameter annotation) throws ServerApiException { + if (annotation == null) { + return; + } + final String argName = annotation.name(); + for (final ApiArgValidator validator : annotation.validations()) { + if (validator == null) { + continue; + } + switch (validator) { + case NotNullOrEmpty: + switch (annotation.type()) { + case UUID: + case STRING: + validateNonEmptyString(paramObj, argName); + break; + } + break; + case PositiveNumber: + switch (annotation.type()) { + case SHORT: + case INTEGER: + case LONG: + validateNaturalNumber(paramObj, argName); + break; + } + break; + } + } + } + @SuppressWarnings({"unchecked", "rawtypes"}) public void processParameters(final BaseCmd cmd, final Map params) { final Map entitiesToAccess = new HashMap(); @@ -112,6 +163,7 @@ public void processParameters(final BaseCmd cmd, final Map params) { // marshall the parameter into the correct type and set the field value try { + validateField(paramObj, parameterAnnotation); setFieldValue(field, cmd, paramObj, parameterAnnotation); } catch (final IllegalArgumentException argEx) { if (s_logger.isDebugEnabled()) { @@ -420,6 +472,7 @@ private Long translateUuidToInternalId(final String uuid, final Parameter annota for (final Class entity : entities) { CallContext.current().putContextParameter(entity, internalId); } + validateNaturalNumber(internalId, annotation.name()); return internalId; } } @@ -452,6 +505,7 @@ private Long translateUuidToInternalId(final String uuid, final Parameter annota throw new InvalidParameterValueException("Invalid parameter " + annotation.name() + " value=" + uuid + " due to incorrect long value format, or entity does not exist or due to incorrect parameter annotation for the field in api cmd class."); } + validateNaturalNumber(internalId, annotation.name()); return internalId; } } From 4347776ac6ef9ae86fb016862f4a6b2376f8319a Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 15 Mar 2016 09:16:06 +0100 Subject: [PATCH 141/203] CLOUDSTACK-8562: DB-Backed Dynamic Role Based API Access Checker This feature allows root administrators to define new roles and associate API permissions to them. A limited form of role-based access control for the CloudStack management server API is provided through a properties file, commands.properties, embedded in the WAR distribution. Therefore, customizing API permissions requires unpacking the distribution and modifying this file consistently on all servers. The old system also does not permit the specification of additional roles. FS: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Dynamic+Role+Based+API+Access+Checker+for+CloudStack DB-Backed Dynamic Role Based API Access Checker for CloudStack brings following changes, features and use-cases: - Moves the API access definitions from commands.properties to the mgmt server DB - Allows defining custom roles (such as a read-only ROOT admin) beyond the current set of four (4) roles - All roles will resolve to one of the four known roles types (Admin, Resource Admin, Domain Admin and User) which maintains this association by requiring all new defined roles to specify a role type. - Allows changes to roles and API permissions per role at runtime including additions or removal of roles and/or modifications of permissions, without the need of restarting management server(s) Upgrade/installation notes: - The feature will be enabled by default for new installations, existing deployments will continue to use the older static role based api access checker with an option to enable this feature - During fresh installation or upgrade, the upgrade paths will add four default roles based on the four default role types - For ease of migration, at the time of upgrade commands.properties will be used to add existing set of permissions to the default roles. cloud.account will have a new role_id column which will be populated based on default roles as well Dynamic-roles migration tool: scripts/util/migrate-dynamicroles.py - Allows admins to migrate to the dynamic role based checker at a future date - Performs a harder one-way migrate and update - Migrates rules from existing commands.properties file into db and deprecates it - Enables an internal hidden switch to enable dynamic role based checker feature Signed-off-by: Rohit Yadav --- .travis.yml | 4 +- api/src/com/cloud/event/EventTypes.java | 18 + api/src/com/cloud/user/Account.java | 2 + api/src/com/cloud/user/AccountService.java | 4 +- api/src/org/apache/cloudstack/acl/Role.java | 27 + .../apache/cloudstack/acl/RolePermission.java | 31 + .../apache/cloudstack/acl/RoleService.java | 52 + .../org/apache/cloudstack/acl/RoleType.java | 80 +- api/src/org/apache/cloudstack/acl/Rule.java | 54 ++ .../apache/cloudstack/api/ApiConstants.java | 7 + .../org/apache/cloudstack/api/BaseCmd.java | 7 +- .../admin/account/CreateAccountCmd.java | 17 +- .../api/command/admin/acl/CreateRoleCmd.java | 105 ++ .../admin/acl/CreateRolePermissionCmd.java | 124 +++ .../api/command/admin/acl/DeleteRoleCmd.java | 83 ++ .../admin/acl/DeleteRolePermissionCmd.java | 83 ++ .../admin/acl/ListRolePermissionsCmd.java | 106 ++ .../api/command/admin/acl/ListRolesCmd.java | 128 +++ .../api/command/admin/acl/UpdateRoleCmd.java | 108 +++ .../admin/acl/UpdateRolePermissionCmd.java | 104 ++ .../command/admin/config/UpdateCfgCmd.java | 12 + .../user/config/ListCapabilitiesCmd.java | 1 + .../api/response/AccountResponse.java | 27 + .../api/response/CapabilitiesResponse.java | 8 + .../api/response/RolePermissionResponse.java | 101 ++ .../cloudstack/api/response/RoleResponse.java | 63 ++ .../cloudstack/api/response/UserResponse.java | 27 + .../apache/cloudstack/acl/RoleTypeTest.java | 100 ++ .../org/apache/cloudstack/acl/RuleTest.java | 98 ++ .../admin/account/CreateAccountCmdTest.java | 10 +- .../api/command/test/UpdateCfgCmdTest.java | 28 +- .../classes/resources/messages.properties | 8 + client/pom.xml | 5 + debian/cloudstack-management.install | 1 - debian/control | 2 +- developer/developer-prefill.sql | 5 + ...spring-engine-schema-core-daos-context.xml | 2 + .../cloud/upgrade/dao/Upgrade481to490.java | 75 +- .../schema/src/com/cloud/user/AccountVO.java | 31 +- .../src/com/cloud/user/dao/AccountDao.java | 2 + .../com/cloud/user/dao/AccountDaoImpl.java | 19 +- .../cloudstack/acl/RolePermissionVO.java | 120 +++ .../src/org/apache/cloudstack/acl/RoleVO.java | 106 ++ .../apache/cloudstack/acl/dao/RoleDao.java | 29 + .../cloudstack/acl/dao/RoleDaoImpl.java | 61 ++ .../acl/dao/RolePermissionsDao.java | 49 + .../acl/dao/RolePermissionsDaoImpl.java | 166 ++++ plugins/acl/dynamic-role-based/pom.xml | 32 + .../acl-dynamic-role-based/module.properties | 18 + .../spring-acl-dynamic-role-based-context.xml | 33 + .../acl/DynamicRoleBasedAPIAccessChecker.java | 144 +++ .../DynamicRoleBasedAPIAccessCheckerTest.java | 164 ++++ .../acl/StaticRoleBasedAPIAccessChecker.java | 48 +- .../command/user/discovery/ListApisCmd.java | 3 +- .../manager/BaremetalVlanManagerImpl.java | 27 +- .../management/MockAccountManager.java | 8 +- plugins/pom.xml | 1 + .../api/command/LdapCreateAccountCmd.java | 41 +- .../api/command/LdapImportUsersCmd.java | 20 +- .../api/command/LinkDomainToLdapCmd.java | 3 +- .../cloudstack/ldap/LdapAuthenticator.java | 4 +- .../ldap/LdapImportUsersCmdSpec.groovy | 2 +- scripts/util/migrate-dynamicroles.py | 136 +++ .../spring-server-core-managers-context.xml | 2 + server/src/com/cloud/api/ApiDBUtils.java | 27 +- .../com/cloud/api/ApiResponseGsonHelper.java | 2 +- server/src/com/cloud/api/ApiServer.java | 8 +- .../com/cloud/api/query/vo/AccountJoinVO.java | 7 + .../cloud/api/query/vo/UserAccountJoinVO.java | 7 + .../api/response/ApiResponseSerializer.java | 2 +- .../cloud/projects/ProjectManagerImpl.java | 2 +- .../cloud/server/ConfigurationServerImpl.java | 6 +- server/src/com/cloud/user/AccountManager.java | 2 +- .../com/cloud/user/AccountManagerImpl.java | 37 +- .../cloudstack/acl/RoleManagerImpl.java | 264 +++++ .../cloud/user/MockAccountManagerImpl.java | 6 +- .../iam/RoleBasedAPIAccessChecker.java | 2 +- .../db/create-default-role-api-mappings.sql | 902 ++++++++++++++++++ setup/db/db/schema-481to490-cleanup.sql | 188 ++++ setup/db/db/schema-481to490.sql | 35 + setup/db/server-setup.sql | 3 +- setup/db/server-setup.xml | 7 + test/integration/smoke/test_dynamicroles.py | 537 +++++++++++ test/integration/smoke/test_staticroles.py | 134 +++ tools/apidoc/gen_toc.py | 1 + tools/marvin/marvin/cloudstackConnection.py | 2 +- tools/marvin/marvin/lib/base.py | 89 +- ui/css/cloudstack3.css | 16 + ui/dictionary.jsp | 7 + ui/dictionary2.jsp | 1 + ui/images/icons.png | Bin 61164 -> 48358 bytes ui/index.jsp | 1 + ui/plugins/quota/quota.js | 16 +- ui/scripts/accounts.js | 31 +- ui/scripts/accountsWizard.js | 38 +- ui/scripts/cloudStack.js | 3 +- ui/scripts/roles.js | 388 ++++++++ ui/scripts/sharedFunctions.js | 11 + .../main/java/com/cloud/utils/ListUtils.java | 31 + .../java/com/cloud/utils/PropertiesUtil.java | 4 + 100 files changed, 5633 insertions(+), 170 deletions(-) create mode 100644 api/src/org/apache/cloudstack/acl/Role.java create mode 100644 api/src/org/apache/cloudstack/acl/RolePermission.java create mode 100644 api/src/org/apache/cloudstack/acl/RoleService.java create mode 100644 api/src/org/apache/cloudstack/acl/Rule.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/acl/CreateRolePermissionCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRoleCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRolePermissionCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/acl/ListRolePermissionsCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java create mode 100644 api/src/org/apache/cloudstack/api/response/RolePermissionResponse.java create mode 100644 api/src/org/apache/cloudstack/api/response/RoleResponse.java create mode 100644 api/test/org/apache/cloudstack/acl/RoleTypeTest.java create mode 100644 api/test/org/apache/cloudstack/acl/RuleTest.java create mode 100644 engine/schema/src/org/apache/cloudstack/acl/RolePermissionVO.java create mode 100644 engine/schema/src/org/apache/cloudstack/acl/RoleVO.java create mode 100644 engine/schema/src/org/apache/cloudstack/acl/dao/RoleDao.java create mode 100644 engine/schema/src/org/apache/cloudstack/acl/dao/RoleDaoImpl.java create mode 100644 engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java create mode 100644 engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java create mode 100644 plugins/acl/dynamic-role-based/pom.xml create mode 100644 plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/module.properties create mode 100644 plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/spring-acl-dynamic-role-based-context.xml create mode 100644 plugins/acl/dynamic-role-based/src/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java create mode 100644 plugins/acl/dynamic-role-based/test/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessCheckerTest.java create mode 100755 scripts/util/migrate-dynamicroles.py create mode 100644 server/src/org/apache/cloudstack/acl/RoleManagerImpl.java create mode 100644 setup/db/db/create-default-role-api-mappings.sql create mode 100644 test/integration/smoke/test_dynamicroles.py create mode 100644 test/integration/smoke/test_staticroles.py create mode 100644 ui/scripts/roles.js create mode 100644 utils/src/main/java/com/cloud/utils/ListUtils.java diff --git a/.travis.yml b/.travis.yml index d160e487aa..9d9822ce11 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,10 +36,10 @@ env: - REGRESSION_INDEX=6 - PATH=$HOME/.local/bin:$PATH matrix: - - TESTS="smoke/test_affinity_groups smoke/test_affinity_groups_projects smoke/test_deploy_vgpu_enabled_vm smoke/test_deploy_vm_iso smoke/test_deploy_vm_root_resize smoke/test_deploy_vm_with_userdata smoke/test_deploy_vms_with_varied_deploymentplanners smoke/test_disk_offerings smoke/test_global_settings smoke/test_guest_vlan_range" + - TESTS="smoke/test_affinity_groups smoke/test_affinity_groups_projects smoke/test_dynamicroles smoke/test_deploy_vgpu_enabled_vm smoke/test_deploy_vm_iso smoke/test_deploy_vm_root_resize smoke/test_deploy_vm_with_userdata smoke/test_deploy_vms_with_varied_deploymentplanners smoke/test_disk_offerings smoke/test_global_settings smoke/test_guest_vlan_range" - TESTS="smoke/test_hosts smoke/test_internal_lb smoke/test_iso smoke/test_list_ids_parameter smoke/test_loadbalance smoke/test_multipleips_per_nic smoke/test_network smoke/test_network_acl smoke/test_nic smoke/test_nic_adapter_type smoke/test_non_contigiousvlan" - TESTS="smoke/test_over_provisioning smoke/test_password_server smoke/test_portable_publicip smoke/test_primary_storage smoke/test_privategw_acl smoke/test_public_ip_range smoke/test_pvlan smoke/test_regions smoke/test_reset_vm_on_reboot smoke/test_resource_detail" - - TESTS="smoke/test_router_dhcphosts smoke/test_routers smoke/test_routers_iptables_default_policy smoke/test_routers_network_ops smoke/test_scale_vm smoke/test_secondary_storage smoke/test_service_offerings smoke/test_snapshots smoke/test_ssvm smoke/test_templates" + - TESTS="smoke/test_router_dhcphosts smoke/test_routers smoke/test_routers_iptables_default_policy smoke/test_routers_network_ops smoke/test_staticroles smoke/test_scale_vm smoke/test_secondary_storage smoke/test_service_offerings smoke/test_snapshots smoke/test_ssvm smoke/test_templates" - TESTS="smoke/test_usage_events smoke/test_vm_life_cycle smoke/test_vm_snapshots smoke/test_volumes smoke/test_vpc_redundant smoke/test_vpc_router_nics smoke/test_vpc_vpn smoke/misc/test_deploy_vm smoke/misc/test_vm_ha smoke/misc/test_escalations_templates smoke/misc/test_vm_sync" - TESTS="component/test_mm_max_limits component/test_acl_isolatednetwork_delete" diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 7349c1f541..23de15295e 100644 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -66,6 +66,8 @@ import com.cloud.vm.Nic; import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.VirtualMachine; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; import org.apache.cloudstack.config.Configuration; import org.apache.cloudstack.usage.Usage; @@ -166,6 +168,14 @@ public class EventTypes { public static final String EVENT_GLOBAL_LOAD_BALANCER_DELETE = "GLOBAL.LB.DELETE"; public static final String EVENT_GLOBAL_LOAD_BALANCER_UPDATE = "GLOBAL.LB.UPDATE"; + // Role events + public static final String EVENT_ROLE_CREATE = "ROLE.CREATE"; + public static final String EVENT_ROLE_UPDATE = "ROLE.UPDATE"; + public static final String EVENT_ROLE_DELETE = "ROLE.DELETE"; + public static final String EVENT_ROLE_PERMISSION_CREATE = "ROLE.PERMISSION.CREATE"; + public static final String EVENT_ROLE_PERMISSION_UPDATE = "ROLE.PERMISSION.UPDATE"; + public static final String EVENT_ROLE_PERMISSION_DELETE = "ROLE.PERMISSION.DELETE"; + // Account events public static final String EVENT_ACCOUNT_ENABLE = "ACCOUNT.ENABLE"; public static final String EVENT_ACCOUNT_DISABLE = "ACCOUNT.DISABLE"; @@ -605,6 +615,14 @@ public class EventTypes { entityEventDetails.put(EVENT_LB_CERT_ASSIGN, LoadBalancer.class); entityEventDetails.put(EVENT_LB_CERT_REMOVE, LoadBalancer.class); + // Role events + entityEventDetails.put(EVENT_ROLE_CREATE, Role.class); + entityEventDetails.put(EVENT_ROLE_UPDATE, Role.class); + entityEventDetails.put(EVENT_ROLE_DELETE, Role.class); + entityEventDetails.put(EVENT_ROLE_PERMISSION_CREATE, RolePermission.class); + entityEventDetails.put(EVENT_ROLE_PERMISSION_UPDATE, RolePermission.class); + entityEventDetails.put(EVENT_ROLE_PERMISSION_DELETE, RolePermission.class); + // Account events entityEventDetails.put(EVENT_ACCOUNT_ENABLE, Account.class); entityEventDetails.put(EVENT_ACCOUNT_DISABLE, Account.class); diff --git a/api/src/com/cloud/user/Account.java b/api/src/com/cloud/user/Account.java index b912e515bf..58cedcd574 100644 --- a/api/src/com/cloud/user/Account.java +++ b/api/src/com/cloud/user/Account.java @@ -46,6 +46,8 @@ public enum State { public short getType(); + public Long getRoleId(); + public State getState(); public Date getRemoved(); diff --git a/api/src/com/cloud/user/AccountService.java b/api/src/com/cloud/user/AccountService.java index 7cc1e3089c..959a710d6d 100644 --- a/api/src/com/cloud/user/AccountService.java +++ b/api/src/com/cloud/user/AccountService.java @@ -57,9 +57,9 @@ public interface AccountService { * @return the user if created successfully, null otherwise */ UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, - short accountType, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID); + short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID); - UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long domainId, String networkDomain, + UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID, User.Source source); /** diff --git a/api/src/org/apache/cloudstack/acl/Role.java b/api/src/org/apache/cloudstack/acl/Role.java new file mode 100644 index 0000000000..b05d886fdb --- /dev/null +++ b/api/src/org/apache/cloudstack/acl/Role.java @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.acl; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface Role extends InternalIdentity, Identity { + String getName(); + RoleType getRoleType(); + String getDescription(); +} diff --git a/api/src/org/apache/cloudstack/acl/RolePermission.java b/api/src/org/apache/cloudstack/acl/RolePermission.java new file mode 100644 index 0000000000..0157a66825 --- /dev/null +++ b/api/src/org/apache/cloudstack/acl/RolePermission.java @@ -0,0 +1,31 @@ +// 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.acl; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface RolePermission extends InternalIdentity, Identity { + enum Permission {ALLOW, DENY} + + long getRoleId(); + Rule getRule(); + Permission getPermission(); + String getDescription(); + long getSortOrder(); +} diff --git a/api/src/org/apache/cloudstack/acl/RoleService.java b/api/src/org/apache/cloudstack/acl/RoleService.java new file mode 100644 index 0000000000..59eef51e78 --- /dev/null +++ b/api/src/org/apache/cloudstack/acl/RoleService.java @@ -0,0 +1,52 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.acl; + +import org.apache.cloudstack.framework.config.ConfigKey; + +import java.util.List; + +public interface RoleService { + + ConfigKey EnableDynamicApiChecker = new ConfigKey<>("Advanced", Boolean.class, "dynamic.apichecker.enabled", "false", + "If set to true, this enables the dynamic role-based api access checker and disables the default static role-based api access checker.", + true); + + boolean isEnabled(); + Role findRole(final Long id); + Role createRole(final String name, final RoleType roleType, final String description); + boolean updateRole(final Role role, final String name, final RoleType roleType, final String description); + boolean deleteRole(final Role role); + + RolePermission findRolePermission(final Long id); + RolePermission findRolePermissionByUuid(final String uuid); + + RolePermission createRolePermission(final Role role, final Rule rule, final RolePermission.Permission permission, final String description); + /** + * updateRolePermission updates the order/position of an role permission + * @param role The role whose permissions needs to be re-ordered + * @param newOrder The new list of ordered role permissions + */ + boolean updateRolePermission(final Role role, final List newOrder); + boolean deleteRolePermission(final RolePermission rolePermission); + + List listRoles(); + List findRolesByName(final String name); + List findRolesByType(final RoleType roleType); + List findAllPermissionsBy(final Long roleId); +} diff --git a/api/src/org/apache/cloudstack/acl/RoleType.java b/api/src/org/apache/cloudstack/acl/RoleType.java index 90e3d1ef60..a8a64a58df 100644 --- a/api/src/org/apache/cloudstack/acl/RoleType.java +++ b/api/src/org/apache/cloudstack/acl/RoleType.java @@ -16,18 +16,90 @@ // under the License. package org.apache.cloudstack.acl; +import com.cloud.user.Account; +import com.google.common.base.Enums; +import com.google.common.base.Strings; + // Enum for default roles in CloudStack public enum RoleType { - Admin(1), ResourceAdmin(2), DomainAdmin(4), User(8), Unknown(0); + Admin(1L, Account.ACCOUNT_TYPE_ADMIN, 1), + ResourceAdmin(2L, Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN, 2), + DomainAdmin(3L, Account.ACCOUNT_TYPE_DOMAIN_ADMIN, 4), + User(4L, Account.ACCOUNT_TYPE_NORMAL, 8), + Unknown(-1L, (short) -1, 0); + private long id; + private short accountType; private int mask; - private RoleType(int mask) { + RoleType(final long id, final short accountType, final int mask) { + this.id = id; + this.accountType = accountType; this.mask = mask; } - public int getValue() { + public long getId() { + return id; + } + + public short getAccountType() { + return accountType; + } + + public int getMask() { return mask; } -} + public static RoleType fromString(final String name) { + if (!Strings.isNullOrEmpty(name) + && Enums.getIfPresent(RoleType.class, name).isPresent()) { + return RoleType.valueOf(name); + } + throw new IllegalStateException("Illegal RoleType name provided"); + } + + public static RoleType fromMask(int mask) { + for (RoleType roleType : RoleType.values()) { + if (roleType.getMask() == mask) { + return roleType; + } + } + return Unknown; + } + + public static RoleType getByAccountType(final short accountType) { + RoleType roleType = RoleType.Unknown; + switch (accountType) { + case Account.ACCOUNT_TYPE_ADMIN: + roleType = RoleType.Admin; + break; + case Account.ACCOUNT_TYPE_DOMAIN_ADMIN: + roleType = RoleType.DomainAdmin; + break; + case Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN: + roleType = RoleType.ResourceAdmin; + break; + case Account.ACCOUNT_TYPE_NORMAL: + roleType = RoleType.User; + break; + } + return roleType; + } + + public static Long getRoleByAccountType(final Long roleId, final Short accountType) { + if (roleId == null && accountType != null) { + RoleType defaultRoleType = RoleType.getByAccountType(accountType); + if (defaultRoleType != null && defaultRoleType != RoleType.Unknown) { + return defaultRoleType.getId(); + } + } + return roleId; + } + + public static Short getAccountTypeByRole(final Role role, final Short accountType) { + if (role != null && role.getId() > 0L) { + return role.getRoleType().getAccountType(); + } + return accountType; + } +} diff --git a/api/src/org/apache/cloudstack/acl/Rule.java b/api/src/org/apache/cloudstack/acl/Rule.java new file mode 100644 index 0000000000..27920107fd --- /dev/null +++ b/api/src/org/apache/cloudstack/acl/Rule.java @@ -0,0 +1,54 @@ +// 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.acl; + +import com.cloud.exception.InvalidParameterValueException; +import com.google.common.base.Strings; + +import java.util.regex.Pattern; + +public final class Rule { + private final String rule; + private final static Pattern ALLOWED_PATTERN = Pattern.compile("^[a-zA-Z0-9*]+$"); + + public Rule(final String rule) { + validate(rule); + this.rule = rule; + } + + public boolean matches(final String commandName) { + return !Strings.isNullOrEmpty(commandName) + && commandName.toLowerCase().matches(rule.toLowerCase().replace("*", "\\w*")); + } + + public String getRuleString() { + return rule; + } + + @Override + public String toString() { + return rule; + } + + private static boolean validate(final String rule) { + if (Strings.isNullOrEmpty(rule) || !ALLOWED_PATTERN.matcher(rule).matches()) { + throw new InvalidParameterValueException("Only API names and wildcards are allowed, invalid rule provided: " + rule); + } + return true; + } +} diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 6f3152b75a..490492533b 100644 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -193,6 +193,7 @@ public class ApiConstants { public static final String PORTABLE_IP_ADDRESS = "portableipaddress"; public static final String PORT_FORWARDING_SERVICE_ID = "portforwardingserviceid"; public static final String POST_URL = "postURL"; + public static final String PARENT = "parent"; public static final String PRIVATE_INTERFACE = "privateinterface"; public static final String PRIVATE_IP = "privateip"; public static final String PRIVATE_PORT = "privateport"; @@ -358,6 +359,12 @@ public class ApiConstants { public static final String PROJECT_IDS = "projectids"; public static final String PROJECT = "project"; public static final String ROLE = "role"; + public static final String ROLE_ID = "roleid"; + public static final String ROLE_TYPE = "roletype"; + public static final String ROLE_NAME = "rolename"; + public static final String PERMISSION = "permission"; + public static final String RULE = "rule"; + public static final String RULE_ORDER = "ruleorder"; public static final String USER = "user"; public static final String ACTIVE_ONLY = "activeonly"; public static final String TOKEN = "token"; diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index 360b277d89..5be75196d3 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -30,6 +30,7 @@ import javax.inject.Inject; import com.cloud.utils.HttpUtils; +import org.apache.cloudstack.acl.RoleService; import org.apache.log4j.Logger; import org.apache.cloudstack.acl.RoleType; @@ -85,6 +86,7 @@ public abstract class BaseCmd { private static final Logger s_logger = Logger.getLogger(BaseCmd.class.getName()); + public static final String RESPONSE_SUFFIX = "response"; public static final String RESPONSE_TYPE_XML = HttpUtils.RESPONSE_TYPE_XML; public static final String RESPONSE_TYPE_JSON = HttpUtils.RESPONSE_TYPE_JSON; public static final String USER_ERROR_MESSAGE = "Internal error executing command, please contact your system administrator"; @@ -104,12 +106,13 @@ public static enum CommandType { @Parameter(name = "response", type = CommandType.STRING) private String responseType; - @Inject public ConfigurationService _configService; @Inject public AccountService _accountService; @Inject + public RoleService roleService; + @Inject public UserVmService _userVmService; @Inject public ManagementService _mgr; @@ -323,7 +326,7 @@ public List getParamFields() { if (allowedRoles.length > 0) { roleIsAllowed = false; for (final RoleType allowedRole : allowedRoles) { - if (allowedRole.getValue() == caller.getType()) { + if (allowedRole.getAccountType() == caller.getType()) { roleIsAllowed = true; break; } diff --git a/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java b/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java index b55ce71498..2e1fbd6f86 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java @@ -22,6 +22,7 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -31,6 +32,7 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.RoleResponse; import org.apache.cloudstack.context.CallContext; import com.cloud.user.Account; @@ -55,10 +57,12 @@ public class CreateAccountCmd extends BaseCmd { @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, - required = true, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") private Short accountType; + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.") + private Long roleId; + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Creates the user under the specified domain.") private Long domainId; @@ -106,7 +110,11 @@ public String getAccountName() { } public Short getAccountType() { - return accountType; + return RoleType.getAccountTypeByRole(roleService.findRole(roleId), accountType); + } + + public Long getRoleId() { + return RoleType.getRoleByAccountType(roleId, accountType); } public Long getDomainId() { @@ -178,7 +186,7 @@ public void execute() { validateParams(); CallContext.current().setEventDetails("Account Name: " + getAccountName() + ", Domain Id:" + getDomainId()); UserAccount userAccount = - _accountService.createUserAccount(getUsername(), getPassword(), getFirstName(), getLastName(), getEmail(), getTimeZone(), getAccountName(), getAccountType(), + _accountService.createUserAccount(getUsername(), getPassword(), getFirstName(), getLastName(), getEmail(), getTimeZone(), getAccountName(), getAccountType(), getRoleId(), getDomainId(), getNetworkDomain(), getDetails(), getAccountUUID(), getUserUUID()); if (userAccount != null) { AccountResponse response = _responseGenerator.createUserAccountResponse(ResponseView.Full, userAccount); @@ -196,5 +204,8 @@ private void validateParams() { if(StringUtils.isEmpty(getPassword())) { throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Empty passwords are not allowed"); } + if (getAccountType() == null && (getRoleId() == null || getRoleId() < 1L)) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Neither account type and role ID are not provided"); + } } } diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java new file mode 100644 index 0000000000..994573d179 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java @@ -0,0 +1,105 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.user.Account; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.response.RoleResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = CreateRoleCmd.APINAME, description = "Creates a role", responseObject = RoleResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class CreateRoleCmd extends BaseCmd { + public static final String APINAME = "createRole"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, + description = "creates a role with this unique name", validations = {ApiArgValidator.NotNullOrEmpty}) + private String roleName; + + @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, + description = "The type of the role, valid options are: Admin, ResourceAdmin, DomainAdmin, User", + validations = {ApiArgValidator.NotNullOrEmpty}) + private String roleType; + + @Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "The description of the role") + private String roleDescription; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getRoleName() { + return roleName; + } + + public RoleType getRoleType() { + return RoleType.fromString(roleType); + } + + public String getRoleDescription() { + return roleDescription; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + private void setupResponse(final Role role) { + final RoleResponse response = new RoleResponse(); + response.setId(role.getUuid()); + response.setRoleName(role.getName()); + response.setRoleType(role.getRoleType()); + response.setResponseName(getCommandName()); + response.setObjectName("role"); + setResponseObject(response); + } + + @Override + public void execute() { + CallContext.current().setEventDetails("Role: " + getRoleName() + ", type:" + getRoleType() + ", description: " + getRoleDescription()); + final Role role = roleService.createRole(getRoleName(), getRoleType(), getRoleDescription()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create role"); + } + setupResponse(role); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRolePermissionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRolePermissionCmd.java new file mode 100644 index 0000000000..aeb3f4ee11 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRolePermissionCmd.java @@ -0,0 +1,124 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.user.Account; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.acl.Rule; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.response.RolePermissionResponse; +import org.apache.cloudstack.api.response.RoleResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = CreateRolePermissionCmd.APINAME, description = "Adds a API permission to a role", responseObject = RolePermissionResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class CreateRolePermissionCmd extends BaseCmd { + public static final String APINAME = "createRolePermission"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, required = true, entityType = RoleResponse.class, + description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) + private Long roleId; + + @Parameter(name = ApiConstants.RULE, type = CommandType.STRING, required = true, description = "The API name or wildcard rule such as list*", + validations = {ApiArgValidator.NotNullOrEmpty}) + private String rule; + + @Parameter(name = ApiConstants.PERMISSION, type = CommandType.STRING, required = true, description = "The rule permission, allow or deny. Default: deny.") + private String permission; + + @Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "The description of the role permission") + private String description; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + return roleId; + } + + public Rule getRule() { + return new Rule(rule); + } + + public RolePermission.Permission getPermission() { + if (Strings.isNullOrEmpty(permission)) { + return null; + } + return RolePermission.Permission.valueOf(permission.toUpperCase()); + } + + public String getDescription() { + return description; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + private void setupResponse(final RolePermission rolePermission, final Role role) { + final RolePermissionResponse response = new RolePermissionResponse(); + response.setId(rolePermission.getUuid()); + response.setRoleId(role.getUuid()); + response.setRule(rolePermission.getRule()); + response.setRulePermission(rolePermission.getPermission()); + response.setDescription(rolePermission.getDescription()); + response.setResponseName(getCommandName()); + response.setObjectName("rolepermission"); + setResponseObject(response); + } + + @Override + public void execute() { + final Role role = roleService.findRole(getRoleId()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role id provided"); + } + CallContext.current().setEventDetails("Role id: " + role.getId() + ", rule:" + getRule() + ", permission: " + getPermission() + ", description: " + getDescription()); + final RolePermission rolePermission = roleService.createRolePermission(role, getRule(), getPermission(), getDescription()); + if (rolePermission == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create role permission"); + } + setupResponse(rolePermission, role); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRoleCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRoleCmd.java new file mode 100644 index 0000000000..bd4a7cdacb --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRoleCmd.java @@ -0,0 +1,83 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.user.Account; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.response.RoleResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = DeleteRoleCmd.APINAME, description = "Deletes a role", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class DeleteRoleCmd extends BaseCmd { + public static final String APINAME = "deleteRole"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, required = true, entityType = RoleResponse.class, + description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) + private Long roleId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + return roleId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + Role role = roleService.findRole(getRoleId()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Cannot find the role with provided id"); + } + CallContext.current().setEventDetails("Role id: " + role.getId()); + boolean result = roleService.deleteRole(role); + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setSuccess(result); + setResponseObject(response); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRolePermissionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRolePermissionCmd.java new file mode 100644 index 0000000000..9c7dc7c986 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRolePermissionCmd.java @@ -0,0 +1,83 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.user.Account; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.response.RolePermissionResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = DeleteRolePermissionCmd.APINAME, description = "Deletes a role permission", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class DeleteRolePermissionCmd extends BaseCmd { + public static final String APINAME = "deleteRolePermission"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, required = true, entityType = RolePermissionResponse.class, + description = "ID of the role permission", validations = {ApiArgValidator.PositiveNumber}) + private Long rolePermissionId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRolePermissionId() { + return rolePermissionId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + RolePermission rolePermission = roleService.findRolePermission(getRolePermissionId()); + if (rolePermission == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role permission id provided"); + } + CallContext.current().setEventDetails("Role permission id: " + rolePermission.getId()); + boolean result = roleService.deleteRolePermission(rolePermission); + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setSuccess(result); + setResponseObject(response); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolePermissionsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolePermissionsCmd.java new file mode 100644 index 0000000000..f20abf4014 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolePermissionsCmd.java @@ -0,0 +1,106 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.RolePermissionResponse; +import org.apache.cloudstack.api.response.RoleResponse; + +import java.util.ArrayList; +import java.util.List; + + +@APICommand(name = ListRolePermissionsCmd.APINAME, description = "Lists role permissions", responseObject = RolePermissionResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class ListRolePermissionsCmd extends BaseCmd { + public static final String APINAME = "listRolePermissions"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, + description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) + private Long roleId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + return roleId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + private void setupResponse(final List rolePermissions, final Long roleId) { + final Role roleProvided = roleService.findRole(roleId); + final ListResponse response = new ListResponse<>(); + final List rolePermissionResponses = new ArrayList<>(); + for (final RolePermission rolePermission : rolePermissions) { + final RolePermissionResponse rolePermissionResponse = new RolePermissionResponse(); + Role role = roleProvided; + if (role == null) { + role = roleService.findRole(rolePermission.getRoleId()); + } + rolePermissionResponse.setRoleId(role.getUuid()); + rolePermissionResponse.setRoleName(role.getName()); + rolePermissionResponse.setId(rolePermission.getUuid()); + rolePermissionResponse.setRule(rolePermission.getRule()); + rolePermissionResponse.setRulePermission(rolePermission.getPermission()); + rolePermissionResponse.setDescription(rolePermission.getDescription()); + rolePermissionResponse.setObjectName("rolepermission"); + rolePermissionResponses.add(rolePermissionResponse); + } + response.setResponses(rolePermissionResponses); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException { + final List rolePermissions = roleService.findAllPermissionsBy(getRoleId()); + setupResponse(rolePermissions, getRoleId()); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java new file mode 100644 index 0000000000..5cf870bfc0 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java @@ -0,0 +1,128 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.RoleResponse; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@APICommand(name = ListRolesCmd.APINAME, description = "Lists dynamic roles in CloudStack", responseObject = RoleResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin}) +public class ListRolesCmd extends BaseCmd { + public static final String APINAME = "listRoles"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "List role by role ID.") + private Long id; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "List role by role name.") + private String roleName; + + @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "List role by role type, valid options are: Admin, ResourceAdmin, DomainAdmin, User.") + private String roleType; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public String getName() { + return roleName; + } + + public RoleType getRoleType() { + if (!Strings.isNullOrEmpty(roleType)) { + return RoleType.valueOf(roleType); + } + return null; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + private void setupResponse(final List roles) { + final ListResponse response = new ListResponse<>(); + final List roleResponses = new ArrayList<>(); + for (final Role role : roles) { + if (role == null) { + continue; + } + final RoleResponse roleResponse = new RoleResponse(); + roleResponse.setId(role.getUuid()); + roleResponse.setRoleName(role.getName()); + roleResponse.setRoleType(role.getRoleType()); + roleResponse.setDescription(role.getDescription()); + roleResponse.setObjectName("role"); + roleResponses.add(roleResponse); + } + response.setResponses(roleResponses); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final List roles; + if (getId() != null && getId() > 0L) { + roles = Collections.singletonList(roleService.findRole(getId())); + } else if (!Strings.isNullOrEmpty(getName())) { + roles = roleService.findRolesByName(getName()); + } else if (getRoleType() != null){ + roles = roleService.findRolesByType(getRoleType()); + } else { + roles = roleService.listRoles(); + } + setupResponse(roles); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java new file mode 100644 index 0000000000..e17fc6f571 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java @@ -0,0 +1,108 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.user.Account; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.response.RoleResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = UpdateRoleCmd.APINAME, description = "Updates a role", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class UpdateRoleCmd extends BaseCmd { + public static final String APINAME = "updateRole"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, required = true, entityType = RoleResponse.class, + description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) + private Long roleId; + + @Parameter(name = ApiConstants.NAME, type = BaseCmd.CommandType.STRING, description = "creates a role with this unique name") + private String roleName; + + @Parameter(name = ApiConstants.TYPE, type = BaseCmd.CommandType.STRING, description = "The type of the role, valid options are: Admin, ResourceAdmin, DomainAdmin, User") + private String roleType; + + @Parameter(name = ApiConstants.DESCRIPTION, type = BaseCmd.CommandType.STRING, description = "The description of the role") + private String roleDescription; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + return roleId; + } + + public String getRoleName() { + return roleName; + } + + public RoleType getRoleType() { + if (!Strings.isNullOrEmpty(roleType)) { + return RoleType.fromString(roleType); + } + return null; + } + + public String getRoleDescription() { + return roleDescription; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + Role role = roleService.findRole(getRoleId()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role id provided"); + } + CallContext.current().setEventDetails("Role: " + getRoleName() + ", type:" + getRoleType() + ", description: " + getRoleDescription()); + boolean result = roleService.updateRole(role, getRoleName(), getRoleType(), getRoleDescription()); + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setSuccess(result); + setResponseObject(response); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java new file mode 100644 index 0000000000..055265c5cc --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java @@ -0,0 +1,104 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.user.Account; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.RolePermissionResponse; +import org.apache.cloudstack.api.response.RoleResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; + +import java.util.ArrayList; +import java.util.List; + +@APICommand(name = UpdateRolePermissionCmd.APINAME, description = "Updates a role permission order", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class UpdateRolePermissionCmd extends BaseCmd { + public static final String APINAME = "updateRolePermission"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, required = true, entityType = RoleResponse.class, + description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) + private Long roleId; + + @Parameter(name = ApiConstants.RULE_ORDER, type = CommandType.LIST, collectionType = CommandType.UUID, required = true, entityType = RolePermissionResponse.class, + description = "The parent role permission uuid, use 0 to move this rule at the top of the list") + private List rulePermissionOrder; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + return roleId; + } + + public List getRulePermissionOrder() { + return rulePermissionOrder; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + final Role role = roleService.findRole(getRoleId()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role id provided"); + } + CallContext.current().setEventDetails("Reordering permissions for role id: " + role.getId()); + final List rolePermissionsOrder = new ArrayList<>(); + for (Long rolePermissionId : getRulePermissionOrder()) { + final RolePermission rolePermission = roleService.findRolePermission(rolePermissionId); + if (rolePermission == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Provided role permission(s) do not exist"); + } + rolePermissionsOrder.add(rolePermission); + } + boolean result = roleService.updateRolePermission(role, rolePermissionsOrder); + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setSuccess(result); + setResponseObject(response); + } +} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java index 0124d5997b..45f790fb70 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.config; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.RoleService; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -81,6 +83,10 @@ public String getCfgName() { return cfgName; } + public void setCfgName(final String cfgName) { + this.cfgName = cfgName; + } + public String getValue() { return value; } @@ -117,6 +123,12 @@ public long getEntityOwnerId() { @Override public void execute() { + if (Strings.isNullOrEmpty(getCfgName())) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Empty configuration name provided"); + } + if (getCfgName().equalsIgnoreCase(RoleService.EnableDynamicApiChecker.key())) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Restricted configuration update not allowed"); + } Configuration cfg = _configService.updateConfiguration(this); if (cfg != null) { ConfigurationResponse response = _responseGenerator.createConfigurationResponse(cfg); diff --git a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java index 24486a3c79..9c526563d4 100644 --- a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java @@ -47,6 +47,7 @@ public void execute() { Map capabilities = _mgr.listCapabilities(this); CapabilitiesResponse response = new CapabilitiesResponse(); response.setSecurityGroupsEnabled((Boolean)capabilities.get("securityGroupsEnabled")); + response.setDynamicRolesEnabled(roleService.isEnabled()); response.setCloudStackVersion((String)capabilities.get("cloudStackVersion")); response.setUserPublicTemplateEnabled((Boolean)capabilities.get("userPublicTemplateEnabled")); response.setSupportELB((String)capabilities.get("supportELB")); diff --git a/api/src/org/apache/cloudstack/api/response/AccountResponse.java b/api/src/org/apache/cloudstack/api/response/AccountResponse.java index 2e50c51858..7b48a1ea8a 100644 --- a/api/src/org/apache/cloudstack/api/response/AccountResponse.java +++ b/api/src/org/apache/cloudstack/api/response/AccountResponse.java @@ -21,6 +21,7 @@ import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; @@ -43,6 +44,18 @@ public class AccountResponse extends BaseResponse implements ResourceLimitAndCou @Param(description = "account type (admin, domain-admin, user)") private Short accountType; + @SerializedName(ApiConstants.ROLE_ID) + @Param(description = "the ID of the role") + private String roleId; + + @SerializedName(ApiConstants.ROLE_TYPE) + @Param(description = "the type of the role (Admin, ResourceAdmin, DomainAdmin, User)") + private String roleType; + + @SerializedName(ApiConstants.ROLE_NAME) + @Param(description = "the name of the role") + private String roleName; + @SerializedName(ApiConstants.DOMAIN_ID) @Param(description = "id of the Domain the account belongs too") private String domainId; @@ -260,6 +273,20 @@ public void setAccountType(Short accountType) { this.accountType = accountType; } + public void setRoleId(String roleId) { + this.roleId = roleId; + } + + public void setRoleType(RoleType roleType) { + if (roleType != null) { + this.roleType = roleType.name(); + } + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } + public void setDomainId(String domainId) { this.domainId = domainId; } diff --git a/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java b/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java index 623a0a231f..bcdad468fa 100644 --- a/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java +++ b/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java @@ -28,6 +28,10 @@ public class CapabilitiesResponse extends BaseResponse { @Param(description = "true if security groups support is enabled, false otherwise") private boolean securityGroupsEnabled; + @SerializedName("dynamicrolesenabled") + @Param(description = "true if dynamic role-based api checker is enabled, false otherwise") + private boolean dynamicRolesEnabled; + @SerializedName("cloudstackversion") @Param(description = "version of the cloud stack") private String cloudStackVersion; @@ -84,6 +88,10 @@ public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) { this.securityGroupsEnabled = securityGroupsEnabled; } + public void setDynamicRolesEnabled(boolean dynamicRolesEnabled) { + this.dynamicRolesEnabled = dynamicRolesEnabled; + } + public void setCloudStackVersion(String cloudStackVersion) { this.cloudStackVersion = cloudStackVersion; } diff --git a/api/src/org/apache/cloudstack/api/response/RolePermissionResponse.java b/api/src/org/apache/cloudstack/api/response/RolePermissionResponse.java new file mode 100644 index 0000000000..ac1c5298c1 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/RolePermissionResponse.java @@ -0,0 +1,101 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.Rule; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +@EntityReference(value = RolePermission.class) +public class RolePermissionResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) + @Param(description = "the ID of the role permission") + private String id; + + @SerializedName(ApiConstants.ROLE_ID) + @Param(description = "the ID of the role to which the role permission belongs") + private String roleId; + + @SerializedName(ApiConstants.ROLE_NAME) + @Param(description = "the name of the role to which the role permission belongs") + private String roleName; + + @SerializedName(ApiConstants.RULE) + @Param(description = "the api name or wildcard rule") + private String rule; + + @SerializedName(ApiConstants.PERMISSION) + @Param(description = "the permission type of the api name or wildcard rule, allow/deny") + private String rulePermission; + + @SerializedName(ApiConstants.DESCRIPTION) + @Param(description = "the description of the role permission") + private String ruleDescription; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getRoleId() { + return roleId; + } + + public void setRoleId(String roleId) { + this.roleId = roleId; + } + + public String getRoleName() { + return roleName; + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } + + public String getRule() { + return rule; + } + + public void setRule(Rule rule) { + if (rule != null) { + this.rule = rule.getRuleString(); + } + } + + public String getRulePermission() { + return rulePermission; + } + + public void setRulePermission(RolePermission.Permission rulePermission) { + if (rulePermission != null) { + this.rulePermission = rulePermission.name().toLowerCase(); + } + } + + public void setDescription(String description) { + this.ruleDescription = description; + } +} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/api/response/RoleResponse.java b/api/src/org/apache/cloudstack/api/response/RoleResponse.java new file mode 100644 index 0000000000..fd4bf28e61 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/RoleResponse.java @@ -0,0 +1,63 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +@EntityReference(value = Role.class) +public class RoleResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) + @Param(description = "the ID of the role") + private String id; + + @SerializedName(ApiConstants.NAME) + @Param(description = "the name of the role") + private String roleName; + + @SerializedName(ApiConstants.TYPE) + @Param(description = "the type of the role") + private String roleType; + + @SerializedName(ApiConstants.DESCRIPTION) + @Param(description = "the description of the role") + private String roleDescription; + + public void setId(String id) { + this.id = id; + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } + + public void setRoleType(RoleType roleType) { + if (roleType != null) { + this.roleType = roleType.name(); + } + } + + public void setDescription(String description) { + this.roleDescription = description; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/UserResponse.java b/api/src/org/apache/cloudstack/api/response/UserResponse.java index 36611ae738..cc986b38a1 100644 --- a/api/src/org/apache/cloudstack/api/response/UserResponse.java +++ b/api/src/org/apache/cloudstack/api/response/UserResponse.java @@ -20,6 +20,7 @@ import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; @@ -65,6 +66,18 @@ public class UserResponse extends BaseResponse { @Param(description = "the account type of the user") private Short accountType; + @SerializedName(ApiConstants.ROLE_ID) + @Param(description = "the ID of the role") + private String roleId; + + @SerializedName(ApiConstants.ROLE_TYPE) + @Param(description = "the type of the role") + private String roleType; + + @SerializedName(ApiConstants.ROLE_NAME) + @Param(description = "the name of the role") + private String roleName; + @SerializedName("domainid") @Param(description = "the domain ID of the user") private String domainId; @@ -174,6 +187,20 @@ public void setAccountType(Short accountType) { this.accountType = accountType; } + public void setRoleId(String roleId) { + this.roleId = roleId; + } + + public void setRoleType(RoleType roleType) { + if (roleType != null) { + this.roleType = roleType.name(); + } + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } + public String getDomainId() { return domainId; } diff --git a/api/test/org/apache/cloudstack/acl/RoleTypeTest.java b/api/test/org/apache/cloudstack/acl/RoleTypeTest.java new file mode 100644 index 0000000000..611b761014 --- /dev/null +++ b/api/test/org/apache/cloudstack/acl/RoleTypeTest.java @@ -0,0 +1,100 @@ +// 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.acl; + +import com.cloud.user.Account; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.Arrays; + +public class RoleTypeTest { + + @Test + public void testValidRoleTypeFromString() { + for (RoleType roleType : RoleType.values()) { + Assert.assertEquals(RoleType.fromString(roleType.name()), roleType); + } + } + + @Test + public void testInvalidRoleTypeFromString() { + for (String roleType : Arrays.asList(null, "", "admin", "12345%&^*")) { + try { + RoleType.fromString(roleType); + Assert.fail("Invalid roletype provided, exception was expected"); + } catch (IllegalStateException e) { + Assert.assertEquals(e.getMessage(), "Illegal RoleType name provided"); + } + } + } + + @Test + public void testDefaultRoleMaskByValue() { + Assert.assertEquals(RoleType.fromMask(1), RoleType.Admin); + Assert.assertEquals(RoleType.fromMask(2), RoleType.ResourceAdmin); + Assert.assertEquals(RoleType.fromMask(4), RoleType.DomainAdmin); + Assert.assertEquals(RoleType.fromMask(8), RoleType.User); + Assert.assertEquals(RoleType.fromMask(0), RoleType.Unknown); + } + + @Test + public void testGetByAccountType() { + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_NORMAL), RoleType.User); + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_ADMIN), RoleType.Admin); + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_DOMAIN_ADMIN), RoleType.DomainAdmin); + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN), RoleType.ResourceAdmin); + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_PROJECT), RoleType.Unknown); + } + + @Test + public void testGetRoleByAccountTypeWhenRoleIdIsProvided() { + Assert.assertEquals(RoleType.getRoleByAccountType(123L, Account.ACCOUNT_TYPE_ADMIN), Long.valueOf(123L)); + Assert.assertEquals(RoleType.getRoleByAccountType(1234L, null), Long.valueOf(1234L)); + } + + @Test + public void testGetRoleByAccountTypeForDefaultAccountTypes() { + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_ADMIN), (Long) RoleType.Admin.getId()); + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_NORMAL), (Long) RoleType.User.getId()); + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_DOMAIN_ADMIN), (Long) RoleType.DomainAdmin.getId()); + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN), (Long) RoleType.ResourceAdmin.getId()); + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_PROJECT), null); + } + + @Test + public void testGetAccountTypeByRoleWhenRoleIsNull() { + for (Short accountType: Arrays.asList( + Account.ACCOUNT_TYPE_NORMAL, + Account.ACCOUNT_TYPE_ADMIN, + Account.ACCOUNT_TYPE_DOMAIN_ADMIN, + Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN, + Account.ACCOUNT_TYPE_PROJECT, + (short) 12345)) { + Assert.assertEquals(RoleType.getAccountTypeByRole(null, accountType), accountType); + } + } + + @Test + public void testGetAccountTypeByRole() { + Role role = Mockito.mock(Role.class); + Mockito.when(role.getRoleType()).thenReturn(RoleType.Admin); + Mockito.when(role.getId()).thenReturn(100L); + Assert.assertEquals(RoleType.getAccountTypeByRole(role, null), (Short) RoleType.Admin.getAccountType()); + } +} \ No newline at end of file diff --git a/api/test/org/apache/cloudstack/acl/RuleTest.java b/api/test/org/apache/cloudstack/acl/RuleTest.java new file mode 100644 index 0000000000..08bd775bd0 --- /dev/null +++ b/api/test/org/apache/cloudstack/acl/RuleTest.java @@ -0,0 +1,98 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.acl; + +import com.cloud.exception.InvalidParameterValueException; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; + +public class RuleTest { + + @Test + public void testToString() throws Exception { + Rule rule = new Rule("someString"); + Assert.assertEquals(rule.toString(), "someString"); + } + + @Test + public void testMatchesEmpty() throws Exception { + Rule rule = new Rule("someString"); + Assert.assertFalse(rule.matches("")); + } + + @Test + public void testMatchesNull() throws Exception { + Rule rule = new Rule("someString"); + Assert.assertFalse(rule.matches(null)); + } + + @Test + public void testMatchesSpace() throws Exception { + Rule rule = new Rule("someString"); + Assert.assertFalse(rule.matches(" ")); + } + + @Test + public void testMatchesAPI() throws Exception { + Rule rule = new Rule("someApi"); + Assert.assertTrue(rule.matches("someApi")); + } + + @Test + public void testMatchesWildcardSuffix() throws Exception { + Rule rule = new Rule("list*"); + Assert.assertTrue(rule.matches("listHosts")); + } + + @Test + public void testMatchesWildcardPrefix() throws Exception { + Rule rule = new Rule("*User"); + Assert.assertTrue(rule.matches("createUser")); + } + + @Test + public void testMatchesWildcardMiddle() throws Exception { + Rule rule = new Rule("list*s"); + Assert.assertTrue(rule.matches("listClusters")); + } + + @Test + public void testValidateRuleWithValidData() throws Exception { + for (String rule : Arrays.asList("a", "1", "someApi", "someApi321", "123SomeApi", + "prefix*", "*middle*", "*Suffix", + "*", "**", "f***", "m0nk3yMa**g1c*")) { + Assert.assertEquals(new Rule(rule).toString(), rule); + } + } + + @Test + public void testValidateRuleWithInvalidData() throws Exception { + for (String rule : Arrays.asList(null, "", " ", " ", "\n", "\t", "\r", "\"", "\'", + "^someApi$", "^someApi", "some$", "some-Api;", "some,Api", + "^", "$", "^$", ".*", "\\w+", "r**l3rd0@Kr3", "j@s1n|+|0ȷ", + "[a-z0-9-]+", "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$")) { + try { + new Rule(rule); + Assert.fail("Invalid rule, exception was expected"); + } catch (InvalidParameterValueException e) { + Assert.assertTrue(e.getMessage().startsWith("Only API names and wildcards are allowed")); + } + } + } +} \ No newline at end of file diff --git a/api/test/org/apache/cloudstack/api/command/admin/account/CreateAccountCmdTest.java b/api/test/org/apache/cloudstack/api/command/admin/account/CreateAccountCmdTest.java index c0a046de43..b50b2269c1 100644 --- a/api/test/org/apache/cloudstack/api/command/admin/account/CreateAccountCmdTest.java +++ b/api/test/org/apache/cloudstack/api/command/admin/account/CreateAccountCmdTest.java @@ -18,6 +18,7 @@ */ package org.apache.cloudstack.api.command.admin.account; +import org.apache.cloudstack.acl.RoleService; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.context.CallContext; @@ -41,10 +42,13 @@ public class CreateAccountCmdTest { @Mock private AccountService accountService; + @Mock + private RoleService roleService; @InjectMocks private CreateAccountCmd createAccountCmd = new CreateAccountCmd(); + private long roleId = 1L; private short accountType = 1; private Long domainId = 1L; @@ -69,7 +73,7 @@ public void testExecuteWithNotBlankPassword() { } catch (ServerApiException e) { Assert.assertTrue("Received exception as the mock accountService createUserAccount returns null user", true); } - Mockito.verify(accountService, Mockito.times(1)).createUserAccount(null, "Test", null, null, null, null, null, accountType, domainId, null, null, null, null); + Mockito.verify(accountService, Mockito.times(1)).createUserAccount(null, "Test", null, null, null, null, null, accountType, roleId, domainId, null, null, null, null); } @Test @@ -82,7 +86,7 @@ public void testExecuteWithNullPassword() { Assert.assertEquals(ApiErrorCode.PARAM_ERROR, e.getErrorCode()); Assert.assertEquals("Empty passwords are not allowed", e.getMessage()); } - Mockito.verify(accountService, Mockito.never()).createUserAccount(null, null, null, null, null, null, null, accountType, domainId, null, null, null, null); + Mockito.verify(accountService, Mockito.never()).createUserAccount(null, null, null, null, null, null, null, accountType, roleId, domainId, null, null, null, null); } @Test @@ -95,6 +99,6 @@ public void testExecuteWithEmptyPassword() { Assert.assertEquals(ApiErrorCode.PARAM_ERROR, e.getErrorCode()); Assert.assertEquals("Empty passwords are not allowed", e.getMessage()); } - Mockito.verify(accountService, Mockito.never()).createUserAccount(null, null, null, null, null, null, null, accountType, domainId, null, null, null, null); + Mockito.verify(accountService, Mockito.never()).createUserAccount(null, null, null, null, null, null, null, accountType, roleId, domainId, null, null, null, null); } } diff --git a/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java index 63c4a03243..65b9330664 100644 --- a/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java +++ b/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java @@ -19,6 +19,7 @@ import junit.framework.Assert; import junit.framework.TestCase; +import org.apache.cloudstack.acl.RoleService; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -48,22 +49,46 @@ public void setUp() { updateCfgCmd = new UpdateCfgCmd(); } + @Test + public void testExecuteForEmptyCfgName() { + updateCfgCmd._configService = configService; + + try { + updateCfgCmd.execute(); + } catch (ServerApiException exception) { + Assert.assertEquals("Empty configuration name provided", exception.getDescription()); + } + } + + @Test + public void testExecuteForRestrictedCfg() { + updateCfgCmd._configService = configService; + updateCfgCmd.setCfgName(RoleService.EnableDynamicApiChecker.key()); + + try { + updateCfgCmd.execute(); + } catch (ServerApiException exception) { + Assert.assertEquals("Restricted configuration update not allowed", exception.getDescription()); + } + } + @Test public void testExecuteForEmptyResult() { updateCfgCmd._configService = configService; + updateCfgCmd.setCfgName("some.cfg"); try { updateCfgCmd.execute(); } catch (ServerApiException exception) { Assert.assertEquals("Failed to update config", exception.getDescription()); } - } @Test public void testExecuteForNullResult() { updateCfgCmd._configService = configService; + updateCfgCmd.setCfgName("some.cfg"); try { Mockito.when(configService.updateConfiguration(updateCfgCmd)).thenReturn(null); @@ -88,6 +113,7 @@ public void testCreateSuccess() { Configuration cfg = Mockito.mock(Configuration.class); updateCfgCmd._configService = configService; updateCfgCmd._responseGenerator = responseGenerator; + updateCfgCmd.setCfgName("some.cfg"); try { Mockito.when(configService.updateConfiguration(updateCfgCmd)).thenReturn(cfg); diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index fbdedda5c2..5e979074b6 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -1095,9 +1095,17 @@ label.retry.interval=Retry Interval label.review=Review label.revoke.project.invite=Revoke invitation label.role=Role +label.roles=Roles +label.roletype=Role Type +label.add.role=Add Role +label.edit.role=Edit Role +label.delete.role=Delete Role +message.role.ordering.fail=Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again. label.root.certificate=Root certificate label.root.disk.controller=Root disk controller label.root.disk.offering=Root Disk Offering +label.permission=Permission +label.rule=Rule label.rules=Rules label.running.vms=Running VMs label.s3.access_key=Access Key diff --git a/client/pom.xml b/client/pom.xml index a1e4f609f4..9bd80b722c 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -50,6 +50,11 @@ cloud-plugin-acl-static-role-based ${project.version} + + org.apache.cloudstack + cloud-plugin-acl-dynamic-role-based + ${project.version} + org.apache.cloudstack cloud-plugin-dedicated-resources diff --git a/debian/cloudstack-management.install b/debian/cloudstack-management.install index 4e016dfe29..c66938263e 100644 --- a/debian/cloudstack-management.install +++ b/debian/cloudstack-management.install @@ -18,7 +18,6 @@ /etc/cloudstack/management/catalina.policy /etc/cloudstack/management/catalina.properties /etc/cloudstack/management/logging.properties -/etc/cloudstack/management/commands.properties /etc/cloudstack/management/ehcache.xml /etc/cloudstack/management/server-ssl.xml /etc/cloudstack/management/server-nonssl.xml diff --git a/debian/control b/debian/control index 05058a8dcf..6e7881b1bc 100644 --- a/debian/control +++ b/debian/control @@ -15,7 +15,7 @@ Description: A common package which contains files which are shared by several C Package: cloudstack-management Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, cloudstack-common (= ${source:Version}), tomcat6, sudo, jsvc, python-mysql.connector, libmysql-java, augeas-tools, mysql-client, adduser, bzip2 +Depends: ${misc:Depends}, ${python:Depends}, cloudstack-common (= ${source:Version}), tomcat6 | tomcat7, sudo, jsvc, python-mysql.connector, libmysql-java, augeas-tools, mysql-client, adduser, bzip2 Conflicts: cloud-server, cloud-client, cloud-client-ui Description: CloudStack server library The CloudStack management server diff --git a/developer/developer-prefill.sql b/developer/developer-prefill.sql index f874118e19..0dbe1803b9 100644 --- a/developer/developer-prefill.sql +++ b/developer/developer-prefill.sql @@ -106,6 +106,11 @@ INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', 'direct.agent.load.size', '1000'); +-- Enable dynamic RBAC by default for fresh deployments +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'RoleService', + 'dynamic.apichecker.enabled', 'true'); + -- Add developer configuration entry; allows management server to be run as a user other than "cloud" INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', diff --git a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index 67ed2a7d25..a3d58fc539 100644 --- a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -113,6 +113,8 @@ + + diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java index 9e5213478e..d1240ecf2c 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java @@ -17,12 +17,21 @@ package com.cloud.upgrade.dao; +import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.db.ScriptRunner; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; +import org.apache.cloudstack.acl.RoleType; import org.apache.log4j.Logger; import java.io.File; +import java.io.FileReader; +import java.io.IOException; import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Map; public class Upgrade481to490 implements DbUpgrade { final static Logger s_logger = Logger.getLogger(Upgrade481to490.class); @@ -53,6 +62,71 @@ public File[] getPrepareScripts() { @Override public void performDataMigration(Connection conn) { + setupRolesAndPermissionsForDynamicChecker(conn); + } + + private void migrateAccountsToDefaultRoles(final Connection conn) { + try (final PreparedStatement selectStatement = conn.prepareStatement("SELECT `id`, `type` FROM `cloud`.`account`;"); + final ResultSet selectResultSet = selectStatement.executeQuery()) { + while (selectResultSet.next()) { + final Long accountId = selectResultSet.getLong(1); + final Short accountType = selectResultSet.getShort(2); + final Long roleId = RoleType.getByAccountType(accountType).getId(); + if (roleId < 1L || roleId > 4L) { + s_logger.warn("Skipping role ID migration due to invalid role_id resolved for account id=" + accountId); + continue; + } + try (final PreparedStatement updateStatement = conn.prepareStatement("UPDATE `cloud`.`account` SET account.role_id = ? WHERE account.id = ? ;")) { + updateStatement.setLong(1, roleId); + updateStatement.setLong(2, accountId); + updateStatement.executeUpdate(); + } catch (SQLException e) { + s_logger.error("Failed to update cloud.account role_id for account id:" + accountId + " with exception: " + e.getMessage()); + throw new CloudRuntimeException("Exception while updating cloud.account role_id", e); + } + } + } catch (SQLException e) { + throw new CloudRuntimeException("Exception while migrating existing account table's role_id column to a role based on account type", e); + } + s_logger.debug("Done migrating existing accounts to use one of default roles based on account type"); + } + + private void setupRolesAndPermissionsForDynamicChecker(final Connection conn) { + final String alterTableSql = "ALTER TABLE `cloud`.`account` " + + "ADD COLUMN `role_id` bigint(20) unsigned COMMENT 'role id for this account' AFTER `type`, " + + "ADD KEY `fk_account__role_id` (`role_id`), " + + "ADD CONSTRAINT `fk_account__role_id` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`);"; + try (final PreparedStatement pstmt = conn.prepareStatement(alterTableSql)) { + pstmt.executeUpdate(); + } catch (SQLException e) { + if (e.getMessage().contains("role_id")) { + s_logger.warn("cloud.account table already has the role_id column, skipping altering table and migration of accounts"); + return; + } else { + throw new CloudRuntimeException("Unable to create column quota_calculated in table cloud_usage.cloud_usage", e); + } + } + + migrateAccountsToDefaultRoles(conn); + + final Map apiMap = PropertiesUtil.processConfigFile(new String[] { PropertiesUtil.getDefaultApiCommandsFileName() }); + if (apiMap == null || apiMap.isEmpty()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("The commands.properties file and default role permissions were not found. " + + "Assuming new installation, configuring default role-api mappings."); + } + String script = Script.findScript("", "db/create-default-role-api-mappings.sql"); + if (script == null) { + s_logger.error("Unable to find default role-api mapping sql file, please configure api per role manually"); + return; + } + try(final FileReader reader = new FileReader(new File(script))) { + ScriptRunner runner = new ScriptRunner(conn, false, true); + runner.runScript(reader); + } catch (SQLException | IOException e) { + s_logger.error("Unable to insert default api-role mappings from file: " + script + ". Please configure api per role manually, giving up!", e); + } + } } @Override @@ -61,7 +135,6 @@ public File[] getCleanupScripts() { if (script == null) { throw new CloudRuntimeException("Unable to find db/schema-481to490-cleanup.sql"); } - return new File[] {new File(script)}; } } diff --git a/engine/schema/src/com/cloud/user/AccountVO.java b/engine/schema/src/com/cloud/user/AccountVO.java index 0f5a0446e9..a504d2fdae 100644 --- a/engine/schema/src/com/cloud/user/AccountVO.java +++ b/engine/schema/src/com/cloud/user/AccountVO.java @@ -16,8 +16,8 @@ // under the License. package com.cloud.user; -import java.util.Date; -import java.util.UUID; +import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.acl.RoleType; import javax.persistence.Column; import javax.persistence.Entity; @@ -27,8 +27,8 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; - -import com.cloud.utils.db.GenericDao; +import java.util.Date; +import java.util.UUID; @Entity @Table(name = "account") @@ -44,6 +44,9 @@ public class AccountVO implements Account { @Column(name = "type") private short type = ACCOUNT_TYPE_NORMAL; + @Column(name = "role_id") + private Long roleId; + @Column(name = "domain_id") private long domainId; @@ -78,13 +81,21 @@ public AccountVO(long id) { uuid = UUID.randomUUID().toString(); } - public AccountVO(String accountName, long domainId, String networkDomain, short type, String uuid) { + public AccountVO(final String accountName, final long domainId, final String networkDomain, final short type, final String uuid) { this.accountName = accountName; this.domainId = domainId; this.networkDomain = networkDomain; this.type = type; - state = State.enabled; + this.state = State.enabled; this.uuid = uuid; + this.roleId = RoleType.getRoleByAccountType(null, type); + } + + public AccountVO(final String accountName, final long domainId, final String networkDomain, final short type, final Long roleId, final String uuid) { + this(accountName, domainId, networkDomain, type, uuid); + if (roleId != null) { + this.roleId = roleId; + } } public void setNeedsCleanup(boolean value) { @@ -122,6 +133,14 @@ public void setType(short type) { this.type = type; } + public Long getRoleId() { + return roleId; + } + + public void setRoleId(long roleId) { + this.roleId = roleId; + } + @Override public long getDomainId() { return domainId; diff --git a/engine/schema/src/com/cloud/user/dao/AccountDao.java b/engine/schema/src/com/cloud/user/dao/AccountDao.java index 4c7ce8e31b..374c9cc43d 100644 --- a/engine/schema/src/com/cloud/user/dao/AccountDao.java +++ b/engine/schema/src/com/cloud/user/dao/AccountDao.java @@ -41,6 +41,8 @@ public interface AccountDao extends GenericDao { List findActiveAccountsForDomain(Long domain); + List findAccountsByRole(Long roleId); + void markForCleanup(long accountId); List listAccounts(String accountName, Long domainId, Filter filter); diff --git a/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java b/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java index bff6213c10..27891503dc 100644 --- a/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java +++ b/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java @@ -44,7 +44,7 @@ public class AccountDaoImpl extends GenericDaoBase implements AccountDao { private static final Logger s_logger = Logger.getLogger(AccountDaoImpl.class); private static final String FIND_USER_ACCOUNT_BY_API_KEY = "SELECT u.id, u.username, u.account_id, u.secret_key, u.state, " - + "a.id, a.account_name, a.type, a.domain_id, a.state " + "FROM `cloud`.`user` u, `cloud`.`account` a " + + "a.id, a.account_name, a.type, a.role_id, a.domain_id, a.state " + "FROM `cloud`.`user` u, `cloud`.`account` a " + "WHERE u.account_id = a.id AND u.api_key = ? and u.removed IS NULL"; protected final SearchBuilder AllFieldsSearch; @@ -53,6 +53,7 @@ public class AccountDaoImpl extends GenericDaoBase implements A protected final SearchBuilder CleanupForRemovedAccountsSearch; protected final SearchBuilder CleanupForDisabledAccountsSearch; protected final SearchBuilder NonProjectAccountSearch; + protected final SearchBuilder AccountByRoleSearch; protected final GenericSearchBuilder AccountIdsSearch; public AccountDaoImpl() { @@ -96,6 +97,10 @@ public AccountDaoImpl() { AccountIdsSearch.selectFields(AccountIdsSearch.entity().getId()); AccountIdsSearch.and("ids", AccountIdsSearch.entity().getDomainId(), Op.IN); AccountIdsSearch.done(); + + AccountByRoleSearch = createSearchBuilder(); + AccountByRoleSearch.and("roleId", AccountByRoleSearch.entity().getRoleId(), SearchCriteria.Op.EQ); + AccountByRoleSearch.done(); } @Override @@ -140,8 +145,9 @@ public Pair findUserAccountByApiKey(String apiKey) { AccountVO a = new AccountVO(rs.getLong(6)); a.setAccountName(rs.getString(7)); a.setType(rs.getShort(8)); - a.setDomainId(rs.getLong(9)); - a.setState(State.valueOf(rs.getString(10))); + a.setRoleId(rs.getLong(9)); + a.setDomainId(rs.getLong(10)); + a.setState(State.valueOf(rs.getString(11))); userAcctPair = new Pair(u, a); } @@ -258,6 +264,13 @@ public List findActiveAccountsForDomain(Long domain) { return listBy(sc); } + @Override + public List findAccountsByRole(Long roleId) { + SearchCriteria sc = AccountByRoleSearch.create(); + sc.setParameters("roleId", roleId); + return listBy(sc); + } + @Override public void markForCleanup(long accountId) { AccountVO account = findByIdIncludingRemoved(accountId); diff --git a/engine/schema/src/org/apache/cloudstack/acl/RolePermissionVO.java b/engine/schema/src/org/apache/cloudstack/acl/RolePermissionVO.java new file mode 100644 index 0000000000..a81cebb70d --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/RolePermissionVO.java @@ -0,0 +1,120 @@ +// 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.acl; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.UUID; + +@Entity +@Table(name = "role_permissions") +public class RolePermissionVO implements RolePermission { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "role_id") + private long roleId; + + @Column(name = "rule") + private String rule; + + @Column(name = "permission", nullable = false) + @Enumerated(value = EnumType.STRING) + private Permission permission = RolePermission.Permission.DENY; + + @Column(name = "description") + private String description; + + @Column(name = "sort_order") + private long sortOrder = 0; + + public RolePermissionVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public RolePermissionVO(final long roleId, final String rule, final Permission permission, final String description) { + this(); + this.roleId = roleId; + this.rule = rule; + this.permission = permission; + this.description = description; + } + + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return uuid; + } + + public long getRoleId() { + return roleId; + } + + public void setRoleId(long roleId) { + this.roleId = roleId; + } + + @Override + public Rule getRule() { + return new Rule(rule); + } + + public void setRule(String rule) { + this.rule = rule; + } + + @Override + public Permission getPermission() { + return permission; + } + + public void setPermission(Permission permission) { + this.permission = permission; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public long getSortOrder() { + return sortOrder; + } + + public void setSortOrder(long sortOrder) { + this.sortOrder = sortOrder; + } +} \ No newline at end of file diff --git a/engine/schema/src/org/apache/cloudstack/acl/RoleVO.java b/engine/schema/src/org/apache/cloudstack/acl/RoleVO.java new file mode 100644 index 0000000000..f3404ab6d7 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/RoleVO.java @@ -0,0 +1,106 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.acl; + +import com.cloud.utils.db.GenericDao; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; +import java.util.UUID; + +@Entity +@Table(name = "roles") +public class RoleVO implements Role { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "name") + private String name; + + @Column(name = "role_type", nullable = false) + @Enumerated(value = EnumType.STRING) + private RoleType roleType = RoleType.User; + + @Column(name = "description") + private String description; + + @Column(name = GenericDao.REMOVED_COLUMN) + private Date removed; + + public RoleVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public RoleVO(final String name, final RoleType roleType, final String description) { + this(); + this.name = name; + this.roleType = roleType; + this.description = description; + } + + public RoleVO(final long id, final String name, final RoleType roleType, final String description) { + this(name, roleType, description); + this.id = id; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public RoleType getRoleType() { + return roleType; + } + + public void setRoleType(RoleType roleType) { + this.roleType = roleType; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDao.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDao.java new file mode 100644 index 0000000000..e53654d998 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDao.java @@ -0,0 +1,29 @@ +// 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.acl.dao; + +import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.acl.RoleVO; + +import java.util.List; + +public interface RoleDao extends GenericDao { + List findAllByName(String roleName); + List findAllByRoleType(RoleType type); +} diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDaoImpl.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDaoImpl.java new file mode 100644 index 0000000000..c7eb496213 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDaoImpl.java @@ -0,0 +1,61 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.acl.dao; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.acl.RoleVO; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import java.util.List; + +@Component +@Local(value = {RoleDao.class}) +public class RoleDaoImpl extends GenericDaoBase implements RoleDao { + private final SearchBuilder RoleByNameSearch; + private final SearchBuilder RoleByTypeSearch; + + public RoleDaoImpl() { + super(); + + RoleByNameSearch = createSearchBuilder(); + RoleByNameSearch.and("roleName", RoleByNameSearch.entity().getName(), SearchCriteria.Op.LIKE); + RoleByNameSearch.done(); + + RoleByTypeSearch = createSearchBuilder(); + RoleByTypeSearch.and("roleType", RoleByTypeSearch.entity().getRoleType(), SearchCriteria.Op.EQ); + RoleByTypeSearch.done(); + } + + @Override + public List findAllByName(final String roleName) { + SearchCriteria sc = RoleByNameSearch.create(); + sc.setParameters("roleName", "%" + roleName + "%"); + return listBy(sc); + } + + @Override + public List findAllByRoleType(final RoleType type) { + SearchCriteria sc = RoleByTypeSearch.create(); + sc.setParameters("roleType", type); + return listBy(sc); + } +} diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java new file mode 100644 index 0000000000..3754491965 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java @@ -0,0 +1,49 @@ +// 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.acl.dao; + +import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RolePermissionVO; + +import java.util.List; + +public interface RolePermissionsDao extends GenericDao { + /** + * Adds a new role permission at the end of the list of role permissions + * @param item the new role permission + * @return returns persisted role permission + */ + RolePermissionVO persist(final RolePermissionVO item); + + /** + * Moves an existing role permission under a given parent role permission + * @param role the existing role + * @param newOrder the new role permissions order + * @return returns true on success + */ + boolean update(final Role role, final List newOrder); + + /** + * Returns ordered linked-list of role permission for a given role + * @param roleId the ID of the role + * @return returns list of role permissions + */ + List findAllByRoleIdSorted(Long roleId); +} diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java new file mode 100644 index 0000000000..960b652a3b --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java @@ -0,0 +1,166 @@ +// 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.acl.dao; + +import com.cloud.utils.db.Attribute; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionStatus; +import com.cloud.utils.db.UpdateBuilder; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RolePermissionVO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Component +@Local(value = {RolePermissionsDao.class}) +public class RolePermissionsDaoImpl extends GenericDaoBase implements RolePermissionsDao { + protected static final Logger LOGGER = Logger.getLogger(RolePermissionsDaoImpl.class); + + private final SearchBuilder RolePermissionsSearch; + private Attribute sortOrderAttribute; + + public RolePermissionsDaoImpl() { + super(); + + RolePermissionsSearch = createSearchBuilder(); + RolePermissionsSearch.and("uuid", RolePermissionsSearch.entity().getUuid(), SearchCriteria.Op.EQ); + RolePermissionsSearch.and("roleId", RolePermissionsSearch.entity().getRoleId(), SearchCriteria.Op.EQ); + RolePermissionsSearch.and("sortOrder", RolePermissionsSearch.entity().getSortOrder(), SearchCriteria.Op.EQ); + RolePermissionsSearch.done(); + + sortOrderAttribute = _allAttributes.get("sortOrder"); + + assert (sortOrderAttribute != null) : "Couldn't find one of these attributes"; + } + + private boolean updateSortOrder(final RolePermissionVO permissionBeingMoved, final RolePermissionVO parentPermission) { + if (parentPermission != null && permissionBeingMoved.getId() == parentPermission.getId()) { + return true; + } + final List newOrderedPermissionsList = new ArrayList<>(); + // Null parent implies item needs to move to the top + if (parentPermission == null) { + newOrderedPermissionsList.add(permissionBeingMoved); + } + for (final RolePermissionVO permission : findAllByRoleIdSorted(permissionBeingMoved.getRoleId())) { + if (permission.getId() == permissionBeingMoved.getId()) { + continue; + } + newOrderedPermissionsList.add(permission); + if (parentPermission != null && permission.getId() == parentPermission.getId()) { + newOrderedPermissionsList.add(permissionBeingMoved); + } + } + long sortOrder = 0L; + for (final RolePermissionVO permission : newOrderedPermissionsList) { + permission.setSortOrder(sortOrder++); + if (!update(permission.getId(), permission)) { + LOGGER.warn("Failed to update item's sort order with id:" + permission.getId() + " while moving permission with id:" + permissionBeingMoved.getId() + " to a new position"); + return false; + } + } + return true; + } + + @Override + public RolePermissionVO persist(final RolePermissionVO item) { + item.setSortOrder(0); + final List permissionsList = findAllByRoleIdSorted(item.getRoleId()); + if (permissionsList != null && permissionsList.size() > 0) { + RolePermission lastRule = permissionsList.get(permissionsList.size() - 1); + item.setSortOrder(lastRule.getSortOrder() + 1); + } + return super.persist(item); + } + + @Override + public boolean update(final Role role, final List newOrder) { + if (role == null || newOrder == null || newOrder.isEmpty()) { + return false; + } + return Transaction.execute(new TransactionCallback() { + @Override + public Boolean doInTransaction(TransactionStatus status) { + final String failMessage = "The role's rule permissions list has changed while you were making updates, aborted re-ordering of rules. Please try again."; + final List currentOrder = findAllByRoleIdSorted(role.getId()); + if (role.getId() < 1L || newOrder.size() != currentOrder.size()) { + throw new CloudRuntimeException(failMessage); + } + final Set newOrderSet = new HashSet<>(); + for (final RolePermission permission : newOrder) { + if (permission == null) { + continue; + } + newOrderSet.add(permission.getId()); + } + final Set currentOrderSet = new HashSet<>(); + for (final RolePermission permission : currentOrder) { + currentOrderSet.add(permission.getId()); + } + if (!newOrderSet.equals(currentOrderSet)) { + throw new CloudRuntimeException(failMessage); + } + long sortOrder = 0L; + for (RolePermission rolePermission : newOrder) { + final SearchCriteria sc = RolePermissionsSearch.create(); + sc.setParameters("uuid", rolePermission.getUuid()); + sc.setParameters("roleId", role.getId()); + sc.setParameters("sortOrder", rolePermission.getSortOrder()); + + final UpdateBuilder ub = getUpdateBuilder(rolePermission); + ub.set(rolePermission, sortOrderAttribute, sortOrder); + final int result = update(ub, sc, null); + if (result < 1) { + throw new CloudRuntimeException(failMessage); + } + sortOrder++; + } + return true; + } + }); + } + + @Override + public List findAllByRoleIdSorted(final Long roleId) { + final SearchCriteria sc = RolePermissionsSearch.create(); + if (roleId != null && roleId > 0L) { + sc.setParameters("roleId", roleId); + } + final Filter searchBySorted = new Filter(RolePermissionVO.class, "sortOrder", true, null, null); + searchBySorted.addOrderBy(RolePermissionVO.class, "id", true); + final List rolePermissionList = listBy(sc, searchBySorted); + if (rolePermissionList == null) { + return Collections.emptyList(); + } + return rolePermissionList; + } +} diff --git a/plugins/acl/dynamic-role-based/pom.xml b/plugins/acl/dynamic-role-based/pom.xml new file mode 100644 index 0000000000..96d7e53d1c --- /dev/null +++ b/plugins/acl/dynamic-role-based/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + cloud-plugin-acl-dynamic-role-based + Apache CloudStack Plugin - ACL Dynamic Role Based + + org.apache.cloudstack + cloudstack-plugins + 4.9.0-SNAPSHOT + ../../pom.xml + + diff --git a/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/module.properties b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/module.properties new file mode 100644 index 0000000000..dda9998224 --- /dev/null +++ b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/module.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +name=acl-dynamic-role-based +parent=api diff --git a/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/spring-acl-dynamic-role-based-context.xml b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/spring-acl-dynamic-role-based-context.xml new file mode 100644 index 0000000000..9ffe465a9a --- /dev/null +++ b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/spring-acl-dynamic-role-based-context.xml @@ -0,0 +1,33 @@ + + + + + + + diff --git a/plugins/acl/dynamic-role-based/src/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java b/plugins/acl/dynamic-role-based/src/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java new file mode 100644 index 0000000000..754d4cc86a --- /dev/null +++ b/plugins/acl/dynamic-role-based/src/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java @@ -0,0 +1,144 @@ +// 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.acl; + +import com.cloud.exception.PermissionDeniedException; +import com.cloud.user.Account; +import com.cloud.user.AccountService; +import com.cloud.user.User; +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.component.PluggableService; +import com.google.common.base.Strings; +import org.apache.cloudstack.api.APICommand; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Local(value = APIChecker.class) +public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements APIChecker { + + @Inject + private AccountService accountService; + @Inject + private RoleService roleService; + + private List services; + private Map> annotationRoleBasedApisMap = new HashMap<>(); + + protected DynamicRoleBasedAPIAccessChecker() { + super(); + for (RoleType roleType : RoleType.values()) { + annotationRoleBasedApisMap.put(roleType, new HashSet()); + } + } + + private void denyApiAccess(final String commandName) throws PermissionDeniedException { + throw new PermissionDeniedException("The API does not exist or is blacklisted for the account's role. " + + "The account with is not allowed to request the api: " + commandName); + } + + public boolean isDisabled() { + return !roleService.isEnabled(); + } + + @Override + public boolean checkAccess(User user, String commandName) throws PermissionDeniedException { + if (isDisabled()) { + return true; + } + Account account = accountService.getAccount(user.getAccountId()); + if (account == null) { + throw new PermissionDeniedException("The account id=" + user.getAccountId() + "for user id=" + user.getId() + "is null"); + } + + final Role accountRole = roleService.findRole(account.getRoleId()); + if (accountRole == null || accountRole.getId() < 1L) { + denyApiAccess(commandName); + } + + // Allow all APIs for root admins + if (accountRole.getRoleType() == RoleType.Admin && accountRole.getId() == RoleType.Admin.getId()) { + return true; + } + + // Check against current list of permissions + for (final RolePermission permission : roleService.findAllPermissionsBy(accountRole.getId())) { + if (permission.getRule().matches(commandName)) { + if (RolePermission.Permission.ALLOW.equals(permission.getPermission())) { + return true; + } else { + denyApiAccess(commandName); + } + } + } + + // Check annotations + if (annotationRoleBasedApisMap.get(accountRole.getRoleType()) != null + && annotationRoleBasedApisMap.get(accountRole.getRoleType()).contains(commandName)) { + return true; + } + + // Default deny all + denyApiAccess(commandName); + return false; + } + + public void addApiToRoleBasedAnnotationsMap(final RoleType roleType, final String commandName) { + if (roleType == null || Strings.isNullOrEmpty(commandName)) { + return; + } + final Set commands = annotationRoleBasedApisMap.get(roleType); + if (commands != null && !commands.contains(commandName)) { + commands.add(commandName); + } + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + super.configure(name, params); + return true; + } + + @Override + public boolean start() { + for (PluggableService service : services) { + for (Class clz : service.getCommands()) { + APICommand command = clz.getAnnotation(APICommand.class); + for (RoleType role : command.authorized()) { + addApiToRoleBasedAnnotationsMap(role, command.name()); + } + } + } + return super.start(); + } + + public List getServices() { + return services; + } + + @Inject + public void setServices(List services) { + this.services = services; + } + +} diff --git a/plugins/acl/dynamic-role-based/test/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessCheckerTest.java b/plugins/acl/dynamic-role-based/test/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessCheckerTest.java new file mode 100644 index 0000000000..12ebbe56f5 --- /dev/null +++ b/plugins/acl/dynamic-role-based/test/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessCheckerTest.java @@ -0,0 +1,164 @@ +// 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.acl; + +import com.cloud.exception.PermissionDeniedException; +import com.cloud.user.Account; +import com.cloud.user.AccountService; +import com.cloud.user.AccountVO; +import com.cloud.user.User; +import com.cloud.user.UserVO; +import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import java.lang.reflect.Field; +import java.util.Collections; + +@RunWith(MockitoJUnitRunner.class) +public class DynamicRoleBasedAPIAccessCheckerTest extends TestCase { + + @Mock + private AccountService accountService; + @Mock + private RoleService roleService; + + private DynamicRoleBasedAPIAccessChecker apiAccessChecker; + + private User getTestUser() { + return new UserVO(12L, "some user", "password", "firstName", "lastName", + "email@gmail.com", "GMT", "uuid", User.Source.UNKNOWN); + } + + private Account getTestAccount() { + return new AccountVO("some name", 1L, "network-domain", (short)0, "some-uuid"); + } + + private Role getTestRole() { + return new RoleVO(4L, "SomeRole", RoleType.User, "some description"); + } + + private void setupMockField(final Object obj, final String fieldName, final Object mock) throws NoSuchFieldException, IllegalAccessException { + Field roleDaoField = DynamicRoleBasedAPIAccessChecker.class.getDeclaredField(fieldName); + roleDaoField.setAccessible(true); + roleDaoField.set(obj, mock); + } + + @Override + @Before + public void setUp() throws NoSuchFieldException, IllegalAccessException { + apiAccessChecker = Mockito.spy(new DynamicRoleBasedAPIAccessChecker()); + setupMockField(apiAccessChecker, "accountService", accountService); + setupMockField(apiAccessChecker, "roleService", roleService); + + Mockito.when(accountService.getAccount(Mockito.anyLong())).thenReturn(getTestAccount()); + Mockito.when(roleService.findRole(Mockito.anyLong())).thenReturn((RoleVO) getTestRole()); + + // Enabled plugin + Mockito.doReturn(false).when(apiAccessChecker).isDisabled(); + Mockito.doCallRealMethod().when(apiAccessChecker).checkAccess(Mockito.any(User.class), Mockito.anyString()); + } + + @Test + public void testInvalidAccountCheckAccess() { + Mockito.when(accountService.getAccount(Mockito.anyLong())).thenReturn(null); + try { + apiAccessChecker.checkAccess(getTestUser(), "someApi"); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testInvalidAccountRoleCheckAccess() { + Mockito.when(roleService.findRole(Mockito.anyLong())).thenReturn(null); + try { + apiAccessChecker.checkAccess(getTestUser(), "someApi"); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testDefaultRootAdminAccess() { + Mockito.when(accountService.getAccount(Mockito.anyLong())).thenReturn(new AccountVO("root admin", 1L, null, (short)1, "some-uuid")); + Mockito.when(roleService.findRole(Mockito.anyLong())).thenReturn(new RoleVO(1L, "SomeRole", RoleType.Admin, "default root admin role")); + assertTrue(apiAccessChecker.checkAccess(getTestUser(), "anyApi")); + } + + @Test + public void testInvalidRolePermissionsCheckAccess() { + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.emptyList()); + try { + apiAccessChecker.checkAccess(getTestUser(), "someApi"); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testValidAllowRolePermissionApiCheckAccess() { + final String allowedApiName = "someAllowedApi"; + final RolePermission permission = new RolePermissionVO(1L, allowedApiName, RolePermission.Permission.ALLOW, null); + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission)); + assertTrue(apiAccessChecker.checkAccess(getTestUser(), allowedApiName)); + } + + @Test + public void testValidAllowRolePermissionWildcardCheckAccess() { + final String allowedApiName = "someAllowedApi"; + final RolePermission permission = new RolePermissionVO(1L, "some*", RolePermission.Permission.ALLOW, null); + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission)); + assertTrue(apiAccessChecker.checkAccess(getTestUser(), allowedApiName)); + } + + @Test + public void testValidDenyRolePermissionApiCheckAccess() { + final String denyApiName = "someDeniedApi"; + final RolePermission permission = new RolePermissionVO(1L, denyApiName, RolePermission.Permission.DENY, null); + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission)); + try { + apiAccessChecker.checkAccess(getTestUser(), denyApiName); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testValidDenyRolePermissionWildcardCheckAccess() { + final String denyApiName = "someDenyApi"; + final RolePermission permission = new RolePermissionVO(1L, "*Deny*", RolePermission.Permission.DENY, null); + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission)); + try { + apiAccessChecker.checkAccess(getTestUser(), denyApiName); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testAnnotationFallbackCheckAccess() { + final String allowedApiName = "someApiWithAnnotations"; + apiAccessChecker.addApiToRoleBasedAnnotationsMap(getTestRole().getRoleType(), allowedApiName); + assertTrue(apiAccessChecker.checkAccess(getTestUser(), allowedApiName)); + } + +} \ No newline at end of file diff --git a/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java b/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java index 9221ea4c78..fc78268fc6 100644 --- a/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java +++ b/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java @@ -41,18 +41,20 @@ // based on the account type, access is granted public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIChecker { - protected static final Logger s_logger = Logger.getLogger(StaticRoleBasedAPIAccessChecker.class); + protected static final Logger LOGGER = Logger.getLogger(StaticRoleBasedAPIAccessChecker.class); - Set commandPropertyFiles = new HashSet(); - Set commandsPropertiesOverrides = new HashSet(); - Map> commandsPropertiesRoleBasedApisMap = new HashMap>(); - Map> annotationRoleBasedApisMap = new HashMap>(); + private Set commandPropertyFiles = new HashSet(); + private Set commandsPropertiesOverrides = new HashSet(); + private Map> commandsPropertiesRoleBasedApisMap = new HashMap>(); + private Map> annotationRoleBasedApisMap = new HashMap>(); + private List services; - List _services; @Inject - AccountService _accountService; + private AccountService accountService; + @Inject + private RoleService roleService; - protected StaticRoleBasedAPIAccessChecker() { + public StaticRoleBasedAPIAccessChecker() { super(); for (RoleType roleType : RoleType.values()) { commandsPropertiesRoleBasedApisMap.put(roleType, new HashSet()); @@ -60,23 +62,31 @@ protected StaticRoleBasedAPIAccessChecker() { } } + public boolean isDisabled() { + return roleService.isEnabled(); + } + @Override public boolean checkAccess(User user, String commandName) throws PermissionDeniedException { - Account account = _accountService.getAccount(user.getAccountId()); + if (isDisabled()) { + return true; + } + + Account account = accountService.getAccount(user.getAccountId()); if (account == null) { throw new PermissionDeniedException("The account id=" + user.getAccountId() + "for user id=" + user.getId() + "is null"); } - RoleType roleType = _accountService.getRoleType(account); + RoleType roleType = accountService.getRoleType(account); boolean isAllowed = commandsPropertiesOverrides.contains(commandName) ? commandsPropertiesRoleBasedApisMap.get(roleType).contains(commandName) : annotationRoleBasedApisMap.get( roleType).contains(commandName); - if (!isAllowed) { - throw new PermissionDeniedException("The API does not exist or is blacklisted. Role type=" + roleType.toString() + " is not allowed to request the api: " + - commandName); + if (isAllowed) { + return true; } - return isAllowed; + + throw new PermissionDeniedException("The API does not exist or is blacklisted. Role type=" + roleType.toString() + " is not allowed to request the api: " + commandName); } @Override @@ -91,7 +101,7 @@ public boolean configure(String name, Map params) throws Configu @Override public boolean start() { - for (PluggableService service : _services) { + for (PluggableService service : services) { for (Class clz : service.getCommands()) { APICommand command = clz.getAnnotation(APICommand.class); for (RoleType role : command.authorized()) { @@ -112,22 +122,22 @@ private void processMapping(Map configMap) { try { short cmdPermissions = Short.parseShort(roleMask); for (RoleType roleType : RoleType.values()) { - if ((cmdPermissions & roleType.getValue()) != 0) + if ((cmdPermissions & roleType.getMask()) != 0) commandsPropertiesRoleBasedApisMap.get(roleType).add(apiName); } } catch (NumberFormatException nfe) { - s_logger.info("Malformed key=value pair for entry: " + entry.toString()); + LOGGER.info("Malformed key=value pair for entry: " + entry.toString()); } } } public List getServices() { - return _services; + return services; } @Inject public void setServices(List services) { - this._services = services; + this.services = services; } public Set getCommandPropertyFiles() { diff --git a/plugins/api/discovery/src/org/apache/cloudstack/api/command/user/discovery/ListApisCmd.java b/plugins/api/discovery/src/org/apache/cloudstack/api/command/user/discovery/ListApisCmd.java index be0d5d5326..66d8c5d64e 100644 --- a/plugins/api/discovery/src/org/apache/cloudstack/api/command/user/discovery/ListApisCmd.java +++ b/plugins/api/discovery/src/org/apache/cloudstack/api/command/user/discovery/ListApisCmd.java @@ -18,6 +18,7 @@ import javax.inject.Inject; +import org.apache.cloudstack.acl.RoleType; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -38,7 +39,7 @@ description = "lists all available apis on the server, provided by the Api Discovery plugin", since = "4.1.0", requestHasSensitiveInfo = false, - responseHasSensitiveInfo = false) + responseHasSensitiveInfo = false, authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) public class ListApisCmd extends BaseCmd { public static final Logger s_logger = Logger.getLogger(ListApisCmd.class.getName()); diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java index 2451b561bc..aca756502e 100644 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java @@ -37,12 +37,13 @@ import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.QueryBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.vm.VirtualMachineProfile; -import com.google.gson.Gson; -import org.apache.cloudstack.api.AddBaremetalRctCmd; -import org.apache.cloudstack.api.DeleteBaremetalRctCmd; -import org.apache.cloudstack.api.ListBaremetalRctCmd; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.VirtualMachineProfile; +import com.google.gson.Gson; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.AddBaremetalRctCmd; +import org.apache.cloudstack.api.DeleteBaremetalRctCmd; +import org.apache.cloudstack.api.ListBaremetalRctCmd; import org.apache.cloudstack.utils.baremetal.BaremetalUtils; import org.springframework.web.client.RestTemplate; @@ -244,12 +245,14 @@ public boolean start() { acnt = new AccountVO(); acnt.setAccountName(BaremetalUtils.BAREMETAL_SYSTEM_ACCOUNT_NAME); - acnt.setUuid(UUID.randomUUID().toString()); - acnt.setState(Account.State.enabled); - acnt.setDomainId(1); - acnt = acntDao.persist(acnt); - - UserVO user = new UserVO(); + acnt.setUuid(UUID.randomUUID().toString()); + acnt.setState(Account.State.enabled); + acnt.setDomainId(1); + acnt.setType(RoleType.User.getAccountType()); + acnt.setRoleId(RoleType.User.getId()); + acnt = acntDao.persist(acnt); + + UserVO user = new UserVO(); user.setState(Account.State.enabled); user.setUuid(UUID.randomUUID().toString()); user.setAccountId(acnt.getAccountId()); diff --git a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java index b5da604335..e56766aaf4 100644 --- a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java +++ b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java @@ -134,14 +134,14 @@ public User createUser(String arg0, String arg1, String arg2, String arg3, Strin } @Override - public UserAccount createUserAccount(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5, String arg6, short arg7, Long arg8, String arg9, + public UserAccount createUserAccount(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5, String arg6, short arg7, Long roleId, Long arg8, String arg9, Map arg10, String arg11, String arg12) { // TODO Auto-generated method stub return null; } @Override - public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, + public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID, User.Source source) { // TODO Auto-generated method stub return null; @@ -392,8 +392,8 @@ public Account getAccount(long accountId) { } @Override - public Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map details, String uuid) { - final AccountVO account = new AccountVO(accountName, domainId, networkDomain, accountType, uuid); + public Account createAccount(String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String uuid) { + final AccountVO account = new AccountVO(accountName, domainId, networkDomain, accountType, roleId, uuid); Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { diff --git a/plugins/pom.xml b/plugins/pom.xml index bafe299da9..1a2581972a 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -50,6 +50,7 @@ api/solidfire-intg-test api/discovery acl/static-role-based + acl/dynamic-role-based affinity-group-processors/host-anti-affinity affinity-group-processors/explicit-dedication deployment-planners/user-concentrated-pod diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java index 1968f85b04..d845857925 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java @@ -16,12 +16,12 @@ // under the License. package org.apache.cloudstack.api.command; -import java.io.UnsupportedEncodingException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Map; - -import javax.inject.Inject; +import com.cloud.domain.DomainVO; +import com.cloud.user.Account; +import com.cloud.user.AccountService; +import com.cloud.user.User; +import com.cloud.user.UserAccount; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -31,6 +31,7 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.RoleResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.ldap.LdapManager; import org.apache.cloudstack.ldap.LdapUser; @@ -38,11 +39,11 @@ import org.apache.log4j.Logger; import org.bouncycastle.util.encoders.Base64; -import com.cloud.domain.DomainVO; -import com.cloud.user.Account; -import com.cloud.user.AccountService; -import com.cloud.user.User; -import com.cloud.user.UserAccount; +import javax.inject.Inject; +import java.io.UnsupportedEncodingException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Map; @APICommand(name = "ldapCreateAccount", description = "Creates an account from an LDAP user", responseObject = AccountResponse.class, since = "4.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class LdapCreateAccountCmd extends BaseCmd { @@ -55,9 +56,12 @@ public class LdapCreateAccountCmd extends BaseCmd { @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "Creates the user under the specified account. If no account is specified, the username will be used as the account name.") private String accountName; - @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, required = true, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") + @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") private Short accountType; + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.") + private Long roleId; + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Creates the user under the specified domain.") private Long domainId; @@ -92,7 +96,7 @@ public LdapCreateAccountCmd(final LdapManager ldapManager, final AccountService UserAccount createCloudstackUserAccount(final LdapUser user, String accountName, Long domainId) { Account account = _accountService.getActiveAccountByName(accountName, domainId); if (account == null) { - return _accountService.createUserAccount(username, generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, accountType, + return _accountService.createUserAccount(username, generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, getAccountType(), getRoleId(), domainId, networkDomain, details, accountUUID, userUUID, User.Source.LDAP); } else { User newUser = _accountService.createUser(username, generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, domainId, @@ -101,6 +105,14 @@ UserAccount createCloudstackUserAccount(final LdapUser user, String accountName, } } + public Short getAccountType() { + return RoleType.getAccountTypeByRole(roleService.findRole(roleId), accountType); + } + + public Long getRoleId() { + return RoleType.getRoleByAccountType(roleId, accountType); + } + private String getAccountName() { String name = accountName; if (accountName == null) { @@ -119,6 +131,9 @@ private Long getDomainId() { @Override public void execute() throws ServerApiException { + if (getAccountType() == null && getRoleId() == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Both account type and role ID are not provided"); + } final CallContext callContext = getCurrentContext(); String finalAccountName = getAccountName(); Long finalDomainId = getDomainId(); diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java index 63549f1111..9fdd700638 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java @@ -29,6 +29,7 @@ import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.user.UserAccount; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -38,6 +39,7 @@ import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.LdapUserResponse; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.RoleResponse; import org.apache.cloudstack.ldap.LdapManager; import org.apache.cloudstack.ldap.LdapUser; import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException; @@ -70,10 +72,12 @@ public class LdapImportUsersCmd extends BaseListCmd { @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, - required = true, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") private Short accountType; + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.") + private Long roleId; + @Parameter(name = ApiConstants.ACCOUNT_DETAILS, type = CommandType.MAP, description = "details for account used to store specific parameters") private Map details; @@ -112,7 +116,7 @@ private void createCloudstackUserAccount(LdapUser user, String accountName, Doma Account account = _accountService.getActiveAccountByName(accountName, domain.getId()); if (account == null) { s_logger.debug("No account exists with name: " + accountName + " creating the account and an user with name: " + user.getUsername() + " in the account"); - _accountService.createUserAccount(user.getUsername(), generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, accountType, + _accountService.createUserAccount(user.getUsername(), generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, getAccountType(), getRoleId(), domain.getId(), domain.getNetworkDomain(), details, UUID.randomUUID().toString(), UUID.randomUUID().toString(), User.Source.LDAP); } else { // check if the user exists. if yes, call update @@ -131,7 +135,9 @@ private void createCloudstackUserAccount(LdapUser user, String accountName, Doma @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { - + if (getAccountType() == null && getRoleId() == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Both account type and role ID are not provided"); + } List users; try { if (StringUtils.isNotBlank(groupName)) { @@ -161,6 +167,14 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE setResponseObject(response); } + public Short getAccountType() { + return RoleType.getAccountTypeByRole(roleService.findRole(roleId), accountType); + } + + public Long getRoleId() { + return RoleType.getRoleByAccountType(roleId, accountType); + } + private String getAccountName(LdapUser user) { String finalAccountName = accountName; if(finalAccountName == null ) { diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java index ae3e706513..477e80f255 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java @@ -23,6 +23,7 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.user.User; import com.cloud.user.UserAccount; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -82,7 +83,7 @@ public void execute() throws ServerApiException { if (account == null) { try { UserAccount userAccount = _accountService.createUserAccount(admin, "", ldapUser.getFirstname(), ldapUser.getLastname(), ldapUser.getEmail(), null, - admin, Account.ACCOUNT_TYPE_DOMAIN_ADMIN, domainId, null, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), User.Source.LDAP); + admin, Account.ACCOUNT_TYPE_DOMAIN_ADMIN, RoleType.DomainAdmin.getId(), domainId, null, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), User.Source.LDAP); response.setAdminId(String.valueOf(userAccount.getAccountId())); s_logger.info("created an account with name " + admin + " in the given domain " + domainId); } catch (Exception e) { diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java index 5683b50a47..add39c5b13 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java @@ -21,6 +21,7 @@ import javax.inject.Inject; +import org.apache.cloudstack.acl.RoleType; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -119,7 +120,8 @@ private void enableUserInCloudStack(UserAccount user) { private void createCloudStackUserAccount(LdapUser user, long domainId, short accountType) { String username = user.getUsername(); - _accountManager.createUserAccount(username, "", user.getFirstname(), user.getLastname(), user.getEmail(), null, username, accountType, domainId, null, null, + _accountManager.createUserAccount(username, "", user.getFirstname(), user.getLastname(), user.getEmail(), null, username, + accountType, RoleType.getByAccountType(accountType).getId(), domainId, null, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), User.Source.LDAP); } diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy index 514caeb17d..434151ae23 100644 --- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy +++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy @@ -246,7 +246,7 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification { 1 * accountService.getActiveAccountByName('ACCOUNT', 0) >> Mock(AccountVO) 1 * accountService.getActiveUserAccount('rmurphy',0) >> Mock(UserAccountVO) 0 * accountService.createUser('rmurphy', _ , 'Ryan', 'Murphy', 'rmurphy@test.com', null, 'ACCOUNT', 0, _) >> Mock(UserVO) - 0 * accountService.createUserAccount('rmurphy', _, 'Ryan', 'Murphy', 'rmurphy@test.com', null, 'ACCOUNT', 2, 0, 'DOMAIN', null, _, _) + 0 * accountService.createUserAccount('rmurphy', _, 'Ryan', 'Murphy', 'rmurphy@test.com', null, 'ACCOUNT', 2, null, 0, 'DOMAIN', null, _, _) 1 * accountService.updateUser(_,'Ryan', 'Murphy', 'rmurphy@test.com', null, null, null, null, null); def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) diff --git a/scripts/util/migrate-dynamicroles.py b/scripts/util/migrate-dynamicroles.py new file mode 100755 index 0000000000..e97e94cb25 --- /dev/null +++ b/scripts/util/migrate-dynamicroles.py @@ -0,0 +1,136 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# 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. + +import os +import sys +import uuid + +from contextlib import closing +from optparse import OptionParser + +try: + import MySQLdb +except ImportError: + print("MySQLdb cannot be imported, please install python-mysqldb(apt) or mysql-python(yum)") + sys.exit(1) + +dryrun = False + + +def runSql(conn, query): + if dryrun: + print("Running SQL query: " + query) + return + with closing(conn.cursor()) as cursor: + cursor.execute(query) + + +def migrateApiRolePermissions(apis, conn): + # All allow for root admin role Admin(id:1) + runSql(conn, "INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 1, '*', 'ALLOW', 0);") + # Migrate rules based on commands.properties rule for ResourceAdmin(id:2), DomainAdmin(id:3), User(id:4) + octetKey = {2:2, 3:4, 4:8} + for role in [2, 3, 4]: + sortOrder = 0 + for api in sorted(apis.keys()): + # Ignore auth commands + if api in ['login', 'logout', 'samlSso', 'samlSlo', 'listIdps', 'listAndSwitchSamlAccount', 'getSPMetadata']: + continue + if (octetKey[role] & int(apis[api])) > 0: + runSql(conn, "INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), %d, '%s', 'ALLOW', %d);" % (role, api, sortOrder)) + sortOrder += 1 + + +def main(): + parser = OptionParser() + parser.add_option("-b", "--db", action="store", type="string", dest="db", default="cloud", + help="The name of the database, default: cloud") + parser.add_option("-u", "--user", action="store", type="string", dest="user", default="cloud", + help="User name a MySQL user with privileges on cloud database") + parser.add_option("-p", "--password", action="store", type="string", dest="password", default="cloud", + help="Password of a MySQL user with privileges on cloud database") + parser.add_option("-H", "--host", action="store", type="string", dest="host", default="127.0.0.1", + help="Host or IP of the MySQL server") + parser.add_option("-P", "--port", action="store", type="int", dest="port", default=3306, + help="Host or IP of the MySQL server") + parser.add_option("-f", "--properties-file", action="store", type="string", dest="commandsfile", default="/etc/cloudstack/management/commands.properties", + help="The commands.properties file") + parser.add_option("-d", "--dryrun", action="store_true", dest="dryrun", default=False, + help="Dry run and debug operations this tool will perform") + (options, args) = parser.parse_args() + + print("Apache CloudStack Role Permission Migration Tool") + print("(c) Apache CloudStack Authors and the ASF, under the Apache License, Version 2.0\n") + + global dryrun + if options.dryrun: + dryrun = True + + conn = MySQLdb.connect( + host=options.host, + user=options.user, + passwd=options.password, + port=int(options.port), + db=options.db) + + if not os.path.isfile(options.commandsfile): + print("Provided commands.properties cannot be accessed or does not exist, please check check permissions") + sys.exit(1) + + while True: + choice = raw_input("Running this migration tool will remove any " + + "default-role permissions from cloud.role_permissions. " + + "Do you want to continue? [y/N]").lower() + if choice == 'y': + break + else: + print("Aborting!") + sys.exit(1) + + # Generate API to permission octet map + apiMap = {} + with open(options.commandsfile) as f: + for line in f.readlines(): + if not line or line == '' or line == '\n' or line.startswith('#'): + continue + name, value = line.split('=') + apiMap[name.strip()] = value.strip() + + # Rename and deprecate old commands.properties file + if not dryrun: + os.rename(options.commandsfile, options.commandsfile + '.deprecated') + print("The commands.properties file has been deprecated and moved at: " + options.commandsfile + '.deprecated') + + # Truncate any rules in cloud.role_permissions table + runSql(conn, "DELETE FROM `cloud`.`role_permissions` WHERE `role_id` in (1,2,3,4);") + + # Migrate rules from commands.properties to cloud.role_permissions + migrateApiRolePermissions(apiMap, conn) + print("Static role permissions from commands.properties have been migrated into the db") + + # Enable dynamic role based API checker + runSql(conn, "UPDATE `cloud`.`configuration` SET value='true' where name='dynamic.apichecker.enabled'") + conn.commit() + conn.close() + + print("Dynamic role based API checker has been enabled!") + + +if __name__ == '__main__': + main() diff --git a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml index e39d918c9d..6618e3ee5c 100644 --- a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml +++ b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml @@ -37,6 +37,8 @@ value="#{pluggableAPIAuthenticatorsRegistry.registered}" /> + + diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index 1c55c674e6..d6b529fa2f 100644 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -27,6 +27,8 @@ import javax.annotation.PostConstruct; import javax.inject.Inject; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleService; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.affinity.dao.AffinityGroupDao; @@ -423,6 +425,7 @@ public class ApiDBUtils { static AffinityGroupJoinDao s_affinityGroupJoinDao; static GlobalLoadBalancingRulesService s_gslbService; static NetworkACLDao s_networkACLDao; + static RoleService s_roleService; static AccountService s_accountService; static ResourceMetaDataService s_resourceDetailsService; static HostGpuGroupsDao s_hostGpuGroupsDao; @@ -646,6 +649,8 @@ public class ApiDBUtils { @Inject private NetworkACLDao networkACLDao; @Inject + private RoleService roleService; + @Inject private AccountService accountService; @Inject private ConfigurationManager configMgr; @@ -768,6 +773,7 @@ void init() { // Note: stats collector should already have been initialized by this time, otherwise a null instance is returned s_statsCollector = StatsCollector.getInstance(); s_networkACLDao = networkACLDao; + s_roleService = roleService; s_accountService = accountService; s_resourceDetailsService = resourceDetailsService; s_hostGpuGroupsDao = hostGpuGroupsDao; @@ -1695,6 +1701,15 @@ public static UserResponse newUserResponse(UserAccountJoinVO usr) { public static UserResponse newUserResponse(UserAccountJoinVO usr, Long domainId) { UserResponse response = s_userAccountJoinDao.newUserResponse(usr); + // Populate user account role information + if (usr.getAccountRoleId() != null) { + Role role = s_roleService.findRole( usr.getAccountRoleId()); + if (role != null) { + response.setRoleId(role.getUuid()); + response.setRoleType(role.getRoleType()); + response.setRoleName(role.getName()); + } + } if (domainId != null && usr.getDomainId() != domainId) response.setIsCallerChildDomain(true); else @@ -1820,7 +1835,17 @@ public static DomainResponse newDomainResponse(ResponseView view, DomainJoinVO v } public static AccountResponse newAccountResponse(ResponseView view, AccountJoinVO ve) { - return s_accountJoinDao.newAccountResponse(view, ve); + AccountResponse response = s_accountJoinDao.newAccountResponse(view, ve); + // Populate account role information + if (ve.getRoleId() != null) { + Role role = s_roleService.findRole(ve.getRoleId()); + if (role != null) { + response.setRoleId(role.getUuid()); + response.setRoleType(role.getRoleType()); + response.setRoleName(role.getName()); + } + } + return response; } public static AccountJoinVO newAccountView(Account e) { diff --git a/server/src/com/cloud/api/ApiResponseGsonHelper.java b/server/src/com/cloud/api/ApiResponseGsonHelper.java index 1708fa764d..19db96ae36 100644 --- a/server/src/com/cloud/api/ApiResponseGsonHelper.java +++ b/server/src/com/cloud/api/ApiResponseGsonHelper.java @@ -68,7 +68,7 @@ public boolean shouldSkipField(FieldAttributes f) { boolean permittedParameter = false; Account caller = CallContext.current().getCallingAccount(); for (RoleType allowedRole : allowedRoles) { - if (allowedRole.getValue() == caller.getType()) { + if (allowedRole.getAccountType() == caller.getType()) { permittedParameter = true; break; } diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index 6ec2f18e77..d7da425b7a 100644 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -797,15 +797,15 @@ public boolean verifyRequest(final Map requestParameters, fina s_logger.debug(ex.getMessage()); throw new ServerApiException(ApiErrorCode.API_LIMIT_EXCEED, ex.getMessage()); } catch (final PermissionDeniedException ex) { - s_logger.debug("The given command:" + commandName + " does not exist or it is not available for user with id:" + userId); - throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "The given command does not exist or it is not available for user"); + s_logger.debug("The user with id:" + userId + " is not allowed to request the API command or the API command does not exist: " + commandName); + throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "The user is not allowed to request the API command or the API command does not exist"); } return true; } else { // check against every available command to see if the command exists or not if (!s_apiNameCmdClassMap.containsKey(commandName) && !commandName.equals("login") && !commandName.equals("logout")) { - s_logger.debug("The given command:" + commandName + " does not exist or it is not available for user with id:" + userId); - throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "The given command does not exist or it is not available for user"); + s_logger.debug("The user with id:" + userId + " is not allowed to request the API command or the API command does not exist: " + commandName); + throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "The user is not allowed to request the API command or the API command does not exist"); } } diff --git a/server/src/com/cloud/api/query/vo/AccountJoinVO.java b/server/src/com/cloud/api/query/vo/AccountJoinVO.java index 8d642edd7c..f251abc472 100644 --- a/server/src/com/cloud/api/query/vo/AccountJoinVO.java +++ b/server/src/com/cloud/api/query/vo/AccountJoinVO.java @@ -48,6 +48,9 @@ public class AccountJoinVO extends BaseViewVO implements InternalIdentity, Ident @Column(name = "type") private short type; + @Column(name = "role_id") + private Long roleId; + @Column(name = "state") @Enumerated(value = EnumType.STRING) private State state; @@ -202,6 +205,10 @@ public short getType() { return type; } + public Long getRoleId() { + return roleId; + } + public State getState() { return state; } diff --git a/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java b/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java index 0e66ca022c..e6b1ace096 100644 --- a/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java @@ -96,6 +96,9 @@ public class UserAccountJoinVO extends BaseViewVO implements InternalIdentity, I @Column(name = "account_type") private short accountType; + @Column(name = "account_role_id") + private Long accountRoleId; + @Column(name = "domain_id") private long domainId; @@ -149,6 +152,10 @@ public short getAccountType() { return accountType; } + public Long getAccountRoleId() { + return accountRoleId; + } + public long getDomainId() { return domainId; } diff --git a/server/src/com/cloud/api/response/ApiResponseSerializer.java b/server/src/com/cloud/api/response/ApiResponseSerializer.java index 59426e6574..2b9717de1e 100644 --- a/server/src/com/cloud/api/response/ApiResponseSerializer.java +++ b/server/src/com/cloud/api/response/ApiResponseSerializer.java @@ -251,7 +251,7 @@ private static void serializeResponseObjFieldsXML(StringBuilder sb, StringBuilde boolean permittedParameter = false; Account caller = CallContext.current().getCallingAccount(); for (RoleType allowedRole : allowedRoles) { - if (allowedRole.getValue() == caller.getType()) { + if (allowedRole.getAccountType() == caller.getType()) { permittedParameter = true; break; } diff --git a/server/src/com/cloud/projects/ProjectManagerImpl.java b/server/src/com/cloud/projects/ProjectManagerImpl.java index ee6650698c..a8dd225c54 100644 --- a/server/src/com/cloud/projects/ProjectManagerImpl.java +++ b/server/src/com/cloud/projects/ProjectManagerImpl.java @@ -211,7 +211,7 @@ public Project doInTransaction(TransactionStatus status) { StringBuilder acctNm = new StringBuilder("PrjAcct-"); acctNm.append(name).append("-").append(ownerFinal.getDomainId()); - Account projectAccount = _accountMgr.createAccount(acctNm.toString(), Account.ACCOUNT_TYPE_PROJECT, domainId, null, null, UUID.randomUUID().toString()); + Account projectAccount = _accountMgr.createAccount(acctNm.toString(), Account.ACCOUNT_TYPE_PROJECT, null, domainId, null, null, UUID.randomUUID().toString()); Project project = _projectDao.persist(new ProjectVO(name, displayText, ownerFinal.getDomainId(), projectAccount.getId())); diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index 16e4ff0590..13f98a2f48 100644 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -449,7 +449,7 @@ public void saveUser() { public void doInTransactionWithoutResult(TransactionStatus status) { TransactionLegacy txn = TransactionLegacy.currentTxn(); // insert system account - String insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, domain_id, account.default) VALUES (1, UUID(), 'system', '1', '1', 1)"; + String insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, role_id, domain_id, account.default) VALUES (1, UUID(), 'system', '1', '1', '1', 1)"; try { PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql); @@ -476,8 +476,8 @@ public void doInTransactionWithoutResult(TransactionStatus status) { String lastname = "cloud"; // create an account for the admin user first - insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, domain_id, account.default) VALUES (" + id + ", UUID(), '" + username - + "', '1', '1', 1)"; + insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, role_id, domain_id, account.default) VALUES (" + id + ", UUID(), '" + username + + "', '1', '1', '1', 1)"; try { PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql); stmt.executeUpdate(); diff --git a/server/src/com/cloud/user/AccountManager.java b/server/src/com/cloud/user/AccountManager.java index 7b9e0936bb..9789a22329 100644 --- a/server/src/com/cloud/user/AccountManager.java +++ b/server/src/com/cloud/user/AccountManager.java @@ -50,7 +50,7 @@ public interface AccountManager extends AccountService { Long checkAccessAndSpecifyAuthority(Account caller, Long zoneId); - Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map details, String uuid); + Account createAccount(String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String uuid); /** * Logs out a user diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index d3eb40c7db..7e80681caa 100644 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -994,9 +994,9 @@ private boolean doDisableAccount(long accountId) throws ConcurrentOperationExcep @ActionEvent(eventType = EventTypes.EVENT_USER_CREATE, eventDescription = "creating User") }) public UserAccount createUserAccount(final String userName, final String password, final String firstName, final String lastName, final String email, final String timezone, - String accountName, final short accountType, Long domainId, final String networkDomain, final Map details, String accountUUID, final String userUUID) { + String accountName, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map details, String accountUUID, final String userUUID) { - return createUserAccount(userName, password, firstName, lastName, email, timezone, accountName, accountType, domainId, networkDomain, details, accountUUID, userUUID, + return createUserAccount(userName, password, firstName, lastName, email, timezone, accountName, accountType, roleId, domainId, networkDomain, details, accountUUID, userUUID, User.Source.UNKNOWN); } @@ -1011,7 +1011,7 @@ public UserAccount createUserAccount(final String userName, final String passwor @ActionEvent(eventType = EventTypes.EVENT_USER_CREATE, eventDescription = "creating User") }) public UserAccount createUserAccount(final String userName, final String password, final String firstName, final String lastName, final String email, - final String timezone, String accountName, final short accountType, Long domainId, final String networkDomain, final Map details, + final String timezone, String accountName, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map details, String accountUUID, final String userUUID, final User.Source source) { if (accountName == null) { @@ -1065,7 +1065,7 @@ public Pair doInTransaction(TransactionStatus status) { if (accountUUID == null) { accountUUID = UUID.randomUUID().toString(); } - AccountVO account = createAccount(accountNameFinal, accountType, domainIdFinal, networkDomain, details, accountUUID); + AccountVO account = createAccount(accountNameFinal, accountType, roleId, domainIdFinal, networkDomain, details, accountUUID); long accountId = account.getId(); // create the first user for the account @@ -1869,27 +1869,10 @@ public Account getAccount(long accountId) { @Override public RoleType getRoleType(Account account) { - RoleType roleType = RoleType.Unknown; - if (account == null) - return roleType; - short accountType = account.getType(); - - // Account type to role type translation - switch (accountType) { - case Account.ACCOUNT_TYPE_ADMIN: - roleType = RoleType.Admin; - break; - case Account.ACCOUNT_TYPE_DOMAIN_ADMIN: - roleType = RoleType.DomainAdmin; - break; - case Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN: - roleType = RoleType.ResourceAdmin; - break; - case Account.ACCOUNT_TYPE_NORMAL: - roleType = RoleType.User; - break; + if (account == null) { + return RoleType.Unknown; } - return roleType; + return RoleType.getByAccountType(account.getType()); } @Override @@ -1916,7 +1899,7 @@ public void markUserRegistered(long userId) { @Override @DB - public AccountVO createAccount(final String accountName, final short accountType, final Long domainId, final String networkDomain, final Map details, + public AccountVO createAccount(final String accountName, final short accountType, final Long roleId, final Long domainId, final String networkDomain, final Map details, final String uuid) { // Validate domain Domain domain = _domainMgr.getDomain(domainId); @@ -1929,7 +1912,7 @@ public AccountVO createAccount(final String accountName, final short accountType } if ((domainId != Domain.ROOT_DOMAIN) && (accountType == Account.ACCOUNT_TYPE_ADMIN)) { - throw new InvalidParameterValueException("Invalid account type " + accountType + " given for an account in domain " + domainId + "; unable to create user."); + throw new InvalidParameterValueException("Invalid account type " + accountType + " given for an account in domain " + domainId + "; unable to create user of admin role type in non-ROOT domain."); } // Validate account/user/domain settings @@ -1961,7 +1944,7 @@ public AccountVO createAccount(final String accountName, final short accountType return Transaction.execute(new TransactionCallback() { @Override public AccountVO doInTransaction(TransactionStatus status) { - AccountVO account = _accountDao.persist(new AccountVO(accountName, domainId, networkDomain, accountType, uuid)); + AccountVO account = _accountDao.persist(new AccountVO(accountName, domainId, networkDomain, accountType, roleId, uuid)); if (account == null) { throw new CloudRuntimeException("Failed to create account name " + accountName + " in domain id=" + domainId); diff --git a/server/src/org/apache/cloudstack/acl/RoleManagerImpl.java b/server/src/org/apache/cloudstack/acl/RoleManagerImpl.java new file mode 100644 index 0000000000..7363b13b35 --- /dev/null +++ b/server/src/org/apache/cloudstack/acl/RoleManagerImpl.java @@ -0,0 +1,264 @@ +// 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.acl; + +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.user.Account; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.ListUtils; +import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.component.PluggableService; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionStatus; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.dao.RoleDao; +import org.apache.cloudstack.acl.dao.RolePermissionsDao; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.admin.acl.CreateRoleCmd; +import org.apache.cloudstack.api.command.admin.acl.CreateRolePermissionCmd; +import org.apache.cloudstack.api.command.admin.acl.DeleteRoleCmd; +import org.apache.cloudstack.api.command.admin.acl.DeleteRolePermissionCmd; +import org.apache.cloudstack.api.command.admin.acl.ListRolePermissionsCmd; +import org.apache.cloudstack.api.command.admin.acl.ListRolesCmd; +import org.apache.cloudstack.api.command.admin.acl.UpdateRoleCmd; +import org.apache.cloudstack.api.command.admin.acl.UpdateRolePermissionCmd; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; + +import javax.ejb.Local; +import javax.inject.Inject; +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Local(value = {RoleService.class}) +public class RoleManagerImpl extends ManagerBase implements RoleService, Configurable, PluggableService { + @Inject + private AccountDao accountDao; + @Inject + private RoleDao roleDao; + @Inject + private RolePermissionsDao rolePermissionsDao; + + private void checkCallerAccess() { + if (!isEnabled()) { + throw new PermissionDeniedException("Dynamic api checker is not enabled, aborting role operation"); + } + Account caller = CallContext.current().getCallingAccount(); + if (caller == null || caller.getRoleId() == null) { + throw new PermissionDeniedException("Restricted API called by an invalid user account"); + } + Role callerRole = findRole(caller.getRoleId()); + if (callerRole == null || callerRole.getRoleType() != RoleType.Admin) { + throw new PermissionDeniedException("Restricted API called by an user account of non-Admin role type"); + } + } + + @Override + public boolean isEnabled() { + File apiCmdFile = PropertiesUtil.findConfigFile(PropertiesUtil.getDefaultApiCommandsFileName()); + return RoleService.EnableDynamicApiChecker.value() && (apiCmdFile == null || !apiCmdFile.exists()); + } + + @Override + public Role findRole(final Long id) { + if (id == null || id < 1L) { + return null; + } + return roleDao.findById(id); + } + + @Override + public RolePermission findRolePermission(final Long id) { + if (id == null) { + return null; + } + return rolePermissionsDao.findById(id); + } + + @Override + public RolePermission findRolePermissionByUuid(final String uuid) { + if (Strings.isNullOrEmpty(uuid)) { + return null; + } + return rolePermissionsDao.findByUuid(uuid); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_CREATE, eventDescription = "creating Role") + public Role createRole(final String name, final RoleType roleType, final String description) { + checkCallerAccess(); + if (roleType == null || roleType == RoleType.Unknown) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role type provided"); + } + return Transaction.execute(new TransactionCallback() { + @Override + public RoleVO doInTransaction(TransactionStatus status) { + return roleDao.persist(new RoleVO(name, roleType, description)); + } + }); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_UPDATE, eventDescription = "updating Role") + public boolean updateRole(final Role role, final String name, final RoleType roleType, final String description) { + checkCallerAccess(); + if (role == null) { + return false; + } + if (roleType != null && roleType == RoleType.Unknown) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unknown is not a valid role type"); + } + RoleVO roleVO = (RoleVO) role; + if (!Strings.isNullOrEmpty(name)) { + roleVO.setName(name); + } + if (roleType != null) { + if (role.getId() <= RoleType.User.getId()) { + throw new PermissionDeniedException("The role type of default roles cannot be changed"); + } + List accounts = accountDao.findAccountsByRole(role.getId()); + if (accounts == null || accounts.isEmpty()) { + roleVO.setRoleType(roleType); + } else { + throw new PermissionDeniedException("Found accounts that have role in use, won't allow to change role type"); + } + } + if (!Strings.isNullOrEmpty(description)) { + roleVO.setDescription(description); + } + return roleDao.update(role.getId(), roleVO); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_DELETE, eventDescription = "deleting Role") + public boolean deleteRole(final Role role) { + checkCallerAccess(); + if (role == null) { + return false; + } + if (role.getId() <= RoleType.User.getId()) { + throw new PermissionDeniedException("Default roles cannot be deleted"); + } + List accounts = accountDao.findAccountsByRole(role.getId()); + if (accounts == null || accounts.size() == 0) { + return Transaction.execute(new TransactionCallback() { + @Override + public Boolean doInTransaction(TransactionStatus status) { + List rolePermissions = rolePermissionsDao.findAllByRoleIdSorted(role.getId()); + if (rolePermissions != null && !rolePermissions.isEmpty()) { + for (RolePermission rolePermission : rolePermissions) { + rolePermissionsDao.remove(rolePermission.getId()); + } + } + return roleDao.remove(role.getId()); + } + }); + } + throw new PermissionDeniedException("Found accounts that have role in use, won't allow to delete role"); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_PERMISSION_CREATE, eventDescription = "creating Role Permission") + public RolePermission createRolePermission(final Role role, final Rule rule, final RolePermission.Permission permission, final String description) { + checkCallerAccess(); + return Transaction.execute(new TransactionCallback() { + @Override + public RolePermissionVO doInTransaction(TransactionStatus status) { + return rolePermissionsDao.persist(new RolePermissionVO(role.getId(), rule.toString(), permission, description)); + } + }); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_PERMISSION_UPDATE, eventDescription = "updating Role Permission order") + public boolean updateRolePermission(final Role role, final List newOrder) { + checkCallerAccess(); + return role != null && newOrder != null && rolePermissionsDao.update(role, newOrder); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_PERMISSION_DELETE, eventDescription = "deleting Role Permission") + public boolean deleteRolePermission(final RolePermission rolePermission) { + checkCallerAccess(); + return rolePermission != null && rolePermissionsDao.remove(rolePermission.getId()); + } + + @Override + public List findRolesByName(final String name) { + List roles = null; + if (!Strings.isNullOrEmpty(name)) { + roles = roleDao.findAllByName(name); + } + return ListUtils.toListOfInterface(roles); + } + + @Override + public List findRolesByType(final RoleType roleType) { + List roles = null; + if (roleType != null) { + roles = roleDao.findAllByRoleType(roleType); + } + return ListUtils.toListOfInterface(roles); + } + + @Override + public List listRoles() { + List roles = roleDao.listAll(); + return ListUtils.toListOfInterface(roles); + } + + @Override + public List findAllPermissionsBy(final Long roleId) { + List permissions = rolePermissionsDao.findAllByRoleIdSorted(roleId); + if (permissions != null) { + return new ArrayList<>(permissions); + } + return Collections.emptyList(); + } + + @Override + public String getConfigComponentName() { + return RoleService.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[]{RoleService.EnableDynamicApiChecker}; + } + + @Override + public List> getCommands() { + final List> cmdList = new ArrayList<>(); + cmdList.add(CreateRoleCmd.class); + cmdList.add(ListRolesCmd.class); + cmdList.add(UpdateRoleCmd.class); + cmdList.add(DeleteRoleCmd.class); + cmdList.add(CreateRolePermissionCmd.class); + cmdList.add(ListRolePermissionsCmd.class); + cmdList.add(UpdateRolePermissionCmd.class); + cmdList.add(DeleteRolePermissionCmd.class); + return cmdList; + } + } diff --git a/server/test/com/cloud/user/MockAccountManagerImpl.java b/server/test/com/cloud/user/MockAccountManagerImpl.java index 3971fd6b4f..fd85167225 100644 --- a/server/test/com/cloud/user/MockAccountManagerImpl.java +++ b/server/test/com/cloud/user/MockAccountManagerImpl.java @@ -328,13 +328,13 @@ public UserAccount getUserByApiKey(String apiKey) { @Override public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, - short accountType, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID) { + short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID) { // TODO Auto-generated method stub return null; } @Override - public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, + public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID, User.Source source) { // TODO Auto-generated method stub return null; @@ -366,7 +366,7 @@ public boolean deleteAccount(AccountVO account, long callerUserId, Account calle } @Override - public Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map details, String uuid) { + public Account createAccount(String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String uuid) { // TODO Auto-generated method stub return null; } diff --git a/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java b/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java index 634ce0a2e0..3072b77a5c 100644 --- a/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java +++ b/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java @@ -196,7 +196,7 @@ private void processMapping(Map configMap) { try { short cmdPermissions = Short.parseShort(roleMask); for (RoleType roleType : RoleType.values()) { - if ((cmdPermissions & roleType.getValue()) != 0) + if ((cmdPermissions & roleType.getMask()) != 0) commandsPropertiesRoleBasedApisMap.get(roleType).add(apiName); } } catch (NumberFormatException nfe) { diff --git a/setup/db/db/create-default-role-api-mappings.sql b/setup/db/db/create-default-role-api-mappings.sql new file mode 100644 index 0000000000..57601fbde1 --- /dev/null +++ b/setup/db/db/create-default-role-api-mappings.sql @@ -0,0 +1,902 @@ +-- 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. + +-- The default admin role (id:1) will be allowed all APIs so need to insert rules for admin role + +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 1, '*', 'ALLOW', 0) ON DUPLICATE KEY UPDATE rule=rule; + +-- Insert default role-api mappings for rest of the default roles: resourceadmin(id:2), domainadmin(id:3), user(id:4) +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'activateProject', 'ALLOW', 0) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'addAccountToProject', 'ALLOW', 1) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'addHost', 'ALLOW', 2) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'addIpToNic', 'ALLOW', 3) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'addLdapConfiguration', 'ALLOW', 4) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'addNicToVirtualMachine', 'ALLOW', 5) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'addVpnUser', 'ALLOW', 6) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'archiveEvents', 'ALLOW', 7) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'assignCertToLoadBalancer', 'ALLOW', 8) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'assignToGlobalLoadBalancerRule', 'ALLOW', 9) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'assignToLoadBalancerRule', 'ALLOW', 10) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'assignVirtualMachine', 'ALLOW', 11) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'associateIpAddress', 'ALLOW', 12) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'associateLun', 'ALLOW', 13) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'attachIso', 'ALLOW', 14) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'attachVolume', 'ALLOW', 15) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'authorizeSamlSso', 'ALLOW', 16) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'authorizeSecurityGroupEgress', 'ALLOW', 17) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'authorizeSecurityGroupIngress', 'ALLOW', 18) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'changeServiceForRouter', 'ALLOW', 19) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'changeServiceForVirtualMachine', 'ALLOW', 20) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'configureInternalLoadBalancerElement', 'ALLOW', 21) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'configureOvsElement', 'ALLOW', 22) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'configureVirtualRouterElement', 'ALLOW', 23) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'copyIso', 'ALLOW', 24) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'copyTemplate', 'ALLOW', 25) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createAccount', 'ALLOW', 26) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createAffinityGroup', 'ALLOW', 27) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createAutoScalePolicy', 'ALLOW', 28) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createAutoScaleVmGroup', 'ALLOW', 29) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createAutoScaleVmProfile', 'ALLOW', 30) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createCondition', 'ALLOW', 31) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createDiskOffering', 'ALLOW', 32) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createEgressFirewallRule', 'ALLOW', 33) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createFirewallRule', 'ALLOW', 34) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createGlobalLoadBalancerRule', 'ALLOW', 35) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createInstanceGroup', 'ALLOW', 36) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createInternalLoadBalancerElement', 'ALLOW', 37) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createIpForwardingRule', 'ALLOW', 38) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createLBHealthCheckPolicy', 'ALLOW', 39) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createLBStickinessPolicy', 'ALLOW', 40) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createLoadBalancer', 'ALLOW', 41) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createLoadBalancerRule', 'ALLOW', 42) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createLunOnFiler', 'ALLOW', 43) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createNetwork', 'ALLOW', 44) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createNetworkACL', 'ALLOW', 45) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createNetworkACLList', 'ALLOW', 46) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createOvsElement', 'ALLOW', 47) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createPool', 'ALLOW', 48) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createPortForwardingRule', 'ALLOW', 49) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createProject', 'ALLOW', 50) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createRemoteAccessVpn', 'ALLOW', 51) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createSSHKeyPair', 'ALLOW', 52) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createSecurityGroup', 'ALLOW', 53) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createServiceOffering', 'ALLOW', 54) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createSnapshot', 'ALLOW', 55) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createSnapshotPolicy', 'ALLOW', 56) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createStaticRoute', 'ALLOW', 57) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createTags', 'ALLOW', 58) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createTemplate', 'ALLOW', 59) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createUser', 'ALLOW', 60) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVMSnapshot', 'ALLOW', 61) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVPC', 'ALLOW', 62) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVirtualRouterElement', 'ALLOW', 63) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVolume', 'ALLOW', 64) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVolumeOnFiler', 'ALLOW', 65) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVpnConnection', 'ALLOW', 66) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVpnCustomerGateway', 'ALLOW', 67) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVpnGateway', 'ALLOW', 68) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteAccount', 'ALLOW', 69) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteAccountFromProject', 'ALLOW', 70) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteAffinityGroup', 'ALLOW', 71) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteAutoScalePolicy', 'ALLOW', 72) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteAutoScaleVmGroup', 'ALLOW', 73) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteAutoScaleVmProfile', 'ALLOW', 74) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteCondition', 'ALLOW', 75) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteDiskOffering', 'ALLOW', 76) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteEgressFirewallRule', 'ALLOW', 77) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteEvents', 'ALLOW', 78) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteFirewallRule', 'ALLOW', 79) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteGlobalLoadBalancerRule', 'ALLOW', 80) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteHost', 'ALLOW', 81) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteInstanceGroup', 'ALLOW', 82) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteIpForwardingRule', 'ALLOW', 83) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteIso', 'ALLOW', 84) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteLBHealthCheckPolicy', 'ALLOW', 85) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteLBStickinessPolicy', 'ALLOW', 86) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteLdapConfiguration', 'ALLOW', 87) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteLoadBalancer', 'ALLOW', 88) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteLoadBalancerRule', 'ALLOW', 89) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteNetwork', 'ALLOW', 90) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteNetworkACL', 'ALLOW', 91) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteNetworkACLList', 'ALLOW', 92) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deletePool', 'ALLOW', 93) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deletePortForwardingRule', 'ALLOW', 94) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteProject', 'ALLOW', 95) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteProjectInvitation', 'ALLOW', 96) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteRemoteAccessVpn', 'ALLOW', 97) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteSSHKeyPair', 'ALLOW', 98) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteSecurityGroup', 'ALLOW', 99) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteServiceOffering', 'ALLOW', 100) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteSnapshot', 'ALLOW', 101) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteSnapshotPolicies', 'ALLOW', 102) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteSslCert', 'ALLOW', 103) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteStaticRoute', 'ALLOW', 104) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteTags', 'ALLOW', 105) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteTemplate', 'ALLOW', 106) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteUser', 'ALLOW', 107) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteVMSnapshot', 'ALLOW', 108) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteVPC', 'ALLOW', 109) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteVolume', 'ALLOW', 110) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteVpnConnection', 'ALLOW', 111) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteVpnCustomerGateway', 'ALLOW', 112) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteVpnGateway', 'ALLOW', 113) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deployVirtualMachine', 'ALLOW', 114) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'destroyLunOnFiler', 'ALLOW', 115) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'destroyRouter', 'ALLOW', 116) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'destroyVirtualMachine', 'ALLOW', 117) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'destroyVolumeOnFiler', 'ALLOW', 118) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'detachIso', 'ALLOW', 119) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'detachVolume', 'ALLOW', 120) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'disableAccount', 'ALLOW', 121) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'disableAutoScaleVmGroup', 'ALLOW', 122) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'disableStaticNat', 'ALLOW', 123) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'disableUser', 'ALLOW', 124) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'disassociateIpAddress', 'ALLOW', 125) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'dissociateLun', 'ALLOW', 126) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'enableAccount', 'ALLOW', 127) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'enableAutoScaleVmGroup', 'ALLOW', 128) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'enableStaticNat', 'ALLOW', 129) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'enableUser', 'ALLOW', 130) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'expungeVirtualMachine', 'ALLOW', 131) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'extractIso', 'ALLOW', 132) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'extractTemplate', 'ALLOW', 133) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'extractVolume', 'ALLOW', 134) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getApiLimit', 'ALLOW', 135) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getCloudIdentifier', 'ALLOW', 136) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getSolidFireAccountId', 'ALLOW', 137) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getSolidFireVolumeAccessGroupId', 'ALLOW', 138) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getSolidFireVolumeIscsiName', 'ALLOW', 139) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getSolidFireVolumeSize', 'ALLOW', 140) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getUploadParamsForTemplate', 'ALLOW', 141) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getUploadParamsForVolume', 'ALLOW', 142) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getVMPassword', 'ALLOW', 143) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getVirtualMachineUserData', 'ALLOW', 144) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'importLdapUsers', 'ALLOW', 145) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'issueNuageVspResourceRequest', 'ALLOW', 146) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'ldapCreateAccount', 'ALLOW', 147) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'linkDomainToLdap', 'ALLOW', 148) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAccounts', 'ALLOW', 149) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAffinityGroupTypes', 'ALLOW', 150) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAffinityGroups', 'ALLOW', 151) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAlerts', 'ALLOW', 152) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listApis', 'ALLOW', 153) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAsyncJobs', 'ALLOW', 154) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAutoScalePolicies', 'ALLOW', 155) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAutoScaleVmGroups', 'ALLOW', 156) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAutoScaleVmProfiles', 'ALLOW', 157) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listCapabilities', 'ALLOW', 158) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listCapacity', 'ALLOW', 159) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listClusters', 'ALLOW', 160) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listConditions', 'ALLOW', 161) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listCounters', 'ALLOW', 162) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listDiskOfferings', 'ALLOW', 163) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listDomainChildren', 'ALLOW', 164) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listDomains', 'ALLOW', 165) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listEgressFirewallRules', 'ALLOW', 166) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listEventTypes', 'ALLOW', 167) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listEvents', 'ALLOW', 168) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listFirewallRules', 'ALLOW', 169) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listGlobalLoadBalancerRules', 'ALLOW', 170) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listHostTags', 'ALLOW', 171) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listHosts', 'ALLOW', 172) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listHypervisors', 'ALLOW', 173) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listInstanceGroups', 'ALLOW', 174) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listInternalLoadBalancerElements', 'ALLOW', 175) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listIpForwardingRules', 'ALLOW', 176) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listIsoPermissions', 'ALLOW', 177) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listIsos', 'ALLOW', 178) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLBHealthCheckPolicies', 'ALLOW', 179) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLBStickinessPolicies', 'ALLOW', 180) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLdapConfigurations', 'ALLOW', 181) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLdapUsers', 'ALLOW', 182) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLoadBalancerRuleInstances', 'ALLOW', 183) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLoadBalancerRules', 'ALLOW', 184) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLoadBalancers', 'ALLOW', 185) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLunsOnFiler', 'ALLOW', 186) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listNetworkACLLists', 'ALLOW', 187) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listNetworkACLs', 'ALLOW', 188) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listNetworkOfferings', 'ALLOW', 189) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listNetworks', 'ALLOW', 190) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listNics', 'ALLOW', 191) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listOsCategories', 'ALLOW', 192) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listOsTypes', 'ALLOW', 193) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listOvsElements', 'ALLOW', 194) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listPods', 'ALLOW', 195) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listPools', 'ALLOW', 196) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listPortForwardingRules', 'ALLOW', 197) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listPrivateGateways', 'ALLOW', 198) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listProjectAccounts', 'ALLOW', 199) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listProjectInvitations', 'ALLOW', 200) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listProjects', 'ALLOW', 201) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listPublicIpAddresses', 'ALLOW', 202) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listRegions', 'ALLOW', 203) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listRemoteAccessVpns', 'ALLOW', 204) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listResourceDetails', 'ALLOW', 205) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listResourceLimits', 'ALLOW', 206) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listRouters', 'ALLOW', 207) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSSHKeyPairs', 'ALLOW', 208) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSamlAuthorization', 'ALLOW', 209) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSecurityGroups', 'ALLOW', 210) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listServiceOfferings', 'ALLOW', 211) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSnapshotPolicies', 'ALLOW', 212) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSnapshots', 'ALLOW', 213) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSslCerts', 'ALLOW', 214) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listStaticRoutes', 'ALLOW', 215) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listStoragePools', 'ALLOW', 216) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listStorageProviders', 'ALLOW', 217) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listStorageTags', 'ALLOW', 218) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSystemVms', 'ALLOW', 219) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listTags', 'ALLOW', 220) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listTemplatePermissions', 'ALLOW', 221) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listTemplates', 'ALLOW', 222) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listUsageRecords', 'ALLOW', 223) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listUsers', 'ALLOW', 224) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVMSnapshot', 'ALLOW', 225) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVPCOfferings', 'ALLOW', 226) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVPCs', 'ALLOW', 227) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVirtualMachines', 'ALLOW', 228) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVirtualRouterElements', 'ALLOW', 229) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVolumes', 'ALLOW', 230) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVolumesOnFiler', 'ALLOW', 231) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVpnConnections', 'ALLOW', 232) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVpnCustomerGateways', 'ALLOW', 233) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVpnGateways', 'ALLOW', 234) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVpnUsers', 'ALLOW', 235) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listZones', 'ALLOW', 236) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'lockAccount', 'ALLOW', 237) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'lockUser', 'ALLOW', 238) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'migrateVolume', 'ALLOW', 239) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'modifyPool', 'ALLOW', 240) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'queryAsyncJobResult', 'ALLOW', 241) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'quotaBalance', 'ALLOW', 242) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'quotaIsEnabled', 'ALLOW', 243) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'quotaStatement', 'ALLOW', 244) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'quotaSummary', 'ALLOW', 245) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'quotaTariffList', 'ALLOW', 246) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'rebootRouter', 'ALLOW', 247) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'rebootVirtualMachine', 'ALLOW', 248) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'recoverVirtualMachine', 'ALLOW', 249) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'registerIso', 'ALLOW', 250) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'registerSSHKeyPair', 'ALLOW', 251) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'registerTemplate', 'ALLOW', 252) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'registerUserKeys', 'ALLOW', 253) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'removeCertFromLoadBalancer', 'ALLOW', 254) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'removeFromGlobalLoadBalancerRule', 'ALLOW', 255) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'removeFromLoadBalancerRule', 'ALLOW', 256) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'removeIpFromNic', 'ALLOW', 257) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'removeNicFromVirtualMachine', 'ALLOW', 258) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'removeVpnUser', 'ALLOW', 259) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'replaceNetworkACLList', 'ALLOW', 260) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'resetPasswordForVirtualMachine', 'ALLOW', 261) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'resetSSHKeyForVirtualMachine', 'ALLOW', 262) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'resetVpnConnection', 'ALLOW', 263) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'resizeVolume', 'ALLOW', 264) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'restartNetwork', 'ALLOW', 265) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'restartVPC', 'ALLOW', 266) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'restoreVirtualMachine', 'ALLOW', 267) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'revertSnapshot', 'ALLOW', 268) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'revertToVMSnapshot', 'ALLOW', 269) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'revokeSecurityGroupEgress', 'ALLOW', 270) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'revokeSecurityGroupIngress', 'ALLOW', 271) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'scaleVirtualMachine', 'ALLOW', 272) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'startRouter', 'ALLOW', 273) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'startVirtualMachine', 'ALLOW', 274) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'stopRouter', 'ALLOW', 275) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'stopVirtualMachine', 'ALLOW', 276) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'suspendProject', 'ALLOW', 277) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateAccount', 'ALLOW', 278) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateAutoScalePolicy', 'ALLOW', 279) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateAutoScaleVmGroup', 'ALLOW', 280) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateAutoScaleVmProfile', 'ALLOW', 281) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateDefaultNicForVirtualMachine', 'ALLOW', 282) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateDiskOffering', 'ALLOW', 283) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateEgressFirewallRule', 'ALLOW', 284) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateFirewallRule', 'ALLOW', 285) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateGlobalLoadBalancerRule', 'ALLOW', 286) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateInstanceGroup', 'ALLOW', 287) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateIpAddress', 'ALLOW', 288) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateIso', 'ALLOW', 289) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateIsoPermissions', 'ALLOW', 290) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateLBHealthCheckPolicy', 'ALLOW', 291) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateLBStickinessPolicy', 'ALLOW', 292) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateLoadBalancer', 'ALLOW', 293) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateLoadBalancerRule', 'ALLOW', 294) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateNetwork', 'ALLOW', 295) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateNetworkACLItem', 'ALLOW', 296) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateNetworkACLList', 'ALLOW', 297) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updatePortForwardingRule', 'ALLOW', 298) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateProject', 'ALLOW', 299) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateProjectInvitation', 'ALLOW', 300) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateRemoteAccessVpn', 'ALLOW', 301) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateResourceCount', 'ALLOW', 302) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateResourceLimit', 'ALLOW', 303) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateServiceOffering', 'ALLOW', 304) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateSnapshotPolicy', 'ALLOW', 305) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateTemplate', 'ALLOW', 306) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateTemplatePermissions', 'ALLOW', 307) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateUser', 'ALLOW', 308) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVMAffinityGroup', 'ALLOW', 309) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVPC', 'ALLOW', 310) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVirtualMachine', 'ALLOW', 311) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVmNicIp', 'ALLOW', 312) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVpnConnection', 'ALLOW', 313) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVpnCustomerGateway', 'ALLOW', 314) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVpnGateway', 'ALLOW', 315) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'uploadSslCert', 'ALLOW', 316) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'uploadVolume', 'ALLOW', 317) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'activateProject', 'ALLOW', 0) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'addAccountToProject', 'ALLOW', 1) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'addIpToNic', 'ALLOW', 2) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'addNicToVirtualMachine', 'ALLOW', 3) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'addVpnUser', 'ALLOW', 4) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'archiveEvents', 'ALLOW', 5) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'assignCertToLoadBalancer', 'ALLOW', 6) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'assignToGlobalLoadBalancerRule', 'ALLOW', 7) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'assignToLoadBalancerRule', 'ALLOW', 8) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'assignVirtualMachine', 'ALLOW', 9) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'associateIpAddress', 'ALLOW', 10) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'associateLun', 'ALLOW', 11) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'attachIso', 'ALLOW', 12) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'attachVolume', 'ALLOW', 13) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'authorizeSamlSso', 'ALLOW', 14) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'authorizeSecurityGroupEgress', 'ALLOW', 15) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'authorizeSecurityGroupIngress', 'ALLOW', 16) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'changeServiceForRouter', 'ALLOW', 17) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'changeServiceForVirtualMachine', 'ALLOW', 18) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'configureInternalLoadBalancerElement', 'ALLOW', 19) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'configureOvsElement', 'ALLOW', 20) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'configureVirtualRouterElement', 'ALLOW', 21) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'copyIso', 'ALLOW', 22) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'copyTemplate', 'ALLOW', 23) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createAccount', 'ALLOW', 24) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createAffinityGroup', 'ALLOW', 25) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createAutoScalePolicy', 'ALLOW', 26) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createAutoScaleVmGroup', 'ALLOW', 27) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createAutoScaleVmProfile', 'ALLOW', 28) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createCondition', 'ALLOW', 29) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createDiskOffering', 'ALLOW', 30) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createEgressFirewallRule', 'ALLOW', 31) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createFirewallRule', 'ALLOW', 32) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createGlobalLoadBalancerRule', 'ALLOW', 33) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createInstanceGroup', 'ALLOW', 34) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createInternalLoadBalancerElement', 'ALLOW', 35) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createIpForwardingRule', 'ALLOW', 36) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createLBHealthCheckPolicy', 'ALLOW', 37) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createLBStickinessPolicy', 'ALLOW', 38) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createLoadBalancer', 'ALLOW', 39) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createLoadBalancerRule', 'ALLOW', 40) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createLunOnFiler', 'ALLOW', 41) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createNetwork', 'ALLOW', 42) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createNetworkACL', 'ALLOW', 43) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createNetworkACLList', 'ALLOW', 44) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createOvsElement', 'ALLOW', 45) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createPool', 'ALLOW', 46) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createPortForwardingRule', 'ALLOW', 47) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createProject', 'ALLOW', 48) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createRemoteAccessVpn', 'ALLOW', 49) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createSSHKeyPair', 'ALLOW', 50) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createSecurityGroup', 'ALLOW', 51) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createServiceOffering', 'ALLOW', 52) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createSnapshot', 'ALLOW', 53) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createSnapshotPolicy', 'ALLOW', 54) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createStaticRoute', 'ALLOW', 55) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createTags', 'ALLOW', 56) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createTemplate', 'ALLOW', 57) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createUser', 'ALLOW', 58) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVMSnapshot', 'ALLOW', 59) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVPC', 'ALLOW', 60) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVirtualRouterElement', 'ALLOW', 61) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVolume', 'ALLOW', 62) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVolumeOnFiler', 'ALLOW', 63) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVpnConnection', 'ALLOW', 64) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVpnCustomerGateway', 'ALLOW', 65) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVpnGateway', 'ALLOW', 66) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteAccount', 'ALLOW', 67) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteAccountFromProject', 'ALLOW', 68) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteAffinityGroup', 'ALLOW', 69) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteAutoScalePolicy', 'ALLOW', 70) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteAutoScaleVmGroup', 'ALLOW', 71) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteAutoScaleVmProfile', 'ALLOW', 72) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteCondition', 'ALLOW', 73) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteDiskOffering', 'ALLOW', 74) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteEgressFirewallRule', 'ALLOW', 75) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteEvents', 'ALLOW', 76) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteFirewallRule', 'ALLOW', 77) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteGlobalLoadBalancerRule', 'ALLOW', 78) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteInstanceGroup', 'ALLOW', 79) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteIpForwardingRule', 'ALLOW', 80) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteIso', 'ALLOW', 81) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteLBHealthCheckPolicy', 'ALLOW', 82) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteLBStickinessPolicy', 'ALLOW', 83) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteLoadBalancer', 'ALLOW', 84) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteLoadBalancerRule', 'ALLOW', 85) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteNetwork', 'ALLOW', 86) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteNetworkACL', 'ALLOW', 87) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteNetworkACLList', 'ALLOW', 88) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deletePool', 'ALLOW', 89) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deletePortForwardingRule', 'ALLOW', 90) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteProject', 'ALLOW', 91) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteProjectInvitation', 'ALLOW', 92) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteRemoteAccessVpn', 'ALLOW', 93) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteSSHKeyPair', 'ALLOW', 94) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteSecurityGroup', 'ALLOW', 95) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteServiceOffering', 'ALLOW', 96) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteSnapshot', 'ALLOW', 97) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteSnapshotPolicies', 'ALLOW', 98) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteSslCert', 'ALLOW', 99) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteStaticRoute', 'ALLOW', 100) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteTags', 'ALLOW', 101) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteTemplate', 'ALLOW', 102) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteUser', 'ALLOW', 103) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteVMSnapshot', 'ALLOW', 104) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteVPC', 'ALLOW', 105) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteVolume', 'ALLOW', 106) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteVpnConnection', 'ALLOW', 107) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteVpnCustomerGateway', 'ALLOW', 108) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteVpnGateway', 'ALLOW', 109) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deployVirtualMachine', 'ALLOW', 110) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'destroyLunOnFiler', 'ALLOW', 111) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'destroyRouter', 'ALLOW', 112) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'destroyVirtualMachine', 'ALLOW', 113) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'destroyVolumeOnFiler', 'ALLOW', 114) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'detachIso', 'ALLOW', 115) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'detachVolume', 'ALLOW', 116) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'disableAccount', 'ALLOW', 117) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'disableAutoScaleVmGroup', 'ALLOW', 118) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'disableStaticNat', 'ALLOW', 119) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'disableUser', 'ALLOW', 120) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'disassociateIpAddress', 'ALLOW', 121) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'dissociateLun', 'ALLOW', 122) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'enableAccount', 'ALLOW', 123) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'enableAutoScaleVmGroup', 'ALLOW', 124) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'enableStaticNat', 'ALLOW', 125) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'enableUser', 'ALLOW', 126) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'expungeVirtualMachine', 'ALLOW', 127) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'extractIso', 'ALLOW', 128) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'extractTemplate', 'ALLOW', 129) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'extractVolume', 'ALLOW', 130) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getApiLimit', 'ALLOW', 131) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getCloudIdentifier', 'ALLOW', 132) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getSolidFireAccountId', 'ALLOW', 133) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getSolidFireVolumeAccessGroupId', 'ALLOW', 134) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getSolidFireVolumeIscsiName', 'ALLOW', 135) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getSolidFireVolumeSize', 'ALLOW', 136) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getUploadParamsForTemplate', 'ALLOW', 137) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getUploadParamsForVolume', 'ALLOW', 138) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getVMPassword', 'ALLOW', 139) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getVirtualMachineUserData', 'ALLOW', 140) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'issueNuageVspResourceRequest', 'ALLOW', 141) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAccounts', 'ALLOW', 142) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAffinityGroupTypes', 'ALLOW', 143) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAffinityGroups', 'ALLOW', 144) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listApis', 'ALLOW', 145) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAsyncJobs', 'ALLOW', 146) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAutoScalePolicies', 'ALLOW', 147) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAutoScaleVmGroups', 'ALLOW', 148) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAutoScaleVmProfiles', 'ALLOW', 149) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listCapabilities', 'ALLOW', 150) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listConditions', 'ALLOW', 151) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listCounters', 'ALLOW', 152) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listDiskOfferings', 'ALLOW', 153) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listDomainChildren', 'ALLOW', 154) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listDomains', 'ALLOW', 155) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listEgressFirewallRules', 'ALLOW', 156) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listEventTypes', 'ALLOW', 157) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listEvents', 'ALLOW', 158) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listFirewallRules', 'ALLOW', 159) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listGlobalLoadBalancerRules', 'ALLOW', 160) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listHostTags', 'ALLOW', 161) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listHypervisors', 'ALLOW', 162) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listInstanceGroups', 'ALLOW', 163) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listInternalLoadBalancerElements', 'ALLOW', 164) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listIpForwardingRules', 'ALLOW', 165) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listIsoPermissions', 'ALLOW', 166) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listIsos', 'ALLOW', 167) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLBHealthCheckPolicies', 'ALLOW', 168) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLBStickinessPolicies', 'ALLOW', 169) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLdapConfigurations', 'ALLOW', 170) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLoadBalancerRuleInstances', 'ALLOW', 171) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLoadBalancerRules', 'ALLOW', 172) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLoadBalancers', 'ALLOW', 173) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLunsOnFiler', 'ALLOW', 174) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listNetworkACLLists', 'ALLOW', 175) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listNetworkACLs', 'ALLOW', 176) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listNetworkOfferings', 'ALLOW', 177) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listNetworks', 'ALLOW', 178) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listNics', 'ALLOW', 179) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listOsCategories', 'ALLOW', 180) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listOsTypes', 'ALLOW', 181) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listOvsElements', 'ALLOW', 182) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listPools', 'ALLOW', 183) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listPortForwardingRules', 'ALLOW', 184) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listPrivateGateways', 'ALLOW', 185) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listProjectAccounts', 'ALLOW', 186) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listProjectInvitations', 'ALLOW', 187) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listProjects', 'ALLOW', 188) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listPublicIpAddresses', 'ALLOW', 189) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listRegions', 'ALLOW', 190) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listRemoteAccessVpns', 'ALLOW', 191) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listResourceDetails', 'ALLOW', 192) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listResourceLimits', 'ALLOW', 193) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listRouters', 'ALLOW', 194) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listSSHKeyPairs', 'ALLOW', 195) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listSamlAuthorization', 'ALLOW', 196) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listSecurityGroups', 'ALLOW', 197) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listServiceOfferings', 'ALLOW', 198) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listSnapshotPolicies', 'ALLOW', 199) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listSnapshots', 'ALLOW', 200) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listSslCerts', 'ALLOW', 201) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listStaticRoutes', 'ALLOW', 202) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listStorageTags', 'ALLOW', 203) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listTags', 'ALLOW', 204) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listTemplatePermissions', 'ALLOW', 205) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listTemplates', 'ALLOW', 206) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listUsageRecords', 'ALLOW', 207) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listUsers', 'ALLOW', 208) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVMSnapshot', 'ALLOW', 209) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVPCOfferings', 'ALLOW', 210) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVPCs', 'ALLOW', 211) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVirtualMachines', 'ALLOW', 212) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVirtualRouterElements', 'ALLOW', 213) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVolumes', 'ALLOW', 214) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVolumesOnFiler', 'ALLOW', 215) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVpnConnections', 'ALLOW', 216) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVpnCustomerGateways', 'ALLOW', 217) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVpnGateways', 'ALLOW', 218) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVpnUsers', 'ALLOW', 219) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listZones', 'ALLOW', 220) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'lockAccount', 'ALLOW', 221) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'lockUser', 'ALLOW', 222) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'migrateVolume', 'ALLOW', 223) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'modifyPool', 'ALLOW', 224) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'queryAsyncJobResult', 'ALLOW', 225) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'quotaBalance', 'ALLOW', 226) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'quotaIsEnabled', 'ALLOW', 227) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'quotaStatement', 'ALLOW', 228) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'quotaSummary', 'ALLOW', 229) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'quotaTariffList', 'ALLOW', 230) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'rebootRouter', 'ALLOW', 231) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'rebootVirtualMachine', 'ALLOW', 232) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'recoverVirtualMachine', 'ALLOW', 233) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'registerIso', 'ALLOW', 234) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'registerSSHKeyPair', 'ALLOW', 235) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'registerTemplate', 'ALLOW', 236) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'registerUserKeys', 'ALLOW', 237) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'removeCertFromLoadBalancer', 'ALLOW', 238) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'removeFromGlobalLoadBalancerRule', 'ALLOW', 239) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'removeFromLoadBalancerRule', 'ALLOW', 240) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'removeIpFromNic', 'ALLOW', 241) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'removeNicFromVirtualMachine', 'ALLOW', 242) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'removeVpnUser', 'ALLOW', 243) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'replaceNetworkACLList', 'ALLOW', 244) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'resetPasswordForVirtualMachine', 'ALLOW', 245) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'resetSSHKeyForVirtualMachine', 'ALLOW', 246) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'resetVpnConnection', 'ALLOW', 247) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'resizeVolume', 'ALLOW', 248) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'restartNetwork', 'ALLOW', 249) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'restartVPC', 'ALLOW', 250) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'restoreVirtualMachine', 'ALLOW', 251) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'revertSnapshot', 'ALLOW', 252) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'revertToVMSnapshot', 'ALLOW', 253) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'revokeSecurityGroupEgress', 'ALLOW', 254) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'revokeSecurityGroupIngress', 'ALLOW', 255) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'scaleVirtualMachine', 'ALLOW', 256) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'startRouter', 'ALLOW', 257) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'startVirtualMachine', 'ALLOW', 258) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'stopRouter', 'ALLOW', 259) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'stopVirtualMachine', 'ALLOW', 260) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'suspendProject', 'ALLOW', 261) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateAccount', 'ALLOW', 262) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateAutoScalePolicy', 'ALLOW', 263) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateAutoScaleVmGroup', 'ALLOW', 264) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateAutoScaleVmProfile', 'ALLOW', 265) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateDefaultNicForVirtualMachine', 'ALLOW', 266) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateDiskOffering', 'ALLOW', 267) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateEgressFirewallRule', 'ALLOW', 268) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateFirewallRule', 'ALLOW', 269) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateGlobalLoadBalancerRule', 'ALLOW', 270) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateInstanceGroup', 'ALLOW', 271) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateIpAddress', 'ALLOW', 272) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateIso', 'ALLOW', 273) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateIsoPermissions', 'ALLOW', 274) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateLBHealthCheckPolicy', 'ALLOW', 275) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateLBStickinessPolicy', 'ALLOW', 276) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateLoadBalancer', 'ALLOW', 277) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateLoadBalancerRule', 'ALLOW', 278) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateNetwork', 'ALLOW', 279) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateNetworkACLItem', 'ALLOW', 280) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateNetworkACLList', 'ALLOW', 281) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updatePortForwardingRule', 'ALLOW', 282) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateProject', 'ALLOW', 283) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateProjectInvitation', 'ALLOW', 284) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateRemoteAccessVpn', 'ALLOW', 285) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateResourceCount', 'ALLOW', 286) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateResourceLimit', 'ALLOW', 287) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateServiceOffering', 'ALLOW', 288) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateSnapshotPolicy', 'ALLOW', 289) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateTemplate', 'ALLOW', 290) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateTemplatePermissions', 'ALLOW', 291) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateUser', 'ALLOW', 292) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVMAffinityGroup', 'ALLOW', 293) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVPC', 'ALLOW', 294) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVirtualMachine', 'ALLOW', 295) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVmNicIp', 'ALLOW', 296) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVpnConnection', 'ALLOW', 297) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVpnCustomerGateway', 'ALLOW', 298) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVpnGateway', 'ALLOW', 299) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'uploadSslCert', 'ALLOW', 300) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'uploadVolume', 'ALLOW', 301) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'activateProject', 'ALLOW', 0) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'addAccountToProject', 'ALLOW', 1) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'addIpToNic', 'ALLOW', 2) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'addNicToVirtualMachine', 'ALLOW', 3) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'addVpnUser', 'ALLOW', 4) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'archiveEvents', 'ALLOW', 5) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'assignCertToLoadBalancer', 'ALLOW', 6) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'assignToGlobalLoadBalancerRule', 'ALLOW', 7) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'assignToLoadBalancerRule', 'ALLOW', 8) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'associateIpAddress', 'ALLOW', 9) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'associateLun', 'ALLOW', 10) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'attachIso', 'ALLOW', 11) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'attachVolume', 'ALLOW', 12) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'authorizeSecurityGroupEgress', 'ALLOW', 13) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'authorizeSecurityGroupIngress', 'ALLOW', 14) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'changeServiceForVirtualMachine', 'ALLOW', 15) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'copyIso', 'ALLOW', 16) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'copyTemplate', 'ALLOW', 17) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createAffinityGroup', 'ALLOW', 18) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createAutoScalePolicy', 'ALLOW', 19) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createAutoScaleVmGroup', 'ALLOW', 20) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createAutoScaleVmProfile', 'ALLOW', 21) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createCondition', 'ALLOW', 22) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createEgressFirewallRule', 'ALLOW', 23) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createFirewallRule', 'ALLOW', 24) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createGlobalLoadBalancerRule', 'ALLOW', 25) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createInstanceGroup', 'ALLOW', 26) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createIpForwardingRule', 'ALLOW', 27) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createLBHealthCheckPolicy', 'ALLOW', 28) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createLBStickinessPolicy', 'ALLOW', 29) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createLoadBalancer', 'ALLOW', 30) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createLoadBalancerRule', 'ALLOW', 31) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createLunOnFiler', 'ALLOW', 32) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createNetwork', 'ALLOW', 33) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createNetworkACL', 'ALLOW', 34) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createNetworkACLList', 'ALLOW', 35) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createPool', 'ALLOW', 36) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createPortForwardingRule', 'ALLOW', 37) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createProject', 'ALLOW', 38) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createRemoteAccessVpn', 'ALLOW', 39) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createSSHKeyPair', 'ALLOW', 40) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createSecurityGroup', 'ALLOW', 41) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createSnapshot', 'ALLOW', 42) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createSnapshotPolicy', 'ALLOW', 43) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createStaticRoute', 'ALLOW', 44) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createTags', 'ALLOW', 45) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createTemplate', 'ALLOW', 46) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVMSnapshot', 'ALLOW', 47) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVPC', 'ALLOW', 48) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVolume', 'ALLOW', 49) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVolumeOnFiler', 'ALLOW', 50) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVpnConnection', 'ALLOW', 51) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVpnCustomerGateway', 'ALLOW', 52) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVpnGateway', 'ALLOW', 53) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteAccountFromProject', 'ALLOW', 54) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteAffinityGroup', 'ALLOW', 55) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteAutoScalePolicy', 'ALLOW', 56) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteAutoScaleVmGroup', 'ALLOW', 57) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteAutoScaleVmProfile', 'ALLOW', 58) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteCondition', 'ALLOW', 59) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteEgressFirewallRule', 'ALLOW', 60) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteEvents', 'ALLOW', 61) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteFirewallRule', 'ALLOW', 62) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteGlobalLoadBalancerRule', 'ALLOW', 63) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteInstanceGroup', 'ALLOW', 64) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteIpForwardingRule', 'ALLOW', 65) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteIso', 'ALLOW', 66) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteLBHealthCheckPolicy', 'ALLOW', 67) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteLBStickinessPolicy', 'ALLOW', 68) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteLoadBalancer', 'ALLOW', 69) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteLoadBalancerRule', 'ALLOW', 70) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteNetwork', 'ALLOW', 71) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteNetworkACL', 'ALLOW', 72) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteNetworkACLList', 'ALLOW', 73) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deletePool', 'ALLOW', 74) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deletePortForwardingRule', 'ALLOW', 75) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteProject', 'ALLOW', 76) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteProjectInvitation', 'ALLOW', 77) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteRemoteAccessVpn', 'ALLOW', 78) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteSSHKeyPair', 'ALLOW', 79) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteSecurityGroup', 'ALLOW', 80) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteSnapshot', 'ALLOW', 81) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteSnapshotPolicies', 'ALLOW', 82) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteSslCert', 'ALLOW', 83) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteStaticRoute', 'ALLOW', 84) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteTags', 'ALLOW', 85) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteTemplate', 'ALLOW', 86) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteVMSnapshot', 'ALLOW', 87) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteVPC', 'ALLOW', 88) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteVolume', 'ALLOW', 89) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteVpnConnection', 'ALLOW', 90) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteVpnCustomerGateway', 'ALLOW', 91) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteVpnGateway', 'ALLOW', 92) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deployVirtualMachine', 'ALLOW', 93) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'destroyLunOnFiler', 'ALLOW', 94) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'destroyVirtualMachine', 'ALLOW', 95) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'destroyVolumeOnFiler', 'ALLOW', 96) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'detachIso', 'ALLOW', 97) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'detachVolume', 'ALLOW', 98) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'disableAutoScaleVmGroup', 'ALLOW', 99) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'disableStaticNat', 'ALLOW', 100) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'disassociateIpAddress', 'ALLOW', 101) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'dissociateLun', 'ALLOW', 102) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'enableAutoScaleVmGroup', 'ALLOW', 103) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'enableStaticNat', 'ALLOW', 104) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'expungeVirtualMachine', 'ALLOW', 105) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'extractIso', 'ALLOW', 106) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'extractTemplate', 'ALLOW', 107) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'extractVolume', 'ALLOW', 108) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getApiLimit', 'ALLOW', 109) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getCloudIdentifier', 'ALLOW', 110) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getSolidFireAccountId', 'ALLOW', 111) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getSolidFireVolumeAccessGroupId', 'ALLOW', 112) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getSolidFireVolumeIscsiName', 'ALLOW', 113) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getSolidFireVolumeSize', 'ALLOW', 114) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getUploadParamsForTemplate', 'ALLOW', 115) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getUploadParamsForVolume', 'ALLOW', 116) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getVMPassword', 'ALLOW', 117) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getVirtualMachineUserData', 'ALLOW', 118) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'issueNuageVspResourceRequest', 'ALLOW', 119) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAccounts', 'ALLOW', 120) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAffinityGroupTypes', 'ALLOW', 121) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAffinityGroups', 'ALLOW', 122) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listApis', 'ALLOW', 123) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAsyncJobs', 'ALLOW', 124) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAutoScalePolicies', 'ALLOW', 125) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAutoScaleVmGroups', 'ALLOW', 126) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAutoScaleVmProfiles', 'ALLOW', 127) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listCapabilities', 'ALLOW', 128) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listConditions', 'ALLOW', 129) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listCounters', 'ALLOW', 130) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listDiskOfferings', 'ALLOW', 131) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listEgressFirewallRules', 'ALLOW', 132) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listEventTypes', 'ALLOW', 133) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listEvents', 'ALLOW', 134) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listFirewallRules', 'ALLOW', 135) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listGlobalLoadBalancerRules', 'ALLOW', 136) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listHypervisors', 'ALLOW', 137) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listInstanceGroups', 'ALLOW', 138) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listIpForwardingRules', 'ALLOW', 139) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listIsoPermissions', 'ALLOW', 140) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listIsos', 'ALLOW', 141) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLBHealthCheckPolicies', 'ALLOW', 142) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLBStickinessPolicies', 'ALLOW', 143) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLdapConfigurations', 'ALLOW', 144) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLoadBalancerRuleInstances', 'ALLOW', 145) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLoadBalancerRules', 'ALLOW', 146) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLoadBalancers', 'ALLOW', 147) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLunsOnFiler', 'ALLOW', 148) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listNetworkACLLists', 'ALLOW', 149) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listNetworkACLs', 'ALLOW', 150) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listNetworkOfferings', 'ALLOW', 151) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listNetworks', 'ALLOW', 152) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listNics', 'ALLOW', 153) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listOsCategories', 'ALLOW', 154) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listOsTypes', 'ALLOW', 155) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listPools', 'ALLOW', 156) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listPortForwardingRules', 'ALLOW', 157) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listPrivateGateways', 'ALLOW', 158) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listProjectAccounts', 'ALLOW', 159) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listProjectInvitations', 'ALLOW', 160) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listProjects', 'ALLOW', 161) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listPublicIpAddresses', 'ALLOW', 162) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listRegions', 'ALLOW', 163) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listRemoteAccessVpns', 'ALLOW', 164) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listResourceDetails', 'ALLOW', 165) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listResourceLimits', 'ALLOW', 166) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listSSHKeyPairs', 'ALLOW', 167) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listSecurityGroups', 'ALLOW', 168) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listServiceOfferings', 'ALLOW', 169) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listSnapshotPolicies', 'ALLOW', 170) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listSnapshots', 'ALLOW', 171) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listSslCerts', 'ALLOW', 172) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listStaticRoutes', 'ALLOW', 173) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listTags', 'ALLOW', 174) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listTemplatePermissions', 'ALLOW', 175) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listTemplates', 'ALLOW', 176) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listUsers', 'ALLOW', 177) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVMSnapshot', 'ALLOW', 178) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVPCOfferings', 'ALLOW', 179) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVPCs', 'ALLOW', 180) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVirtualMachines', 'ALLOW', 181) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVolumes', 'ALLOW', 182) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVolumesOnFiler', 'ALLOW', 183) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVpnConnections', 'ALLOW', 184) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVpnCustomerGateways', 'ALLOW', 185) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVpnGateways', 'ALLOW', 186) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVpnUsers', 'ALLOW', 187) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listZones', 'ALLOW', 188) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'migrateVolume', 'ALLOW', 189) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'modifyPool', 'ALLOW', 190) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'queryAsyncJobResult', 'ALLOW', 191) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'quotaBalance', 'ALLOW', 192) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'quotaIsEnabled', 'ALLOW', 193) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'quotaStatement', 'ALLOW', 194) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'quotaSummary', 'ALLOW', 195) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'quotaTariffList', 'ALLOW', 196) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'rebootVirtualMachine', 'ALLOW', 197) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'recoverVirtualMachine', 'ALLOW', 198) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'registerIso', 'ALLOW', 199) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'registerSSHKeyPair', 'ALLOW', 200) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'registerTemplate', 'ALLOW', 201) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'registerUserKeys', 'ALLOW', 202) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'removeCertFromLoadBalancer', 'ALLOW', 203) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'removeFromGlobalLoadBalancerRule', 'ALLOW', 204) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'removeFromLoadBalancerRule', 'ALLOW', 205) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'removeIpFromNic', 'ALLOW', 206) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'removeNicFromVirtualMachine', 'ALLOW', 207) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'removeVpnUser', 'ALLOW', 208) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'replaceNetworkACLList', 'ALLOW', 209) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'resetPasswordForVirtualMachine', 'ALLOW', 210) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'resetSSHKeyForVirtualMachine', 'ALLOW', 211) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'resetVpnConnection', 'ALLOW', 212) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'resizeVolume', 'ALLOW', 213) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'restartNetwork', 'ALLOW', 214) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'restartVPC', 'ALLOW', 215) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'restoreVirtualMachine', 'ALLOW', 216) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'revertSnapshot', 'ALLOW', 217) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'revertToVMSnapshot', 'ALLOW', 218) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'revokeSecurityGroupEgress', 'ALLOW', 219) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'revokeSecurityGroupIngress', 'ALLOW', 220) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'scaleVirtualMachine', 'ALLOW', 221) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'startVirtualMachine', 'ALLOW', 222) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'stopVirtualMachine', 'ALLOW', 223) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'suspendProject', 'ALLOW', 224) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateAutoScalePolicy', 'ALLOW', 225) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateAutoScaleVmGroup', 'ALLOW', 226) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateAutoScaleVmProfile', 'ALLOW', 227) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateDefaultNicForVirtualMachine', 'ALLOW', 228) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateEgressFirewallRule', 'ALLOW', 229) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateFirewallRule', 'ALLOW', 230) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateGlobalLoadBalancerRule', 'ALLOW', 231) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateInstanceGroup', 'ALLOW', 232) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateIpAddress', 'ALLOW', 233) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateIso', 'ALLOW', 234) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateIsoPermissions', 'ALLOW', 235) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateLBHealthCheckPolicy', 'ALLOW', 236) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateLBStickinessPolicy', 'ALLOW', 237) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateLoadBalancer', 'ALLOW', 238) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateLoadBalancerRule', 'ALLOW', 239) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateNetwork', 'ALLOW', 240) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateNetworkACLItem', 'ALLOW', 241) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateNetworkACLList', 'ALLOW', 242) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updatePortForwardingRule', 'ALLOW', 243) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateProject', 'ALLOW', 244) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateProjectInvitation', 'ALLOW', 245) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateRemoteAccessVpn', 'ALLOW', 246) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateSnapshotPolicy', 'ALLOW', 247) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateTemplate', 'ALLOW', 248) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateTemplatePermissions', 'ALLOW', 249) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateUser', 'ALLOW', 250) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVMAffinityGroup', 'ALLOW', 251) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVPC', 'ALLOW', 252) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVirtualMachine', 'ALLOW', 253) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVmNicIp', 'ALLOW', 254) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVpnConnection', 'ALLOW', 255) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVpnCustomerGateway', 'ALLOW', 256) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVpnGateway', 'ALLOW', 257) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'uploadSslCert', 'ALLOW', 258) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'uploadVolume', 'ALLOW', 259) ON DUPLICATE KEY UPDATE rule=rule; diff --git a/setup/db/db/schema-481to490-cleanup.sql b/setup/db/db/schema-481to490-cleanup.sql index b1bb702727..ba206459f2 100644 --- a/setup/db/db/schema-481to490-cleanup.sql +++ b/setup/db/db/schema-481to490-cleanup.sql @@ -82,4 +82,192 @@ ALTER TABLE `cloud`.`vm_work_job` DROP INDEX `id` ; ALTER TABLE `cloud`.`vpc_gateways` DROP INDEX `id` ; ALTER TABLE `cloud`.`vpn_users` DROP INDEX `id` ; +-- Dynamic roles changes +DROP VIEW IF EXISTS `cloud`.`account_view`; +CREATE VIEW `cloud`.`account_view` AS + select + account.id, + account.uuid, + account.account_name, + account.type, + account.role_id, + account.state, + account.removed, + account.cleanup_needed, + account.network_domain, + account.default, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path, + data_center.id data_center_id, + data_center.uuid data_center_uuid, + data_center.name data_center_name, + account_netstats_view.bytesReceived, + account_netstats_view.bytesSent, + vmlimit.max vmLimit, + vmcount.count vmTotal, + runningvm.vmcount runningVms, + stoppedvm.vmcount stoppedVms, + iplimit.max ipLimit, + ipcount.count ipTotal, + free_ip_view.free_ip ipFree, + volumelimit.max volumeLimit, + volumecount.count volumeTotal, + snapshotlimit.max snapshotLimit, + snapshotcount.count snapshotTotal, + templatelimit.max templateLimit, + templatecount.count templateTotal, + vpclimit.max vpcLimit, + vpccount.count vpcTotal, + projectlimit.max projectLimit, + projectcount.count projectTotal, + networklimit.max networkLimit, + networkcount.count networkTotal, + cpulimit.max cpuLimit, + cpucount.count cpuTotal, + memorylimit.max memoryLimit, + memorycount.count memoryTotal, + primary_storage_limit.max primaryStorageLimit, + primary_storage_count.count primaryStorageTotal, + secondary_storage_limit.max secondaryStorageLimit, + secondary_storage_count.count secondaryStorageTotal, + async_job.id job_id, + async_job.uuid job_uuid, + async_job.job_status job_status, + async_job.account_id job_account_id + from + `cloud`.`free_ip_view`, + `cloud`.`account` + inner join + `cloud`.`domain` ON account.domain_id = domain.id + left join + `cloud`.`data_center` ON account.default_zone_id = data_center.id + left join + `cloud`.`account_netstats_view` ON account.id = account_netstats_view.account_id + left join + `cloud`.`resource_limit` vmlimit ON account.id = vmlimit.account_id + and vmlimit.type = 'user_vm' + left join + `cloud`.`resource_count` vmcount ON account.id = vmcount.account_id + and vmcount.type = 'user_vm' + left join + `cloud`.`account_vmstats_view` runningvm ON account.id = runningvm.account_id + and runningvm.state = 'Running' + left join + `cloud`.`account_vmstats_view` stoppedvm ON account.id = stoppedvm.account_id + and stoppedvm.state = 'Stopped' + left join + `cloud`.`resource_limit` iplimit ON account.id = iplimit.account_id + and iplimit.type = 'public_ip' + left join + `cloud`.`resource_count` ipcount ON account.id = ipcount.account_id + and ipcount.type = 'public_ip' + left join + `cloud`.`resource_limit` volumelimit ON account.id = volumelimit.account_id + and volumelimit.type = 'volume' + left join + `cloud`.`resource_count` volumecount ON account.id = volumecount.account_id + and volumecount.type = 'volume' + left join + `cloud`.`resource_limit` snapshotlimit ON account.id = snapshotlimit.account_id + and snapshotlimit.type = 'snapshot' + left join + `cloud`.`resource_count` snapshotcount ON account.id = snapshotcount.account_id + and snapshotcount.type = 'snapshot' + left join + `cloud`.`resource_limit` templatelimit ON account.id = templatelimit.account_id + and templatelimit.type = 'template' + left join + `cloud`.`resource_count` templatecount ON account.id = templatecount.account_id + and templatecount.type = 'template' + left join + `cloud`.`resource_limit` vpclimit ON account.id = vpclimit.account_id + and vpclimit.type = 'vpc' + left join + `cloud`.`resource_count` vpccount ON account.id = vpccount.account_id + and vpccount.type = 'vpc' + left join + `cloud`.`resource_limit` projectlimit ON account.id = projectlimit.account_id + and projectlimit.type = 'project' + left join + `cloud`.`resource_count` projectcount ON account.id = projectcount.account_id + and projectcount.type = 'project' + left join + `cloud`.`resource_limit` networklimit ON account.id = networklimit.account_id + and networklimit.type = 'network' + left join + `cloud`.`resource_count` networkcount ON account.id = networkcount.account_id + and networkcount.type = 'network' + left join + `cloud`.`resource_limit` cpulimit ON account.id = cpulimit.account_id + and cpulimit.type = 'cpu' + left join + `cloud`.`resource_count` cpucount ON account.id = cpucount.account_id + and cpucount.type = 'cpu' + left join + `cloud`.`resource_limit` memorylimit ON account.id = memorylimit.account_id + and memorylimit.type = 'memory' + left join + `cloud`.`resource_count` memorycount ON account.id = memorycount.account_id + and memorycount.type = 'memory' + left join + `cloud`.`resource_limit` primary_storage_limit ON account.id = primary_storage_limit.account_id + and primary_storage_limit.type = 'primary_storage' + left join + `cloud`.`resource_count` primary_storage_count ON account.id = primary_storage_count.account_id + and primary_storage_count.type = 'primary_storage' + left join + `cloud`.`resource_limit` secondary_storage_limit ON account.id = secondary_storage_limit.account_id + and secondary_storage_limit.type = 'secondary_storage' + left join + `cloud`.`resource_count` secondary_storage_count ON account.id = secondary_storage_count.account_id + and secondary_storage_count.type = 'secondary_storage' + left join + `cloud`.`async_job` ON async_job.instance_id = account.id + and async_job.instance_type = 'Account' + and async_job.job_status = 0; +DROP VIEW IF EXISTS `cloud`.`user_view`; +CREATE VIEW `cloud`.`user_view` AS + select + user.id, + user.uuid, + user.username, + user.password, + user.firstname, + user.lastname, + user.email, + user.state, + user.api_key, + user.secret_key, + user.created, + user.removed, + user.timezone, + user.registration_token, + user.is_registered, + user.incorrect_login_attempts, + user.default, + account.id account_id, + account.uuid account_uuid, + account.account_name account_name, + account.type account_type, + account.role_id account_role_id, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path, + async_job.id job_id, + async_job.uuid job_uuid, + async_job.job_status job_status, + async_job.account_id job_account_id + from + `cloud`.`user` + inner join + `cloud`.`account` ON user.account_id = account.id + inner join + `cloud`.`domain` ON account.domain_id = domain.id + left join + `cloud`.`async_job` ON async_job.instance_id = user.id + and async_job.instance_type = 'User' + and async_job.job_status = 0; diff --git a/setup/db/db/schema-481to490.sql b/setup/db/db/schema-481to490.sql index a02615ffa7..a2622ed536 100644 --- a/setup/db/db/schema-481to490.sql +++ b/setup/db/db/schema-481to490.sql @@ -436,3 +436,38 @@ VIEW `account_vmstats_view` AS (`vm_instance`.`vm_type` = 'User' and `vm_instance`.`removed` is NULL) GROUP BY `vm_instance`.`account_id` , `vm_instance`.`state`; -- End CLOUDSTACK-9340 + +-- Dynamic roles +CREATE TABLE IF NOT EXISTS `cloud`.`roles` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(255) UNIQUE, + `name` varchar(255) COMMENT 'unique name of the dynamic role', + `role_type` varchar(255) NOT NULL COMMENT 'the type of the role', + `removed` datetime COMMENT 'date removed', + `description` text COMMENT 'description of the role', + PRIMARY KEY (`id`), + KEY `i_roles__name` (`name`), + KEY `i_roles__role_type` (`role_type`), + UNIQUE KEY (`name`, `role_type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `cloud`.`role_permissions` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(255) UNIQUE, + `role_id` bigint(20) unsigned NOT NULL COMMENT 'id of the role', + `rule` varchar(255) NOT NULL COMMENT 'rule for the role, api name or wildcard', + `permission` varchar(255) NOT NULL COMMENT 'access authority, allow or deny', + `description` text COMMENT 'description of the rule', + `sort_order` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT 'permission sort order', + PRIMARY KEY (`id`), + KEY `fk_role_permissions__role_id` (`role_id`), + KEY `i_role_permissions__sort_order` (`sort_order`), + UNIQUE KEY (`role_id`, `rule`), + CONSTRAINT `fk_role_permissions__role_id` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Default CloudStack roles +INSERT INTO `cloud`.`roles` (`id`, `uuid`, `name`, `role_type`, `description`) values (1, UUID(), 'Root Admin', 'Admin', 'Default root admin role') ON DUPLICATE KEY UPDATE name=name; +INSERT INTO `cloud`.`roles` (`id`, `uuid`, `name`, `role_type`, `description`) values (2, UUID(), 'Resource Admin', 'ResourceAdmin', 'Default resource admin role') ON DUPLICATE KEY UPDATE name=name; +INSERT INTO `cloud`.`roles` (`id`, `uuid`, `name`, `role_type`, `description`) values (3, UUID(), 'Domain Admin', 'DomainAdmin', 'Default domain admin role') ON DUPLICATE KEY UPDATE name=name; +INSERT INTO `cloud`.`roles` (`id`, `uuid`, `name`, `role_type`, `description`) values (4, UUID(), 'User', 'User', 'Default Root Admin role') ON DUPLICATE KEY UPDATE name=name; diff --git a/setup/db/server-setup.sql b/setup/db/server-setup.sql index b7f5c3fc30..df2c924855 100644 --- a/setup/db/server-setup.sql +++ b/setup/db/server-setup.sql @@ -25,4 +25,5 @@ INSERT INTO `cloud`.`domain` (id, uuid, name, parent, path, owner) VALUES (1, UU INSERT INTO `cloud`.`configuration` (category, instance, component, name, value, description) VALUES ('Hidden', 'DEFAULT', 'none', 'init', null, null); -- INSERT INTO `cloud`.`configuration` (category, instance, component, name, value, description) VALUES ('Advanced', 'DEFAULT', 'AgentManager', 'xenserver.public.network.device', 'public-network', "[OPTIONAL]The name of the XenServer network containing the physical network interface that is connected to the public network "); - +-- Enable dynamic RBAC by default for fresh deployments +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'RoleService', 'dynamic.apichecker.enabled', 'true'); diff --git a/setup/db/server-setup.xml b/setup/db/server-setup.xml index bb8878f8d3..178f29aea3 100755 --- a/setup/db/server-setup.xml +++ b/setup/db/server-setup.xml @@ -239,6 +239,13 @@ under the License. qatest-vmops.com + + dynamic.apichecker.enabled + true + + - - Apache CloudStack v4.6.0 Root Admin API Reference + + + Apache CloudStack v4.9.0 Root Admin API Reference

@@ -65,16 +65,16 @@ version="1.0"> - +
- +
-
-

Request parameters

- - - +
+

Request parameters

+
Parameter Name
+ + @@ -87,7 +87,7 @@ version="1.0"> - + @@ -95,16 +95,16 @@ version="1.0">
Parameter Name Description Required
- - -
-

Response Tags

- - - + + +
+

Response Tags

+
Response Name
+ + - + @@ -112,31 +112,31 @@ version="1.0"> - + - + - - + + - - - - - + + + + +
Response Name Description
- - - + + - - + + + @@ -149,10 +149,10 @@ version="1.0"> - @@ -161,4 +161,3 @@ version="1.0"> - diff --git a/tools/apidoc/generatedomainadmincommands.xsl b/tools/apidoc/generatedomainadmincommands.xsl deleted file mode 100644 index e260b4fab4..0000000000 --- a/tools/apidoc/generatedomainadmincommands.xsl +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - - - -Apache CloudStack | The Power Behind Your Cloud - - - -
-
-
-
- -
-
- -
-
- -
- -
- -
-
- - -
- -
- -
-
-
-
- - - - Apache CloudStack v4.6.0 Domain Admin API Reference - -

-

-

-
-
- - -
- -
-
-
-

Request parameters

- - - - - - - - - - - - - - - - - - - - - -
Parameter NameDescriptionRequired
-
- - -
-

Response Tags

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Response NameDescription
- -
- - -
-
- - -
-
- - -
-
- - -
-
- diff --git a/tools/apidoc/generatetoc.xsl b/tools/apidoc/generatetoc.xsl index 2cd1b0059a..687e626a5d 100644 --- a/tools/apidoc/generatetoc.xsl +++ b/tools/apidoc/generatetoc.xsl @@ -25,7 +25,7 @@ version="1.0"> -

Cloudstack API Version 4.6.0

+

Cloudstack API Version 4.9.0


Table of Contents

diff --git a/tools/apidoc/generatetoc_header.xsl b/tools/apidoc/generatetoc_header.xsl index f760430964..6362ab8610 100644 --- a/tools/apidoc/generatetoc_header.xsl +++ b/tools/apidoc/generatetoc_header.xsl @@ -52,7 +52,7 @@ version="1.0">
-

Apache CloudStack API Documentation (v4.6.0)

+

Apache CloudStack API Documentation (v4.9.0)

diff --git a/tools/apidoc/generateusercommands.xsl b/tools/apidoc/generateusercommands.xsl deleted file mode 100644 index c9ec8572e3..0000000000 --- a/tools/apidoc/generateusercommands.xsl +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - - - - - -Apache CloudStack | The Power Behind Your Cloud - - - -
-
-
-
-
- -
-
- -
- -
- -
-
- -
- -
- -
-
-
-
- - - - Apache CloudStack v4.6.0 User API Reference - -

-

-

-
-
- - -
- -
-
-
-

Request parameters

-

Name

- - - - - - - - - - - - - - - - - - - - -
Parameter NameDescriptionRequired
- - - -
-

Response Tags

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Response NameDescription
- -
- - - - - - - - - - - - - - - - - diff --git a/tools/apidoc/pom.xml b/tools/apidoc/pom.xml index 75cb1650d1..63af063bfc 100644 --- a/tools/apidoc/pom.xml +++ b/tools/apidoc/pom.xml @@ -61,8 +61,6 @@ ${client.config.jars} ${client.config.jars} ./target - -f - ${client.config.conf}/commands.properties From 003b97bcffe640e38d089c98e8215de4c8a805e6 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Wed, 4 May 2016 15:28:12 +0530 Subject: [PATCH 143/203] maven: Fix jstl version usage This would fix regression from recent mvn version changes. Without this patch users get redirected to error.jsp as jstl-1.2 jar is not installed Signed-off-by: Rohit Yadav --- pom.xml | 3 ++- server/pom.xml | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 30e96a6107..b75afd2ed2 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,8 @@ 1.2.8 2.0.4 2.5 - 1.2.1 + 1.2 + 1.2.1 1.0-20081010.060147 6.0 3.2.16.RELEASE diff --git a/server/pom.xml b/server/pom.xml index 8461d18a4f..32695094e6 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -69,10 +69,15 @@ javax.mail mail
+ + jstl + jstl + ${cs.jstl.version} + javax.servlet.jsp.jstl javax.servlet.jsp.jstl-api - ${cs.jstl.version} + ${cs.jstl-api.version} commons-codec From 71c9c90e0c81ea9e0f90ab71d3430d62cd8fa02e Mon Sep 17 00:00:00 2001 From: Nick Livens Date: Mon, 2 May 2016 13:16:14 +0200 Subject: [PATCH 144/203] CLOUDSTACK-9365 : updateVirtualMachine with userdata should not error when a VM is attached to multiple networks from which one or more doesn't support userdata --- .../src/com/cloud/vm/UserVmManagerImpl.java | 38 +++++++++----- .../test/com/cloud/vm/UserVmManagerTest.java | 52 +++++++++++++++++++ 2 files changed, 76 insertions(+), 14 deletions(-) diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index cc007d9021..83ee2489c6 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2492,24 +2492,34 @@ private boolean updateUserDataInternal(UserVm vm) throws ResourceUnavailableExce return false; } + boolean userDataApplied = false; for (Nic nic : nics) { - Network network = _networkDao.findById(nic.getNetworkId()); - NicProfile nicProfile = new NicProfile(nic, network, null, null, null, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag( - template.getHypervisorType(), network)); + userDataApplied |= applyUserData(template.getHypervisorType(), vm, nic); + } + return userDataApplied; + } - VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vm); + protected boolean applyUserData(HypervisorType hyperVisorType, UserVm vm, Nic nic) throws ResourceUnavailableException, InsufficientCapacityException { + Network network = _networkDao.findById(nic.getNetworkId()); + NicProfile nicProfile = new NicProfile(nic, network, null, null, null, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag( + hyperVisorType, network)); + VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vm); - UserDataServiceProvider element = _networkModel.getUserDataUpdateProvider(network); - if (element == null) { - throw new CloudRuntimeException("Can't find network element for " + Service.UserData.getName() + " provider needed for UserData update"); - } - boolean result = element.saveUserData(network, nicProfile, vmProfile); - if (!result) { - s_logger.error("Failed to update userdata for vm " + vm + " and nic " + nic); - } + if (_networkModel.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Service.UserData)) { + UserDataServiceProvider element = _networkModel.getUserDataUpdateProvider(network); + if (element == null) { + throw new CloudRuntimeException("Can't find network element for " + Service.UserData.getName() + " provider needed for UserData update"); + } + boolean result = element.saveUserData(network, nicProfile, vmProfile); + if (!result) { + s_logger.error("Failed to update userdata for vm " + vm + " and nic " + nic); + } else { + return true; + } + } else { + s_logger.debug("Not applying userdata for nic id=" + nic.getId() + " in vm id=" + vmProfile.getId() + " because it is not supported in network id=" + network.getId()); } - - return true; + return false; } @Override diff --git a/server/test/com/cloud/vm/UserVmManagerTest.java b/server/test/com/cloud/vm/UserVmManagerTest.java index 637a309221..9df3f68971 100644 --- a/server/test/com/cloud/vm/UserVmManagerTest.java +++ b/server/test/com/cloud/vm/UserVmManagerTest.java @@ -17,6 +17,8 @@ package com.cloud.vm; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyFloat; @@ -37,9 +39,11 @@ import java.util.List; import java.util.UUID; +import com.cloud.network.element.UserDataServiceProvider; import com.cloud.storage.Storage; import com.cloud.user.User; import com.cloud.event.dao.UsageEventDao; +import com.cloud.uservm.UserVm; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -929,6 +933,54 @@ public void testUpdateVmNicIpFailure3() throws Exception { } } + @Test + public void testApplyUserDataInNetworkWithoutUserDataSupport() throws Exception { + UserVm userVm = mock(UserVm.class); + when(userVm.getId()).thenReturn(1L); + + when(_nicMock.getNetworkId()).thenReturn(2L); + when(_networkMock.getNetworkOfferingId()).thenReturn(3L); + when(_networkDao.findById(2L)).thenReturn(_networkMock); + + // No userdata support + assertFalse(_userVmMgr.applyUserData(HypervisorType.KVM, userVm, _nicMock)); + } + + @Test(expected = CloudRuntimeException.class) + public void testApplyUserDataInNetworkWithoutElement() throws Exception { + UserVm userVm = mock(UserVm.class); + when(userVm.getId()).thenReturn(1L); + + when(_nicMock.getNetworkId()).thenReturn(2L); + when(_networkMock.getNetworkOfferingId()).thenReturn(3L); + when(_networkDao.findById(2L)).thenReturn(_networkMock); + + UserDataServiceProvider userDataServiceProvider = mock(UserDataServiceProvider.class); + when(userDataServiceProvider.saveUserData(any(Network.class), any(NicProfile.class), any(VirtualMachineProfile.class))).thenReturn(true); + + // Userdata support, but no implementing element + when(_networkModel.areServicesSupportedByNetworkOffering(3L, Service.UserData)).thenReturn(true); + _userVmMgr.applyUserData(HypervisorType.KVM, userVm, _nicMock); + } + + @Test + public void testApplyUserDataSuccessful() throws Exception { + UserVm userVm = mock(UserVm.class); + when(userVm.getId()).thenReturn(1L); + + when(_nicMock.getNetworkId()).thenReturn(2L); + when(_networkMock.getNetworkOfferingId()).thenReturn(3L); + when(_networkDao.findById(2L)).thenReturn(_networkMock); + + UserDataServiceProvider userDataServiceProvider = mock(UserDataServiceProvider.class); + when(userDataServiceProvider.saveUserData(any(Network.class), any(NicProfile.class), any(VirtualMachineProfile.class))).thenReturn(true); + + // Userdata support with implementing element + when(_networkModel.areServicesSupportedByNetworkOffering(3L, Service.UserData)).thenReturn(true); + when(_networkModel.getUserDataUpdateProvider(_networkMock)).thenReturn(userDataServiceProvider); + assertTrue(_userVmMgr.applyUserData(HypervisorType.KVM, userVm, _nicMock)); + } + @Test public void testPersistDeviceBusInfoWithNullController() { when(_vmMock.getDetail(any(String.class))).thenReturn(null); From 9df51faa8a2f0678e7927ac6ef23752b1eae8f71 Mon Sep 17 00:00:00 2001 From: rahul singal Date: Mon, 9 May 2016 13:24:53 +0200 Subject: [PATCH 145/203] Marvin script for cloudstack-9365 --- .../test_deploy_vm_userdata_multi_nic.py | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100755 test/integration/component/test_deploy_vm_userdata_multi_nic.py diff --git a/test/integration/component/test_deploy_vm_userdata_multi_nic.py b/test/integration/component/test_deploy_vm_userdata_multi_nic.py new file mode 100755 index 0000000000..86c0f1317b --- /dev/null +++ b/test/integration/component/test_deploy_vm_userdata_multi_nic.py @@ -0,0 +1,188 @@ +# 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. + + +# this script will cover VMdeployment with Userdata tests for MultiNic + +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.lib.base import (Account, + Network, + NetworkOffering, + ServiceOffering, + VirtualMachine) +from marvin.lib.common import (get_domain, + get_template, + get_zone, + list_virtual_machines) +from marvin.lib.utils import cleanup_resources +from nose.plugins.attrib import attr +import base64 +import random +import string + +_multiprocess_shared_ = True + + +class TestDeployVmWithUserDataMultiNic(cloudstackTestCase): + """Tests for UserData + """ + + @classmethod + def setUpClass(cls): + cls.testClient = super(TestDeployVmWithUserDataMultiNic, cls).getClsTestClient() + cls.api_client = cls.testClient.getApiClient() + cls.test_data = cls.testClient.getParsedTestDataConfig() + + # Get Domain, Zone, Template + cls.domain = get_domain(cls.api_client) + cls.zone = get_zone( + cls.api_client, + cls.testClient.getZoneForTests()) + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.test_data["ostype"] + ) + if cls.zone.localstorageenabled: + cls.storagetype = 'local' + cls.test_data["service_offerings"][ + "tiny"]["storagetype"] = 'local' + else: + cls.storagetype = 'shared' + cls.test_data["service_offerings"][ + "tiny"]["storagetype"] = 'shared' + + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.test_data["service_offerings"]["tiny"] + ) + + # Create Network offering without userdata + cls.network_offering_nouserdata = NetworkOffering.create( + cls.api_client, + cls.test_data["network_offering"] + ) + # Enable Network offering + cls.network_offering_nouserdata.update(cls.api_client, state='Enabled') + + # Create Network Offering with all the serices + cls.network_offering_all = NetworkOffering.create( + cls.api_client, + cls.test_data["isolated_network_offering"] + ) + # Enable Network offering + cls.network_offering_all.update(cls.api_client, state='Enabled') + + cls._cleanup = [ + cls.service_offering, + cls.network_offering_nouserdata, + cls.network_offering_all + ] + + # Generate userdata of 2500 bytes. This is larger than the 2048 bytes limit. + # CS however allows for upto 4K bytes in the code. So this must succeed. + # Overall, the query length must not exceed 4K, for then the json decoder + # will fail this operation at the marvin client side itcls. + + cls.userdata = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(2500)) + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.hypervisor = self.testClient.getHypervisorInfo() + self.dbclient = self.testClient.getDbConnection() + self.account = Account.create( + self.apiclient, + self.test_data["account"], + admin=True, + domainid=self.domain.id + ) + self.cleanup = [] + return + + def tearDown(self): + try: + self.account.delete(self.apiclient) + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["simulator", "devcloud", "basic", "advanced"], required_hardware="false") + def test_deployvm_multinic(self): + """Test userdata update when non default nic is without userdata for deploy and update + """ + + self.userdata = base64.b64encode(self.userdata) + + network1 = Network.create( + self.apiclient, + self.test_data["isolated_network"], + accountid=self.account.name, + domainid=self.account.domainid, + networkofferingid=self.network_offering_all.id, + zoneid=self.zone.id + ) + + self.test_data["network_without_acl"]["netmask"] = "255.255.255.128" + + network2 = Network.create( + self.apiclient, + self.test_data["network_without_acl"], + accountid=self.account.name, + domainid=self.account.domainid, + networkofferingid=self.network_offering_nouserdata.id, + gateway="10.2.1.1", + zoneid=self.zone.id + ) + + deployVmResponse = VirtualMachine.create( + self.apiclient, + services=self.test_data["virtual_machine_userdata"], + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + networkids=[str(network1.id), str(network2.id)], + templateid=self.template.id, + zoneid=self.zone.id + ) + + vms = list_virtual_machines( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid, + id=deployVmResponse.id + ) + self.assert_(len(vms) > 0, "There are no Vms deployed in the account %s" % self.account.name) + vm = vms[0] + self.assert_(vm.id == str(deployVmResponse.id), "Vm deployed is different from the test") + self.assert_(vm.state == "Running", "VM is not in Running state") + + try: + updateresponse = deployVmResponse.update(self.apiclient, userdata=self.userdata) + except Exception as e: + self.fail("Failed to update userdata: %s" % e) + + self.debug("virtual machine update response is: %s" % updateresponse) + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) From dad9e5d86835ccdaa39a3c62047b7fce3a32de6d Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Thu, 13 Aug 2015 18:44:12 -0600 Subject: [PATCH 146/203] CLOUDSTACK-8813: Notify listeners when a host has been added to a cluster, is about to be removed from a cluster, or has been removed from a cluster --- .../agent/api/CreateStoragePoolCommand.java | 7 +- .../agent/api/ModifyStoragePoolAnswer.java | 37 +- .../agent/api/ModifyStoragePoolCommand.java | 46 +- .../cloud/agent/api/ModifyTargetsAnswer.java | 23 + .../cloud/agent/api/ModifyTargetsCommand.java | 57 + .../api/storage/DataStoreProviderManager.java | 4 + .../api/storage/HypervisorHostListener.java | 6 + .../api/storage/PrimaryDataStoreDriver.java | 16 +- .../src/com/cloud/agent/AgentManager.java | 10 +- .../src/com/cloud/agent/Listener.java | 18 + .../com/cloud/agent/manager/AgentAttache.java | 8 +- .../cloud/agent/manager/AgentManagerImpl.java | 53 +- .../agent/manager/SynchronousListener.java | 12 + .../cloud/vm/VirtualMachineManagerImpl.java | 12 + .../orchestration/NetworkOrchestrator.java | 11 + .../datastore/db/PrimaryDataStoreDao.java | 2 + .../datastore/db/PrimaryDataStoreDaoImpl.java | 8 + .../test/DirectAgentManagerSimpleImpl.java | 9 +- .../storage/RemoteHostEndPoint.java | 12 + .../DataStoreProviderManagerImpl.java | 1 + .../provider/DefaultHostListener.java | 14 + .../discoverer/HypervServerDiscoverer.java | 12 + .../ovm3/resources/Ovm3Discoverer.java | 12 + .../cloud/resource/SimulatorDiscoverer.java | 12 + .../SimulatorSecondaryDiscoverer.java | 12 + .../vmware/manager/VmwareManagerImpl.java | 12 + .../vmware/resource/VmwareResource.java | 51 +- .../resource/VmwareStorageProcessor.java | 78 +- .../discoverer/XcpServerDiscoverer.java | 17 +- ...CitrixModifyStoragePoolCommandWrapper.java | 5 +- .../network/manager/NuageVspManagerImpl.java | 15 + .../provider/ElastistorHostListener.java | 14 + .../provider/NexentaHostListener.java | 29 +- .../SolidFirePrimaryDataStoreDriver.java | 27 +- .../SolidFirePrimaryDataStoreLifeCycle.java | 6 +- ...idFireSharedPrimaryDataStoreLifeCycle.java | 62 +- .../provider/SolidFireHostListener.java | 230 ++- .../provider/SolidFireSharedHostListener.java | 181 +- .../storage/datastore/util/SolidFireUtil.java | 129 +- .../cloud/capacity/CapacityManagerImpl.java | 12 + .../capacity/ComputeCapacityListener.java | 12 + .../capacity/StorageCapacityListener.java | 12 + .../consoleproxy/ConsoleProxyListener.java | 12 + .../deploy/DeploymentPlanningManagerImpl.java | 12 + .../discoverer/LibvirtServerDiscoverer.java | 12 + .../network/NetworkUsageManagerImpl.java | 12 + .../cloud/network/SshKeysDistriMonitor.java | 16 +- .../VirtualNetworkApplianceManagerImpl.java | 229 +-- .../security/SecurityGroupListener.java | 16 +- .../cloud/resource/ResourceManagerImpl.java | 59 +- .../storage/ImageStoreUploadMonitorImpl.java | 12 + .../storage/LocalStoragePoolListener.java | 30 +- .../com/cloud/storage/StorageManagerImpl.java | 2 +- .../storage/download/DownloadListener.java | 18 +- .../storage/listener/StoragePoolMonitor.java | 83 +- .../storage/listener/StorageSyncListener.java | 12 + .../secondary/SecondaryStorageListener.java | 12 + .../cloud/storage/upload/UploadListener.java | 15 +- .../plugins/solidfire/TestAddRemoveHosts.py | 710 +++++++ .../plugins/solidfire/TestSnapshots.py | 1472 +++++++++++++++ .../plugins/solidfire/TestVMSnapshots.py | 862 +++++++++ .../plugins/solidfire/TestVolumes.py | 1676 +++++++++++++++++ ui/scripts/system.js | 7 +- 63 files changed, 6210 insertions(+), 375 deletions(-) create mode 100644 core/src/com/cloud/agent/api/ModifyTargetsAnswer.java create mode 100644 core/src/com/cloud/agent/api/ModifyTargetsCommand.java create mode 100644 test/integration/plugins/solidfire/TestAddRemoveHosts.py create mode 100644 test/integration/plugins/solidfire/TestSnapshots.py create mode 100644 test/integration/plugins/solidfire/TestVMSnapshots.py create mode 100644 test/integration/plugins/solidfire/TestVolumes.py diff --git a/core/src/com/cloud/agent/api/CreateStoragePoolCommand.java b/core/src/com/cloud/agent/api/CreateStoragePoolCommand.java index 90a5e39714..52746fefc5 100644 --- a/core/src/com/cloud/agent/api/CreateStoragePoolCommand.java +++ b/core/src/com/cloud/agent/api/CreateStoragePoolCommand.java @@ -19,10 +19,10 @@ package com.cloud.agent.api; -import com.cloud.storage.StoragePool; - import java.util.Map; +import com.cloud.storage.StoragePool; + public class CreateStoragePoolCommand extends ModifyStoragePoolCommand { public static final String DATASTORE_NAME = "datastoreName"; public static final String IQN = "iqn"; @@ -32,9 +32,6 @@ public class CreateStoragePoolCommand extends ModifyStoragePoolCommand { private boolean _createDatastore; private Map _details; - public CreateStoragePoolCommand() { - } - public CreateStoragePoolCommand(boolean add, StoragePool pool) { super(add, pool); } diff --git a/core/src/com/cloud/agent/api/ModifyStoragePoolAnswer.java b/core/src/com/cloud/agent/api/ModifyStoragePoolAnswer.java index b92bb72082..0e42d9a6d1 100644 --- a/core/src/com/cloud/agent/api/ModifyStoragePoolAnswer.java +++ b/core/src/com/cloud/agent/api/ModifyStoragePoolAnswer.java @@ -24,44 +24,41 @@ import com.cloud.storage.template.TemplateProp; public class ModifyStoragePoolAnswer extends Answer { - StoragePoolInfo poolInfo; - Map templateInfo; - String localDatastoreName = null; - - protected ModifyStoragePoolAnswer() { - } + private StoragePoolInfo _poolInfo; + private Map _templateInfo; + private String _localDatastoreName; public ModifyStoragePoolAnswer(ModifyStoragePoolCommand cmd, long capacityBytes, long availableBytes, Map tInfo) { super(cmd); - this.result = true; - this.poolInfo = - new StoragePoolInfo(null, cmd.getPool().getHost(), cmd.getPool().getPath(), cmd.getLocalPath(), cmd.getPool().getType(), capacityBytes, availableBytes); - this.templateInfo = tInfo; - } + result = true; - public StoragePoolInfo getPoolInfo() { - return poolInfo; + _poolInfo = new StoragePoolInfo(null, cmd.getPool().getHost(), cmd.getPool().getPath(), cmd.getLocalPath(), cmd.getPool().getType(), capacityBytes, availableBytes); + + _templateInfo = tInfo; } public void setPoolInfo(StoragePoolInfo poolInfo) { - this.poolInfo = poolInfo; + _poolInfo = poolInfo; } - public Map getTemplateInfo() { - return templateInfo; + public StoragePoolInfo getPoolInfo() { + return _poolInfo; } public void setTemplateInfo(Map templateInfo) { - this.templateInfo = templateInfo; + _templateInfo = templateInfo; } - public String getLocalDatastoreName() { - return localDatastoreName; + public Map getTemplateInfo() { + return _templateInfo; } public void setLocalDatastoreName(String localDatastoreName) { - this.localDatastoreName = localDatastoreName; + _localDatastoreName = localDatastoreName; } + public String getLocalDatastoreName() { + return _localDatastoreName; + } } diff --git a/core/src/com/cloud/agent/api/ModifyStoragePoolCommand.java b/core/src/com/cloud/agent/api/ModifyStoragePoolCommand.java index 136eb0938e..9ec4a278f2 100644 --- a/core/src/com/cloud/agent/api/ModifyStoragePoolCommand.java +++ b/core/src/com/cloud/agent/api/ModifyStoragePoolCommand.java @@ -26,51 +26,49 @@ import com.cloud.storage.StoragePool; public class ModifyStoragePoolCommand extends Command { - - boolean add; - StorageFilerTO pool; - String localPath; - String[] options; public static final String LOCAL_PATH_PREFIX = "/mnt/"; - public ModifyStoragePoolCommand() { - - } + private boolean _add; + private StorageFilerTO _pool; + private String _localPath; + private String _storagePath; public ModifyStoragePoolCommand(boolean add, StoragePool pool, String localPath) { - this.add = add; - this.pool = new StorageFilerTO(pool); - this.localPath = localPath; - + _add = add; + _pool = new StorageFilerTO(pool); + _localPath = localPath; } public ModifyStoragePoolCommand(boolean add, StoragePool pool) { this(add, pool, LOCAL_PATH_PREFIX + File.separator + UUID.nameUUIDFromBytes((pool.getHostAddress() + pool.getPath()).getBytes())); } - public StorageFilerTO getPool() { - return pool; + public boolean getAdd() { + return _add; } public void setPool(StoragePool pool) { - this.pool = new StorageFilerTO(pool); + _pool = new StorageFilerTO(pool); } - public boolean getAdd() { - return add; + public StorageFilerTO getPool() { + return _pool; } - @Override - public boolean executeInSequence() { - return false; + public String getLocalPath() { + return _localPath; } - public String getLocalPath() { - return localPath; + public void setStoragePath(String storagePath) { + _storagePath = storagePath; } - public void setOptions(String[] options) { - this.options = options; + public String getStoragePath() { + return _storagePath; } + @Override + public boolean executeInSequence() { + return false; + } } diff --git a/core/src/com/cloud/agent/api/ModifyTargetsAnswer.java b/core/src/com/cloud/agent/api/ModifyTargetsAnswer.java new file mode 100644 index 0000000000..c192e4a0df --- /dev/null +++ b/core/src/com/cloud/agent/api/ModifyTargetsAnswer.java @@ -0,0 +1,23 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.agent.api; + +public class ModifyTargetsAnswer extends Answer { +} diff --git a/core/src/com/cloud/agent/api/ModifyTargetsCommand.java b/core/src/com/cloud/agent/api/ModifyTargetsCommand.java new file mode 100644 index 0000000000..721516be2c --- /dev/null +++ b/core/src/com/cloud/agent/api/ModifyTargetsCommand.java @@ -0,0 +1,57 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.agent.api; + +import java.util.List; +import java.util.Map; + +public class ModifyTargetsCommand extends Command { + public static final String IQN = "iqn"; + public static final String STORAGE_HOST = "storageHost"; + public static final String STORAGE_PORT = "storagePort"; + public static final String CHAP_NAME = "chapName"; + public static final String CHAP_SECRET = "chapSecret"; + public static final String MUTUAL_CHAP_NAME = "mutualChapName"; + public static final String MUTUAL_CHAP_SECRET = "mutualChapSecret"; + + private boolean _add; + private List> _targets; + + public void setAdd(boolean add) { + _add = add; + } + + public boolean getAdd() { + return _add; + } + + public void setTargets(List> targets) { + _targets = targets; + } + + public List> getTargets() { + return _targets; + } + + @Override + public boolean executeInSequence() { + return false; + } +} diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java index d643d7fab7..e476d8f3b3 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java @@ -18,6 +18,8 @@ */ package org.apache.cloudstack.engine.subsystem.api.storage; +import java.util.List; + import com.cloud.storage.DataStoreProviderApiService; import com.cloud.utils.component.Manager; @@ -29,4 +31,6 @@ public interface DataStoreProviderManager extends Manager, DataStoreProviderApiS DataStoreProvider getDefaultImageDataStoreProvider(); DataStoreProvider getDefaultCacheDataStoreProvider(); + + List getProviders(); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java index 82ba8b6105..d7e8522a40 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java @@ -21,7 +21,13 @@ import com.cloud.exception.StorageConflictException; public interface HypervisorHostListener { + boolean hostAdded(long hostId); + boolean hostConnect(long hostId, long poolId) throws StorageConflictException; boolean hostDisconnected(long hostId, long poolId); + + boolean hostAboutToBeRemoved(long hostId); + + boolean hostRemoved(long hostId, long clusterId); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java index 0c6bd93982..e0c0d28e9d 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java @@ -26,27 +26,27 @@ import com.cloud.storage.Volume; public interface PrimaryDataStoreDriver extends DataStoreDriver { - public ChapInfo getChapInfo(VolumeInfo volumeInfo); + ChapInfo getChapInfo(VolumeInfo volumeInfo); - public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore); + boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore); - public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore); + void revokeAccess(DataObject dataObject, Host host, DataStore dataStore); // intended for managed storage (cloud.storage_pool.managed = true) // if not managed, return volume.getSize() - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool storagePool); + long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool storagePool); // intended for managed storage (cloud.storage_pool.managed = true) // if managed storage, return the total number of bytes currently in use for the storage pool in question // if not managed storage, return 0 - public long getUsedBytes(StoragePool storagePool); + long getUsedBytes(StoragePool storagePool); // intended for managed storage (cloud.storage_pool.managed = true) // if managed storage, return the total number of IOPS currently in use for the storage pool in question // if not managed storage, return 0 - public long getUsedIops(StoragePool storagePool); + long getUsedIops(StoragePool storagePool); - public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback); + void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback); - public void revertSnapshot(SnapshotInfo snapshotOnImageStore, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback callback); + void revertSnapshot(SnapshotInfo snapshotOnImageStore, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback callback); } diff --git a/engine/components-api/src/com/cloud/agent/AgentManager.java b/engine/components-api/src/com/cloud/agent/AgentManager.java index e9e32495d8..244772d67d 100644 --- a/engine/components-api/src/com/cloud/agent/AgentManager.java +++ b/engine/components-api/src/com/cloud/agent/AgentManager.java @@ -42,7 +42,7 @@ public enum TapAgentsAction { Add, Del, Contains, } - boolean handleDirectConnectAgent(Host host, StartupCommand[] cmds, ServerResource resource, boolean forRebalance) throws ConnectionException; + boolean handleDirectConnectAgent(Host host, StartupCommand[] cmds, ServerResource resource, boolean forRebalance, boolean newHost) throws ConnectionException; /** * easy send method that returns null if there's any errors. It handles all exceptions. @@ -131,8 +131,6 @@ public enum TapAgentsAction { Answer sendTo(Long dcId, HypervisorType type, Command cmd); -// public AgentAttache handleDirectConnectAgent(HostVO host, StartupCommand[] cmds, ServerResource resource, boolean forRebalance) throws ConnectionException; - public boolean agentStatusTransitTo(HostVO host, Status.Event e, long msId); boolean isAgentAttached(long hostId); @@ -146,4 +144,10 @@ public enum TapAgentsAction { boolean reconnect(long hostId); void rescan(); + + void notifyMonitorsOfNewlyAddedHost(long hostId); + + void notifyMonitorsOfHostAboutToBeRemoved(long hostId); + + void notifyMonitorsOfRemovedHost(long hostId, long clusterId); } diff --git a/engine/components-api/src/com/cloud/agent/Listener.java b/engine/components-api/src/com/cloud/agent/Listener.java index 242f90cfee..843a634b4c 100644 --- a/engine/components-api/src/com/cloud/agent/Listener.java +++ b/engine/components-api/src/com/cloud/agent/Listener.java @@ -63,6 +63,12 @@ public interface Listener { */ AgentControlAnswer processControlCommand(long agentId, AgentControlCommand cmd); + /** + * This method is called by AgentManager when a host is added to a cluster. + * @param long the ID of the newly added host + */ + void processHostAdded(long hostId); + /** * This method is called by AgentManager when an agent made a * connection to this server if the listener has @@ -86,6 +92,18 @@ public interface Listener { */ boolean processDisconnect(long agentId, Status state); + /** + * This method is called by AgentManager when a host is about to be removed from a cluster. + * @param long the ID of the host that's about to be removed + */ + void processHostAboutToBeRemoved(long hostId); + + /** + * This method is called by AgentManager when a host is removed from a cluster. + * @param long the ID of the newly removed host + */ + void processHostRemoved(long hostId, long clusterId); + /** * If this Listener is passed to the send() method, this method * is called by AgentManager after processing an answer diff --git a/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java b/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java index 0acac3c047..d5ec900983 100644 --- a/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java +++ b/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java @@ -44,6 +44,7 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.MaintainCommand; import com.cloud.agent.api.MigrateCommand; +import com.cloud.agent.api.ModifyTargetsCommand; import com.cloud.agent.api.PingTestCommand; import com.cloud.agent.api.PvlanSetupCommand; import com.cloud.agent.api.ReadyCommand; @@ -109,11 +110,12 @@ public int compare(final Object o1, final Object o2) { protected AgentManagerImpl _agentMgr; - public final static String[] s_commandsAllowedInMaintenanceMode = new String[] {MaintainCommand.class.toString(), MigrateCommand.class.toString(), + public final static String[] s_commandsAllowedInMaintenanceMode = new String[] { MaintainCommand.class.toString(), MigrateCommand.class.toString(), StopCommand.class.toString(), CheckVirtualMachineCommand.class.toString(), PingTestCommand.class.toString(), CheckHealthCommand.class.toString(), ReadyCommand.class.toString(), ShutdownCommand.class.toString(), SetupCommand.class.toString(), - CleanupNetworkRulesCmd.class.toString(), CheckNetworkCommand.class.toString(), PvlanSetupCommand.class.toString(), CheckOnHostCommand.class.toString()}; - protected final static String[] s_commandsNotAllowedInConnectingMode = new String[] {StartCommand.class.toString(), CreateCommand.class.toString()}; + CleanupNetworkRulesCmd.class.toString(), CheckNetworkCommand.class.toString(), PvlanSetupCommand.class.toString(), CheckOnHostCommand.class.toString(), + ModifyTargetsCommand.class.toString() }; + protected final static String[] s_commandsNotAllowedInConnectingMode = new String[] { StartCommand.class.toString(), CreateCommand.class.toString() }; static { Arrays.sort(s_commandsAllowedInMaintenanceMode); Arrays.sort(s_commandsNotAllowedInConnectingMode); diff --git a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java index 45a7dca465..efd9eedef6 100644 --- a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -538,6 +538,17 @@ public void removeAgent(final AgentAttache attache, final Status nextState) { } } + @Override + public void notifyMonitorsOfNewlyAddedHost(long hostId) { + for (final Pair monitor : _hostMonitors) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Sending host added to listener: " + monitor.second().getClass().getSimpleName()); + } + + monitor.second().processHostAdded(hostId); + } + } + protected AgentAttache notifyMonitorsOfConnection(final AgentAttache attache, final StartupCommand[] cmd, final boolean forRebalance) throws ConnectionException { final long hostId = attache.getId(); final HostVO host = _hostDao.findById(hostId); @@ -1001,6 +1012,28 @@ public boolean reconnect(final long hostId) { return true; } + @Override + public void notifyMonitorsOfHostAboutToBeRemoved(long hostId) { + for (final Pair monitor : _hostMonitors) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Sending host about to be removed to listener: " + monitor.second().getClass().getSimpleName()); + } + + monitor.second().processHostAboutToBeRemoved(hostId); + } + } + + @Override + public void notifyMonitorsOfRemovedHost(long hostId, long clusterId) { + for (final Pair monitor : _hostMonitors) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Sending host removed to listener: " + monitor.second().getClass().getSimpleName()); + } + + monitor.second().processHostRemoved(hostId, clusterId); + } + } + public boolean executeUserRequest(final long hostId, final Event event) throws AgentUnavailableException { if (event == Event.AgentDisconnected) { if (s_logger.isDebugEnabled()) { @@ -1464,7 +1497,8 @@ public void disconnectWithoutInvestigation(final long hostId, final Status.Event } @Override - public boolean handleDirectConnectAgent(final Host host, final StartupCommand[] cmds, final ServerResource resource, final boolean forRebalance) throws ConnectionException { + public boolean handleDirectConnectAgent(final Host host, final StartupCommand[] cmds, final ServerResource resource, + final boolean forRebalance, boolean newHost) throws ConnectionException { AgentAttache attache; attache = createAttacheForDirectConnect(host, resource); @@ -1473,6 +1507,11 @@ public boolean handleDirectConnectAgent(final Host host, final StartupCommand[] answers[i] = new StartupAnswer(cmds[i], attache.getId(), PingInterval.value()); } attache.process(answers); + + if (newHost) { + notifyMonitorsOfNewlyAddedHost(host.getId()); + } + attache = notifyMonitorsOfConnection(attache, cmds, forRebalance); return attache != null; @@ -1617,6 +1656,10 @@ public AgentControlAnswer processControlCommand(final long agentId, final AgentC return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(final Host host, final StartupCommand cmd, final boolean forRebalance) { if (host.getType().equals(Host.Type.TrafficMonitor) || host.getType().equals(Host.Type.SecondaryStorage)) { @@ -1633,6 +1676,14 @@ public boolean processDisconnect(final long agentId, final Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(final long agentId, final long seq) { return true; diff --git a/engine/orchestration/src/com/cloud/agent/manager/SynchronousListener.java b/engine/orchestration/src/com/cloud/agent/manager/SynchronousListener.java index 28c60c1a07..96d40777f8 100644 --- a/engine/orchestration/src/com/cloud/agent/manager/SynchronousListener.java +++ b/engine/orchestration/src/com/cloud/agent/manager/SynchronousListener.java @@ -78,6 +78,18 @@ public synchronized boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) { } diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java index 43228e8bfa..9523b928ed 100644 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -2786,6 +2786,18 @@ public boolean processDisconnect(final long agentId, final Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(final Host agent, final StartupCommand cmd, final boolean forRebalance) throws ConnectionException { if (!(cmd instanceof StartupRoutingCommand)) { diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index e4272720bc..66185c6097 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -3001,6 +3001,9 @@ public AgentControlAnswer processControlCommand(final long agentId, final AgentC return null; } + public void processHostAdded(long hostId) { + } + @Override public void processConnect(final Host host, final StartupCommand cmd, final boolean forRebalance) throws ConnectionException { if (!(cmd instanceof StartupRoutingCommand)) { @@ -3088,6 +3091,14 @@ public boolean processDisconnect(final long agentId, final Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { return false; diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java index d265da15de..32d1d79224 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java @@ -64,6 +64,8 @@ public interface PrimaryDataStoreDao extends GenericDao { */ List findPoolByName(String name); + List findPoolsByProvider(String provider); + /** * Find pools by the pod that matches the details. * diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java index fd617cce09..c451e1dee4 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java @@ -79,6 +79,7 @@ public PrimaryDataStoreDaoImpl() { AllFieldSearch.and("path", AllFieldSearch.entity().getPath(), SearchCriteria.Op.EQ); AllFieldSearch.and("podId", AllFieldSearch.entity().getPodId(), Op.EQ); AllFieldSearch.and("clusterId", AllFieldSearch.entity().getClusterId(), Op.EQ); + AllFieldSearch.and("storage_provider_name", AllFieldSearch.entity().getStorageProviderName(), Op.EQ); AllFieldSearch.done(); DcPodSearch = createSearchBuilder(); @@ -128,6 +129,13 @@ public List findPoolByName(String name) { return listIncludingRemovedBy(sc); } + @Override + public List findPoolsByProvider(String provider) { + SearchCriteria sc = AllFieldSearch.create(); + sc.setParameters("storage_provider_name", provider); + return listBy(sc); + } + @Override public StoragePoolVO findPoolByUUID(String uuid) { SearchCriteria sc = AllFieldSearch.create(); diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java index b34b697af0..0e4755e034 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java @@ -278,9 +278,16 @@ public boolean isAgentAttached(long hostId) { } @Override - public boolean handleDirectConnectAgent(Host host, StartupCommand[] cmds, ServerResource resource, boolean forRebalance) throws ConnectionException { + public boolean handleDirectConnectAgent(Host host, StartupCommand[] cmds, ServerResource resource, boolean forRebalance, boolean newHost) throws ConnectionException { // TODO Auto-generated method stub return false; } + @Override + public void notifyMonitorsOfHostAboutToBeRemoved(long hostId) { + } + + @Override + public void notifyMonitorsOfRemovedHost(long hostId, long clusterId) { + } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java b/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java index 1f59cc6cc8..3bad62eb57 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java +++ b/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java @@ -160,6 +160,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { // TODO Auto-generated method stub @@ -172,6 +176,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { // TODO Auto-generated method stub diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java index 6e36514c49..98eeb6b440 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java @@ -218,6 +218,7 @@ public void setImageStoreProviderMgr(ImageStoreProviderManager imageDataStorePro this.imageStoreProviderMgr = imageDataStoreProviderMgr; } + @Override public List getProviders() { return providers; } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java index 89af0765fd..64533d54d2 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java @@ -54,6 +54,11 @@ public class DefaultHostListener implements HypervisorHostListener { @Inject PrimaryDataStoreDao primaryStoreDao; + @Override + public boolean hostAdded(long hostId) { + return true; + } + @Override public boolean hostConnect(long hostId, long poolId) throws StorageConflictException { StoragePool pool = (StoragePool)this.dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary); @@ -109,4 +114,13 @@ public boolean hostDisconnected(long hostId, long poolId) { return false; } + @Override + public boolean hostAboutToBeRemoved(long hostId) { + return true; + } + + @Override + public boolean hostRemoved(long hostId, long clusterId) { + return true; + } } diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java index fd8db4a564..fd54d43241 100644 --- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java +++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java @@ -106,6 +106,10 @@ public final AgentControlAnswer processControlCommand(final long agentId, final return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public final void processConnect(final Host agent, final StartupCommand cmd, final boolean forRebalance) throws ConnectionException { // Limit the commands we can process @@ -176,6 +180,14 @@ public final boolean processDisconnect(final long agentId, final Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public final boolean isRecurring() { return false; diff --git a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3Discoverer.java b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3Discoverer.java index 4743600d50..3f245273a2 100755 --- a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3Discoverer.java +++ b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3Discoverer.java @@ -338,6 +338,10 @@ public AgentControlAnswer processControlCommand(long agentId, return null; } + @Override + public void processHostAdded(long hostId) { + } + /* for reconnecting */ @Override public void processConnect(Host host, StartupCommand cmd, @@ -351,6 +355,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { return false; diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java index 76eb1c08a7..c942c8ff55 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java @@ -245,6 +245,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { @@ -273,6 +277,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { return false; diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java index 6e75244c32..e09a5a950a 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java @@ -140,6 +140,10 @@ public boolean processCommands(long agentId, long seq, Command[] commands) { return false; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { @@ -155,6 +159,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { return false; 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 f27e938e73..63124e1ca9 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -841,6 +841,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) { if (cmd instanceof StartupCommand) { @@ -882,6 +886,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { return false; diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 14a73bb3a0..82e7f65b6a 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -148,6 +148,8 @@ import com.cloud.agent.api.ModifySshKeysCommand; import com.cloud.agent.api.ModifyStoragePoolAnswer; import com.cloud.agent.api.ModifyStoragePoolCommand; +import com.cloud.agent.api.ModifyTargetsAnswer; +import com.cloud.agent.api.ModifyTargetsCommand; import com.cloud.agent.api.NetworkUsageAnswer; import com.cloud.agent.api.NetworkUsageCommand; import com.cloud.agent.api.PingCommand; @@ -409,6 +411,8 @@ public Answer executeRequest(Command cmd) { answer = execute((DestroyCommand)cmd); } else if (clz == CreateStoragePoolCommand.class) { return execute((CreateStoragePoolCommand)cmd); + } else if (clz == ModifyTargetsCommand.class) { + answer = execute((ModifyTargetsCommand)cmd); } else if (clz == ModifyStoragePoolCommand.class) { answer = execute((ModifyStoragePoolCommand)cmd); } else if (clz == DeleteStoragePoolCommand.class) { @@ -933,7 +937,7 @@ private PlugNicAnswer execute(PlugNicCommand cmd) { */ // Fallback to E1000 if no specific nicAdapter is passed VirtualEthernetCardType nicDeviceType = VirtualEthernetCardType.E1000; - Map details = cmd.getDetails(); + Map details = cmd.getDetails(); if (details != null) { nicDeviceType = VirtualEthernetCardType.valueOf((String) details.get("nicAdapter")); } @@ -3527,7 +3531,6 @@ protected Answer execute(MigrateWithStorageCommand cmd) { private Answer execute(MigrateVolumeCommand cmd) { String volumePath = cmd.getVolumePath(); StorageFilerTO poolTo = cmd.getPool(); - Volume.Type volumeType = cmd.getVolumeType(); if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource MigrateVolumeCommand: " + _gson.toJson(cmd)); @@ -3608,7 +3611,6 @@ private Answer execute(MigrateVolumeCommand cmd) { // Consolidate VM disks. // In case of a linked clone VM, if VM's disks are not consolidated, // further volume operations on the ROOT volume such as volume snapshot etc. will result in DB inconsistencies. - String apiVersion = HypervisorHostHelper.getVcenterApiVersion(vmMo.getContext()); if (!vmMo.consolidateVmDisks()) { s_logger.warn("VM disk consolidation failed after storage migration."); } else { @@ -3677,6 +3679,14 @@ protected Answer execute(CreateStoragePoolCommand cmd) { return new Answer(cmd, true, "success"); } + protected Answer execute(ModifyTargetsCommand cmd) { + VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); + + handleTargets(cmd.getAdd(), cmd.getTargets(), (HostMO)hyperHost); + + return new ModifyTargetsAnswer(); + } + protected Answer execute(ModifyStoragePoolCommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource ModifyStoragePoolCommand: " + _gson.toJson(cmd)); @@ -3690,34 +3700,53 @@ protected Answer execute(ModifyStoragePoolCommand cmd) { throw new Exception("Unsupported storage pool type " + pool.getType()); } - ManagedObjectReference morDatastore = null; - morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, pool.getUuid()); - if (morDatastore == null) - morDatastore = - hyperHost.mountDatastore(pool.getType() == StoragePoolType.VMFS, pool.getHost(), pool.getPort(), pool.getPath(), pool.getUuid().replace("-", "")); + ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, pool.getUuid()); + + if (morDatastore == null) { + morDatastore = hyperHost.mountDatastore(pool.getType() == StoragePoolType.VMFS, pool.getHost(), pool.getPort(), pool.getPath(), pool.getUuid().replace("-", "")); + } assert (morDatastore != null); + DatastoreSummary summary = new DatastoreMO(getServiceContext(), morDatastore).getSummary(); + long capacity = summary.getCapacity(); long available = summary.getFreeSpace(); + Map tInfo = new HashMap(); ModifyStoragePoolAnswer answer = new ModifyStoragePoolAnswer(cmd, capacity, available, tInfo); + if (cmd.getAdd() && pool.getType() == StoragePoolType.VMFS) { answer.setLocalDatastoreName(morDatastore.getValue()); } + return answer; } catch (Throwable e) { if (e instanceof RemoteException) { s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context"); + invalidateServiceContext(); } String msg = "ModifyStoragePoolCommand failed due to " + VmwareHelper.getExceptionMessage(e); + s_logger.error(msg, e); + return new Answer(cmd, false, msg); } } + private void handleTargets(boolean add, List> targets, HostMO host) { + if (targets != null && targets.size() > 0) { + try { + _storageProcessor.handleTargetsForHost(add, targets, host); + } + catch (Exception ex) { + s_logger.warn(ex.getMessage()); + } + } + } + protected Answer execute(DeleteStoragePoolCommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource DeleteStoragePoolCommand: " + _gson.toJson(cmd)); @@ -4701,12 +4730,6 @@ protected HashMap syncHostVmStates() { } } - private boolean isVmInCluster(String vmName) throws Exception { - VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); - - return hyperHost.findVmOnPeerHyperHost(vmName) != null; - } - protected OptionValue[] configureVnc(OptionValue[] optionsToMerge, VmwareHypervisorHost hyperHost, String vmName, String vncPassword, String keyboardLayout) throws Exception { diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index 310313ab37..21f79f983e 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -71,6 +71,7 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.ModifyTargetsCommand; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.DiskTO; @@ -1911,14 +1912,77 @@ private static int getMBsFromBytes(long bytes) { return (int)(bytes / (1024L * 1024L)); } - private void addRemoveInternetScsiTargetsToAllHosts(VmwareContext context, final boolean add, final List lstTargets, - List> lstHosts) throws Exception { - ExecutorService executorService = Executors.newFixedThreadPool(lstHosts.size()); + public void handleTargetsForHost(boolean add, List> targets, HostMO host) throws Exception { + List lstTargets = new ArrayList(); - final List exceptions = new ArrayList(); + for (Map mapTarget : targets) { + HostInternetScsiHbaStaticTarget target = new HostInternetScsiHbaStaticTarget(); - for (Pair hostPair : lstHosts) { + String targetAddress = mapTarget.get(ModifyTargetsCommand.STORAGE_HOST); + Integer targetPort = Integer.parseInt(mapTarget.get(ModifyTargetsCommand.STORAGE_PORT)); + String iScsiName = trimIqn(mapTarget.get(ModifyTargetsCommand.IQN)); + + target.setAddress(targetAddress); + target.setPort(targetPort); + target.setIScsiName(iScsiName); + + String chapName = mapTarget.get(ModifyTargetsCommand.CHAP_NAME); + String chapSecret = mapTarget.get(ModifyTargetsCommand.CHAP_SECRET); + + if (StringUtils.isNotBlank(chapName) && StringUtils.isNotBlank(chapSecret)) { + HostInternetScsiHbaAuthenticationProperties auth = new HostInternetScsiHbaAuthenticationProperties(); + + String strAuthType = "chapRequired"; + + auth.setChapAuthEnabled(true); + auth.setChapInherited(false); + auth.setChapAuthenticationType(strAuthType); + auth.setChapName(chapName); + auth.setChapSecret(chapSecret); + + String mutualChapName = mapTarget.get(ModifyTargetsCommand.MUTUAL_CHAP_NAME); + String mutualChapSecret = mapTarget.get(ModifyTargetsCommand.MUTUAL_CHAP_SECRET); + + if (StringUtils.isNotBlank(mutualChapName) && StringUtils.isNotBlank(mutualChapSecret)) { + auth.setMutualChapInherited(false); + auth.setMutualChapAuthenticationType(strAuthType); + auth.setMutualChapName(mutualChapName); + auth.setMutualChapSecret(mutualChapSecret); + } + + target.setAuthenticationProperties(auth); + } + + lstTargets.add(target); + } + + List hosts = new ArrayList<>(); + + hosts.add(host); + + addRemoveInternetScsiTargetsToAllHosts(add, lstTargets, hosts); + } + + private void addRemoveInternetScsiTargetsToAllHosts(VmwareContext context, final boolean add, final List targets, + List> hostPairs) throws Exception { + List hosts = new ArrayList<>(); + + for (Pair hostPair : hostPairs) { HostMO host = new HostMO(context, hostPair.first()); + + hosts.add(host); + } + + addRemoveInternetScsiTargetsToAllHosts(add, targets, hosts); + } + + private void addRemoveInternetScsiTargetsToAllHosts(final boolean add, final List targets, + List hosts) throws Exception { + ExecutorService executorService = Executors.newFixedThreadPool(hosts.size()); + + final List exceptions = new ArrayList(); + + for (HostMO host : hosts) { HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO(); boolean iScsiHbaConfigured = false; @@ -1938,9 +2002,9 @@ private void addRemoveInternetScsiTargetsToAllHosts(VmwareContext context, final public void run() { try { if (add) { - hss.addInternetScsiStaticTargets(iScsiHbaDevice, lstTargets); + hss.addInternetScsiStaticTargets(iScsiHbaDevice, targets); } else { - hss.removeInternetScsiStaticTargets(iScsiHbaDevice, lstTargets); + hss.removeInternetScsiStaticTargets(iScsiHbaDevice, targets); } hss.rescanHba(iScsiHbaDevice); diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/discoverer/XcpServerDiscoverer.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/discoverer/XcpServerDiscoverer.java index 63c44853d1..4416c20dd6 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/discoverer/XcpServerDiscoverer.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/discoverer/XcpServerDiscoverer.java @@ -113,16 +113,15 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L protected String _guestNic; protected boolean _setupMultipath; protected String _instance; - private String xs620snapshothotfix = "Xenserver-Vdi-Copy-HotFix"; @Inject protected AlertManager _alertMgr; @Inject protected AgentManager _agentMgr; @Inject - VMTemplateDao _tmpltDao; + private VMTemplateDao _tmpltDao; @Inject - HostPodDao _podDao; + private HostPodDao _podDao; protected XcpServerDiscoverer() { } @@ -542,6 +541,10 @@ private void createXsToolsISO() { } } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(com.cloud.host.Host agent, StartupCommand cmd, boolean forRebalance) throws ConnectionException { if (!(cmd instanceof StartupRoutingCommand)) { @@ -629,6 +632,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { return false; diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixModifyStoragePoolCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixModifyStoragePoolCommandWrapper.java index 67d456ff3c..4c7136e28f 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixModifyStoragePoolCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixModifyStoragePoolCommandWrapper.java @@ -49,7 +49,8 @@ public Answer execute(final ModifyStoragePoolCommand command, final CitrixResour final boolean add = command.getAdd(); if (add) { try { - final SR sr = citrixResourceBase.getStorageRepository(conn, pool.getUuid()); + final String srName = command.getStoragePath() != null ? command.getStoragePath() : pool.getUuid(); + final SR sr = citrixResourceBase.getStorageRepository(conn, srName); citrixResourceBase.setupHeartbeatSr(conn, sr, false); final long capacity = sr.getPhysicalSize(conn); final long available = capacity - sr.getPhysicalUtilisation(conn); @@ -81,7 +82,7 @@ public Answer execute(final ModifyStoragePoolCommand command, final CitrixResour if (result == null || !result.split("#")[1].equals("0")) { throw new CloudRuntimeException("Unable to remove heartbeat file entry for SR " + srUuid + " due to " + result); } - return new Answer(command, true, "seccuss"); + return new Answer(command, true, "success"); } catch (final XenAPIException e) { final String msg = "ModifyStoragePoolCommand remove XenAPIException:" + e.toString() + " host:" + citrixResourceBase.getHost().getUuid() + " pool: " + pool.getHost() + pool.getPath(); diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java index 16fd11de3c..f38a9c702c 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java @@ -735,6 +735,11 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { @@ -745,6 +750,16 @@ public boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + + } + @Override public boolean isRecurring() { return false; diff --git a/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/provider/ElastistorHostListener.java b/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/provider/ElastistorHostListener.java index c2624eaa25..b40e60ecf7 100644 --- a/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/provider/ElastistorHostListener.java +++ b/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/provider/ElastistorHostListener.java @@ -76,6 +76,11 @@ public class ElastistorHostListener implements HypervisorHostListener { @Inject HostDao _hostDao; + @Override + public boolean hostAdded(long hostId) { + return true; + } + @Override public boolean hostConnect(long hostId, long poolId) { StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary); @@ -126,4 +131,13 @@ public boolean hostDisconnected(long hostId, long poolId) { return false; } + @Override + public boolean hostAboutToBeRemoved(long hostId) { + return true; + } + + @Override + public boolean hostRemoved(long hostId, long clusterId) { + return true; + } } diff --git a/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/provider/NexentaHostListener.java b/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/provider/NexentaHostListener.java index 950325288f..5fe759902b 100644 --- a/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/provider/NexentaHostListener.java +++ b/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/provider/NexentaHostListener.java @@ -23,13 +23,40 @@ import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; public class NexentaHostListener implements HypervisorHostListener { - private static final Logger logger = Logger.getLogger(NexentaHostListener.class); + private static final Logger s_logger = Logger.getLogger(NexentaHostListener.class); + @Override + public boolean hostAdded(long hostId) { + s_logger.trace("hostAdded(long) invoked"); + + return true; + } + + @Override public boolean hostConnect(long hostId, long poolId) { + s_logger.trace("hostConnect(long, long) invoked"); + return true; } + @Override public boolean hostDisconnected(long hostId, long poolId) { + s_logger.trace("hostDisconnected(long, long) invoked"); + + return true; + } + + @Override + public boolean hostAboutToBeRemoved(long hostId) { + s_logger.trace("hostAboutToBeRemoved(long) invoked"); + + return true; + } + + @Override + public boolean hostRemoved(long hostId, long clusterId) { + s_logger.trace("hostRemoved(long) invoked"); + return true; } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java index 61e199c74c..5f647db110 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java @@ -76,7 +76,6 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { private static final Logger s_logger = Logger.getLogger(SolidFirePrimaryDataStoreDriver.class); - private static final int s_lockTimeInSeconds = 300; private static final int s_lowestHypervisorSnapshotReserve = 10; @Inject private AccountDao _accountDao; @@ -141,8 +140,12 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); - if (!lock.lock(s_lockTimeInSeconds)) { - s_logger.debug("Couldn't lock the DB (in grantAccess) on the following string: " + cluster.getUuid()); + if (!lock.lock(SolidFireUtil.s_lockTimeInSeconds)) { + String errMsg = "Couldn't lock the DB (in grantAccess) on the following string: " + cluster.getUuid(); + + s_logger.debug(errMsg); + + throw new CloudRuntimeException(errMsg); } try { @@ -161,10 +164,9 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore if (vagId != null) { SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); - String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hosts)); long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); - SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, volumeIds); + SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); } else { SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolumeId, storagePoolId, cluster.getUuid(), hosts, _clusterDetailsDao); @@ -196,8 +198,12 @@ public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore) GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); - if (!lock.lock(s_lockTimeInSeconds)) { - s_logger.debug("Couldn't lock the DB (in revokeAccess) on the following string: " + cluster.getUuid()); + if (!lock.lock(SolidFireUtil.s_lockTimeInSeconds)) { + String errMsg = "Couldn't lock the DB (in revokeAccess) on the following string: " + cluster.getUuid(); + + s_logger.debug(errMsg); + + throw new CloudRuntimeException(errMsg); } try { @@ -206,16 +212,13 @@ public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore) String vagId = clusterDetail != null ? clusterDetail.getValue() : null; if (vagId != null) { - List hosts = _hostDao.findByClusterId(clusterId); - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); - String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hosts)); long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false); - SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, volumeIds); + SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); } } finally { @@ -701,7 +704,7 @@ private String deleteSnapshot(SnapshotInfo snapshotInfo, long storagePoolId) { } @Override - public void revertSnapshot(SnapshotInfo snapshot, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback callback) { + public void revertSnapshot(SnapshotInfo snapshotOnImageStore, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback callback) { throw new UnsupportedOperationException("Reverting not supported. Create a template or volume based on the snapshot instead."); } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java index 4b38f221df..f89c97a899 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java @@ -136,7 +136,7 @@ public DataStore initialize(Map dsInfos) { lClusterDefaultMinIops = Long.parseLong(clusterDefaultMinIops); } } catch (NumberFormatException ex) { - s_logger.warn("Cannot parse the setting of " + SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS + + s_logger.warn("Cannot parse the setting " + SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS + ", using default value: " + lClusterDefaultMinIops + ". Exception: " + ex); } @@ -148,7 +148,7 @@ public DataStore initialize(Map dsInfos) { lClusterDefaultMaxIops = Long.parseLong(clusterDefaultMaxIops); } } catch (NumberFormatException ex) { - s_logger.warn("Cannot parse the setting of " + SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS + + s_logger.warn("Cannot parse the setting " + SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS + ", using default value: " + lClusterDefaultMaxIops + ". Exception: " + ex); } @@ -160,7 +160,7 @@ public DataStore initialize(Map dsInfos) { fClusterDefaultBurstIopsPercentOfMaxIops = Float.parseFloat(clusterDefaultBurstIopsPercentOfMaxIops); } } catch (NumberFormatException ex) { - s_logger.warn("Cannot parse the setting of " + SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS + + s_logger.warn("Cannot parse the setting " + SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS + ", using default value: " + fClusterDefaultBurstIopsPercentOfMaxIops + ". Exception: " + ex); } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java index 7cb690014b..6921e4f487 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java @@ -70,6 +70,7 @@ import com.cloud.user.AccountDetailsDao; import com.cloud.user.AccountVO; import com.cloud.user.dao.AccountDao; +import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle { @@ -178,8 +179,7 @@ public DataStore initialize(Map dsInfos) { lMinIops = Long.parseLong(minIops); } } catch (Exception ex) { - s_logger.info("[ignored]" - + "error getting minimals iops: " + ex.getLocalizedMessage()); + s_logger.info("[ignored] error getting Min IOPS: " + ex.getLocalizedMessage()); } try { @@ -189,8 +189,7 @@ public DataStore initialize(Map dsInfos) { lMaxIops = Long.parseLong(maxIops); } } catch (Exception ex) { - s_logger.info("[ignored]" - + "error getting maximal iops: " + ex.getLocalizedMessage()); + s_logger.info("[ignored] error getting Max IOPS: " + ex.getLocalizedMessage()); } try { @@ -200,8 +199,7 @@ public DataStore initialize(Map dsInfos) { lBurstIops = Long.parseLong(burstIops); } } catch (Exception ex) { - s_logger.info("[ignored]" - + "error getting iops bursts: " + ex.getLocalizedMessage()); + s_logger.info("[ignored] error getting Burst IOPS: " + ex.getLocalizedMessage()); } if (lMinIops > lMaxIops) { @@ -255,14 +253,27 @@ public DataStore initialize(Map dsInfos) { parameters.setPath(iqn); } - // this adds a row in the cloud.storage_pool table for this SolidFire volume - DataStore dataStore = _primaryDataStoreHelper.createPrimaryDataStore(parameters); + ClusterVO cluster = _clusterDao.findById(clusterId); + + GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); + + if (!lock.lock(SolidFireUtil.s_lockTimeInSeconds)) { + String errMsg = "Couldn't lock the DB on the following string: " + cluster.getUuid(); + + s_logger.debug(errMsg); + + throw new CloudRuntimeException(errMsg); + } + + DataStore dataStore = null; - // now that we have a DataStore (we need the id from the DataStore instance), we can create a Volume Access Group, if need be, and - // place the newly created volume in the Volume Access Group try { + // this adds a row in the cloud.storage_pool table for this SolidFire volume + dataStore = _primaryDataStoreHelper.createPrimaryDataStore(parameters); + + // now that we have a DataStore (we need the id from the DataStore instance), we can create a Volume Access Group, if need be, and + // place the newly created volume in the Volume Access Group List hosts = _hostDao.findByClusterId(clusterId); - ClusterVO cluster = _clusterDao.findById(clusterId); SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolume.getId(), dataStore.getId(), cluster.getUuid(), hosts, _clusterDetailsDao); @@ -275,6 +286,10 @@ public DataStore initialize(Map dsInfos) { throw new CloudRuntimeException(ex.getMessage()); } + finally { + lock.unlock(); + lock.releaseRef(); + } return dataStore; } @@ -546,7 +561,25 @@ public boolean deleteDataStore(DataStore dataStore) { } if (clusterId != null) { - removeVolumeFromVag(storagePool.getId(), clusterId); + ClusterVO cluster = _clusterDao.findById(clusterId); + + GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); + + if (!lock.lock(SolidFireUtil.s_lockTimeInSeconds)) { + String errMsg = "Couldn't lock the DB on the following string: " + cluster.getUuid(); + + s_logger.debug(errMsg); + + throw new CloudRuntimeException(errMsg); + } + + try { + removeVolumeFromVag(storagePool.getId(), clusterId); + } + finally { + lock.unlock(); + lock.releaseRef(); + } } deleteSolidFireVolume(storagePool.getId()); @@ -561,16 +594,13 @@ private void removeVolumeFromVag(long storagePoolId, long clusterId) { String vagId = clusterDetail != null ? clusterDetail.getValue() : null; if (vagId != null) { - List hosts = _hostDao.findByClusterId(clusterId); - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); - String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hosts)); long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false); - SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, volumeIds); + SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java index d8e4ec61ec..082e1a3d2b 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java @@ -18,40 +18,69 @@ */ package org.apache.cloudstack.storage.datastore.provider; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import javax.inject.Inject; import org.apache.log4j.Logger; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.ModifyStoragePoolAnswer; import com.cloud.agent.api.ModifyStoragePoolCommand; +import com.cloud.agent.api.ModifyTargetsCommand; import com.cloud.alert.AlertManager; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.dao.ClusterDao; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.DataStoreRole; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; +import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.dao.VMInstanceDao; public class SolidFireHostListener implements HypervisorHostListener { private static final Logger s_logger = Logger.getLogger(SolidFireHostListener.class); - @Inject - private AgentManager _agentMgr; - @Inject - private AlertManager _alertMgr; - @Inject - private DataStoreManager _dataStoreMgr; - @Inject - private HostDao _hostDao; - @Inject - private StoragePoolHostDao storagePoolHostDao; + @Inject private AgentManager _agentMgr; + @Inject private AlertManager _alertMgr; + @Inject private ClusterDao _clusterDao; + @Inject private ClusterDetailsDao _clusterDetailsDao; + @Inject private DataStoreManager _dataStoreMgr; + @Inject private HostDao _hostDao; + @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; + @Inject private StoragePoolHostDao storagePoolHostDao; + @Inject private VMInstanceDao _vmDao; + @Inject private VolumeDao _volumeDao; + + @Override + public boolean hostAdded(long hostId) { + HostVO host = _hostDao.findById(hostId); + + SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, host.getClusterId(), true, SolidFireUtil.PROVIDER_NAME, + _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao); + + handleVMware(host, true); + + return true; + } @Override public boolean hostConnect(long hostId, long storagePoolId) { @@ -65,14 +94,174 @@ public boolean hostConnect(long hostId, long storagePoolId) { storagePoolHostDao.persist(storagePoolHost); } - // just want to send the ModifyStoragePoolCommand for KVM - if (host.getHypervisorType() != HypervisorType.KVM) { - return true; + if (host.getHypervisorType().equals(HypervisorType.XenServer)) { + handleXenServer(host.getClusterId(), host.getId(), storagePoolId); + } + else if (host.getHypervisorType().equals(HypervisorType.KVM)) { + handleKVM(hostId, storagePoolId); + } + + return true; + } + + @Override + public boolean hostDisconnected(long hostId, long storagePoolId) { + StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId); + + if (storagePoolHost != null) { + storagePoolHostDao.deleteStoragePoolHostDetails(hostId, storagePoolId); + } + + return true; + } + + @Override + public boolean hostAboutToBeRemoved(long hostId) { + HostVO host = _hostDao.findById(hostId); + + handleVMware(host, false); + + return true; + } + + @Override + public boolean hostRemoved(long hostId, long clusterId) { + SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, clusterId, false, SolidFireUtil.PROVIDER_NAME, + _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao); + + return true; + } + + private void handleXenServer(long clusterId, long hostId, long storagePoolId) { + List storagePaths = getStoragePaths(clusterId, storagePoolId); + + StoragePool storagePool = (StoragePool)_dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + + for (String storagePath : storagePaths) { + ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool); + + cmd.setStoragePath(storagePath); + + sendModifyStoragePoolCommand(cmd, storagePool, hostId); + } + } + + private void handleVMware(HostVO host, boolean add) { + if (HypervisorType.VMware.equals(host.getHypervisorType())) { + List storagePools = _storagePoolDao.findPoolsByProvider(SolidFireUtil.PROVIDER_NAME); + + if (storagePools != null && storagePools.size() > 0) { + List> targets = new ArrayList<>(); + + for (StoragePoolVO storagePool : storagePools) { + List> targetsForClusterAndStoragePool = getTargets(host.getClusterId(), storagePool.getId()); + + targets.addAll(targetsForClusterAndStoragePool); + } + + ModifyTargetsCommand cmd = new ModifyTargetsCommand(); + + cmd.setAdd(add); + cmd.setTargets(targets); + + sendModifyTargetsCommand(cmd, host.getId()); + } } + } + private void handleKVM(long hostId, long storagePoolId) { StoragePool storagePool = (StoragePool)_dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool); + sendModifyStoragePoolCommand(cmd, storagePool, hostId); + } + + private List getStoragePaths(long clusterId, long storagePoolId) { + List storagePaths = new ArrayList<>(); + + // If you do not pass in null for the second parameter, you only get back applicable ROOT disks. + List volumes = _volumeDao.findByPoolId(storagePoolId, null); + + if (volumes != null) { + for (VolumeVO volume : volumes) { + Long instanceId = volume.getInstanceId(); + + if (instanceId != null) { + VMInstanceVO vmInstance = _vmDao.findById(instanceId); + + Long hostIdForVm = vmInstance.getHostId() != null ? vmInstance.getHostId() : vmInstance.getLastHostId(); + + if (hostIdForVm != null) { + HostVO hostForVm = _hostDao.findById(hostIdForVm); + + if (hostForVm.getClusterId().equals(clusterId)) { + storagePaths.add(volume.get_iScsiName()); + } + } + } + } + } + + return storagePaths; + } + + private List> getTargets(long clusterId, long storagePoolId) { + List> targets = new ArrayList<>(); + + StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); + + // If you do not pass in null for the second parameter, you only get back applicable ROOT disks. + List volumes = _volumeDao.findByPoolId(storagePoolId, null); + + if (volumes != null) { + for (VolumeVO volume : volumes) { + Long instanceId = volume.getInstanceId(); + + if (instanceId != null) { + VMInstanceVO vmInstance = _vmDao.findById(instanceId); + + Long hostIdForVm = vmInstance.getHostId() != null ? vmInstance.getHostId() : vmInstance.getLastHostId(); + + if (hostIdForVm != null) { + HostVO hostForVm = _hostDao.findById(hostIdForVm); + + if (hostForVm.getClusterId().equals(clusterId)) { + Map details = new HashMap<>(); + + details.put(ModifyTargetsCommand.IQN, volume.get_iScsiName()); + details.put(ModifyTargetsCommand.STORAGE_HOST, storagePool.getHostAddress()); + details.put(ModifyTargetsCommand.STORAGE_PORT, String.valueOf(storagePool.getPort())); + + targets.add(details); + } + } + } + } + } + + return targets; + } + + private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { + Answer answer = _agentMgr.easySend(hostId, cmd); + + if (answer == null) { + throw new CloudRuntimeException("Unable to get an answer to the modify targets command"); + } + + if (!answer.getResult()) { + String msg = "Unable to modify targets on the following host: " + hostId; + + HostVO host = _hostDao.findById(hostId); + + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), msg, msg); + + throw new CloudRuntimeException(msg); + } + } + + private void sendModifyStoragePoolCommand(ModifyStoragePoolCommand cmd, StoragePool storagePool, long hostId) { Answer answer = _agentMgr.easySend(hostId, cmd); if (answer == null) { @@ -80,7 +269,7 @@ public boolean hostConnect(long hostId, long storagePoolId) { } if (!answer.getResult()) { - String msg = "Unable to attach storage pool " + storagePoolId + " to host " + hostId; + String msg = "Unable to attach storage pool " + storagePool.getId() + " to host " + hostId; _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg); @@ -91,18 +280,5 @@ public boolean hostConnect(long hostId, long storagePoolId) { assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer expected ; Pool = " + storagePool.getId() + " Host = " + hostId; s_logger.info("Connection established between storage pool " + storagePool + " and host + " + hostId); - - return true; - } - - @Override - public boolean hostDisconnected(long hostId, long storagePoolId) { - StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId); - - if (storagePoolHost != null) { - storagePoolHostDao.deleteStoragePoolHostDetails(hostId, storagePoolId); - } - - return true; } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java index 9881d1d179..e505cd07ba 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java @@ -18,18 +18,33 @@ */ package org.apache.cloudstack.storage.datastore.provider; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.ModifyStoragePoolAnswer; import com.cloud.agent.api.ModifyStoragePoolCommand; +import com.cloud.agent.api.ModifyTargetsCommand; import com.cloud.alert.AlertManager; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.DataStoreRole; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; @@ -37,56 +52,168 @@ import com.cloud.utils.exception.CloudRuntimeException; public class SolidFireSharedHostListener implements HypervisorHostListener { - private static final Logger s_logger = Logger.getLogger(DefaultHostListener.class); - - @Inject private AgentManager agentMgr; - @Inject private DataStoreManager dataStoreMgr; - @Inject private AlertManager alertMgr; - @Inject private StoragePoolHostDao storagePoolHostDao; - @Inject private PrimaryDataStoreDao primaryStoreDao; + private static final Logger s_logger = Logger.getLogger(SolidFireSharedHostListener.class); + + @Inject private AgentManager _agentMgr; + @Inject private AlertManager _alertMgr; + @Inject private ClusterDao _clusterDao; + @Inject private ClusterDetailsDao _clusterDetailsDao; + @Inject private DataStoreManager _dataStoreMgr; + @Inject private HostDao _hostDao; + @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private StoragePoolHostDao _storagePoolHostDao; + @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; @Override - public boolean hostConnect(long hostId, long storagePoolId) { - StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId); + public boolean hostAdded(long hostId) { + HostVO host = _hostDao.findById(hostId); - if (storagePoolHost == null) { - storagePoolHost = new StoragePoolHostVO(storagePoolId, hostId, ""); + SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, host.getClusterId(), true, SolidFireUtil.SHARED_PROVIDER_NAME, + _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao); - storagePoolHostDao.persist(storagePoolHost); - } + handleVMware(hostId, true); + + return true; + } - StoragePool storagePool = (StoragePool)dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + @Override + public boolean hostConnect(long hostId, long storagePoolId) { + StoragePool storagePool = (StoragePool)_dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool); - Answer answer = agentMgr.easySend(hostId, cmd); - if (answer == null) { - throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command for storage pool: " + storagePool.getId()); - } + ModifyStoragePoolAnswer answer = sendModifyStoragePoolCommand(cmd, storagePool, hostId); - if (!answer.getResult()) { - String msg = "Unable to attach storage pool " + storagePoolId + " to the host " + hostId; + StoragePoolHostVO storagePoolHost = _storagePoolHostDao.findByPoolHost(storagePoolId, hostId); - alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg); + if (storagePoolHost != null) { + storagePoolHost.setLocalPath(answer.getPoolInfo().getLocalPath().replaceAll("//", "/")); + } else { + storagePoolHost = new StoragePoolHostVO(storagePoolId, hostId, answer.getPoolInfo().getLocalPath().replaceAll("//", "/")); - throw new CloudRuntimeException(msg); + _storagePoolHostDao.persist(storagePoolHost); } - assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer not returned from ModifyStoragePoolCommand; Storage pool = " + - storagePool.getId() + "; Host=" + hostId; + StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); + + storagePoolVO.setCapacityBytes(answer.getPoolInfo().getCapacityBytes()); + storagePoolVO.setUsedBytes(answer.getPoolInfo().getCapacityBytes() - answer.getPoolInfo().getAvailableBytes()); - s_logger.info("Connection established between storage pool " + storagePool + " and host + " + hostId); + _storagePoolDao.update(storagePoolId, storagePoolVO); return true; } @Override public boolean hostDisconnected(long hostId, long storagePoolId) { - StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId); + StoragePoolHostVO storagePoolHost = _storagePoolHostDao.findByPoolHost(storagePoolId, hostId); if (storagePoolHost != null) { - storagePoolHostDao.deleteStoragePoolHostDetails(hostId, storagePoolId); + _storagePoolHostDao.deleteStoragePoolHostDetails(hostId, storagePoolId); } return true; } + + @Override + public boolean hostAboutToBeRemoved(long hostId) { + handleVMware(hostId, false); + + return true; + } + + @Override + public boolean hostRemoved(long hostId, long clusterId) { + SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, clusterId, false, SolidFireUtil.SHARED_PROVIDER_NAME, + _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao); + + return true; + } + + private void handleVMware(long hostId, boolean add) { + HostVO host = _hostDao.findById(hostId); + + if (HypervisorType.VMware.equals(host.getHypervisorType())) { + List storagePools = _storagePoolDao.findPoolsByProvider(SolidFireUtil.SHARED_PROVIDER_NAME); + + if (storagePools != null && storagePools.size() > 0) { + List> targets = new ArrayList<>(); + + for (StoragePoolVO storagePool : storagePools) { + if (storagePool.getClusterId().equals(host.getClusterId())) { + long storagePoolId = storagePool.getId(); + + StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.IQN); + + String iqn = storagePoolDetail.getValue(); + + storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_VIP); + + String sVip = storagePoolDetail.getValue(); + + storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_PORT); + + String sPort = storagePoolDetail.getValue(); + + Map details = new HashMap<>(); + + details.put(ModifyTargetsCommand.IQN, iqn); + details.put(ModifyTargetsCommand.STORAGE_HOST, sVip); + details.put(ModifyTargetsCommand.STORAGE_PORT, sPort); + + targets.add(details); + } + } + + if (targets.size() > 0) { + ModifyTargetsCommand cmd = new ModifyTargetsCommand(); + + cmd.setAdd(add); + cmd.setTargets(targets); + + sendModifyTargetsCommand(cmd, hostId); + } + } + } + } + + private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { + Answer answer = _agentMgr.easySend(hostId, cmd); + + if (answer == null) { + throw new CloudRuntimeException("Unable to get an answer to the modify targets command"); + } + + if (!answer.getResult()) { + String msg = "Unable to modify targets on the following host: " + hostId; + + HostVO host = _hostDao.findById(hostId); + + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), msg, msg); + + throw new CloudRuntimeException(msg); + } + } + + private ModifyStoragePoolAnswer sendModifyStoragePoolCommand(ModifyStoragePoolCommand cmd, StoragePool storagePool, long hostId) { + Answer answer = _agentMgr.easySend(hostId, cmd); + + if (answer == null) { + throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command for storage pool: " + storagePool.getId()); + } + + if (!answer.getResult()) { + String msg = "Unable to attach storage pool " + storagePool.getId() + " to the host " + hostId; + + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg); + + throw new CloudRuntimeException(msg); + } + + assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer not returned from ModifyStoragePoolCommand; Storage pool = " + + storagePool.getId() + "; Host = " + hostId; + + s_logger.info("Connection established between storage pool " + storagePool + " and host " + hostId); + + return (ModifyStoragePoolAnswer)answer; + } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java index 9c486db429..7268e72914 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java @@ -28,6 +28,7 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -58,14 +59,19 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.utils.security.SSLUtils; import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsVO; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.dao.ClusterDao; import com.cloud.host.Host; import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; import com.cloud.user.AccountDetailVO; import com.cloud.user.AccountDetailsDao; +import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; public class SolidFireUtil { @@ -73,6 +79,8 @@ public class SolidFireUtil { public static final String PROVIDER_NAME = "SolidFire"; public static final String SHARED_PROVIDER_NAME = "SolidFireShared"; + public static final int s_lockTimeInSeconds = 300; + public static final String LOG_PREFIX = "SolidFire: "; public static final String MANAGEMENT_VIP = "mVip"; @@ -124,6 +132,22 @@ public static class SolidFireConnection { private final String _clusterAdminPassword; public SolidFireConnection(String managementVip, int managementPort, String clusterAdminUsername, String clusterAdminPassword) { + if (managementVip == null) { + throw new CloudRuntimeException("The management VIP cannot be 'null'."); + } + + if (managementPort <= 0) { + throw new CloudRuntimeException("The management port must be a positive integer."); + } + + if (clusterAdminUsername == null) { + throw new CloudRuntimeException("The cluster admin username cannot be 'null'."); + } + + if (clusterAdminPassword == null) { + throw new CloudRuntimeException("The cluster admin password cannot be 'null'."); + } + _managementVip = managementVip; _managementPort = managementPort; _clusterAdminUsername = clusterAdminUsername; @@ -145,6 +169,22 @@ public String getClusterAdminUsername() { public String getClusterAdminPassword() { return _clusterAdminPassword; } + + @Override + public int hashCode() { + return _managementVip.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof SolidFireConnection)) { + return false; + } + + SolidFireConnection sfConnection = (SolidFireConnection)obj; + + return _managementVip.equals(sfConnection.getManagementVip()); + } } public static SolidFireConnection getSolidFireConnection(long storagePoolId, StoragePoolDetailsDao storagePoolDetailsDao) { @@ -238,6 +278,58 @@ public static SolidFireAccount getSolidFireAccount(SolidFireConnection sfConnect } } + public static void hostAddedToOrRemovedFromCluster(long hostId, long clusterId, boolean added, String storageProvider, + ClusterDao clusterDao, ClusterDetailsDao clusterDetailsDao, PrimaryDataStoreDao storagePoolDao, StoragePoolDetailsDao storagePoolDetailsDao, HostDao hostDao) { + ClusterVO cluster = clusterDao.findById(clusterId); + + GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); + + if (!lock.lock(s_lockTimeInSeconds)) { + String errMsg = "Couldn't lock the DB on the following string: " + cluster.getUuid(); + + s_logger.debug(errMsg); + + throw new CloudRuntimeException(errMsg); + } + + try { + List storagePools = storagePoolDao.findPoolsByProvider(storageProvider); + + if (storagePools != null && storagePools.size() > 0) { + List sfConnections = new ArrayList(); + + for (StoragePoolVO storagePool : storagePools) { + ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePool.getId())); + + String vagId = clusterDetail != null ? clusterDetail.getValue() : null; + + if (vagId != null) { + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), storagePoolDetailsDao); + + if (!sfConnections.contains(sfConnection)) { + sfConnections.add(sfConnection); + + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); + + List hostsToAddOrRemove = new ArrayList<>(); + HostVO hostToAddOrRemove = hostDao.findByIdIncludingRemoved(hostId); + + hostsToAddOrRemove.add(hostToAddOrRemove); + + String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hostsToAddOrRemove), added); + + SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, sfVag.getVolumeIds()); + } + } + } + } + } + finally { + lock.unlock(); + lock.releaseRef(); + } + } + public static long placeVolumeInVolumeAccessGroup(SolidFireConnection sfConnection, long sfVolumeId, long storagePoolId, String vagUuid, List hosts, ClusterDetailsDao clusterDetailsDao) { if (hosts == null || hosts.isEmpty()) { @@ -264,8 +356,7 @@ public static long placeVolumeInVolumeAccessGroup(SolidFireConnection sfConnecti long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); - SolidFireUtil.modifySolidFireVag(sfConnection, lVagId, - sfVag.getInitiators(), volumeIds); + SolidFireUtil.modifySolidFireVag(sfConnection, lVagId, sfVag.getInitiators(), volumeIds); } ClusterDetailsVO clusterDetail = new ClusterDetailsVO(hosts.get(0).getClusterId(), getVagKey(storagePoolId), String.valueOf(lVagId)); @@ -289,20 +380,34 @@ public static boolean hostsSupport_iScsi(List hosts) { return true; } - public static String[] getNewHostIqns(String[] currentIqns, String[] newIqns) { - List lstIqns = new ArrayList(); + public static String[] getNewHostIqns(String[] iqns, String[] iqnsToAddOrRemove, boolean add) { + if (add) { + return getNewHostIqnsAdd(iqns, iqnsToAddOrRemove); + } + + return getNewHostIqnsRemove(iqns, iqnsToAddOrRemove); + } - if (currentIqns != null) { - for (String currentIqn : currentIqns) { - lstIqns.add(currentIqn); + private static String[] getNewHostIqnsAdd(String[] iqns, String[] iqnsToAdd) { + List lstIqns = iqns != null ? new ArrayList<>(Arrays.asList(iqns)) : new ArrayList(); + + if (iqnsToAdd != null) { + for (String iqnToAdd : iqnsToAdd) { + if (!lstIqns.contains(iqnToAdd)) { + lstIqns.add(iqnToAdd); + } } } - if (newIqns != null) { - for (String newIqn : newIqns) { - if (!lstIqns.contains(newIqn)) { - lstIqns.add(newIqn); - } + return lstIqns.toArray(new String[0]); + } + + private static String[] getNewHostIqnsRemove(String[] iqns, String[] iqnsToRemove) { + List lstIqns = iqns != null ? new ArrayList<>(Arrays.asList(iqns)) : new ArrayList(); + + if (iqnsToRemove != null) { + for (String iqnToRemove : iqnsToRemove) { + lstIqns.remove(iqnToRemove); } } diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index ac97bc96ab..13794c7636 100644 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -981,6 +981,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { // TODO Auto-generated method stub @@ -993,6 +997,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { // TODO Auto-generated method stub diff --git a/server/src/com/cloud/capacity/ComputeCapacityListener.java b/server/src/com/cloud/capacity/ComputeCapacityListener.java index d8a3e6a893..453960de5c 100644 --- a/server/src/com/cloud/capacity/ComputeCapacityListener.java +++ b/server/src/com/cloud/capacity/ComputeCapacityListener.java @@ -55,6 +55,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host server, StartupCommand startup, boolean forRebalance) throws ConnectionException { if (!(startup instanceof StartupRoutingCommand)) { @@ -68,6 +72,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { return false; diff --git a/server/src/com/cloud/capacity/StorageCapacityListener.java b/server/src/com/cloud/capacity/StorageCapacityListener.java index f83cbd3a53..e2d5a5d0aa 100644 --- a/server/src/com/cloud/capacity/StorageCapacityListener.java +++ b/server/src/com/cloud/capacity/StorageCapacityListener.java @@ -58,6 +58,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host server, StartupCommand startup, boolean forRebalance) throws ConnectionException { @@ -81,6 +85,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { return false; diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyListener.java b/server/src/com/cloud/consoleproxy/ConsoleProxyListener.java index 2c1bbd6732..77c9d5a17a 100644 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyListener.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyListener.java @@ -63,6 +63,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) { _proxyMgr.onAgentConnect(host, cmd); @@ -78,6 +82,14 @@ public boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { return true; diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index f5d2af92be..2b3358aee8 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -899,6 +899,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { if (!(cmd instanceof StartupRoutingCommand)) { @@ -920,6 +924,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { // TODO Auto-generated method stub diff --git a/server/src/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java b/server/src/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java index 48be8f2851..13a1a64cd2 100644 --- a/server/src/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java +++ b/server/src/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java @@ -85,6 +85,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) { } @@ -95,6 +99,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { // TODO Auto-generated method stub diff --git a/server/src/com/cloud/network/NetworkUsageManagerImpl.java b/server/src/com/cloud/network/NetworkUsageManagerImpl.java index a0356ca90b..b7adecda0d 100644 --- a/server/src/com/cloud/network/NetworkUsageManagerImpl.java +++ b/server/src/com/cloud/network/NetworkUsageManagerImpl.java @@ -483,6 +483,10 @@ public boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) { if (cmd instanceof StartupTrafficMonitorCommand) { @@ -498,6 +502,14 @@ public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) return; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { return true; diff --git a/server/src/com/cloud/network/SshKeysDistriMonitor.java b/server/src/com/cloud/network/SshKeysDistriMonitor.java index 1eeb3a3213..e263c548cd 100644 --- a/server/src/com/cloud/network/SshKeysDistriMonitor.java +++ b/server/src/com/cloud/network/SshKeysDistriMonitor.java @@ -40,12 +40,10 @@ public class SshKeysDistriMonitor implements Listener { private static final Logger s_logger = Logger.getLogger(SshKeysDistriMonitor.class); AgentManager _agentMgr; - private final HostDao _hostDao; private ConfigurationDao _configDao; public SshKeysDistriMonitor(AgentManager mgr, HostDao host, ConfigurationDao config) { - this._agentMgr = mgr; - _hostDao = host; + _agentMgr = mgr; _configDao = config; } @@ -67,6 +65,18 @@ public synchronized boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { if (cmd instanceof StartupRoutingCommand) { diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index ac8b86816a..fc448a347a 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -251,159 +251,98 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V Configurable, StateListener { private static final Logger s_logger = Logger.getLogger(VirtualNetworkApplianceManagerImpl.class); - @Inject - EntityManager _entityMgr; - @Inject - DataCenterDao _dcDao = null; - @Inject - VlanDao _vlanDao = null; - @Inject - FirewallRulesDao _rulesDao = null; - @Inject - LoadBalancerDao _loadBalancerDao = null; - @Inject - LoadBalancerVMMapDao _loadBalancerVMMapDao = null; - @Inject - IPAddressDao _ipAddressDao = null; - @Inject - VMTemplateDao _templateDao = null; - @Inject - DomainRouterDao _routerDao = null; - @Inject - UserDao _userDao = null; - @Inject - UserStatisticsDao _userStatsDao = null; - @Inject - HostDao _hostDao = null; - @Inject - ConfigurationDao _configDao; - @Inject - HostPodDao _podDao = null; - @Inject - UserStatsLogDao _userStatsLogDao = null; - @Inject - AgentManager _agentMgr; - @Inject - AlertManager _alertMgr; - @Inject - AccountManager _accountMgr; - @Inject - ConfigurationManager _configMgr; - @Inject - ConfigurationServer _configServer; - @Inject - ServiceOfferingDao _serviceOfferingDao = null; - @Inject - UserVmDao _userVmDao; - @Inject - VMInstanceDao _vmDao; - @Inject - NetworkOfferingDao _networkOfferingDao = null; - @Inject - GuestOSDao _guestOSDao = null; - @Inject - NetworkOrchestrationService _networkMgr; - @Inject - NetworkModel _networkModel; - @Inject - VirtualMachineManager _itMgr; - @Inject - VpnUserDao _vpnUsersDao; - @Inject - RulesManager _rulesMgr; - @Inject - NetworkDao _networkDao; - @Inject - LoadBalancingRulesManager _lbMgr; - @Inject - PortForwardingRulesDao _pfRulesDao; - @Inject - RemoteAccessVpnDao _vpnDao; - @Inject - NicDao _nicDao; - @Inject - NicIpAliasDao _nicIpAliasDao; - @Inject - VolumeDao _volumeDao = null; - @Inject - UserVmDetailsDao _vmDetailsDao; - @Inject - ClusterDao _clusterDao; - @Inject - ResourceManager _resourceMgr; - @Inject - PhysicalNetworkServiceProviderDao _physicalProviderDao; - @Inject - VirtualRouterProviderDao _vrProviderDao; - @Inject - ManagementServerHostDao _msHostDao; - @Inject - Site2SiteCustomerGatewayDao _s2sCustomerGatewayDao; - @Inject - Site2SiteVpnGatewayDao _s2sVpnGatewayDao; - @Inject - Site2SiteVpnConnectionDao _s2sVpnConnectionDao; - @Inject - Site2SiteVpnManager _s2sVpnMgr; - @Inject - UserIpv6AddressDao _ipv6Dao; - @Inject - NetworkService _networkSvc; - @Inject - IpAddressManager _ipAddrMgr; - @Inject - ConfigDepot _configDepot; - @Inject - MonitoringServiceDao _monitorServiceDao; - @Inject - AsyncJobManager _asyncMgr; - @Inject - protected VpcDao _vpcDao; - @Inject - protected ApiAsyncJobDispatcher _asyncDispatcher; - @Inject - OpRouterMonitorServiceDao _opRouterMonitorServiceDao; - - @Inject - protected NetworkTopologyContext _networkTopologyContext; + @Inject private EntityManager _entityMgr; + @Inject private DataCenterDao _dcDao; + @Inject protected VlanDao _vlanDao; + @Inject private FirewallRulesDao _rulesDao; + @Inject private LoadBalancerDao _loadBalancerDao; + @Inject private LoadBalancerVMMapDao _loadBalancerVMMapDao; + @Inject protected IPAddressDao _ipAddressDao; + @Inject private VMTemplateDao _templateDao; + @Inject protected DomainRouterDao _routerDao; + @Inject private UserDao _userDao; + @Inject protected UserStatisticsDao _userStatsDao; + @Inject private HostDao _hostDao; + @Inject private ConfigurationDao _configDao; + @Inject private HostPodDao _podDao; + @Inject private UserStatsLogDao _userStatsLogDao; + @Inject protected AgentManager _agentMgr; + @Inject private AlertManager _alertMgr; + @Inject private AccountManager _accountMgr; + @Inject private ConfigurationManager _configMgr; + @Inject private ConfigurationServer _configServer; + @Inject private ServiceOfferingDao _serviceOfferingDao; + @Inject private UserVmDao _userVmDao; + @Inject private VMInstanceDao _vmDao; + @Inject private NetworkOfferingDao _networkOfferingDao; + @Inject private GuestOSDao _guestOSDao; + @Inject private NetworkOrchestrationService _networkMgr; + @Inject protected NetworkModel _networkModel; + @Inject protected VirtualMachineManager _itMgr; + @Inject private VpnUserDao _vpnUsersDao; + @Inject private RulesManager _rulesMgr; + @Inject protected NetworkDao _networkDao; + @Inject private LoadBalancingRulesManager _lbMgr; + @Inject private PortForwardingRulesDao _pfRulesDao; + @Inject protected RemoteAccessVpnDao _vpnDao; + @Inject protected NicDao _nicDao; + @Inject private NicIpAliasDao _nicIpAliasDao; + @Inject private VolumeDao _volumeDao; + @Inject private UserVmDetailsDao _vmDetailsDao; + @Inject private ClusterDao _clusterDao; + @Inject private ResourceManager _resourceMgr; + @Inject private PhysicalNetworkServiceProviderDao _physicalProviderDao; + @Inject protected VirtualRouterProviderDao _vrProviderDao; + @Inject private ManagementServerHostDao _msHostDao; + @Inject private Site2SiteCustomerGatewayDao _s2sCustomerGatewayDao; + @Inject private Site2SiteVpnGatewayDao _s2sVpnGatewayDao; + @Inject private Site2SiteVpnConnectionDao _s2sVpnConnectionDao; + @Inject private Site2SiteVpnManager _s2sVpnMgr; + @Inject private UserIpv6AddressDao _ipv6Dao; + @Inject private NetworkService _networkSvc; + @Inject private IpAddressManager _ipAddrMgr; + @Inject private ConfigDepot _configDepot; + @Inject private MonitoringServiceDao _monitorServiceDao; + @Inject private AsyncJobManager _asyncMgr; + @Inject protected VpcDao _vpcDao; + @Inject protected ApiAsyncJobDispatcher _asyncDispatcher; + @Inject private OpRouterMonitorServiceDao _opRouterMonitorServiceDao; + + @Inject protected NetworkTopologyContext _networkTopologyContext; @Autowired @Qualifier("networkHelper") protected NetworkHelper _nwHelper; - @Inject - protected RouterControlHelper _routerControlHelper; + @Inject protected RouterControlHelper _routerControlHelper; - @Inject - protected CommandSetupHelper _commandSetupHelper; - @Inject - protected RouterDeploymentDefinitionBuilder _routerDeploymentManagerBuilder; + @Inject protected CommandSetupHelper _commandSetupHelper; + @Inject protected RouterDeploymentDefinitionBuilder _routerDeploymentManagerBuilder; - int _routerRamSize; - int _routerCpuMHz; - int _retry = 2; - String _mgmtCidr; + private int _routerRamSize; + private int _routerCpuMHz; + private String _mgmtCidr; - int _routerStatsInterval = 300; - int _routerCheckInterval = 30; - int _rvrStatusUpdatePoolSize = 10; + private int _routerStatsInterval = 300; + private int _routerCheckInterval = 30; + private int _rvrStatusUpdatePoolSize = 10; private String _dnsBasicZoneUpdates = "all"; - private final Set _guestOSNeedGatewayOnNonDefaultNetwork = new HashSet(); + private final Set _guestOSNeedGatewayOnNonDefaultNetwork = new HashSet<>(); private boolean _disableRpFilter = false; - int _routerExtraPublicNics = 2; + private int _routerExtraPublicNics = 2; private int _usageAggregationRange = 1440; private String _usageTimeZone = "GMT"; private final long mgmtSrvrId = MacAddress.getMacAddress().toLong(); private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 5; // 5 seconds private boolean _dailyOrHourly = false; - ScheduledExecutorService _executor; - ScheduledExecutorService _checkExecutor; - ScheduledExecutorService _networkStatsUpdateExecutor; - ExecutorService _rvrStatusUpdateExecutor; + private ScheduledExecutorService _executor; + private ScheduledExecutorService _checkExecutor; + private ScheduledExecutorService _networkStatsUpdateExecutor; + private ExecutorService _rvrStatusUpdateExecutor; - BlockingQueue _vrUpdateQueue = null; + private BlockingQueue _vrUpdateQueue; @Override public VirtualRouter destroyRouter(final long routerId, final Account caller, final Long callerUserId) throws ResourceUnavailableException, ConcurrentOperationException { @@ -586,10 +525,7 @@ public boolean configure(final String name, final Map params) th } } - String value = configs.get("start.retry"); - _retry = NumbersUtil.parseInt(value, 2); - - value = configs.get("router.stats.interval"); + String value = configs.get("router.stats.interval"); _routerStatsInterval = NumbersUtil.parseInt(value, 300); value = configs.get("router.check.interval"); @@ -1591,9 +1527,6 @@ protected StringBuilder createGuestBootLoadArgs(final NicProfile guestNic, final protected StringBuilder createRedundantRouterArgs(final NicProfile nic, final DomainRouterVO router) { final StringBuilder buf = new StringBuilder(); - final long networkId = nic.getNetworkId(); - final NetworkVO network = _networkDao.findById(networkId); - final boolean isRedundant = router.getIsRedundantRouter(); if (isRedundant) { buf.append(" redundant_router=1"); @@ -2361,6 +2294,10 @@ public boolean processCommands(final long agentId, final long seq, final Command return false; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(final Host host, final StartupCommand cmd, final boolean forRebalance) throws ConnectionException { final List routers = _routerDao.listIsolatedByHostId(host.getId()); @@ -2395,6 +2332,14 @@ public boolean processDisconnect(final long agentId, final Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(final long agentId, final long seq) { return false; diff --git a/server/src/com/cloud/network/security/SecurityGroupListener.java b/server/src/com/cloud/network/security/SecurityGroupListener.java index af963b1ad4..32186cc046 100644 --- a/server/src/com/cloud/network/security/SecurityGroupListener.java +++ b/server/src/com/cloud/network/security/SecurityGroupListener.java @@ -81,7 +81,7 @@ public boolean isRecurring() { @Override public boolean processAnswers(long agentId, long seq, Answer[] answers) { List affectedVms = new ArrayList(); - int commandNum = 0; + for (Answer ans : answers) { if (ans instanceof SecurityGroupRuleAnswer) { SecurityGroupRuleAnswer ruleAnswer = (SecurityGroupRuleAnswer)ans; @@ -106,7 +106,7 @@ public boolean processAnswers(long agentId, long seq, Answer[] answers) { } } } - commandNum++; + if (_workTracker != null) _workTracker.processAnswers(agentId, seq, answers); } @@ -151,6 +151,10 @@ public boolean processCommands(long agentId, long seq, Command[] commands) { return processed; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) { if (s_logger.isInfoEnabled()) @@ -188,6 +192,14 @@ public boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { if (_workTracker != null) { diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 8341075b72..fb34901d81 100644 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -771,6 +771,9 @@ private List discoverHostsFull(final Long dcId, final Long podId, Long c _hostTagsDao.persist(host.getId(), hostTags); } hosts.add(host); + + _agentMgr.notifyMonitorsOfNewlyAddedHost(host.getId()); + return hosts; } } @@ -843,10 +846,13 @@ protected boolean doDeleteHost(final long hostId, final boolean isForced, final return true; } + long clusterId = host.getClusterId(); + + _agentMgr.notifyMonitorsOfHostAboutToBeRemoved(host.getId()); + Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(final TransactionStatus status) { - _dcDao.releasePrivateIpAddress(host.getPrivateIpAddress(), host.getDataCenterId(), null); _agentMgr.disconnectWithoutInvestigation(hostId, Status.Event.Remove); @@ -920,6 +926,8 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } }); + _agentMgr.notifyMonitorsOfRemovedHost(host.getId(), clusterId); + return true; } @@ -1570,17 +1578,35 @@ private boolean checkCIDR(final HostPodVO pod, final String serverPrivateIP, fin return true; } + private HostVO getNewHost(StartupCommand[] startupCommands) { + StartupCommand startupCommand = startupCommands[0]; + + HostVO host = findHostByGuid(startupCommand.getGuid()); + + if (host != null) { + return host; + } + + host = findHostByGuid(startupCommand.getGuidWithoutResource()); + + if (host != null) { + return host; + } + + return null; + } + protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource resource, final Map details, List hostTags, final ResourceStateAdapter.Event stateEvent) { - final StartupCommand startup = cmds[0]; - HostVO host = findHostByGuid(startup.getGuid()); - boolean isNew = false; - if (host == null) { - host = findHostByGuid(startup.getGuidWithoutResource()); - } + boolean newHost = false; + StartupCommand startup = cmds[0]; + + HostVO host = getNewHost(cmds); + if (host == null) { host = new HostVO(startup.getGuid()); - isNew = true; + + newHost = true; } String dataCenter = startup.getDataCenter(); @@ -1695,7 +1721,7 @@ protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource throw new CloudRuntimeException("No resource state adapter response"); } - if (isNew) { + if (newHost) { host = _hostDao.persist(host); } else { _hostDao.update(host.getId(), host); @@ -1794,9 +1820,13 @@ private Host createHostAndAgent(final ServerResource resource, final Map params) throws Configu _storagePoolAcquisitionWaitSeconds = NumbersUtil.parseInt(configs.get("pool.acquisition.wait.seconds"), 1800); s_logger.info("pool.acquisition.wait.seconds is configured as " + _storagePoolAcquisitionWaitSeconds + " seconds"); - _agentMgr.registerForHostEvents(new StoragePoolMonitor(this, _storagePoolDao), true, false, true); + _agentMgr.registerForHostEvents(new StoragePoolMonitor(this, _storagePoolDao, _dataStoreProviderMgr), true, false, true); String value = _configDao.getValue(Config.StorageTemplateCleanupEnabled.key()); _templateCleanupEnabled = (value == null ? true : Boolean.parseBoolean(value)); diff --git a/server/src/com/cloud/storage/download/DownloadListener.java b/server/src/com/cloud/storage/download/DownloadListener.java index 814ce3c44b..51f9d42980 100644 --- a/server/src/com/cloud/storage/download/DownloadListener.java +++ b/server/src/com/cloud/storage/download/DownloadListener.java @@ -270,9 +270,7 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman } @Override - public boolean processDisconnect(long agentId, com.cloud.host.Status state) { - setDisconnected(); - return true; + public void processHostAdded(long hostId) { } @Override @@ -310,6 +308,20 @@ else if (cmd instanceof StartupSecondaryStorageCommand) { } } + @Override + public boolean processDisconnect(long agentId, com.cloud.host.Status state) { + setDisconnected(); + return true; + } + + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + public void setCommand(DownloadCommand cmd) { this._cmd = cmd; } diff --git a/server/src/com/cloud/storage/listener/StoragePoolMonitor.java b/server/src/com/cloud/storage/listener/StoragePoolMonitor.java index ad65bd63b6..dcbe4744ad 100644 --- a/server/src/com/cloud/storage/listener/StoragePoolMonitor.java +++ b/server/src/com/cloud/storage/listener/StoragePoolMonitor.java @@ -22,6 +22,10 @@ import org.apache.log4j.Logger; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreProvider; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; @@ -46,13 +50,14 @@ public class StoragePoolMonitor implements Listener { private static final Logger s_logger = Logger.getLogger(StoragePoolMonitor.class); private final StorageManagerImpl _storageManager; private final PrimaryDataStoreDao _poolDao; + private DataStoreProviderManager _dataStoreProviderMgr; @Inject OCFS2Manager _ocfs2Mgr; - public StoragePoolMonitor(StorageManagerImpl mgr, PrimaryDataStoreDao poolDao) { - this._storageManager = mgr; - this._poolDao = poolDao; - + public StoragePoolMonitor(StorageManagerImpl mgr, PrimaryDataStoreDao poolDao, DataStoreProviderManager dataStoreProviderMgr) { + _storageManager = mgr; + _poolDao = poolDao; + _dataStoreProviderMgr = dataStoreProviderMgr; } @Override @@ -66,8 +71,25 @@ public synchronized boolean processAnswers(long agentId, long seq, Answer[] resp } @Override - public synchronized boolean processDisconnect(long agentId, Status state) { - return true; + public void processHostAdded(long hostId) { + List providers = _dataStoreProviderMgr.getProviders(); + + if (providers != null) { + for (DataStoreProvider provider : providers) { + if (provider instanceof PrimaryDataStoreProvider) { + try { + HypervisorHostListener hypervisorHostListener = provider.getHostListener(); + + if (hypervisorHostListener != null) { + hypervisorHostListener.hostAdded(hostId); + } + } + catch (Exception ex) { + s_logger.error("hostAdded(long) failed for storage provider " + provider.getName(), ex); + } + } + } + } } @Override @@ -111,6 +133,55 @@ public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) } } + @Override + public synchronized boolean processDisconnect(long agentId, Status state) { + return true; + } + + @Override + public void processHostAboutToBeRemoved(long hostId) { + List providers = _dataStoreProviderMgr.getProviders(); + + if (providers != null) { + for (DataStoreProvider provider : providers) { + if (provider instanceof PrimaryDataStoreProvider) { + try { + HypervisorHostListener hypervisorHostListener = provider.getHostListener(); + + if (hypervisorHostListener != null) { + hypervisorHostListener.hostAboutToBeRemoved(hostId); + } + } + catch (Exception ex) { + s_logger.error("hostAboutToBeRemoved(long) failed for storage provider " + provider.getName(), ex); + } + } + } + } + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + List providers = _dataStoreProviderMgr.getProviders(); + + if (providers != null) { + for (DataStoreProvider provider : providers) { + if (provider instanceof PrimaryDataStoreProvider) { + try { + HypervisorHostListener hypervisorHostListener = provider.getHostListener(); + + if (hypervisorHostListener != null) { + hypervisorHostListener.hostRemoved(hostId, clusterId); + } + } + catch (Exception ex) { + s_logger.error("hostRemoved(long, long) failed for storage provider " + provider.getName(), ex); + } + } + } + } + } + @Override public boolean processCommands(long agentId, long seq, Command[] req) { return false; diff --git a/server/src/com/cloud/storage/listener/StorageSyncListener.java b/server/src/com/cloud/storage/listener/StorageSyncListener.java index fe15d30b95..eeef434367 100644 --- a/server/src/com/cloud/storage/listener/StorageSyncListener.java +++ b/server/src/com/cloud/storage/listener/StorageSyncListener.java @@ -50,6 +50,10 @@ public boolean processAnswers(long agentId, long seq, Answer[] answers) { return true; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) { } @@ -60,6 +64,14 @@ public boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processCommands(long agentId, long seq, Command[] request) { return false; diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java b/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java index 43613e7f9c..b78a548729 100644 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java @@ -65,6 +65,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) { if ((cmd instanceof StartupStorageCommand)) { @@ -91,6 +95,14 @@ public boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { return true; diff --git a/server/src/com/cloud/storage/upload/UploadListener.java b/server/src/com/cloud/storage/upload/UploadListener.java index f6ad815d00..838676ef0f 100644 --- a/server/src/com/cloud/storage/upload/UploadListener.java +++ b/server/src/com/cloud/storage/upload/UploadListener.java @@ -113,8 +113,6 @@ protected void runInContext() { private DataStore sserver; - private boolean uploadActive = true; - private UploadDao uploadDao; private final UploadMonitorImpl uploadMonitor; @@ -250,6 +248,10 @@ public boolean processCommands(long agentId, long seq, Command[] commands) { return false; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) { if (!(cmd instanceof StartupStorageCommand)) { @@ -270,7 +272,6 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman } public void setUploadInactive(Status reason) { - uploadActive = false; uploadMonitor.handleUploadEvent(accountId, typeName, type, uploadId, reason, eventId); } @@ -294,6 +295,14 @@ public boolean processDisconnect(long agentId, com.cloud.host.Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { return true; diff --git a/test/integration/plugins/solidfire/TestAddRemoveHosts.py b/test/integration/plugins/solidfire/TestAddRemoveHosts.py new file mode 100644 index 0000000000..518d022cae --- /dev/null +++ b/test/integration/plugins/solidfire/TestAddRemoveHosts.py @@ -0,0 +1,710 @@ +# 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. + +import logging +import random +import SignedAPICall +import time +import XenAPI + +# All tests inherit from cloudstackTestCase +from marvin.cloudstackTestCase import cloudstackTestCase + +# Import Integration Libraries + +# base - contains all resources as entities and defines create, delete, list operations on them +from marvin.lib.base import Account, ServiceOffering, User, Host, StoragePool, VirtualMachine + +# common - commonly used methods for all tests are listed here +from marvin.lib.common import get_domain, get_template, get_zone, list_hosts, list_clusters, list_volumes + +# utils - utility classes for common cleanup, external library wrappers, etc. +from marvin.lib.utils import cleanup_resources + +from solidfire import solidfire_element_api as sf_api + + +class TestData: + account = "account" + capacityBytes = "capacitybytes" + capacityIops = "capacityiops" + clusterId = "clusterId" + computeOffering = "computeoffering" + displayText = "displaytext" + diskSize = "disksize" + domainId = "domainId" + hypervisor = "hypervisor" + login = "login" + mvip = "mvip" + name = "name" + newHost = "newHost" + newHostDisplayName = "newHostDisplayName" + osType = "ostype" + password = "password" + podId = "podid" + port = "port" + primaryStorage = "primarystorage" + primaryStorage2 = "primarystorage2" + provider = "provider" + scope = "scope" + solidFire = "solidfire" + storageTag = "SolidFire_SAN_1" + storageTag2 = "SolidFire_Volume_1" + tags = "tags" + url = "url" + urlOfNewHost = "urlOfNewHost" + user = "user" + username = "username" + virtualMachine = "virtualmachine" + volume_1 = "volume_1" + xenServer = "xenserver" + zoneId = "zoneid" + + def __init__(self): + self.testdata = { + TestData.solidFire: { + TestData.mvip: "192.168.139.112", + TestData.login: "admin", + TestData.password: "admin", + TestData.port: 443, + TestData.url: "https://192.168.139.112:443" + }, + TestData.xenServer: { + TestData.username: "root", + TestData.password: "solidfire" + }, + TestData.urlOfNewHost: "https://192.168.129.243", + TestData.account: { + "email": "test@test.com", + "firstname": "John", + "lastname": "Doe", + TestData.username: "test", + TestData.password: "test" + }, + TestData.user: { + "email": "user@test.com", + "firstname": "Jane", + "lastname": "Doe", + TestData.username: "testuser", + TestData.password: "password" + }, + TestData.newHost: { + TestData.username: "root", + TestData.password: "solidfire", + TestData.url: "http://192.168.129.243", + TestData.podId : "1", + TestData.zoneId: "1" + }, + TestData.primaryStorage: { + TestData.name: "SolidFire-%d" % random.randint(0, 100), + TestData.scope: "ZONE", + TestData.url: "MVIP=192.168.139.112;SVIP=10.10.8.112;" + + "clusterAdminUsername=admin;clusterAdminPassword=admin;" + + "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" + + "clusterDefaultBurstIopsPercentOfMaxIops=1.5;", + TestData.provider: "SolidFire", + TestData.tags: TestData.storageTag, + TestData.capacityIops: 4500000, + TestData.capacityBytes: 2251799813685248, + TestData.hypervisor: "Any" + }, + TestData.primaryStorage2: { + TestData.name: "SolidFireShared-%d" % random.randint(0, 100), + TestData.scope: "CLUSTER", + TestData.url: "MVIP=192.168.139.112;SVIP=10.10.8.112;" + + "clusterAdminUsername=admin;clusterAdminPassword=admin;" + + "minIops=5000;maxIops=50000;burstIops=75000", + TestData.provider: "SolidFireShared", + TestData.tags: TestData.storageTag2, + TestData.capacityIops: 5000, + TestData.capacityBytes: 1099511627776, + TestData.hypervisor: "XenServer", + TestData.podId: 1 + }, + TestData.virtualMachine: { + TestData.name: "TestVM", + "displayname": "Test VM" + }, + TestData.computeOffering: { + TestData.name: "SF_CO_1", + TestData.displayText: "SF_CO_1 (Min IOPS = 10,000; Max IOPS = 15,000)", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 128, + "storagetype": "shared", + "customizediops": False, + "miniops": "10000", + "maxiops": "15000", + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag + }, + TestData.volume_1: { + "diskname": "testvolume", + }, + "volume2": { + "diskname": "testvolume2", + }, + TestData.newHostDisplayName: "XenServer-6.5-3", + TestData.osType: "CentOS 5.6(64-bit) no GUI (XenServer)", + TestData.zoneId: 1, + TestData.clusterId: 1, + TestData.domainId: 1, + TestData.url: "192.168.129.50" + } + + +class TestAddRemoveHosts(cloudstackTestCase): + _vag_id_should_be_non_zero_int_err_msg = "The SolidFire VAG ID should be a non-zero integer." + _sf_account_id_should_be_non_zero_int_err_msg = "The SolidFire account ID should be a non-zero integer." + + @classmethod + def setUpClass(cls): + # Set up API client + testclient = super(TestAddRemoveHosts, cls).getClsTestClient() + cls.apiClient = testclient.getApiClient() + cls.dbConnection = testclient.getDbConnection() + + cls.testdata = TestData().testdata + + cls.xs_pool_master_ip = list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name="XenServer-6.5-1")[0].ipaddress + + # Set up XenAPI connection + host_ip = "https://" + cls.xs_pool_master_ip + + cls.xen_session = XenAPI.Session(host_ip) + + xenserver = cls.testdata[TestData.xenServer] + + cls.xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password]) + + # Set up SolidFire connection + cls.sf_client = sf_api.SolidFireAPI(endpoint_dict=cls.testdata[TestData.solidFire]) + + # Get Resources from Cloud Infrastructure + cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId]) + cls.cluster = list_clusters(cls.apiClient)[0] + cls.template = get_template(cls.apiClient, cls.zone.id, cls.testdata[TestData.osType]) + cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId]) + + # Create test account + cls.account = Account.create( + cls.apiClient, + cls.testdata[TestData.account], + admin=1 + ) + + # Set up connection to make customized API calls + user = User.create( + cls.apiClient, + cls.testdata[TestData.user], + account=cls.account.name, + domainid=cls.domain.id + ) + + url = cls.testdata[TestData.url] + + api_url = "http://" + url + ":8080/client/api" + userkeys = User.registerUserKeys(cls.apiClient, user.id) + + cls.cs_api = SignedAPICall.CloudStack(api_url, userkeys.apikey, userkeys.secretkey) + + cls.compute_offering = ServiceOffering.create( + cls.apiClient, + cls.testdata[TestData.computeOffering] + ) + + cls._cleanup = [ + cls.compute_offering, + user, + cls.account + ] + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.apiClient, cls._cleanup) + + cls._purge_solidfire_volumes() + except Exception as e: + logging.debug("Exception in tearDownClass(cls): %s" % e) + + def setUp(self): + self.virtual_machine = None + + self.cleanup = [] + + def tearDown(self): + try: + if self.virtual_machine is not None: + self.virtual_machine.delete(self.apiClient, True) + + cleanup_resources(self.apiClient, self.cleanup) + except Exception as e: + logging.debug("Exception in tearDown(self): %s" % e) + + def test_add_remove_host_with_solidfire_plugin_1(self): + primarystorage = self.testdata[TestData.primaryStorage] + + primary_storage = StoragePool.create( + self.apiClient, + primarystorage, + scope=primarystorage[TestData.scope], + zoneid=self.zone.id, + provider=primarystorage[TestData.provider], + tags=primarystorage[TestData.tags], + capacityiops=primarystorage[TestData.capacityIops], + capacitybytes=primarystorage[TestData.capacityBytes], + hypervisor=primarystorage[TestData.hypervisor] + ) + + self.cleanup.append(primary_storage) + + self.virtual_machine = VirtualMachine.create( + self.apiClient, + self.testdata[TestData.virtualMachine], + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=self.template.id, + domainid=self.domain.id, + startvm=True + ) + + root_volume = self._get_root_volume(self.virtual_machine) + + sf_iscsi_name = self._get_iqn(root_volume) + + self._perform_add_remove_host(primary_storage.id, sf_iscsi_name) + + def test_add_remove_host_with_solidfire_plugin_2(self): + primarystorage2 = self.testdata[TestData.primaryStorage2] + + primary_storage_2 = StoragePool.create( + self.apiClient, + primarystorage2, + scope=primarystorage2[TestData.scope], + zoneid=self.zone.id, + clusterid=self.cluster.id, + provider=primarystorage2[TestData.provider], + tags=primarystorage2[TestData.tags], + capacityiops=primarystorage2[TestData.capacityIops], + capacitybytes=primarystorage2[TestData.capacityBytes], + hypervisor=primarystorage2[TestData.hypervisor] + ) + + self.cleanup.append(primary_storage_2) + + sf_iscsi_name = self._get_iqn_2(primary_storage_2) + + self._perform_add_remove_host(primary_storage_2.id, sf_iscsi_name) + + def test_add_remove_host_with_solidfire_plugin_3(self): + primarystorage = self.testdata[TestData.primaryStorage] + + primary_storage = StoragePool.create( + self.apiClient, + primarystorage, + scope=primarystorage[TestData.scope], + zoneid=self.zone.id, + provider=primarystorage[TestData.provider], + tags=primarystorage[TestData.tags], + capacityiops=primarystorage[TestData.capacityIops], + capacitybytes=primarystorage[TestData.capacityBytes], + hypervisor=primarystorage[TestData.hypervisor] + ) + + self.cleanup.append(primary_storage) + + self.virtual_machine = VirtualMachine.create( + self.apiClient, + self.testdata[TestData.virtualMachine], + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=self.template.id, + domainid=self.domain.id, + startvm=True + ) + + root_volume = self._get_root_volume(self.virtual_machine) + + sf_iscsi_name = self._get_iqn(root_volume) + + primarystorage2 = self.testdata[TestData.primaryStorage2] + + primary_storage_2 = StoragePool.create( + self.apiClient, + primarystorage2, + scope=primarystorage2[TestData.scope], + zoneid=self.zone.id, + clusterid=self.cluster.id, + provider=primarystorage2[TestData.provider], + tags=primarystorage2[TestData.tags], + capacityiops=primarystorage2[TestData.capacityIops], + capacitybytes=primarystorage2[TestData.capacityBytes], + hypervisor=primarystorage2[TestData.hypervisor] + ) + + self.cleanup.append(primary_storage_2) + + self._perform_add_remove_host(primary_storage.id, sf_iscsi_name) + + def test_add_remove_host_with_solidfire_plugin_4(self): + primarystorage2 = self.testdata[TestData.primaryStorage2] + + primary_storage_2 = StoragePool.create( + self.apiClient, + primarystorage2, + scope=primarystorage2[TestData.scope], + zoneid=self.zone.id, + clusterid=self.cluster.id, + provider=primarystorage2[TestData.provider], + tags=primarystorage2[TestData.tags], + capacityiops=primarystorage2[TestData.capacityIops], + capacitybytes=primarystorage2[TestData.capacityBytes], + hypervisor=primarystorage2[TestData.hypervisor] + ) + + self.cleanup.append(primary_storage_2) + + sf_iscsi_name = self._get_iqn_2(primary_storage_2) + + primarystorage = self.testdata[TestData.primaryStorage] + + primary_storage = StoragePool.create( + self.apiClient, + primarystorage, + scope=primarystorage[TestData.scope], + zoneid=self.zone.id, + provider=primarystorage[TestData.provider], + tags=primarystorage[TestData.tags], + capacityiops=primarystorage[TestData.capacityIops], + capacitybytes=primarystorage[TestData.capacityBytes], + hypervisor=primarystorage[TestData.hypervisor] + ) + + self.cleanup.append(primary_storage) + + self.virtual_machine = VirtualMachine.create( + self.apiClient, + self.testdata[TestData.virtualMachine], + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=self.template.id, + domainid=self.domain.id, + startvm=True + ) + + self._perform_add_remove_host(primary_storage_2.id, sf_iscsi_name) + + def _perform_add_remove_host(self, primary_storage_id, sf_iscsi_name): + xen_sr = self.xen_session.xenapi.SR.get_by_name_label(sf_iscsi_name)[0] + + pbds = self.xen_session.xenapi.SR.get_PBDs(xen_sr) + + self._verify_all_pbds_attached(pbds) + + num_pbds = len(pbds) + + sf_vag_id = self._get_sf_vag_id(self.cluster.id, primary_storage_id) + + host_iscsi_iqns = self._get_host_iscsi_iqns() + + sf_vag = self._get_sf_vag(sf_vag_id) + + sf_vag_initiators = self._get_sf_vag_initiators(sf_vag) + + self._verifyVag(host_iscsi_iqns, sf_vag_initiators) + + sf_vag_initiators_len_orig = len(sf_vag_initiators) + + xen_session = XenAPI.Session(self.testdata[TestData.urlOfNewHost]) + + xenserver = self.testdata[TestData.xenServer] + + xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password]) + + xen_session.xenapi.pool.join(self.xs_pool_master_ip, xenserver[TestData.username], xenserver[TestData.password]) + + time.sleep(60) + + pbds = self.xen_session.xenapi.SR.get_PBDs(xen_sr) + + self.assertEqual( + len(pbds), + num_pbds + 1, + "'len(pbds)' is not equal to 'num_pbds + 1'." + ) + + num_pbds = num_pbds + 1 + + num_pbds_not_attached = 0 + + for pbd in pbds: + pbd_record = self.xen_session.xenapi.PBD.get_record(pbd) + + if pbd_record["currently_attached"] == False: + num_pbds_not_attached = num_pbds_not_attached + 1 + + self.assertEqual( + num_pbds_not_attached, + 1, + "'num_pbds_not_attached' is not equal to 1." + ) + + host = Host.create( + self.apiClient, + self.cluster, + self.testdata[TestData.newHost], + hypervisor="XenServer" + ) + + self.assertTrue( + isinstance(host, Host), + "'host' is not a 'Host'." + ) + + pbds = self.xen_session.xenapi.SR.get_PBDs(xen_sr) + + self.assertEqual( + len(pbds), + num_pbds, + "'len(pbds)' is not equal to 'num_pbds'." + ) + + self._verify_all_pbds_attached(pbds) + + host_iscsi_iqns = self._get_host_iscsi_iqns() + + sf_vag = self._get_sf_vag(sf_vag_id) + + sf_vag_initiators = self._get_sf_vag_initiators(sf_vag) + + self._verifyVag(host_iscsi_iqns, sf_vag_initiators) + + sf_vag_initiators_len_new = len(sf_vag_initiators) + + self.assertEqual( + sf_vag_initiators_len_new, + sf_vag_initiators_len_orig + 1, + "sf_vag_initiators_len_new' != sf_vag_initiators_len_orig + 1" + ) + + host.delete(self.apiClient) + + pbds = self.xen_session.xenapi.SR.get_PBDs(xen_sr) + + self.assertEqual( + len(pbds), + num_pbds, + "'len(pbds)' is not equal to 'num_pbds'." + ) + + self._verify_all_pbds_attached(pbds) + + host_iscsi_iqns = self._get_host_iscsi_iqns() + + sf_vag = self._get_sf_vag(sf_vag_id) + + sf_vag_initiators = self._get_sf_vag_initiators(sf_vag) + + self.assertEqual( + len(host_iscsi_iqns) - 1, + len(sf_vag_initiators), + "'len(host_iscsi_iqns) - 1' is not equal to 'len(sf_vag_initiators)'." + ) + + host_ref = self.xen_session.xenapi.host.get_by_name_label(self.testdata[TestData.newHostDisplayName])[0] + + self.xen_session.xenapi.pool.eject(host_ref) + + time.sleep(120) + + pbds = self.xen_session.xenapi.SR.get_PBDs(xen_sr) + + self.assertEqual( + len(pbds), + num_pbds - 1, + "'len(pbds)' is not equal to 'num_pbds - 1'." + ) + + self._verify_all_pbds_attached(pbds) + + host_iscsi_iqns = self._get_host_iscsi_iqns() + + sf_vag = self._get_sf_vag(sf_vag_id) + + sf_vag_initiators = self._get_sf_vag_initiators(sf_vag) + + self._verifyVag(host_iscsi_iqns, sf_vag_initiators) + + sf_vag_initiators_len_new = len(sf_vag_initiators) + + self.assertEqual( + sf_vag_initiators_len_new, + sf_vag_initiators_len_orig, + "sf_vag_initiators_len_new' != sf_vag_initiators_len_orig" + ) + + def _verify_all_pbds_attached(self, pbds): + for pbd in pbds: + pbd_record = self.xen_session.xenapi.PBD.get_record(pbd) + + self.assertEqual( + pbd_record["currently_attached"], + True, + "Not all PBDs are currently attached." + ) + + def _get_root_volume(self, vm): + list_volumes_response = list_volumes( + self.apiClient, + virtualmachineid=vm.id, + listall=True + ) + + self.assertNotEqual( + list_volumes_response, + None, + "'list_volumes_response' should not be equal to 'None'." + ) + + self.assertEqual( + len(list_volumes_response) > 0, + True, + "'len(list_volumes_response)' should be greater than 0." + ) + + for volume in list_volumes_response: + if volume.type.upper() == "ROOT": + return volume + + self.assert_(False, "Unable to locate the ROOT volume of the VM with the following ID: " + str(vm.id)) + + def _get_iqn(self, volume): + # Get volume IQN + sf_iscsi_name_request = {'volumeid': volume.id} + # put this commented line back once PR 1403 is in + # sf_iscsi_name_result = self.cs_api.getVolumeiScsiName(sf_iscsi_name_request) + sf_iscsi_name_result = self.cs_api.getSolidFireVolumeIscsiName(sf_iscsi_name_request) + # sf_iscsi_name = sf_iscsi_name_result['apivolumeiscsiname']['volumeiScsiName'] + sf_iscsi_name = sf_iscsi_name_result['apisolidfirevolumeiscsiname']['solidFireVolumeIscsiName'] + + self._check_iscsi_name(sf_iscsi_name) + + return sf_iscsi_name + + def _get_iqn_2(self, primary_storage): + sql_query = "Select path From storage_pool Where uuid = '" + str(primary_storage.id) + "'" + + # make sure you can connect to MySQL: https://teamtreehouse.com/community/cant-connect-remotely-to-mysql-server-with-mysql-workbench + sql_result = self.dbConnection.execute(sql_query) + + return sql_result[0][0] + + def _check_iscsi_name(self, sf_iscsi_name): + self.assertEqual( + sf_iscsi_name[0], + "/", + "The iSCSI name needs to start with a forward slash." + ) + + def _get_host_iscsi_iqns(self): + hosts = self.xen_session.xenapi.host.get_all() + + self.assertEqual( + isinstance(hosts, list), + True, + "'hosts' is not a list." + ) + + host_iscsi_iqns = [] + + for host in hosts: + host_iscsi_iqns.append(self._get_host_iscsi_iqn(host)) + + return host_iscsi_iqns + + def _get_host_iscsi_iqn(self, host): + other_config = self.xen_session.xenapi.host.get_other_config(host) + + return other_config["iscsi_iqn"] + + def _get_sf_vag_id(self, cluster_id, primary_storage_id): + # Get SF Volume Access Group ID + sf_vag_id_request = {'clusterid': cluster_id, 'storageid': primary_storage_id} + sf_vag_id_result = self.cs_api.getSolidFireVolumeAccessGroupId(sf_vag_id_request) + sf_vag_id = sf_vag_id_result['apisolidfirevolumeaccessgroupid']['solidFireVolumeAccessGroupId'] + + self.assertEqual( + isinstance(sf_vag_id, int), + True, + TestAddRemoveHosts._vag_id_should_be_non_zero_int_err_msg + ) + + return sf_vag_id + + def _get_sf_vag(self, sf_vag_id): + return self.sf_client.list_volume_access_groups(sf_vag_id, 1)["volumeAccessGroups"][0] + + def _get_sf_vag_initiators(self, sf_vag): + return sf_vag["initiators"] + + def _verifyVag(self, host_iscsi_iqns, sf_vag_initiators): + self.assertEqual( + isinstance(host_iscsi_iqns, list), + True, + "'host_iscsi_iqns' is not a list." + ) + + self.assertEqual( + isinstance(sf_vag_initiators, list), + True, + "'sf_vag_initiators' is not a list." + ) + + self.assertEqual( + len(host_iscsi_iqns), + len(sf_vag_initiators), + "Lists are not the same size." + ) + + for host_iscsi_iqn in host_iscsi_iqns: + # an error should occur if host_iscsi_iqn is not in sf_vag_initiators + sf_vag_initiators.index(host_iscsi_iqn) + + def _check_list(self, in_list, expected_size_of_list, err_msg): + self.assertEqual( + isinstance(in_list, list), + True, + "'in_list' is not a list." + ) + + self.assertEqual( + len(in_list), + expected_size_of_list, + err_msg + ) + + @classmethod + def _purge_solidfire_volumes(cls): + deleted_volumes = cls.sf_client.list_deleted_volumes() + + for deleted_volume in deleted_volumes: + cls.sf_client.purge_deleted_volume(deleted_volume['volumeID']) + diff --git a/test/integration/plugins/solidfire/TestSnapshots.py b/test/integration/plugins/solidfire/TestSnapshots.py new file mode 100644 index 0000000000..9c3d25580c --- /dev/null +++ b/test/integration/plugins/solidfire/TestSnapshots.py @@ -0,0 +1,1472 @@ +# 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. + +import logging +import random +import SignedAPICall +import time +import XenAPI + +# All tests inherit from cloudstackTestCase +from marvin.cloudstackTestCase import cloudstackTestCase + +from nose.plugins.attrib import attr + +# Import Integration Libraries + +# base - contains all resources as entities and defines create, delete, list operations on them +from marvin.lib.base import Account, DiskOffering, ServiceOffering, Snapshot, StoragePool, Template, User, VirtualMachine, Volume + +# common - commonly used methods for all tests are listed here +from marvin.lib.common import get_domain, get_template, get_zone, list_clusters, list_hosts, list_volumes + +# utils - utility classes for common cleanup, external library wrappers, etc. +from marvin.lib.utils import cleanup_resources + +from solidfire import solidfire_element_api as sf_api + +# on April 10, 2016: Ran 3 tests in 7742.481s with three hosts +# on May 2, 2016: Ran 3 tests in 7409.770s with two hosts + + +class TestData(): + account = "account" + capacityBytes = "capacitybytes" + capacityIops = "capacityiops" + clusterId = "clusterId" + computeOffering = "computeoffering" + diskName = "diskname" + diskOffering = "diskoffering" + domainId = "domainId" + hypervisor = "hypervisor" + login = "login" + mvip = "mvip" + password = "password" + port = "port" + primaryStorage = "primarystorage" + provider = "provider" + scope = "scope" + solidFire = "solidfire" + storageTag = "SolidFire_SAN_1" + tags = "tags" + templateName = "templatename" + url = "url" + user = "user" + username = "username" + virtualMachine = "virtualmachine" + volume_1 = "volume_1" + volume_2 = "volume_2" + xenServer = "xenserver" + zoneId = "zoneId" + + def __init__(self): + self.testdata = { + TestData.solidFire: { + TestData.mvip: "192.168.139.112", + TestData.login: "admin", + TestData.password: "admin", + TestData.port: 443, + TestData.url: "https://192.168.139.112:443" + }, + TestData.xenServer: { + TestData.username: "root", + TestData.password: "solidfire" + }, + TestData.account: { + "email": "test@test.com", + "firstname": "John", + "lastname": "Doe", + "username": "test", + "password": "test" + }, + "testaccount": { + "email": "test2@test2.com", + "firstname": "Jane", + "lastname": "Doe", + TestData.username: "test2", + TestData.password: "test" + }, + TestData.user: { + "email": "user@test.com", + "firstname": "Jane", + "lastname": "Doe", + TestData.username: "testuser", + TestData.password: "password" + }, + TestData.primaryStorage: { + "name": "SolidFire-%d" % random.randint(0, 100), + TestData.scope: "ZONE", + "url": "MVIP=192.168.139.112;SVIP=10.10.8.112;" + + "clusterAdminUsername=admin;clusterAdminPassword=admin;" + + "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" + + "clusterDefaultBurstIopsPercentOfMaxIops=1.5;", + TestData.provider: "SolidFire", + TestData.tags: TestData.storageTag, + TestData.capacityIops: 4500000, + TestData.capacityBytes: 2251799813685248, + TestData.hypervisor: "Any" + }, + TestData.virtualMachine: { + "name": "TestVM", + "displayname": "Test VM" + }, + TestData.computeOffering: { + "name": "SF_CO_1", + "displaytext": "SF_CO_1 (Min IOPS = 10,000; Max IOPS = 15,000)", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 128, + "storagetype": "shared", + "customizediops": False, + "miniops": "10000", + "maxiops": "15000", + "hypervisorsnapshotreserve": 200, + "tags": "SolidFire_SAN_1" + }, + TestData.diskOffering: { + "name": "SF_DO_1", + "displaytext": "SF_DO_1 (Min IOPS = 300; Max IOPS = 500)", + "disksize": 128, + "customizediops": False, + "miniops": 300, + "maxiops": 500, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "testdiskofferings": { + "customiopsdo": { + "name": "SF_Custom_Iops_DO", + "displaytext": "Customized Iops DO", + "disksize": 128, + "customizediops": True, + "miniops": 500, + "maxiops": 1000, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "customsizedo": { + "name": "SF_Custom_Size_DO", + "displaytext": "Customized Size DO", + "disksize": 175, + "customizediops": False, + "miniops": 500, + "maxiops": 1000, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "customsizeandiopsdo": { + "name": "SF_Custom_Iops_Size_DO", + "displaytext": "Customized Size and Iops DO", + "disksize": 200, + "customizediops": True, + "miniops": 400, + "maxiops": 800, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "newiopsdo": { + "name": "SF_New_Iops_DO", + "displaytext": "New Iops (min=350, max = 700)", + "disksize": 128, + "miniops": 350, + "maxiops": 700, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "newsizedo": { + "name": "SF_New_Size_DO", + "displaytext": "New Size: 175", + "disksize": 175, + "miniops": 400, + "maxiops": 800, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "newsizeandiopsdo": { + "name": "SF_New_Size_Iops_DO", + "displaytext": "New Size and Iops", + "disksize": 200, + "miniops": 200, + "maxiops": 400, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + } + }, + TestData.volume_1: { + TestData.diskName: "test-volume", + }, + TestData.volume_2: { + TestData.diskName: "test-volume-2", + }, + TestData.templateName: "CentOS 5.6(64-bit) no GUI (XenServer)", + TestData.zoneId: 1, + TestData.clusterId: 1, + TestData.domainId: 1, + TestData.url: "192.168.129.50" + } + + +class TestSnapshots(cloudstackTestCase): + _should_be_zero_volume_access_groups_in_list_err_msg = "There shouldn't be any volume access groups in this list." + _should_be_zero_snapshots_in_list_err_msg = "There shouldn't be any snapshots in this list." + _should_only_be_one_snapshot_in_list_err_msg = "There should only be one snapshot in this list." + _should_be_two_snapshots_in_list_err_msg = "There should be two snapshots in this list." + _should_be_three_snapshots_in_list_err_msg = "There should be three snapshots in this list." + _should_be_zero_volumes_in_list_err_msg = "There shouldn't be any volumes in this list." + _should_only_be_one_volume_in_list_err_msg = "There should only be one volume in this list." + _should_be_two_volumes_in_list_err_msg = "There should be two volumes in this list." + _should_be_three_volumes_in_list_err_msg = "There should be three volumes in this list." + _should_be_four_volumes_in_list_err_msg = "There should be four volumes in this list." + _should_be_five_volumes_in_list_err_msg = "There should be five volumes in this list." + _should_be_six_volumes_in_list_err_msg = "There should be six volumes in this list." + _should_be_seven_volumes_in_list_err_msg = "There should be seven volumes in this list." + _should_be_five_items_in_list_err_msg = "There should be five items in this list." + _sf_account_id_should_be_non_zero_int_err_msg = "The SolidFire account ID should be a non-zero integer." + + @classmethod + def setUpClass(cls): + # Set up API client + testclient = super(TestSnapshots, cls).getClsTestClient() + cls.apiClient = testclient.getApiClient() + cls.dbConnection = testclient.getDbConnection() + + cls.testdata = TestData().testdata + + # Set up xenAPI connection + host_ip = "https://" + \ + list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name="XenServer-6.5-1")[0].ipaddress + + # Set up XenAPI connection + cls.xen_session = XenAPI.Session(host_ip) + + xenserver = cls.testdata[TestData.xenServer] + + cls.xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password]) + + # Set up SolidFire connection + cls.sf_client = sf_api.SolidFireAPI(endpoint_dict=cls.testdata[TestData.solidFire]) + + # Get Resources from Cloud Infrastructure + cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId]) + cls.cluster = list_clusters(cls.apiClient)[0] + cls.template = get_template(cls.apiClient, cls.zone.id, template_name=cls.testdata[TestData.templateName]) + cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId]) + + # Create test account + cls.account = Account.create( + cls.apiClient, + cls.testdata["account"], + admin=1 + ) + + # Set up connection to make customized API calls + cls.user = User.create( + cls.apiClient, + cls.testdata["user"], + account=cls.account.name, + domainid=cls.domain.id + ) + + url = cls.testdata[TestData.url] + + api_url = "http://" + url + ":8080/client/api" + userkeys = User.registerUserKeys(cls.apiClient, cls.user.id) + + cls.cs_api = SignedAPICall.CloudStack(api_url, userkeys.apikey, userkeys.secretkey) + + primarystorage = cls.testdata[TestData.primaryStorage] + + cls.primary_storage = StoragePool.create( + cls.apiClient, + primarystorage, + scope=primarystorage[TestData.scope], + zoneid=cls.zone.id, + provider=primarystorage[TestData.provider], + tags=primarystorage[TestData.tags], + capacityiops=primarystorage[TestData.capacityIops], + capacitybytes=primarystorage[TestData.capacityBytes], + hypervisor=primarystorage[TestData.hypervisor] + ) + + cls.compute_offering = ServiceOffering.create( + cls.apiClient, + cls.testdata[TestData.computeOffering] + ) + + cls.disk_offering = DiskOffering.create( + cls.apiClient, + cls.testdata[TestData.diskOffering] + ) + + # Resources that are to be destroyed + cls._cleanup = [ + cls.compute_offering, + cls.disk_offering, + cls.user, + cls.account + ] + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.apiClient, cls._cleanup) + + cls.primary_storage.delete(cls.apiClient) + + cls._purge_solidfire_volumes() + except Exception as e: + logging.debug("Exception in tearDownClass(cls): %s" % e) + + def setUp(self): + self.cleanup = [] + + def tearDown(self): + cleanup_resources(self.apiClient, self.cleanup) + + @attr(hypervisor='XenServer') + def test_01_create_volume_snapshot_using_sf_snapshot(self): + self._set_supports_resign(True) + + virtual_machine = VirtualMachine.create( + self.apiClient, + self.testdata[TestData.virtualMachine], + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=self.template.id, + domainid=self.domain.id, + startvm=True + ) + + list_volumes_response = list_volumes( + self.apiClient, + virtualmachineid=virtual_machine.id, + listall=True + ) + + self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + vm_1_root_volume = list_volumes_response[0] + vm_1_root_volume_name = vm_1_root_volume.name + + sf_account_id = self._get_sf_account_id(self.account.id, self.primary_storage.id) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name) + + # Get snapshot information for volume from SolidFire cluster + sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume['volumeID']) + + self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg) + + primary_storage_db_id = self._get_cs_storage_pool_db_id(self.primary_storage) + + vol_snap_1 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 1, TestSnapshots._should_only_be_one_snapshot_in_list_err_msg) + + vol_snap_2 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 2, TestSnapshots._should_be_two_snapshots_in_list_err_msg) + + vol_snap_3 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 3, TestSnapshots._should_be_three_snapshots_in_list_err_msg) + + self._delete_and_test_snapshot(vol_snap_2) + + self._delete_and_test_snapshot(vol_snap_1) + + self._delete_and_test_snapshot(vol_snap_3) + + vol_snap_1 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 1, TestSnapshots._should_only_be_one_snapshot_in_list_err_msg) + + vol_snap_2 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 2, TestSnapshots._should_be_two_snapshots_in_list_err_msg) + + virtual_machine.delete(self.apiClient, True) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name) + + self._delete_and_test_snapshot(vol_snap_1) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name) + + self._delete_and_test_snapshot(vol_snap_2) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 0, TestSnapshots._should_be_zero_volumes_in_list_err_msg) + + virtual_machine = VirtualMachine.create( + self.apiClient, + self.testdata[TestData.virtualMachine], + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=self.template.id, + domainid=self.domain.id, + startvm=True + ) + + list_volumes_response = list_volumes( + self.apiClient, + virtualmachineid=virtual_machine.id, + listall=True + ) + + self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + vm_1_root_volume = list_volumes_response[0] + vm_1_root_volume_name = vm_1_root_volume.name + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name) + + # Get snapshot information for volume from SolidFire cluster + sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume['volumeID']) + + self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg) + + vol_snap_1 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 1, TestSnapshots._should_only_be_one_snapshot_in_list_err_msg) + + vol_snap_2 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 2, TestSnapshots._should_be_two_snapshots_in_list_err_msg) + + vol_snap_3 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 3, TestSnapshots._should_be_three_snapshots_in_list_err_msg) + + services = {"displaytext": "Template-1", "name": "Template-1-name", "ostype": "CentOS 5.6 (64-bit)", "ispublic": "true"} + + template = Template.create_from_snapshot(self.apiClient, vol_snap_2, services) + + self.cleanup.append(template) + + virtual_machine_dict = {"name": "TestVM2", "displayname": "Test VM 2"} + + virtual_machine_2 = VirtualMachine.create( + self.apiClient, + virtual_machine_dict, + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=template.id, + domainid=self.domain.id, + startvm=True + ) + + list_volumes_response = list_volumes( + self.apiClient, + virtualmachineid=virtual_machine_2.id, + listall=True + ) + + self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + vm_2_root_volume = list_volumes_response[0] + vm_2_root_volume_name = vm_2_root_volume.name + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name) + + # Get snapshot information for volume from SolidFire cluster + sf_snapshots_2 = self.sf_client.list_snapshots(volume_id=sf_volume_2['volumeID']) + + self._check_list(sf_snapshots_2, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg) + + vol_snap_a = self._create_and_test_snapshot(vm_2_root_volume.id, sf_volume_2, primary_storage_db_id, 1, TestSnapshots._should_only_be_one_snapshot_in_list_err_msg) + + services = {"diskname": "Vol-1", "zoneid": self.testdata[TestData.zoneId], "size": 100, "ispublic": True} + + volume_created_from_snapshot = Volume.create_from_snapshot(self.apiClient, vol_snap_a.id, services, account=self.account.name, domainid=self.domain.id) + + volume_created_from_snapshot_name = volume_created_from_snapshot.name + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg) + + sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name) + sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name) + sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name) + + self._check_list(sf_volume_3['volumeAccessGroups'], 0, TestSnapshots._should_be_zero_volume_access_groups_in_list_err_msg) + + volume_created_from_snapshot = virtual_machine.attach_volume( + self.apiClient, + volume_created_from_snapshot + ) + + self._delete_and_test_snapshot(vol_snap_a) + + virtual_machine.delete(self.apiClient, True) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg) + + sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name) + sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name) + sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name) + + volume_created_from_snapshot = virtual_machine_2.attach_volume( + self.apiClient, + volume_created_from_snapshot + ) + + self._delete_and_test_snapshot(vol_snap_2) + + self._delete_and_test_snapshot(vol_snap_3) + + self._delete_and_test_snapshot(vol_snap_1) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name) + sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name) + + virtual_machine_2.delete(self.apiClient, True) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name) + + list_volumes_response = list_volumes( + self.apiClient, + listall=True + ) + + self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + data_volume = list_volumes_response[0] + + data_volume = Volume(data_volume.__dict__) + + data_volume.delete(self.apiClient) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 0, TestSnapshots._should_be_zero_volumes_in_list_err_msg) + + @attr(hypervisor='XenServer') + def test_02_create_volume_snapshot_using_sf_volume(self): + self._set_supports_resign(False) + + virtual_machine = VirtualMachine.create( + self.apiClient, + self.testdata[TestData.virtualMachine], + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=self.template.id, + domainid=self.domain.id, + startvm=True + ) + + list_volumes_response = list_volumes( + self.apiClient, + virtualmachineid=virtual_machine.id, + listall=True + ) + + self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + vm_1_root_volume = list_volumes_response[0] + vm_1_root_volume_name = vm_1_root_volume.name + + sf_account_id = self._get_sf_account_id(self.account.id, self.primary_storage.id) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name) + + # Get snapshot information for volume from SolidFire cluster + sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume['volumeID']) + + self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg) + + primary_storage_db_id = self._get_cs_storage_pool_db_id(self.primary_storage) + + sf_volume_id = sf_volume['volumeID'] + sf_volume_size = sf_volume['totalSize'] + + vol_snap_1 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 1, primary_storage_db_id, sf_volume_size, + sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + vol_snap_2 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 2, primary_storage_db_id, sf_volume_size, + sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg) + + vol_snap_3 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 3, primary_storage_db_id, sf_volume_size, + sf_account_id, 4, TestSnapshots._should_be_four_volumes_in_list_err_msg) + + self._delete_and_test_snapshot_2(vol_snap_2, sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg) + + self._delete_and_test_snapshot_2(vol_snap_1, sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + self._delete_and_test_snapshot_2(vol_snap_3, sf_account_id, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + vol_snap_1 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 4, primary_storage_db_id, sf_volume_size, + sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + vol_snap_2 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 5, primary_storage_db_id, sf_volume_size, + sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg) + + virtual_machine.delete(self.apiClient, True) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + self._delete_and_test_snapshot_2(vol_snap_1, sf_account_id, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + self._delete_and_test_snapshot_2(vol_snap_2, sf_account_id, 0, TestSnapshots._should_be_zero_volumes_in_list_err_msg) + + virtual_machine = VirtualMachine.create( + self.apiClient, + self.testdata[TestData.virtualMachine], + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=self.template.id, + domainid=self.domain.id, + startvm=True + ) + + list_volumes_response = list_volumes( + self.apiClient, + virtualmachineid=virtual_machine.id, + listall=True + ) + + self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + vm_1_root_volume = list_volumes_response[0] + vm_1_root_volume_name = vm_1_root_volume.name + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name) + + # Get snapshot information for volume from SolidFire cluster + sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume['volumeID']) + + self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg) + + sf_volume_id = sf_volume['volumeID'] + sf_volume_size = sf_volume['totalSize'] + + vol_snap_1 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 1, primary_storage_db_id, sf_volume_size, + sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + vol_snap_2 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 2, primary_storage_db_id, sf_volume_size, + sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg) + + vol_snap_3 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 3, primary_storage_db_id, sf_volume_size, + sf_account_id, 4, TestSnapshots._should_be_four_volumes_in_list_err_msg) + + services = {"displaytext": "Template-1", "name": "Template-1-name", "ostype": "CentOS 5.6 (64-bit)", "ispublic": "true"} + + template = Template.create_from_snapshot(self.apiClient, vol_snap_2, services) + + self.cleanup.append(template) + + virtual_machine_dict = {"name": "TestVM2", "displayname": "Test VM 2"} + + virtual_machine_2 = VirtualMachine.create( + self.apiClient, + virtual_machine_dict, + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=template.id, + domainid=self.domain.id, + startvm=True + ) + + list_volumes_response = list_volumes( + self.apiClient, + virtualmachineid=virtual_machine_2.id, + listall=True + ) + + self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + vm_2_root_volume = list_volumes_response[0] + vm_2_root_volume_name = vm_2_root_volume.name + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 5, TestSnapshots._should_be_five_volumes_in_list_err_msg) + + sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name) + + # Get snapshot information for volume from SolidFire cluster + sf_snapshots_2 = self.sf_client.list_snapshots(volume_id=sf_volume_2['volumeID']) + + self._check_list(sf_snapshots_2, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg) + + sf_volume_id_2 = sf_volume_2['volumeID'] + sf_volume_size_2 = sf_volume_2['totalSize'] + + vol_snap_a = self._create_and_test_snapshot_2(vm_2_root_volume.id, sf_volume_id_2, sf_volume_id + 5, primary_storage_db_id, sf_volume_size_2, + sf_account_id, 6, TestSnapshots._should_be_six_volumes_in_list_err_msg) + + services = {"diskname": "Vol-1", "zoneid": self.testdata[TestData.zoneId], "size": 100, "ispublic": True} + + volume_created_from_snapshot = Volume.create_from_snapshot(self.apiClient, vol_snap_a.id, services, account=self.account.name, domainid=self.domain.id) + + volume_created_from_snapshot_name = volume_created_from_snapshot.name + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 7, TestSnapshots._should_be_seven_volumes_in_list_err_msg) + + sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name) + sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name) + sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name) + + self._check_list(sf_volume_3['volumeAccessGroups'], 0, TestSnapshots._should_be_zero_volume_access_groups_in_list_err_msg) + + volume_created_from_snapshot = virtual_machine.attach_volume( + self.apiClient, + volume_created_from_snapshot + ) + + self._delete_and_test_snapshot_2(vol_snap_a, sf_account_id, 6, TestSnapshots._should_be_six_volumes_in_list_err_msg) + + virtual_machine.delete(self.apiClient, True) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 5, TestSnapshots._should_be_five_volumes_in_list_err_msg) + + sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name) + sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name) + + volume_created_from_snapshot = virtual_machine_2.attach_volume( + self.apiClient, + volume_created_from_snapshot + ) + + self._delete_and_test_snapshot_2(vol_snap_2, sf_account_id, 4, TestSnapshots._should_be_four_volumes_in_list_err_msg) + + self._delete_and_test_snapshot_2(vol_snap_3, sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg) + + self._delete_and_test_snapshot_2(vol_snap_1, sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + virtual_machine_2.delete(self.apiClient, True) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + list_volumes_response = list_volumes( + self.apiClient, + listall=True + ) + + self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + data_volume = list_volumes_response[0] + + data_volume = Volume(data_volume.__dict__) + + data_volume.delete(self.apiClient) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 0, TestSnapshots._should_be_zero_volumes_in_list_err_msg) + + virtual_machine = VirtualMachine.create( + self.apiClient, + self.testdata[TestData.virtualMachine], + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=template.id, + domainid=self.domain.id, + startvm=True + ) + + list_volumes_response = list_volumes( + self.apiClient, + virtualmachineid=virtual_machine.id, + listall=True + ) + + self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + vm_1_root_volume = list_volumes_response[0] + vm_1_root_volume_name = vm_1_root_volume.name + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + time.sleep(60) + + virtual_machine.stop(self.apiClient, True) + + sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name) + + sf_volume_id = sf_volume['volumeID'] + sf_volume_size = sf_volume['totalSize'] + + vol_snap_1 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 1, primary_storage_db_id, sf_volume_size, + sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + services = {"diskname": "Vol-1", "zoneid": self.testdata[TestData.zoneId], "size": 100, "ispublic": True} + + volume_created_from_snapshot = Volume.create_from_snapshot(self.apiClient, vol_snap_1.id, services, account=self.account.name, domainid=self.domain.id) + + volume_created_from_snapshot_name = volume_created_from_snapshot.name + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg) + + sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name) + + self._check_list(sf_volume_2['volumeAccessGroups'], 0, TestSnapshots._should_be_zero_volume_access_groups_in_list_err_msg) + + volume_created_from_snapshot = virtual_machine.attach_volume( + self.apiClient, + volume_created_from_snapshot + ) + + sf_volume_id_2 = sf_volume_2['volumeID'] + sf_volume_size_2 = sf_volume_2['totalSize'] + + vol_snap_a = self._create_and_test_snapshot_2(volume_created_from_snapshot.id, sf_volume_id_2, sf_volume_id + 3, primary_storage_db_id, sf_volume_size_2, + sf_account_id, 4, TestSnapshots._should_be_four_volumes_in_list_err_msg) + + self._delete_and_test_snapshot_2(vol_snap_1, sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg) + + self._delete_and_test_snapshot_2(vol_snap_a, sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + virtual_machine.delete(self.apiClient, True) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + list_volumes_response = list_volumes( + self.apiClient, + listall=True + ) + + self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + vol_snap_a = self._create_and_test_snapshot_2(volume_created_from_snapshot.id, sf_volume_id_2, sf_volume_id + 4, primary_storage_db_id, sf_volume_size_2, + sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + data_volume = list_volumes_response[0] + + data_volume = Volume(data_volume.__dict__) + + data_volume.delete(self.apiClient) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + list_volumes_response = list_volumes( + self.apiClient, + listall=True + ) + + self.assertEqual( + list_volumes_response, + None, + "'list_volumes_response' should be equal to 'None'." + ) + + self._delete_and_test_snapshot_2(vol_snap_a, sf_account_id, 0, TestSnapshots._should_be_zero_volumes_in_list_err_msg) + + @attr(hypervisor='XenServer') + def test_03_create_volume_snapshot_using_sf_volume_and_sf_snapshot(self): + self._set_supports_resign(False) + + virtual_machine = VirtualMachine.create( + self.apiClient, + self.testdata[TestData.virtualMachine], + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=self.template.id, + domainid=self.domain.id, + startvm=True + ) + + list_volumes_response = list_volumes( + self.apiClient, + virtualmachineid=virtual_machine.id, + listall=True + ) + + self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + vm_1_root_volume = list_volumes_response[0] + vm_1_root_volume_name = vm_1_root_volume.name + + sf_account_id = self._get_sf_account_id(self.account.id, self.primary_storage.id) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name) + + # Get snapshot information for volume from SolidFire cluster + sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume['volumeID']) + + self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg) + + primary_storage_db_id = self._get_cs_storage_pool_db_id(self.primary_storage) + + sf_volume_id = sf_volume['volumeID'] + sf_volume_size = sf_volume['totalSize'] + + vol_snap_1 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 1, primary_storage_db_id, sf_volume_size, + sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + vol_snap_2 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 2, primary_storage_db_id, sf_volume_size, + sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg) + + self._set_supports_resign(True) + + vol_snap_a = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 1, TestSnapshots._should_only_be_one_snapshot_in_list_err_msg) + + vol_snap_b = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 2, TestSnapshots._should_be_two_snapshots_in_list_err_msg) + + services = {"displaytext": "Template-1", "name": "Template-1-name", "ostype": "CentOS 5.6 (64-bit)", "ispublic": "true"} + + template_1 = Template.create_from_snapshot(self.apiClient, vol_snap_1, services) + + self.cleanup.append(template_1) + + virtual_machine_dict = {"name": "TestVM2", "displayname": "Test VM 2"} + + virtual_machine_2 = VirtualMachine.create( + self.apiClient, + virtual_machine_dict, + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=template_1.id, + domainid=self.domain.id, + startvm=True + ) + + list_volumes_response = list_volumes( + self.apiClient, + virtualmachineid=virtual_machine_2.id, + listall=True + ) + + self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + vm_2_root_volume = list_volumes_response[0] + vm_2_root_volume_name = vm_2_root_volume.name + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 4, TestSnapshots._should_be_four_volumes_in_list_err_msg) + + sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name) + + # Get snapshot information for volume from SolidFire cluster + sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume_2['volumeID']) + + self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg) + + services = {"diskname": "Vol-1", "zoneid": self.testdata[TestData.zoneId], "size": 100, "ispublic": True} + + volume_created_from_snapshot_1 = Volume.create_from_snapshot(self.apiClient, vol_snap_2.id, services, account=self.account.name, domainid=self.domain.id) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 5, TestSnapshots._should_be_five_volumes_in_list_err_msg) + + volume_created_from_snapshot_1 = virtual_machine_2.attach_volume( + self.apiClient, + volume_created_from_snapshot_1 + ) + + services = {"displaytext": "Template-A", "name": "Template-A-name", "ostype": "CentOS 5.6 (64-bit)", "ispublic": "true"} + + template_a = Template.create_from_snapshot(self.apiClient, vol_snap_a, services) + + self.cleanup.append(template_a) + + virtual_machine_dict = {"name": "TestVM3", "displayname": "Test VM 3"} + + virtual_machine_3 = VirtualMachine.create( + self.apiClient, + virtual_machine_dict, + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=template_a.id, + domainid=self.domain.id, + startvm=True + ) + + list_volumes_response = list_volumes( + self.apiClient, + virtualmachineid=virtual_machine_3.id, + listall=True + ) + + self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + vm_3_root_volume = list_volumes_response[0] + vm_3_root_volume_name = vm_3_root_volume.name + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 6, TestSnapshots._should_be_six_volumes_in_list_err_msg) + + sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, vm_3_root_volume_name) + + # Get snapshot information for volume from SolidFire cluster + sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume_3['volumeID']) + + self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg) + + services = {"diskname": "Vol-A", "zoneid": self.testdata[TestData.zoneId], "size": 100, "ispublic": True} + + volume_created_from_snapshot_a = Volume.create_from_snapshot(self.apiClient, vol_snap_b.id, services, account=self.account.name, domainid=self.domain.id) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 7, TestSnapshots._should_be_seven_volumes_in_list_err_msg) + + volume_created_from_snapshot_a = virtual_machine_3.attach_volume( + self.apiClient, + volume_created_from_snapshot_a + ) + + virtual_machine.delete(self.apiClient, True) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + # should still be 7 volumes because the SolidFire volume for the root disk of the VM just destroyed + # is still needed for the SolidFire snapshots + self._check_list(sf_volumes, 7, TestSnapshots._should_be_seven_volumes_in_list_err_msg) + + virtual_machine_2.delete(self.apiClient, True) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 6, TestSnapshots._should_be_six_volumes_in_list_err_msg) + + virtual_machine_3.delete(self.apiClient, True) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 5, TestSnapshots._should_be_five_volumes_in_list_err_msg) + + data_volume = Volume(volume_created_from_snapshot_a.__dict__) + + data_volume.delete(self.apiClient) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 4, TestSnapshots._should_be_four_volumes_in_list_err_msg) + + data_volume = Volume(volume_created_from_snapshot_1.__dict__) + + data_volume.delete(self.apiClient) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg) + + self._delete_and_test_snapshot_2(vol_snap_1, sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + self._delete_and_test_snapshot(vol_snap_b) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + # should still be 2 volumes because the SolidFire volume for the root disk of the VM just destroyed + # is still needed for the SolidFire snapshots + self._check_list(sf_volumes, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg) + + self._delete_and_test_snapshot(vol_snap_a) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + self._delete_and_test_snapshot_2(vol_snap_2, sf_account_id, 0, TestSnapshots._should_be_zero_volumes_in_list_err_msg) + + def _set_supports_resign(self, supports_resign): + supports_resign = str(supports_resign) + + sql_query = "Update host_details Set value = '" + supports_resign + "' Where name = 'supportsResign'" + + # make sure you can connect to MySQL: https://teamtreehouse.com/community/cant-connect-remotely-to-mysql-server-with-mysql-workbench + self.dbConnection.execute(sql_query) + + def _check_list(self, in_list, expected_size_of_list, err_msg): + self.assertEqual( + isinstance(in_list, list), + True, + "'in_list' is not a list." + ) + + self.assertEqual( + len(in_list), + expected_size_of_list, + err_msg + ) + + def _check_list_not_empty(self, in_list): + self.assertEqual( + isinstance(in_list, list), + True, + "'in_list' is not a list." + ) + + self.assertGreater( + len(in_list), + 0, + "The size of 'in_list' must be greater than zero." + ) + + # used when SolidFire snapshots are being used for CloudStack volume snapshots + def _check_snapshot_details(self, sf_snapshot_details, cs_snapshot_id, sf_volume_id, sf_snapshot_id, storage_pool_id, sf_volume_size): + self._check_list(sf_snapshot_details, 5, TestSnapshots._should_be_five_items_in_list_err_msg) + + self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "takeSnapshot", "true") + self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "volumeId", sf_volume_id) + self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "snapshotId", sf_snapshot_id) + self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "sfStoragePoolId", storage_pool_id) + self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "sfVolumeSize", sf_volume_size) + + # used when SolidFire volumes are being used for CloudStack volume snapshots + def _check_snapshot_details_2(self, sf_snapshot_details, cs_snapshot_id, sf_volume_id, storage_pool_id, sf_volume_size): + self._check_list(sf_snapshot_details, 5, TestSnapshots._should_be_five_items_in_list_err_msg) + + self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "volumeId", sf_volume_id) + self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "sfStoragePoolId", storage_pool_id) + self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "sfVolumeSize", sf_volume_size) + self._check_snapshot_detail_starts_with(sf_snapshot_details, cs_snapshot_id, "iqn", "/iqn.") + self._check_snapshot_detail_size(sf_snapshot_details, cs_snapshot_id, "path", 36) + + def _check_snapshot_detail(self, sf_snapshot_details_list, cs_snapshot_id, snapshot_detail_key, snapshot_detail_value): + for sf_snapshot_detail_dict in sf_snapshot_details_list: + if sf_snapshot_detail_dict["volumeSnapshotId"] != cs_snapshot_id: + raise Exception("This snapshot detail does not apply to the expected CloudStack volume snapshot.") + + if sf_snapshot_detail_dict["snapshotDetailsName"] == snapshot_detail_key: + if sf_snapshot_detail_dict["snapshotDetailsValue"] == str(snapshot_detail_value): + return + + raise Exception("There is a problem with the snapshot details key '" + snapshot_detail_key + "' and value '" + str(snapshot_detail_value) + "'.") + + def _check_snapshot_detail_starts_with(self, sf_snapshot_details_list, cs_snapshot_id, snapshot_detail_key, starts_with): + for sf_snapshot_detail_dict in sf_snapshot_details_list: + if sf_snapshot_detail_dict["volumeSnapshotId"] != cs_snapshot_id: + raise Exception("This snapshot detail does not apply to the expected CloudStack volume snapshot.") + + if sf_snapshot_detail_dict["snapshotDetailsName"] == snapshot_detail_key: + if sf_snapshot_detail_dict["snapshotDetailsValue"].startswith(starts_with): + return + + raise Exception("There is a problem with the snapshot details key '" + snapshot_detail_key + "' and 'starts with' value '" + starts_with + "'.") + + def _check_snapshot_detail_size(self, sf_snapshot_details_list, cs_snapshot_id, snapshot_detail_key, length): + for sf_snapshot_detail_dict in sf_snapshot_details_list: + if sf_snapshot_detail_dict["volumeSnapshotId"] != cs_snapshot_id: + raise Exception("This snapshot detail does not apply to the expected CloudStack volume snapshot.") + + if sf_snapshot_detail_dict["snapshotDetailsName"] == snapshot_detail_key: + if len(sf_snapshot_detail_dict["snapshotDetailsValue"]) == length: + return + + raise Exception("There is a problem with the snapshot details key '" + snapshot_detail_key + "' and 'length' value '" + str(length) + "'.") + + def _most_recent_sf_snapshot(self, sf_snapshots): + self._check_list_not_empty(sf_snapshots) + + most_recent_id = 0 + sf_snapshot_to_return = None + + for sf_snapshot in sf_snapshots: + if (sf_snapshot['snapshotID'] > most_recent_id): + sf_snapshot_to_return = sf_snapshot + + most_recent_id = sf_snapshot['snapshotID'] + + if (sf_snapshot_to_return == None): + raise Exception("Unable to find the most recent SolidFire snapshot in the provided list") + + return sf_snapshot_to_return + + def _get_cs_volume_snapshot_db_id(self, vol_snap): + return self._get_db_id("snapshots", vol_snap) + + def _get_cs_storage_pool_db_id(self, storage_pool): + return self._get_db_id("storage_pool", storage_pool) + + def _get_db_id(self, table, db_obj): + sql_query = "Select id From " + table + " Where uuid = '" + str(db_obj.id) + "'" + + # make sure you can connect to MySQL: https://teamtreehouse.com/community/cant-connect-remotely-to-mysql-server-with-mysql-workbench + sql_result = self.dbConnection.execute(sql_query) + + return sql_result[0][0] + + def _get_sf_volume_by_name(self, sf_volumes, sf_volume_name): + self._check_list_not_empty(sf_volumes) + + sf_volume = None + + for volume in sf_volumes: + if volume['name'] == sf_volume_name: + sf_volume = volume + + break + + self.assertNotEqual( + sf_volume, + None, + "The SolidFire volume could not be found in the expected account." + ) + + return sf_volume + + def _get_sf_volume_by_id(self, sf_volumes, sf_volume_id): + self._check_list_not_empty(sf_volumes) + + sf_volume = None + + for volume in sf_volumes: + if volume['volumeID'] == sf_volume_id: + sf_volume = volume + + break + + self.assertNotEqual( + sf_volume, + None, + "The SolidFire volume could not be found in the expected account." + ) + + return sf_volume + + def _get_sf_account_id(self, cs_account_id, primary_storage_id): + sf_account_id_request = {'accountid': cs_account_id, 'storageid': primary_storage_id} + sf_account_id_result = self.cs_api.getSolidFireAccountId(sf_account_id_request) + sf_account_id = sf_account_id_result['apisolidfireaccountid']['solidFireAccountId'] + + self.assertEqual( + isinstance(sf_account_id, int), + True, + TestSnapshots._sf_account_id_should_be_non_zero_int_err_msg + ) + + return sf_account_id + + def _get_snapshot_detail(self, sf_snapshot_details_list, key): + for sf_snapshot_detail_dict in sf_snapshot_details_list: + if sf_snapshot_detail_dict["snapshotDetailsName"] == key: + return sf_snapshot_detail_dict["snapshotDetailsValue"] + + raise Exception("Unable to find the following snapshot details key: " + key) + + def _check_sf_snapshot_does_not_exist(self, sf_snapshots, sf_snapshot_id): + for sf_snapshot in sf_snapshots: + if sf_snapshot["snapshotID"] == sf_snapshot: + raise Exception("The following SolidFire snapshot ID should not exist: " + sf_snapshot_id) + + def _check_snapshot_details_do_not_exist(self, vol_snap_db_id): + sql_query = "Select count(*) From snapshot_details Where snapshot_id = " + str(vol_snap_db_id) + + # make sure you can connect to MySQL: https://teamtreehouse.com/community/cant-connect-remotely-to-mysql-server-with-mysql-workbench + sql_result = self.dbConnection.execute(sql_query) + + self.assertEqual( + sql_result[0][0], + 0, + "Snapshot details should not exist for the following CloudStack volume snapshot DB ID: " + str(vol_snap_db_id) + ) + + # used when SolidFire snapshots are being used for CloudStack volume snapshots + def _create_and_test_snapshot(self, volume_id_for_snapshot, sf_volume, primary_storage_db_id, expected_num_snapshots, snapshot_err_msg): + vol_snap = Snapshot.create( + self.apiClient, + volume_id=volume_id_for_snapshot + ) + + sf_volume_id = sf_volume['volumeID'] + + # Get snapshot information for volume from SolidFire cluster + sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume_id) + + self._check_list(sf_snapshots, expected_num_snapshots, snapshot_err_msg) + + sf_snapshot = self._most_recent_sf_snapshot(sf_snapshots) + + sf_snapshot_details_request = {'snapshotid': vol_snap.id} + sf_snapshot_details_response = self.cs_api.getVolumeSnapshotDetails(sf_snapshot_details_request) + sf_snapshot_details = sf_snapshot_details_response['null'] # 'null' gets me the list that's in the dictionary + + vol_snap_db_id = self._get_cs_volume_snapshot_db_id(vol_snap) + + self._check_snapshot_details(sf_snapshot_details, vol_snap_db_id, sf_volume_id, sf_snapshot['snapshotID'], primary_storage_db_id, sf_volume['totalSize']) + + return vol_snap + + # used when SolidFire volumes are being used for CloudStack volume snapshots + def _create_and_test_snapshot_2(self, volume_id_for_snapshot, sf_volume_id, sf_volume_id_for_volume_snapshot, primary_storage_db_id, sf_volume_size, + sf_account_id, expected_num_volumes, volume_err_msg): + vol_snap = Snapshot.create( + self.apiClient, + volume_id=volume_id_for_snapshot + ) + + # Get snapshot information for volume from SolidFire cluster + sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume_id) + + self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg) + + sf_snapshot_details_request = {'snapshotid': vol_snap.id} + sf_snapshot_details_response = self.cs_api.getVolumeSnapshotDetails(sf_snapshot_details_request) + sf_snapshot_details = sf_snapshot_details_response['null'] # 'null' gets me the list that's in the dictionary + + vol_snap_db_id = self._get_cs_volume_snapshot_db_id(vol_snap) + + self._check_snapshot_details_2(sf_snapshot_details, vol_snap_db_id, sf_volume_id_for_volume_snapshot, primary_storage_db_id, sf_volume_size) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, expected_num_volumes, volume_err_msg) + + sf_volume_for_snapshot = self._get_sf_volume_by_id(sf_volumes, sf_volume_id_for_volume_snapshot) + + self._check_list(sf_volume_for_snapshot['volumeAccessGroups'], 0, TestSnapshots._should_be_zero_volume_access_groups_in_list_err_msg) + + return vol_snap + + # used when SolidFire snapshots are being used for CloudStack volume snapshots + def _delete_and_test_snapshot(self, vol_snap): + vol_snap_id = vol_snap.id + vol_snap_db_id = self._get_cs_volume_snapshot_db_id(vol_snap) + + sf_snapshot_details_request = {'snapshotid': vol_snap_id} + sf_snapshot_details_response = self.cs_api.getVolumeSnapshotDetails(sf_snapshot_details_request) + sf_snapshot_details = sf_snapshot_details_response['null'] # 'null' gets me the list that's in the dictionary + + sf_volume_id = self._get_snapshot_detail(sf_snapshot_details, "volumeId") + sf_snapshot_id = self._get_snapshot_detail(sf_snapshot_details, "snapshotId") + + vol_snap.delete(self.apiClient) + + # Get snapshot information for volume from SolidFire cluster + sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume_id) + + self._check_sf_snapshot_does_not_exist(sf_snapshots, sf_snapshot_id) + + self._check_snapshot_details_do_not_exist(vol_snap_db_id) + + # used when SolidFire volumes are being used for CloudStack volume snapshots + def _delete_and_test_snapshot_2(self, vol_snap, sf_account_id, expected_num_volumes, volume_err_msg): + vol_snap_db_id = self._get_cs_volume_snapshot_db_id(vol_snap) + + vol_snap.delete(self.apiClient) + + self._check_snapshot_details_do_not_exist(vol_snap_db_id) + + # Get volume information from SolidFire cluster + sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id) + + self._check_list(sf_volumes, expected_num_volumes, volume_err_msg) + + @classmethod + def _purge_solidfire_volumes(cls): + deleted_volumes = cls.sf_client.list_deleted_volumes() + + for deleted_volume in deleted_volumes: + cls.sf_client.purge_deleted_volume(deleted_volume['volumeID']) + diff --git a/test/integration/plugins/solidfire/TestVMSnapshots.py b/test/integration/plugins/solidfire/TestVMSnapshots.py new file mode 100644 index 0000000000..8fba8f8641 --- /dev/null +++ b/test/integration/plugins/solidfire/TestVMSnapshots.py @@ -0,0 +1,862 @@ +# 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. + +import logging +import random +import SignedAPICall +import XenAPI + +# All tests inherit from cloudstackTestCase +from marvin.cloudstackTestCase import cloudstackTestCase + +# Import Integration Libraries + +# base - contains all resources as entities and defines create, delete, list operations on them +from marvin.lib.base import Account, DiskOffering, ServiceOffering, StoragePool, User, VirtualMachine, VmSnapshot, Volume + +# common - commonly used methods for all tests are listed here +from marvin.lib.common import get_domain, get_template, get_zone, list_hosts, list_volumes + +# utils - utility classes for common cleanup, external library wrappers, etc. +from marvin.lib.utils import cleanup_resources + +from solidfire import solidfire_element_api as sf_api + +# on April 15, 2016: Ran 2 tests in 800.299s with three hosts +# on May 2, 2016: Ran 2 tests in 789.729s with two hosts + + +class TestData: + account = "account" + capacityBytes = "capacitybytes" + capacityIops = "capacityiops" + clusterId = "clusterId" + computeOffering = "computeoffering" + diskOffering = "diskoffering" + domainId = "domainId" + hypervisor = "hypervisor" + login = "login" + mvip = "mvip" + password = "password" + port = "port" + primaryStorage = "primarystorage" + provider = "provider" + scope = "scope" + solidFire = "solidfire" + storageTag = "SolidFire_SAN_1" + tags = "tags" + templateName = "templatename" + url = "url" + user = "user" + username = "username" + virtualMachine = "virtualmachine" + volume_1 = "volume_1" + xenServer = "xenserver" + zoneId = "zoneId" + + def __init__(self): + self.testdata = { + TestData.solidFire: { + TestData.mvip: "192.168.139.112", + TestData.login: "admin", + TestData.password: "admin", + TestData.port: 443, + TestData.url: "https://192.168.139.112:443" + }, + TestData.xenServer: { + TestData.username: "root", + TestData.password: "solidfire" + }, + TestData.account: { + "email": "test@test.com", + "firstname": "John", + "lastname": "Doe", + TestData.username: "test", + TestData.password: "test" + }, + TestData.user: { + "email": "user@test.com", + "firstname": "Jane", + "lastname": "Doe", + TestData.username: "testuser", + TestData.password: "password" + }, + TestData.primaryStorage: { + "name": "SolidFire-%d" % random.randint(0, 100), + TestData.scope: "ZONE", + "url": "MVIP=192.168.139.112;SVIP=10.10.8.112;" + + "clusterAdminUsername=admin;clusterAdminPassword=admin;" + + "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" + + "clusterDefaultBurstIopsPercentOfMaxIops=1.5;", + TestData.provider: "SolidFire", + TestData.tags: TestData.storageTag, + TestData.capacityIops: 4500000, + TestData.capacityBytes: 2251799813685248, + TestData.hypervisor: "Any" + }, + TestData.virtualMachine: { + "name": "TestVM", + "displayname": "Test VM" + }, + TestData.computeOffering: { + "name": "SF_CO_1", + "displaytext": "SF_CO_1 (Min IOPS = 10,000; Max IOPS = 15,000)", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 128, + "storagetype": "shared", + "customizediops": False, + "miniops": "10000", + "maxiops": "15000", + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag + }, + TestData.diskOffering: { + "name": "SF_DO_1", + "displaytext": "SF_DO_1 (Min IOPS = 300; Max IOPS = 500)", + "disksize": 128, + "customizediops": False, + "miniops": 300, + "maxiops": 500, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "testdiskofferings": { + "customiopsdo": { + "name": "SF_Custom_IOPS_DO", + "displaytext": "Customized IOPS DO (Size = 128 GB; Min IOPS = 500; Max IOPS = 1000)", + "disksize": 128, + "customizediops": True, + "miniops": 500, + "maxiops": 1000, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "customsizedo": { + "name": "SF_Custom_Size_DO", + "displaytext": "Customized IOPS DO (Min IOPS = 500; Max IOPS = 1000)", + "disksize": 175, + "customizediops": False, + "miniops": 500, + "maxiops": 1000, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "customsizeandiopsdo": { + "name": "SF_Custom_Size_IOPS_DO", + "displaytext": "Customized Size and IOPS DO", + "disksize": 200, + "customizediops": True, + "miniops": 400, + "maxiops": 800, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "newiopsdo": { + "name": "SF_New_IOPS_DO", + "displaytext": "New IOPS (Size = 128 GB; Min IOPS = 350, Max IOPS = 700)", + "disksize": 128, + "miniops": 350, + "maxiops": 700, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "newsizedo": { + "name": "SF_New_Size_DO", + "displaytext": "New Size: 175", + "disksize": 175, + "miniops": 400, + "maxiops": 800, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "newsizeandiopsdo": { + "name": "SF_New_Size_IOPS_DO", + "displaytext": "New Size and IOPS", + "disksize": 200, + "miniops": 200, + "maxiops": 400, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + } + }, + TestData.volume_1: { + "diskname": "testvolume", + }, + "volume2": { + "diskname": "testvolume2", + }, + TestData.templateName: "CentOS 5.6(64-bit) no GUI (XenServer)", + TestData.zoneId: 1, + TestData.clusterId: 1, + TestData.domainId: 1, + TestData.url: "192.168.129.50" + } + + +class TestVMSnapshots(cloudstackTestCase): + _should_be_no_vm_snapshots_err_msg = "There should be no VM snapshots." + _should_only_be_one_vm_snapshot_err_msg = "There should only be one VM snapshot." + _should_only_be_one_root_volume_err_msg = "There should only be one root volume." + _path_should_have_changed_err_msg = "The 'path' in the 'DB' should have changed." + _path_should_not_have_changed_err_msg = "The 'path' in the 'DB' should not have changed." + _should_only_be_one_vdi_err_msg = "There should only be one VDI." + _should_be_three_vdis_err_msg = "There should be three VDIs." + _active_vdis_should_not_be_the_same_err_msg = "The active VDIs should not be the same." + _active_vdis_should_be_the_same_err_msg = "The active VDIs should be the same." + _snapshot_vdis_should_be_the_same_err_msg = "The snapshot VDIs should be the same." + _base_vdis_should_be_the_same_err_msg = "The base VDIs should be the same." + _snapshot_parent_not_correct_err_msg = "Snapshot's parent is not correct." + + @classmethod + def setUpClass(cls): + # Set up API client + testclient = super(TestVMSnapshots, cls).getClsTestClient() + cls.apiClient = testclient.getApiClient() + + cls.testdata = TestData().testdata + + # Set up XenAPI connection + host_ip = "https://" + \ + list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name="XenServer-6.5-1")[0].ipaddress + + cls.xen_session = XenAPI.Session(host_ip) + + xenserver = cls.testdata[TestData.xenServer] + + cls.xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password]) + + # Set up SolidFire connection + cls.sf_client = sf_api.SolidFireAPI(endpoint_dict=cls.testdata[TestData.solidFire]) + + # Get Resources from Cloud Infrastructure + cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId]) + template = get_template(cls.apiClient, cls.zone.id, template_name=cls.testdata[TestData.templateName]) + cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId]) + + # Create test account + cls.account = Account.create( + cls.apiClient, + cls.testdata[TestData.account], + admin=1 + ) + + # Set up connection to make customized API calls + user = User.create( + cls.apiClient, + cls.testdata[TestData.user], + account=cls.account.name, + domainid=cls.domain.id + ) + + url = cls.testdata[TestData.url] + + api_url = "http://" + url + ":8080/client/api" + userkeys = User.registerUserKeys(cls.apiClient, user.id) + + cls.cs_api = SignedAPICall.CloudStack(api_url, userkeys.apikey, userkeys.secretkey) + + primarystorage = cls.testdata[TestData.primaryStorage] + + cls.primary_storage = StoragePool.create( + cls.apiClient, + primarystorage, + scope=primarystorage[TestData.scope], + zoneid=cls.zone.id, + provider=primarystorage[TestData.provider], + tags=primarystorage[TestData.tags], + capacityiops=primarystorage[TestData.capacityIops], + capacitybytes=primarystorage[TestData.capacityBytes], + hypervisor=primarystorage[TestData.hypervisor] + ) + + compute_offering = ServiceOffering.create( + cls.apiClient, + cls.testdata[TestData.computeOffering] + ) + + cls.disk_offering = DiskOffering.create( + cls.apiClient, + cls.testdata[TestData.diskOffering] + ) + + # Create VM and volume for tests + cls.virtual_machine = VirtualMachine.create( + cls.apiClient, + cls.testdata[TestData.virtualMachine], + accountid=cls.account.name, + zoneid=cls.zone.id, + serviceofferingid=compute_offering.id, + templateid=template.id, + domainid=cls.domain.id, + startvm=True + ) + + cls._cleanup = [ + cls.virtual_machine, + compute_offering, + cls.disk_offering, + user, + cls.account + ] + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.apiClient, cls._cleanup) + + cls.primary_storage.delete(cls.apiClient) + + cls._purge_solidfire_volumes() + except Exception as e: + logging.debug("Exception in tearDownClass(cls): %s" % e) + + def setUp(self): + self.cleanup = [] + + def tearDown(self): + try: + cleanup_resources(self.apiClient, self.cleanup) + except Exception as e: + logging.debug("Exception in tearDown(self): %s" % e) + + def test_01_take_VM_snapshot(self): + self.virtual_machine.start(self.apiClient) + + root_volumes = list_volumes(self.apiClient, type="ROOT", listAll="true") + + self._check_list(root_volumes, 1, TestVMSnapshots._should_only_be_one_root_volume_err_msg) + + root_volume = root_volumes[0] + + volume_id = {'volumeid': root_volume.id} + + sf_iscsi_name_result = self.cs_api.getVolumeiScsiName(volume_id) + sf_iscsi_name = sf_iscsi_name_result['apivolumeiscsiname']['volumeiScsiName'] + + self._check_iscsi_name(sf_iscsi_name) + + root_volume_path_1 = self._get_path(volume_id) + + ####################################### + ####################################### + # STEP 1: Take snapshot of running VM # + ####################################### + ####################################### + vm_snapshot = VmSnapshot.create( + self.apiClient, + vmid=self.virtual_machine.id, + snapshotmemory="false", + name="Test Snapshot", + description="Test Snapshot Desc" + ) + + list_vm_snapshots = VmSnapshot.list(self.apiClient, listAll="true") + + self._verify_vm_snapshot(list_vm_snapshots, vm_snapshot) + + root_volume_path_2 = self._get_path(volume_id) + + self.assertEqual( + root_volume_path_1, + root_volume_path_2, + TestVMSnapshots._path_should_not_have_changed_err_msg + ) + + xen_sr = self.xen_session.xenapi.SR.get_by_name_label(sf_iscsi_name)[0] + + xen_vdis = self.xen_session.xenapi.SR.get_VDIs(xen_sr) + + self._check_list(xen_vdis, 3, TestVMSnapshots._should_be_three_vdis_err_msg) + + vdis_after_create = self._get_vdis(xen_vdis) + + vdiSnapshotOf = self.xen_session.xenapi.VDI.get_record(vdis_after_create.snapshot_vdi["snapshot_of"]) + + self.assertEqual( + vdiSnapshotOf["uuid"], + vdis_after_create.active_vdi["uuid"], + TestVMSnapshots._snapshot_parent_not_correct_err_msg + ) + + ####################################### + ####################################### + ### STEP 2: Revert VM to Snapshot ### + ####################################### + ####################################### + self.virtual_machine.stop(self.apiClient) + + VmSnapshot.revertToSnapshot(self.apiClient, vmsnapshotid=vm_snapshot.id) + + list_vm_snapshots = VmSnapshot.list(self.apiClient, listAll="true") + + self._check_list(list_vm_snapshots, 1, TestVMSnapshots._should_only_be_one_vm_snapshot_err_msg) + + root_volume_path_3 = self._get_path(volume_id) + + self.assertNotEqual( + root_volume_path_1, + root_volume_path_3, + TestVMSnapshots._path_should_have_changed_err_msg + ) + + xen_vdis = self.xen_session.xenapi.SR.get_VDIs(xen_sr) + + self._check_list(xen_vdis, 3, TestVMSnapshots._should_be_three_vdis_err_msg) + + vdis_after_revert = self._get_vdis(xen_vdis) + + self.assertNotEqual( + vdis_after_create.active_vdi["uuid"], + vdis_after_revert.active_vdi["uuid"], + TestVMSnapshots._active_vdis_should_not_be_the_same_err_msg + ) + + self.assertEqual( + vdis_after_create.snapshot_vdi["uuid"], + vdis_after_revert.snapshot_vdi["uuid"], + TestVMSnapshots._snapshot_vdis_should_be_the_same_err_msg + ) + + self.assertEqual( + vdis_after_create.base_vdi["uuid"], + vdis_after_revert.base_vdi["uuid"], + TestVMSnapshots._base_vdis_should_be_the_same_err_msg + ) + + ####################################### + ####################################### + ##### STEP 3: Delete VM snapshot ##### + ####################################### + ####################################### + VmSnapshot.deleteVMSnapshot(self.apiClient, vmsnapshotid=vm_snapshot.id) + + list_vm_snapshots = VmSnapshot.list(self.apiClient, listAll="true") + + self.assertEqual( + list_vm_snapshots, + None, + TestVMSnapshots._should_be_no_vm_snapshots_err_msg + ) + + root_volume_path_4 = self._get_path(volume_id) + + self.assertEqual( + root_volume_path_3, + root_volume_path_4, + TestVMSnapshots._path_should_not_have_changed_err_msg + ) + + xen_vdis = self.xen_session.xenapi.SR.get_VDIs(xen_sr) + + self._check_list(xen_vdis, 1, TestVMSnapshots._should_only_be_one_vdi_err_msg) + + vdis_after_delete = self._get_vdis(xen_vdis, True) + + self.assertEqual( + vdis_after_revert.active_vdi["uuid"], + vdis_after_delete.active_vdi["uuid"], + TestVMSnapshots._active_vdis_should_be_the_same_err_msg + ) + + ####################################### + ####################################### + ##### STEP 4: Start VM ##### + ####################################### + ####################################### + self.virtual_machine.start(self.apiClient) + + def test_02_take_VM_snapshot_with_data_disk(self): + self.virtual_machine.start(self.apiClient) + + data_volume = Volume.create( + self.apiClient, + self.testdata[TestData.volume_1], + account=self.account.name, + domainid=self.domain.id, + zoneid=self.zone.id, + diskofferingid=self.disk_offering.id + ) + + self.cleanup = [data_volume] + + self.virtual_machine.attach_volume(self.apiClient, data_volume) + + root_volumes = list_volumes(self.apiClient, type="ROOT", listAll="true") + + self._check_list(root_volumes, 1, TestVMSnapshots._should_only_be_one_root_volume_err_msg) + + root_volume = root_volumes[0] + + root_volume_id = {'volumeid': root_volume.id} + + sf_iscsi_name_result = self.cs_api.getVolumeiScsiName(root_volume_id) + sf_iscsi_root_volume_name = sf_iscsi_name_result['apivolumeiscsiname']['volumeiScsiName'] + + self._check_iscsi_name(sf_iscsi_root_volume_name) + + root_volume_path_1 = self._get_path(root_volume_id) + + data_volumes = list_volumes(self.apiClient, type="DATADISK", listAll="true") + + self._check_list(data_volumes, 1, "There should only be one data volume.") + + data_volume = data_volumes[0] + + data_volume_id = {'volumeid': data_volume.id} + + sf_iscsi_name_result = self.cs_api.getVolumeiScsiName(data_volume_id) + sf_iscsi_data_volume_name = sf_iscsi_name_result['apivolumeiscsiname']['volumeiScsiName'] + + self._check_iscsi_name(sf_iscsi_data_volume_name) + + data_volume_path_1 = self._get_path(data_volume_id) + + ####################################### + ####################################### + # STEP 1: Take snapshot of running VM # + ####################################### + ####################################### + vm_snapshot = VmSnapshot.create( + self.apiClient, + vmid=self.virtual_machine.id, + snapshotmemory="false", + name="Test Snapshot", + description="Test Snapshot Desc" + ) + + list_vm_snapshots = VmSnapshot.list(self.apiClient, listAll="true") + + self._verify_vm_snapshot(list_vm_snapshots, vm_snapshot) + + root_volume_path_2 = self._get_path(root_volume_id) + + self.assertEqual( + root_volume_path_1, + root_volume_path_2, + TestVMSnapshots._path_should_not_have_changed_err_msg + ) + + data_volume_path_2 = self._get_path(data_volume_id) + + self.assertEqual( + data_volume_path_1, + data_volume_path_2, + TestVMSnapshots._path_should_not_have_changed_err_msg + ) + + root_volume_xen_sr = self.xen_session.xenapi.SR.get_by_name_label(sf_iscsi_root_volume_name)[0] + + root_volume_xen_vdis = self.xen_session.xenapi.SR.get_VDIs(root_volume_xen_sr) + + self._check_list(root_volume_xen_vdis, 3, TestVMSnapshots._should_be_three_vdis_err_msg) + + root_volume_vdis_after_create = self._get_vdis(root_volume_xen_vdis) + + vdiSnapshotOf = self.xen_session.xenapi.VDI.get_record(root_volume_vdis_after_create.snapshot_vdi["snapshot_of"]) + + self.assertEqual( + vdiSnapshotOf["uuid"], + root_volume_vdis_after_create.active_vdi["uuid"], + TestVMSnapshots._snapshot_parent_not_correct_err_msg + ) + + data_volume_xen_sr = self.xen_session.xenapi.SR.get_by_name_label(sf_iscsi_data_volume_name)[0] + + data_volume_xen_vdis = self.xen_session.xenapi.SR.get_VDIs(data_volume_xen_sr) + + self._check_list(data_volume_xen_vdis, 3, TestVMSnapshots._should_be_three_vdis_err_msg) + + data_volume_vdis_after_create = self._get_vdis(data_volume_xen_vdis) + + vdiSnapshotOf = self.xen_session.xenapi.VDI.get_record(data_volume_vdis_after_create.snapshot_vdi["snapshot_of"]) + + self.assertEqual( + vdiSnapshotOf["uuid"], + data_volume_vdis_after_create.active_vdi["uuid"], + TestVMSnapshots._snapshot_parent_not_correct_err_msg + ) + + ####################################### + ####################################### + ### STEP 2: Revert VM to Snapshot ### + ####################################### + ####################################### + self.virtual_machine.stop(self.apiClient) + + VmSnapshot.revertToSnapshot(self.apiClient, vmsnapshotid=vm_snapshot.id) + + list_vm_snapshots = VmSnapshot.list(self.apiClient, listAll="true") + + self._check_list(list_vm_snapshots, 1, TestVMSnapshots._should_only_be_one_vm_snapshot_err_msg) + + root_volume_path_3 = self._get_path(root_volume_id) + + self.assertNotEqual( + root_volume_path_1, + root_volume_path_3, + TestVMSnapshots._path_should_have_changed_err_msg + ) + + root_volume_xen_vdis = self.xen_session.xenapi.SR.get_VDIs(root_volume_xen_sr) + + self._check_list(root_volume_xen_vdis, 3, TestVMSnapshots._should_be_three_vdis_err_msg) + + root_volume_vdis_after_revert = self._get_vdis(root_volume_xen_vdis) + + self.assertNotEqual( + root_volume_vdis_after_create.active_vdi["uuid"], + root_volume_vdis_after_revert.active_vdi["uuid"], + TestVMSnapshots._active_vdis_should_not_be_the_same_err_msg + ) + + self.assertEqual( + root_volume_vdis_after_create.snapshot_vdi["uuid"], + root_volume_vdis_after_revert.snapshot_vdi["uuid"], + TestVMSnapshots._snapshot_vdis_should_be_the_same_err_msg + ) + + self.assertEqual( + root_volume_vdis_after_create.base_vdi["uuid"], + root_volume_vdis_after_revert.base_vdi["uuid"], + TestVMSnapshots._base_vdis_should_be_the_same_err_msg + ) + + data_volume_path_3 = self._get_path(data_volume_id) + + self.assertNotEqual( + data_volume_path_1, + data_volume_path_3, + TestVMSnapshots._path_should_have_changed_err_msg + ) + + data_volume_xen_vdis = self.xen_session.xenapi.SR.get_VDIs(data_volume_xen_sr) + + self._check_list(data_volume_xen_vdis, 3, TestVMSnapshots._should_be_three_vdis_err_msg) + + data_volume_vdis_after_revert = self._get_vdis(data_volume_xen_vdis) + + self.assertNotEqual( + data_volume_vdis_after_create.active_vdi["uuid"], + data_volume_vdis_after_revert.active_vdi["uuid"], + TestVMSnapshots._active_vdis_should_not_be_the_same_err_msg + ) + + self.assertEqual( + data_volume_vdis_after_create.snapshot_vdi["uuid"], + data_volume_vdis_after_revert.snapshot_vdi["uuid"], + TestVMSnapshots._snapshot_vdis_should_be_the_same_err_msg + ) + + self.assertEqual( + data_volume_vdis_after_create.base_vdi["uuid"], + data_volume_vdis_after_revert.base_vdi["uuid"], + TestVMSnapshots._base_vdis_should_be_the_same_err_msg + ) + + ####################################### + ####################################### + ##### STEP 3: Delete VM snapshot ##### + ####################################### + ####################################### + VmSnapshot.deleteVMSnapshot(self.apiClient, vmsnapshotid=vm_snapshot.id) + + list_vm_snapshots = VmSnapshot.list(self.apiClient, listAll="true") + + self.assertEqual( + list_vm_snapshots, + None, + TestVMSnapshots._should_be_no_vm_snapshots_err_msg + ) + + root_volume_path_4 = self._get_path(root_volume_id) + + self.assertEqual( + root_volume_path_3, + root_volume_path_4, + TestVMSnapshots._path_should_not_have_changed_err_msg + ) + + root_volume_xen_vdis = self.xen_session.xenapi.SR.get_VDIs(root_volume_xen_sr) + + self._check_list(root_volume_xen_vdis, 1, TestVMSnapshots._should_only_be_one_vdi_err_msg) + + root_volume_vdis_after_delete = self._get_vdis(root_volume_xen_vdis, True) + + self.assertEqual( + root_volume_vdis_after_revert.active_vdi["uuid"], + root_volume_vdis_after_delete.active_vdi["uuid"], + TestVMSnapshots._active_vdis_should_be_the_same_err_msg + ) + + data_volume_path_4 = self._get_path(data_volume_id) + + self.assertEqual( + data_volume_path_3, + data_volume_path_4, + TestVMSnapshots._path_should_not_have_changed_err_msg + ) + + data_volume_xen_vdis = self.xen_session.xenapi.SR.get_VDIs(data_volume_xen_sr) + + self._check_list(data_volume_xen_vdis, 1, TestVMSnapshots._should_only_be_one_vdi_err_msg) + + data_volume_vdis_after_delete = self._get_vdis(data_volume_xen_vdis, True) + + self.assertEqual( + data_volume_vdis_after_revert.active_vdi["uuid"], + data_volume_vdis_after_delete.active_vdi["uuid"], + TestVMSnapshots._active_vdis_should_be_the_same_err_msg + ) + + ####################################### + ####################################### + ##### STEP 4: Start VM ##### + ####################################### + ####################################### + self.virtual_machine.detach_volume(self.apiClient, data_volume) + + self.virtual_machine.start(self.apiClient) + + def _get_path(self, volume_id): + path_result = self.cs_api.getPathForVolume(volume_id) + + return path_result['apipathforvolume']['path'] + + def _verify_vm_snapshot(self, list_vm_snapshots, vm_snapshot): + self._check_list(list_vm_snapshots, 1, TestVMSnapshots._should_only_be_one_vm_snapshot_err_msg) + + vm_snapshot_from_list = list_vm_snapshots[0] + + self.assertEqual( + vm_snapshot.id, + vm_snapshot_from_list.id, + "There is a problem with the VM snapshot ID." + ) + + self.assertEqual( + vm_snapshot.virtualmachineid, + self.virtual_machine.id, + "The ID of the snapshot's virtual machine does not match the expected virtual machine." + ) + + self.assertEqual( + vm_snapshot.state, + "Ready", + "The snapshot is not in the 'Ready' state." + ) + + def _check_iscsi_name(self, sf_iscsi_name): + self.assertEqual( + sf_iscsi_name[0], + "/", + "The iSCSI name needs to start with a forward slash." + ) + + def _check_list(self, in_list, expected_size_of_list, err_msg): + self.assertEqual( + isinstance(in_list, list), + True, + "'in_list' is not a list." + ) + + self.assertEqual( + len(in_list), + expected_size_of_list, + err_msg + ) + + def _get_vdis(self, xen_vdis, only_active_expected=False): + expected_number_of_vdis = 1 if only_active_expected else 3 + + self.assertEqual( + len(xen_vdis), + expected_number_of_vdis, + "The list had an unexpected number of items in it." + ) + + active_vdi = None + snapshot_vdi = None + base_vdi = None + + for temp_vdi in xen_vdis: + temp = self.xen_session.xenapi.VDI.get_record(temp_vdi) + + if temp["name_label"] == "base copy": + base_vdi = temp + else: + if temp["is_a_snapshot"] == True: + snapshot_vdi = temp + else: + active_vdi = temp + + self.assertNotEqual( + active_vdi, + None, + "The active VDI could not be located." + ) + + if only_active_expected: + self.assertEqual( + snapshot_vdi, + None, + "The snapshot VDI should not be present." + ) + + self.assertEqual( + base_vdi, + None, + "The base VDI should not be present." + ) + else: + self.assertNotEqual( + snapshot_vdi, + None, + "The snapshot VDI could not be located." + ) + + self.assertNotEqual( + base_vdi, + None, + "The base VDI could not be located." + ) + + class VdiCollection(object): + pass + + vdis = VdiCollection() + + vdis.active_vdi = active_vdi + vdis.snapshot_vdi = snapshot_vdi + vdis.base_vdi = base_vdi + + return vdis + + @classmethod + def _purge_solidfire_volumes(cls): + deleted_volumes = cls.sf_client.list_deleted_volumes() + + for deleted_volume in deleted_volumes: + cls.sf_client.purge_deleted_volume(deleted_volume['volumeID']) + diff --git a/test/integration/plugins/solidfire/TestVolumes.py b/test/integration/plugins/solidfire/TestVolumes.py new file mode 100644 index 0000000000..ed7d42ae24 --- /dev/null +++ b/test/integration/plugins/solidfire/TestVolumes.py @@ -0,0 +1,1676 @@ +# 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. + +import logging +import random +import SignedAPICall +import XenAPI + +# All tests inherit from cloudstackTestCase +from marvin.cloudstackTestCase import cloudstackTestCase + +from nose.plugins.attrib import attr + +# Import Integration Libraries + +# base - contains all resources as entities and defines create, delete, list operations on them +from marvin.lib.base import Account, DiskOffering, ServiceOffering, StoragePool, User, VirtualMachine, Volume + +# common - commonly used methods for all tests are listed here +from marvin.lib.common import get_domain, get_template, get_zone, list_clusters, list_hosts, list_virtual_machines, \ + list_volumes + +# utils - utility classes for common cleanup, external library wrappers, etc. +from marvin.lib.utils import cleanup_resources + +from solidfire import solidfire_element_api as sf_api + +# on April 14, 2016: Ran 11 tests in 2494.043s with three hosts (resign = True) +# on April 14, 2016: Ran 11 tests in 2033.516s with three hosts (resign = False) + +# on May 2, 2016: Ran 11 tests in 2352.461s with two hosts (resign = True) +# on May 2, 2016: Ran 11 tests in 1982.066s with two hosts (resign = False) + + +class TestData(): + account = "account" + capacityBytes = "capacitybytes" + capacityIops = "capacityiops" + clusterId = "clusterId" + computeOffering = "computeoffering" + diskName = "diskname" + diskOffering = "diskoffering" + domainId = "domainId" + hypervisor = "hypervisor" + login = "login" + mvip = "mvip" + password = "password" + port = "port" + primaryStorage = "primarystorage" + provider = "provider" + scope = "scope" + solidFire = "solidfire" + storageTag = "SolidFire_SAN_1" + tags = "tags" + templateCacheName = "centos56-x86-64-xen" + templateName = "templatename" + testAccount = "testaccount" + url = "url" + user = "user" + username = "username" + virtualMachine = "virtualmachine" + virtualMachine2 = "virtualmachine2" + volume_1 = "volume_1" + volume_2 = "volume_2" + xenServer = "xenserver" + zoneId = "zoneId" + + def __init__(self): + self.testdata = { + TestData.solidFire: { + TestData.mvip: "192.168.139.112", + TestData.login: "admin", + TestData.password: "admin", + TestData.port: 443, + TestData.url: "https://192.168.139.112:443" + }, + TestData.xenServer: { + TestData.username: "root", + TestData.password: "solidfire" + }, + TestData.account: { + "email": "test@test.com", + "firstname": "John", + "lastname": "Doe", + "username": "test", + "password": "test" + }, + TestData.testAccount: { + "email": "test2@test2.com", + "firstname": "Jane", + "lastname": "Doe", + "username": "test2", + "password": "test" + }, + TestData.user: { + "email": "user@test.com", + "firstname": "Jane", + "lastname": "Doe", + "username": "testuser", + "password": "password" + }, + TestData.primaryStorage: { + "name": "SolidFire-%d" % random.randint(0, 100), + TestData.scope: "ZONE", + "url": "MVIP=192.168.139.112;SVIP=10.10.8.112;" + + "clusterAdminUsername=admin;clusterAdminPassword=admin;" + + "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" + + "clusterDefaultBurstIopsPercentOfMaxIops=1.5;", + TestData.provider: "SolidFire", + TestData.tags: TestData.storageTag, + TestData.capacityIops: 4500000, + TestData.capacityBytes: 2251799813685248, + TestData.hypervisor: "Any" + }, + TestData.virtualMachine: { + "name": "TestVM", + "displayname": "Test VM" + }, + TestData.virtualMachine2: { + "name": "TestVM2", + "displayname": "Test VM 2" + }, + TestData.computeOffering: { + "name": "SF_CO_1", + "displaytext": "SF_CO_1 (Min IOPS = 10,000; Max IOPS = 15,000)", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 128, + "storagetype": "shared", + "customizediops": False, + "miniops": "10000", + "maxiops": "15000", + "hypervisorsnapshotreserve": 200, + "tags": "SolidFire_SAN_1" + }, + TestData.diskOffering: { + "name": "SF_DO_1", + "displaytext": "SF_DO_1 (Min IOPS = 300; Max IOPS = 500)", + "disksize": 128, + "customizediops": False, + "miniops": 300, + "maxiops": 500, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "testdiskofferings": { + "customiopsdo": { + "name": "SF_Custom_Iops_DO", + "displaytext": "Customized Iops DO", + "disksize": 128, + "customizediops": True, + "miniops": 500, + "maxiops": 1000, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "customsizedo": { + "name": "SF_Custom_Size_DO", + "displaytext": "Customized Size DO", + "disksize": 175, + "customizediops": False, + "miniops": 500, + "maxiops": 1000, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "customsizeandiopsdo": { + "name": "SF_Custom_Iops_Size_DO", + "displaytext": "Customized Size and Iops DO", + "disksize": 200, + "customizediops": True, + "miniops": 400, + "maxiops": 800, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "newiopsdo": { + "name": "SF_New_Iops_DO", + "displaytext": "New Iops (min=350, max = 700)", + "disksize": 128, + "miniops": 350, + "maxiops": 700, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "newsizedo": { + "name": "SF_New_Size_DO", + "displaytext": "New Size: 175", + "disksize": 175, + "miniops": 400, + "maxiops": 800, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + }, + "newsizeandiopsdo": { + "name": "SF_New_Size_Iops_DO", + "displaytext": "New Size and Iops", + "disksize": 200, + "miniops": 200, + "maxiops": 400, + "hypervisorsnapshotreserve": 200, + TestData.tags: TestData.storageTag, + "storagetype": "shared" + } + }, + TestData.volume_1: { + TestData.diskName: "test-volume", + }, + TestData.volume_2: { + TestData.diskName: "test-volume-2", + }, + TestData.templateName: "CentOS 5.6(64-bit) no GUI (XenServer)", + TestData.zoneId: 1, + TestData.clusterId: 1, + TestData.domainId: 1, + TestData.url: "192.168.129.50" + } + + +class TestVolumes(cloudstackTestCase): + _should_only_be_one_vm_in_list_err_msg = "There should only be one VM in this list." + _should_only_be_one_volume_in_list_err_msg = "There should only be one volume in this list." + _sf_account_id_should_be_non_zero_int_err_msg = "The SolidFire account ID should be a non-zero integer." + _vag_id_should_be_non_zero_int_err_msg = "The SolidFire VAG ID should be a non-zero integer." + _volume_size_should_be_non_zero_int_err_msg = "The SolidFire volume size should be a non-zero integer." + _volume_vm_id_and_vm_id_do_not_match_err_msg = "The volume's VM ID and the VM's ID do not match." + _vm_not_in_running_state_err_msg = "The VM is not in the 'Running' state." + _vm_not_in_stopped_state_err_msg = "The VM is not in the 'Stopped' state." + _sr_not_shared_err_msg = "The SR is not shared." + _volume_response_should_not_be_zero_err_msg = "The length of the response for the SolidFire-volume query should not be zero." + _list_should_be_empty = "The list should be empty." + _volume_should_not_be_in_a_vag = "The volume should not be in a volume access group." + + @classmethod + def setUpClass(cls): + # Set up API client + testclient = super(TestVolumes, cls).getClsTestClient() + cls.apiClient = testclient.getApiClient() + cls.dbConnection = testclient.getDbConnection() + + cls.testdata = TestData().testdata + + cls.supports_resign = True + + cls._set_supports_resign() + + # Set up xenAPI connection + host_ip = "https://" + \ + list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name="XenServer-6.5-1")[0].ipaddress + + # Set up XenAPI connection + cls.xen_session = XenAPI.Session(host_ip) + + xenserver = cls.testdata[TestData.xenServer] + + cls.xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password]) + + # Set up SolidFire connection + cls.sf_client = sf_api.SolidFireAPI(endpoint_dict=cls.testdata[TestData.solidFire]) + + # Get Resources from Cloud Infrastructure + cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId]) + cls.cluster = list_clusters(cls.apiClient)[0] + cls.template = get_template(cls.apiClient, cls.zone.id, template_name=cls.testdata[TestData.templateName]) + cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId]) + + # Create test account + cls.account = Account.create( + cls.apiClient, + cls.testdata["account"], + admin=1 + ) + + # Set up connection to make customized API calls + cls.user = User.create( + cls.apiClient, + cls.testdata["user"], + account=cls.account.name, + domainid=cls.domain.id + ) + + url = cls.testdata[TestData.url] + + api_url = "http://" + url + ":8080/client/api" + userkeys = User.registerUserKeys(cls.apiClient, cls.user.id) + + cls.cs_api = SignedAPICall.CloudStack(api_url, userkeys.apikey, userkeys.secretkey) + + primarystorage = cls.testdata[TestData.primaryStorage] + + cls.primary_storage = StoragePool.create( + cls.apiClient, + primarystorage, + scope=primarystorage[TestData.scope], + zoneid=cls.zone.id, + provider=primarystorage[TestData.provider], + tags=primarystorage[TestData.tags], + capacityiops=primarystorage[TestData.capacityIops], + capacitybytes=primarystorage[TestData.capacityBytes], + hypervisor=primarystorage[TestData.hypervisor] + ) + + cls.compute_offering = ServiceOffering.create( + cls.apiClient, + cls.testdata[TestData.computeOffering] + ) + + cls.disk_offering = DiskOffering.create( + cls.apiClient, + cls.testdata[TestData.diskOffering] + ) + + # Create VM and volume for tests + cls.virtual_machine = VirtualMachine.create( + cls.apiClient, + cls.testdata[TestData.virtualMachine], + accountid=cls.account.name, + zoneid=cls.zone.id, + serviceofferingid=cls.compute_offering.id, + templateid=cls.template.id, + domainid=cls.domain.id, + startvm=True + ) + + cls.volume = Volume.create( + cls.apiClient, + cls.testdata[TestData.volume_1], + account=cls.account.name, + domainid=cls.domain.id, + zoneid=cls.zone.id, + diskofferingid=cls.disk_offering.id + ) + + # Resources that are to be destroyed + cls._cleanup = [ + cls.volume, + cls.virtual_machine, + cls.compute_offering, + cls.disk_offering, + cls.user, + cls.account + ] + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.apiClient, cls._cleanup) + + cls.primary_storage.delete(cls.apiClient) + + cls._purge_solidfire_volumes() + except Exception as e: + logging.debug("Exception in tearDownClass(cls): %s" % e) + + def setUp(self): + self.attached = False + self.cleanup = [] + + def tearDown(self): + if self.attached: + self.virtual_machine.detach_volume(self.apiClient, self.volume) + + cleanup_resources(self.apiClient, self.cleanup) + + @attr(hypervisor='XenServer') + def test_00_check_template_cache(self): + if self.supports_resign == False: + return + + sf_volumes = self._get_sf_volumes() + + sf_volume = self._check_and_get_sf_volume(sf_volumes, TestData.templateCacheName) + + self.assertEqual( + len(sf_volume['volumeAccessGroups']), + 0, + "The volume should not be in a VAG." + ) + + sf_account_id = sf_volume["accountID"] + + sf_account = self.sf_client.get_account_by_id(sf_account_id)["account"] + + sf_account_name = sf_account["username"] + + self.assertEqual( + sf_account_name.endswith("_1"), + True, + "The template cache volume's account does not end with '_1'." + ) + + @attr(hypervisor='XenServer') + def test_01_attach_new_volume_to_stopped_VM(self): + '''Attach a volume to a stopped virtual machine, then start VM''' + + self.virtual_machine.stop(self.apiClient) + + new_volume = Volume.create( + self.apiClient, + self.testdata[TestData.volume_2], + account=self.account.name, + domainid=self.domain.id, + zoneid=self.zone.id, + diskofferingid=self.disk_offering.id + ) + + self.cleanup.append(new_volume) + + self._check_and_get_cs_volume(new_volume.id, self.testdata[TestData.volume_2][TestData.diskName]) + + new_volume = self.virtual_machine.attach_volume( + self.apiClient, + new_volume + ) + + newvolume = self._check_and_get_cs_volume(new_volume.id, self.testdata[TestData.volume_2][TestData.diskName]) + + self.virtual_machine.start(self.apiClient) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + newvolume.virtualmachineid, + vm.id, + TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg + ) + + self.assertEqual( + vm.state.lower(), + "running", + TestVolumes._vm_not_in_running_state_err_msg + ) + + sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id) + + sf_volume_size = self._get_volume_size_with_hsr(new_volume) + + sf_vag_id = self._get_vag_id() + + sf_iscsi_name = self._get_iqn(new_volume) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, newvolume.name) + + self._check_size_and_iops(sf_volume, newvolume, sf_volume_size) + + self._check_vag(sf_volume, sf_vag_id) + + self._check_xen_sr(sf_iscsi_name) + + # Detach volume + new_volume = self.virtual_machine.detach_volume( + self.apiClient, + new_volume + ) + + @attr(hypervisor='XenServer') + def test_02_attach_detach_attach_volume(self): + '''Attach, detach, and attach volume to a running VM''' + + self.virtual_machine.start(self.apiClient) + + sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id) + + sf_vag_id = self._get_vag_id() + + self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + ####################################### + ####################################### + # STEP 1: Attach volume to running VM # + ####################################### + ####################################### + + self.volume = self.virtual_machine.attach_volume( + self.apiClient, + self.volume + ) + + self.attached = True + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + vm.id, + TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg + ) + + self.assertEqual( + vm.state.lower(), + 'running', + TestVolumes._vm_not_in_running_state_err_msg + ) + + sf_iscsi_name = self._get_iqn(self.volume) + + sf_volume_size = self._get_volume_size_with_hsr(self.volume) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self._check_size_and_iops(sf_volume, vol, sf_volume_size) + + self._check_vag(sf_volume, sf_vag_id) + + self._check_xen_sr(sf_iscsi_name) + + ######################################### + ######################################### + # STEP 2: Detach volume from running VM # + ######################################### + ######################################### + + self.volume = self.virtual_machine.detach_volume( + self.apiClient, + self.volume + ) + + self.attached = False + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + None, + "The volume should not be attached to a VM." + ) + + self.assertEqual( + vm.state.lower(), + 'running', + str(vm.state) + ) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self.assertEqual( + len(sf_volume['volumeAccessGroups']), + 0, + "The volume should not be in a VAG." + ) + + self._check_xen_sr(sf_iscsi_name, False) + + ####################################### + ####################################### + # STEP 3: Attach volume to running VM # + ####################################### + ####################################### + + self.volume = self.virtual_machine.attach_volume( + self.apiClient, + self.volume + ) + + self.attached = True + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + vm.id, + TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg + ) + + self.assertEqual( + vm.state.lower(), + 'running', + TestVolumes._vm_not_in_running_state_err_msg + ) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self._check_vag(sf_volume, sf_vag_id) + + self._check_xen_sr(sf_iscsi_name) + + @attr(hypervisor='XenServer') + def test_03_attached_volume_reboot_VM(self): + '''Attach volume to running VM, then reboot.''' + + self.virtual_machine.start(self.apiClient) + + sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id) + + sf_vag_id = self._get_vag_id() + + self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + ####################################### + ####################################### + # STEP 1: Attach volume to running VM # + ####################################### + ####################################### + + self.volume = self.virtual_machine.attach_volume( + self.apiClient, + self.volume + ) + + self.attached = True + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + vm.id, + TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg + ) + + self.assertEqual( + vm.state.lower(), + 'running', + TestVolumes._vm_not_in_running_state_err_msg + ) + + sf_iscsi_name = self._get_iqn(self.volume) + + sf_volume_size = self._get_volume_size_with_hsr(self.volume) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self._check_size_and_iops(sf_volume, vol, sf_volume_size) + + self._check_vag(sf_volume, sf_vag_id) + + self._check_xen_sr(sf_iscsi_name) + + ####################################### + ####################################### + # STEP 2: Reboot VM with attached vol # + ####################################### + ####################################### + self.virtual_machine.reboot(self.apiClient) + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + sf_iscsi_name = self._get_iqn(self.volume) + + sf_volume_size = self._get_volume_size_with_hsr(self.volume) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self._check_size_and_iops(sf_volume, vol, sf_volume_size) + + self._check_vag(sf_volume, sf_vag_id) + + self._check_xen_sr(sf_iscsi_name) + + @attr(hypervisor='XenServer') + def test_04_detach_volume_reboot(self): + '''Detach volume from a running VM, then reboot.''' + + self.virtual_machine.start(self.apiClient) + + sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id) + + sf_vag_id = self._get_vag_id() + + self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + ####################################### + ####################################### + # STEP 1: Attach volume to running VM # + ####################################### + ####################################### + + self.volume = self.virtual_machine.attach_volume( + self.apiClient, + self.volume + ) + + self.attached = True + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + vm.id, + TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg + ) + + self.assertEqual( + vm.state.lower(), + 'running', + TestVolumes._vm_not_in_running_state_err_msg + ) + + sf_iscsi_name = self._get_iqn(self.volume) + + sf_volume_size = self._get_volume_size_with_hsr(self.volume) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self._check_size_and_iops(sf_volume, vol, sf_volume_size) + + self._check_vag(sf_volume, sf_vag_id) + + self._check_xen_sr(sf_iscsi_name) + + ######################################### + ######################################### + # STEP 2: Detach volume from running VM # + ######################################### + ######################################### + + self.volume = self.virtual_machine.detach_volume( + self.apiClient, + self.volume + ) + + self.attached = False + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + None, + "The volume should not be attached to a VM." + ) + + self.assertEqual( + vm.state.lower(), + 'running', + TestVolumes._vm_not_in_running_state_err_msg + ) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self.assertEqual( + len(sf_volume['volumeAccessGroups']), + 0, + TestVolumes._volume_should_not_be_in_a_vag + ) + + self._check_xen_sr(sf_iscsi_name, False) + + ####################################### + ####################################### + # STEP 3: Reboot VM with detached vol # + ####################################### + ####################################### + + self.virtual_machine.reboot(self.apiClient) + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self.assertEqual( + len(sf_volume['volumeAccessGroups']), + 0, + TestVolumes._volume_should_not_be_in_a_vag + ) + + self._check_xen_sr(sf_iscsi_name, False) + + @attr(hypervisor='XenServer') + def test_05_detach_vol_stopped_VM_start(self): + '''Detach volume from a stopped VM, then start.''' + + self.virtual_machine.start(self.apiClient) + + sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id) + + sf_vag_id = self._get_vag_id() + + self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + ####################################### + ####################################### + # STEP 1: Attach volume to running VM # + ####################################### + ####################################### + + self.volume = self.virtual_machine.attach_volume( + self.apiClient, + self.volume + ) + + self.attached = True + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + vm.id, + TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg + ) + + self.assertEqual( + vm.state.lower(), + 'running', + TestVolumes._vm_not_in_running_state_err_msg + ) + + sf_iscsi_name = self._get_iqn(self.volume) + + sf_volume_size = self._get_volume_size_with_hsr(self.volume) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self._check_size_and_iops(sf_volume, vol, sf_volume_size) + + self._check_vag(sf_volume, sf_vag_id) + + self._check_xen_sr(sf_iscsi_name) + + ######################################### + ######################################### + # STEP 2: Detach volume from stopped VM # + ######################################### + ######################################### + + self.virtual_machine.stop(self.apiClient) + + self.volume = self.virtual_machine.detach_volume( + self.apiClient, + self.volume + ) + + self.attached = False + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + None, + "The volume should not be attached to a VM." + ) + + self.assertEqual( + vm.state.lower(), + 'stopped', + TestVolumes._vm_not_in_stopped_state_err_msg + ) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self.assertEqual( + len(sf_volume['volumeAccessGroups']), + 0, + TestVolumes._volume_should_not_be_in_a_vag + ) + + self._check_xen_sr(sf_iscsi_name, False) + + ####################################### + ####################################### + # STEP 3: Start VM with detached vol # + ####################################### + ####################################### + + self.virtual_machine.start(self.apiClient) + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self.assertEqual( + len(sf_volume['volumeAccessGroups']), + 0, + TestVolumes._volume_should_not_be_in_a_vag + ) + + self._check_xen_sr(sf_iscsi_name, False) + + @attr(hypervisor='XenServer') + def test_06_attach_volume_to_stopped_VM(self): + '''Attach a volume to a stopped virtual machine, then start VM''' + + self.virtual_machine.stop(self.apiClient) + + sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id) + + sf_vag_id = self._get_vag_id() + + self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + ####################################### + ####################################### + # STEP 1: Attach volume to stopped VM # + ####################################### + ####################################### + + self.volume = self.virtual_machine.attach_volume( + self.apiClient, + self.volume + ) + + self.attached = True + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + vm.id, + TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg + ) + + self.assertEqual( + vm.state.lower(), + 'stopped', + TestVolumes._vm_not_in_stopped_state_err_msg + ) + + sf_iscsi_name = self._get_iqn(self.volume) + + sf_volume_size = self._get_volume_size_with_hsr(self.volume) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self._check_size_and_iops(sf_volume, vol, sf_volume_size) + + self._check_vag(sf_volume, sf_vag_id) + + self._check_xen_sr(sf_iscsi_name) + + self.virtual_machine.start(self.apiClient) + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + vm.id, + TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg + ) + + self.assertEqual( + vm.state.lower(), + 'running', + TestVolumes._vm_not_in_running_state_err_msg + ) + + sf_iscsi_name = self._get_iqn(self.volume) + + sf_volume_size = self._get_volume_size_with_hsr(self.volume) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self._check_size_and_iops(sf_volume, vol, sf_volume_size) + + self._check_vag(sf_volume, sf_vag_id) + + self._check_xen_sr(sf_iscsi_name) + + @attr(hypervisor='XenServer') + def test_07_destroy_expunge_VM_with_volume(self): + '''Destroy and expunge VM with attached volume''' + + ####################################### + ####################################### + # STEP 1: Create VM and attach volume # + ####################################### + ####################################### + + test_virtual_machine = VirtualMachine.create( + self.apiClient, + self.testdata[TestData.virtualMachine2], + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=self.template.id, + domainid=self.domain.id, + startvm=True + ) + + self.volume = test_virtual_machine.attach_volume( + self.apiClient, + self.volume + ) + + self.attached = True + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(test_virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + vm.id, + TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg + ) + + self.assertEqual( + vm.state.lower(), + 'running', + TestVolumes._vm_not_in_running_state_err_msg + ) + + sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id) + + sf_volume_size = self._get_volume_size_with_hsr(self.volume) + + sf_vag_id = self._get_vag_id() + + sf_iscsi_name = self._get_iqn(self.volume) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self._check_size_and_iops(sf_volume, vol, sf_volume_size) + + self._check_vag(sf_volume, sf_vag_id) + + self._check_xen_sr(sf_iscsi_name) + + ####################################### + ####################################### + # STEP 2: Destroy and Expunge VM # + ####################################### + ####################################### + + test_virtual_machine.delete(self.apiClient, True) + + self.attached = False + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + self.assertEqual( + vol.virtualmachineid, + None, + "Check if attached to virtual machine" + ) + + self.assertEqual( + vol.vmname, + None, + "Check if VM was expunged" + ) + + list_virtual_machine_response = list_virtual_machines( + self.apiClient, + id=test_virtual_machine.id + ) + + self.assertEqual( + list_virtual_machine_response, + None, + "Check if VM was actually expunged" + ) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self._check_size_and_iops(sf_volume, vol, sf_volume_size) + + self.assertEqual( + len(sf_volume['volumeAccessGroups']), + 0, + TestVolumes._volume_should_not_be_in_a_vag + ) + + self._check_xen_sr(sf_iscsi_name, False) + + @attr(hypervisor='XenServer') + def test_08_delete_volume_was_attached(self): + '''Delete volume that was attached to a VM and is detached now''' + + self.virtual_machine.start(self.apiClient) + + ####################################### + ####################################### + # STEP 1: Create vol and attach to VM # + ####################################### + ####################################### + + new_volume = Volume.create( + self.apiClient, + self.testdata[TestData.volume_2], + account=self.account.name, + domainid=self.domain.id, + zoneid=self.zone.id, + diskofferingid=self.disk_offering.id + ) + + volume_to_delete_later = new_volume + + self._check_and_get_cs_volume(new_volume.id, self.testdata[TestData.volume_2][TestData.diskName]) + + new_volume = self.virtual_machine.attach_volume( + self.apiClient, + new_volume + ) + + vol = self._check_and_get_cs_volume(new_volume.id, self.testdata[TestData.volume_2][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + vm.id, + "Check if attached to virtual machine" + ) + + self.assertEqual( + vm.state.lower(), + 'running', + str(vm.state) + ) + + sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id) + + sf_volume_size = self._get_volume_size_with_hsr(new_volume) + + sf_vag_id = self._get_vag_id() + + sf_iscsi_name = self._get_iqn(new_volume) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self._check_size_and_iops(sf_volume, vol, sf_volume_size) + + self._check_vag(sf_volume, sf_vag_id) + + self._check_xen_sr(sf_iscsi_name) + + ####################################### + ####################################### + # STEP 2: Detach and delete volume # + ####################################### + ####################################### + + new_volume = self.virtual_machine.detach_volume( + self.apiClient, + new_volume + ) + + vol = self._check_and_get_cs_volume(new_volume.id, self.testdata[TestData.volume_2][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + None, + "Check if attached to virtual machine" + ) + + self.assertEqual( + vm.state.lower(), + 'running', + str(vm.state) + ) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self._check_size_and_iops(sf_volume, vol, sf_volume_size) + + self.assertEqual( + len(sf_volume['volumeAccessGroups']), + 0, + TestVolumes._volume_should_not_be_in_a_vag + ) + + self._check_xen_sr(sf_iscsi_name, False) + + volume_to_delete_later.delete(self.apiClient) + + list_volumes_response = list_volumes( + self.apiClient, + id=new_volume.id + ) + + self.assertEqual( + list_volumes_response, + None, + "Check volume was deleted" + ) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + self._check_and_get_sf_volume(sf_volumes, vol.name, False) + + @attr(hypervisor='XenServer') + def test_09_attach_volumes_multiple_accounts(self): + '''Attach a data disk to a VM in one account and attach another data disk to a VM in another account''' + + self.virtual_machine.start(self.apiClient) + + ####################################### + ####################################### + # STEP 1: Create account, VM, and vol # + ####################################### + ####################################### + + test_account = Account.create( + self.apiClient, + self.testdata[TestData.testAccount], + admin=1 + ) + + self.cleanup.append(test_account) + + test_virtual_machine = VirtualMachine.create( + self.apiClient, + self.testdata[TestData.virtualMachine2], + accountid=test_account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=self.template.id, + domainid=self.domain.id, + startvm=True + ) + + test_volume = Volume.create( + self.apiClient, + self.testdata[TestData.volume_2], + zoneid=self.zone.id, + account=test_account.name, + domainid=self.domain.id, + diskofferingid=self.disk_offering.id + ) + + self._check_and_get_cs_volume(test_volume.id, self.testdata[TestData.volume_2][TestData.diskName]) + + ####################################### + ####################################### + # STEP 2: Attach volumes to VMs # + ####################################### + ####################################### + + self.volume = self.virtual_machine.attach_volume( + self.apiClient, + self.volume + ) + + self.attached = True + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + vm = self._get_vm(self.virtual_machine.id) + + self.assertEqual( + vol.virtualmachineid, + vm.id, + "Check if attached to virtual machine" + ) + + self.assertEqual( + vm.state.lower(), + 'running', + str(vm.state) + ) + + test_volume = test_virtual_machine.attach_volume( + self.apiClient, + test_volume + ) + + test_vol = self._check_and_get_cs_volume(test_volume.id, self.testdata[TestData.volume_2][TestData.diskName]) + + test_vm = self._get_vm(test_virtual_machine.id) + + self.assertEqual( + test_vol.virtualmachineid, + test_vm.id, + "Check if attached to virtual machine of other acct" + ) + + self.assertEqual( + test_vm.state.lower(), + 'running', + str(test_vm.state) + ) + + sf_vag_id = self._get_vag_id() + + sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id) + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + sf_volume_size = self._get_volume_size_with_hsr(vol) + + self._check_size_and_iops(sf_volume, vol, sf_volume_size) + + sf_iscsi_name = self._get_iqn(self.volume) + + self._check_xen_sr(sf_iscsi_name) + + self._check_vag(sf_volume, sf_vag_id) + + sf_test_account_id = self._get_sf_account_id(self.primary_storage.id, test_account.id) + + sf_test_volumes = self._get_sf_volumes(sf_test_account_id) + + sf_test_volume = self._check_and_get_sf_volume(sf_test_volumes, test_vol.name) + + sf_test_volume_size = self._get_volume_size_with_hsr(test_vol) + + self._check_size_and_iops(sf_test_volume, test_vol, sf_test_volume_size) + + sf_test_iscsi_name = self._get_iqn(test_volume) + + self._check_xen_sr(sf_test_iscsi_name) + + self._check_vag(sf_test_volume, sf_vag_id) + + @attr(hypervisor='XenServer') + def test_10_attach_more_than_one_disk_to_VM(self): + '''Attach more than one disk to a VM''' + + self.virtual_machine.start(self.apiClient) + + volume_2 = Volume.create( + self.apiClient, + self.testdata[TestData.volume_2], + zoneid=self.zone.id, + account=self.account.name, + domainid=self.domain.id, + diskofferingid=self.disk_offering.id + ) + + self.cleanup.append(volume_2) + + self._check_and_get_cs_volume(volume_2.id, self.testdata[TestData.volume_2][TestData.diskName]) + + ####################################### + ####################################### + # Step 1: Attach volumes to VM # + ####################################### + ####################################### + + self.virtual_machine.attach_volume( + self.apiClient, + self.volume + ) + + self.attached = True + + vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) + + self.virtual_machine.attach_volume( + self.apiClient, + volume_2 + ) + + vol_2 = self._check_and_get_cs_volume(volume_2.id, self.testdata[TestData.volume_2][TestData.diskName]) + + sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id) + + sf_volume_size = self._get_volume_size_with_hsr(self.volume) + + sf_volume_2_size = self._get_volume_size_with_hsr(volume_2) + + sf_vag_id = self._get_vag_id() + + sf_volumes = self._get_sf_volumes(sf_account_id) + + sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name) + + self._check_size_and_iops(sf_volume, vol, sf_volume_size) + + sf_iscsi_name = self._get_iqn(self.volume) + + self._check_xen_sr(sf_iscsi_name) + + self._check_vag(sf_volume, sf_vag_id) + + sf_volume_2 = self._check_and_get_sf_volume(sf_volumes, vol_2.name) + + self._check_size_and_iops(sf_volume_2, vol_2, sf_volume_2_size) + + sf_iscsi_name_2 = self._get_iqn(volume_2) + + self._check_xen_sr(sf_iscsi_name_2) + + self._check_vag(sf_volume_2, sf_vag_id) + + self.virtual_machine.detach_volume(self.apiClient, volume_2) + + ''' + @attr(hypervisor = 'XenServer') + def _test_11_attach_disk_to_running_vm_change_iops(self): + Attach a disk to a running VM, then change iops + self.custom_iops_disk_offering = DiskOffering.create( + + )''' + + def _check_list(self, in_list, expected_size_of_list, err_msg): + self.assertEqual( + isinstance(in_list, list), + True, + "'in_list' is not a list." + ) + + self.assertEqual( + len(in_list), + expected_size_of_list, + err_msg + ) + + def _check_iscsi_name(self, sf_iscsi_name): + self.assertEqual( + sf_iscsi_name[0], + "/", + "The iSCSI name needs to start with a forward slash." + ) + + def _check_volume(self, volume, volume_name): + self.assertTrue( + volume.name.startswith(volume_name), + "The volume name is incorrect." + ) + + self.assertEqual( + volume.diskofferingid, + self.disk_offering.id, + "The disk offering is incorrect." + ) + + self.assertEqual( + volume.zoneid, + self.zone.id, + "The zone is incorrect." + ) + + self.assertEqual( + volume.storagetype, + self.disk_offering.storagetype, + "The storage type is incorrect." + ) + + def _check_size_and_iops(self, sf_volume, volume, size): + self.assertEqual( + sf_volume['qos']['minIOPS'], + volume.miniops, + "Check QOS - Min IOPS: " + str(sf_volume['qos']['minIOPS']) + ) + + self.assertEqual( + sf_volume['qos']['maxIOPS'], + volume.maxiops, + "Check QOS - Max IOPS: " + str(sf_volume['qos']['maxIOPS']) + ) + + self.assertEqual( + sf_volume['totalSize'], + size, + "Check SF volume size: " + str(sf_volume['totalSize']) + ) + + def _check_vag(self, sf_volume, sf_vag_id): + self.assertEqual( + len(sf_volume['volumeAccessGroups']), + 1, + "The volume should only be in one VAG." + ) + + self.assertEqual( + sf_volume['volumeAccessGroups'][0], + sf_vag_id, + "The volume is not in the VAG with the following ID: " + str(sf_vag_id) + "." + ) + + def _check_and_get_cs_volume(self, volume_id, volume_name): + list_volumes_response = list_volumes( + self.apiClient, + id=volume_id + ) + + self._check_list(list_volumes_response, 1, TestVolumes._should_only_be_one_volume_in_list_err_msg) + + cs_volume = list_volumes_response[0] + + self._check_volume(cs_volume, volume_name) + + return cs_volume + + def _get_sf_account_id(self, primary_storage_id, account_id): + sf_account_id_request = {'storageid': primary_storage_id, 'accountid': account_id} + sf_account_id_result = self.cs_api.getSolidFireAccountId(sf_account_id_request) + sf_account_id = sf_account_id_result['apisolidfireaccountid']['solidFireAccountId'] + + self.assertEqual( + isinstance(sf_account_id, int), + True, + TestVolumes._sf_account_id_should_be_non_zero_int_err_msg + ) + + return sf_account_id + + def _get_volume_size_with_hsr(self, cs_volume): + # Get underlying SF volume size with hypervisor snapshot reserve + sf_volume_size_request = {'volumeid': cs_volume.id} + sf_volume_size_result = self.cs_api.getSolidFireVolumeSize(sf_volume_size_request) + sf_volume_size = sf_volume_size_result['apisolidfirevolumesize']['solidFireVolumeSize'] + + self.assertEqual( + isinstance(sf_volume_size, int), + True, + "The SolidFire volume size should be a non-zero integer." + ) + + return sf_volume_size + + def _get_vag_id(self): + # Get SF Volume Access Group ID + sf_vag_id_request = {'clusterid': self.cluster.id, 'storageid': self.primary_storage.id} + sf_vag_id_result = self.cs_api.getSolidFireVolumeAccessGroupId(sf_vag_id_request) + sf_vag_id = sf_vag_id_result['apisolidfirevolumeaccessgroupid']['solidFireVolumeAccessGroupId'] + + self.assertEqual( + isinstance(sf_vag_id, int), + True, + TestVolumes._vag_id_should_be_non_zero_int_err_msg + ) + + return sf_vag_id + + def _get_iqn(self, volume): + # Get volume IQN + sf_iscsi_name_request = {'volumeid': volume.id} + sf_iscsi_name_result = self.cs_api.getVolumeiScsiName(sf_iscsi_name_request) + sf_iscsi_name = sf_iscsi_name_result['apivolumeiscsiname']['volumeiScsiName'] + + self._check_iscsi_name(sf_iscsi_name) + + return sf_iscsi_name + + def _get_vm(self, vm_id): + list_vms_response = list_virtual_machines(self.apiClient, id=vm_id) + + self._check_list(list_vms_response, 1, TestVolumes._should_only_be_one_vm_in_list_err_msg) + + return list_vms_response[0] + + def _check_and_get_sf_volume(self, sf_volumes, sf_volume_name, should_exist=True): + sf_volume = None + + for volume in sf_volumes: + if volume['name'] == sf_volume_name: + sf_volume = volume + break + + if should_exist: + self.assertNotEqual( + sf_volume, + None, + "Check if SF volume was created in correct account: " + str(sf_volumes) + ) + else: + self.assertEqual( + sf_volume, + None, + "Check if SF volume was deleted: " + str(sf_volumes) + ) + + return sf_volume + + def _check_xen_sr(self, xen_sr_name, should_exist=True): + if should_exist: + xen_sr = self.xen_session.xenapi.SR.get_by_name_label(xen_sr_name)[0] + + self.sr_shared = self.xen_session.xenapi.SR.get_shared(xen_sr) + + self.assertEqual( + self.sr_shared, + True, + TestVolumes._sr_not_shared_err_msg + ) + else: + xen_sr = self.xen_session.xenapi.SR.get_by_name_label(xen_sr_name) + + self._check_list(xen_sr, 0, TestVolumes._list_should_be_empty) + + def _get_sf_volumes(self, sf_account_id=None): + if sf_account_id is not None: + sf_volumes = self.sf_client.list_volumes_for_account(sf_account_id) + else: + sf_volumes = self.sf_client.list_active_volumes() + + self.assertNotEqual( + len(sf_volumes), + 0, + TestVolumes._volume_response_should_not_be_zero_err_msg + ) + + return sf_volumes + + @classmethod + def _set_supports_resign(cls): + supports_resign = str(cls.supports_resign) + + sql_query = "Update host_details Set value = '" + supports_resign + "' Where name = 'supportsResign'" + + # make sure you can connect to MySQL: https://teamtreehouse.com/community/cant-connect-remotely-to-mysql-server-with-mysql-workbench + cls.dbConnection.execute(sql_query) + + @classmethod + def _purge_solidfire_volumes(cls): + deleted_volumes = cls.sf_client.list_deleted_volumes() + + for deleted_volume in deleted_volumes: + cls.sf_client.purge_deleted_volume(deleted_volume['volumeID']) + diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 4cb8094add..2f6397596e 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -16336,8 +16336,11 @@ } }); - if (args.context.hosts[0].hypervisor == "XenServer"){ - cloudStack.dialog.notice({ message: _s("The host has been deleted. Please eject the host from XenServer Pool") }) + if (args.context.hosts[0].hypervisor == "XenServer") { + cloudStack.dialog.notice({ message: _s("The host has been removed. Please eject the host from the XenServer Resource Pool.") }) + } + else if (args.context.hosts[0].hypervisor == "VMware") { + cloudStack.dialog.notice({ message: _s("The host has been removed. Please eject the host from the vSphere Cluster.") }) } } }); From 07564469e9a2ddd0334e8bdd30deed3ed53c3f09 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Mon, 28 Dec 2015 16:37:03 +0530 Subject: [PATCH 147/203] CLOUDSTACK-9299: Out-of-band Management for CloudStack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support access to a host’s out-of-band management interface (e.g. IPMI, iLO, DRAC, etc.) to manage host power operations (on/off etc.) and querying current power state in CloudStack. Given the wide range of out-of-band management interfaces such as iLO and iDRA, the service implementation allows for development of separate drivers as plugins. This feature comes with a ipmitool based driver that uses the ipmitool (http://linux.die.net/man/1/ipmitool) to communicate with any out-of-band management interface that support IPMI 2.0. This feature allows following common use-cases: - Restarting stalled/failed hosts - Powering off under-utilised hosts - Powering on hosts for provisioning or to increase capacity - Allowing system administrators to see the current power state of the host For testing this feature `ipmisim` can be used: https://pypi.python.org/pypi/ipmisim FS: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Out-of-band+Management+for+CloudStack Signed-off-by: Rohit Yadav --- .travis.yml | 2 +- api/src/com/cloud/event/EventTypes.java | 16 + .../com/cloud/resource/ResourceService.java | 3 + .../apache/cloudstack/alert/AlertService.java | 1 + .../apache/cloudstack/api/ApiConstants.java | 6 +- .../apache/cloudstack/api/BaseResponse.java | 31 +- .../api/command/admin/host/ListHostsCmd.java | 21 +- .../ChangeOutOfBandManagementPasswordCmd.java | 112 ++++ .../ConfigureOutOfBandManagementCmd.java | 125 ++++ ...sableOutOfBandManagementForClusterCmd.java | 103 ++++ .../DisableOutOfBandManagementForHostCmd.java | 104 ++++ .../DisableOutOfBandManagementForZoneCmd.java | 103 ++++ ...nableOutOfBandManagementForClusterCmd.java | 103 ++++ .../EnableOutOfBandManagementForHostCmd.java | 104 ++++ .../EnableOutOfBandManagementForZoneCmd.java | 103 ++++ ...ssueOutOfBandManagementPowerActionCmd.java | 124 ++++ .../api/response/ClusterResponse.java | 13 + .../cloudstack/api/response/HostResponse.java | 13 + .../response/OutOfBandManagementResponse.java | 189 ++++++ .../cloudstack/api/response/ZoneResponse.java | 6 +- .../OutOfBandManagement.java | 150 +++++ .../OutOfBandManagementDriver.java | 25 + .../OutOfBandManagementService.java | 55 ++ ...ManagementDriverChangePasswordCommand.java | 34 ++ .../OutOfBandManagementDriverCommand.java | 43 ++ ...OutOfBandManagementDriverPowerCommand.java | 33 + .../OutOfBandManagementDriverResponse.java | 85 +++ .../classes/resources/messages.properties | 20 + client/pom.xml | 5 + ...core-lifecycle-api-context-inheritable.xml | 1 - .../spring-core-registry-core-context.xml | 7 +- .../outofbandmanagement/module.properties | 21 + ...utofbandmanagement-context-inheritable.xml | 36 ++ debian/control | 2 +- developer/developer-prefill.sql | 12 + .../cloud/agent/manager/AgentManagerImpl.java | 3 + .../manager/ClusteredAgentManagerImpl.java | 1 + ...spring-engine-schema-core-daos-context.xml | 2 +- .../cloud/dc/dao/DataCenterDetailsDao.java | 4 +- .../dc/dao/DataCenterDetailsDaoImpl.java | 26 +- .../src/com/cloud/host/dao/HostDao.java | 4 + .../src/com/cloud/host/dao/HostDaoImpl.java | 17 + .../OutOfBandManagementVO.java | 193 ++++++ .../dao/OutOfBandManagementDao.java | 31 + .../dao/OutOfBandManagementDaoImpl.java | 158 +++++ .../ipmitool/pom.xml | 41 ++ .../cloudstack/ipmitool/module.properties | 18 + .../ipmitool/spring-ipmitool-context.xml | 34 ++ .../IpmitoolOutOfBandManagementDriver.java | 167 +++++ .../driver/ipmitool/IpmitoolWrapper.java | 181 ++++++ .../driver/ipmitool/IpmitoolWrapperTest.java | 115 ++++ plugins/pom.xml | 1 + .../spring-server-core-managers-context.xml | 4 + .../src/com/cloud/alert/AlertManagerImpl.java | 3 +- .../src/com/cloud/api/ApiResponseHelper.java | 4 + .../com/cloud/api/query/QueryManagerImpl.java | 12 + .../cloud/api/query/dao/HostJoinDaoImpl.java | 16 +- .../com/cloud/api/query/vo/HostJoinVO.java | 16 + .../cloud/resource/ResourceManagerImpl.java | 6 + .../cloud/server/ManagementServerImpl.java | 20 + .../src/com/cloud/server/StatsCollector.java | 48 +- .../OutOfBandManagementBackgroundTask.java | 50 ++ .../OutOfBandManagementServiceImpl.java | 555 +++++++++++++++++ .../resource/MockResourceManagerImpl.java | 7 + .../OutOfBandManagementServiceTest.java | 116 ++++ setup/db/db/schema-481to490-cleanup.sql | 77 +++ setup/db/db/schema-481to490.sql | 23 + setup/dev/advanced.cfg | 16 +- .../smoke/test_outofbandmanagement.py | 575 ++++++++++++++++++ tools/apidoc/gen_toc.py | 1 + tools/marvin/setup.py | 3 +- tools/travis/before_install.sh | 13 +- ui/css/cloudstack3.css | 48 ++ ui/dictionary.jsp | 21 + ui/scripts/metrics.js | 16 + ui/scripts/system.js | 573 ++++++++++++++++- .../com/cloud/utils/fsm/StateMachine2.java | 10 + .../utils/process/ProcessResult.java | 46 ++ .../utils/process/ProcessRunner.java | 115 ++++ .../cloudstack/utils/process/ProcessTest.java | 69 +++ 80 files changed, 5227 insertions(+), 43 deletions(-) create mode 100644 api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForClusterCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForZoneCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForClusterCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForHostCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForZoneCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java create mode 100644 api/src/org/apache/cloudstack/api/response/OutOfBandManagementResponse.java create mode 100644 api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagement.java create mode 100644 api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementDriver.java create mode 100644 api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementService.java create mode 100644 api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverChangePasswordCommand.java create mode 100644 api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverCommand.java create mode 100644 api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverPowerCommand.java create mode 100644 api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverResponse.java create mode 100644 core/resources/META-INF/cloudstack/outofbandmanagement/module.properties create mode 100644 core/resources/META-INF/cloudstack/outofbandmanagement/spring-core-lifecycle-outofbandmanagement-context-inheritable.xml create mode 100644 engine/schema/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementVO.java create mode 100644 engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDao.java create mode 100644 engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDaoImpl.java create mode 100644 plugins/outofbandmanagement-drivers/ipmitool/pom.xml create mode 100644 plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/module.properties create mode 100644 plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/spring-ipmitool-context.xml create mode 100644 plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolOutOfBandManagementDriver.java create mode 100644 plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapper.java create mode 100644 plugins/outofbandmanagement-drivers/ipmitool/test/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapperTest.java create mode 100644 server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementBackgroundTask.java create mode 100644 server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceImpl.java create mode 100644 server/test/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceTest.java create mode 100644 test/integration/smoke/test_outofbandmanagement.py create mode 100644 utils/src/main/java/org/apache/cloudstack/utils/process/ProcessResult.java create mode 100644 utils/src/main/java/org/apache/cloudstack/utils/process/ProcessRunner.java create mode 100644 utils/src/test/java/org/apache/cloudstack/utils/process/ProcessTest.java diff --git a/.travis.yml b/.travis.yml index 9d9822ce11..9ff6f18c54 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ env: matrix: - TESTS="smoke/test_affinity_groups smoke/test_affinity_groups_projects smoke/test_dynamicroles smoke/test_deploy_vgpu_enabled_vm smoke/test_deploy_vm_iso smoke/test_deploy_vm_root_resize smoke/test_deploy_vm_with_userdata smoke/test_deploy_vms_with_varied_deploymentplanners smoke/test_disk_offerings smoke/test_global_settings smoke/test_guest_vlan_range" - TESTS="smoke/test_hosts smoke/test_internal_lb smoke/test_iso smoke/test_list_ids_parameter smoke/test_loadbalance smoke/test_multipleips_per_nic smoke/test_network smoke/test_network_acl smoke/test_nic smoke/test_nic_adapter_type smoke/test_non_contigiousvlan" - - TESTS="smoke/test_over_provisioning smoke/test_password_server smoke/test_portable_publicip smoke/test_primary_storage smoke/test_privategw_acl smoke/test_public_ip_range smoke/test_pvlan smoke/test_regions smoke/test_reset_vm_on_reboot smoke/test_resource_detail" + - TESTS="smoke/test_outofbandmanagement smoke/test_over_provisioning smoke/test_password_server smoke/test_portable_publicip smoke/test_primary_storage smoke/test_privategw_acl smoke/test_public_ip_range smoke/test_pvlan smoke/test_regions smoke/test_reset_vm_on_reboot smoke/test_resource_detail" - TESTS="smoke/test_router_dhcphosts smoke/test_routers smoke/test_routers_iptables_default_policy smoke/test_routers_network_ops smoke/test_staticroles smoke/test_scale_vm smoke/test_secondary_storage smoke/test_service_offerings smoke/test_snapshots smoke/test_ssvm smoke/test_templates" - TESTS="smoke/test_usage_events smoke/test_vm_life_cycle smoke/test_vm_snapshots smoke/test_volumes smoke/test_vpc_redundant smoke/test_vpc_router_nics smoke/test_vpc_vpn smoke/misc/test_deploy_vm smoke/misc/test_vm_ha smoke/misc/test_escalations_templates smoke/misc/test_vm_sync" diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 23de15295e..3cc4eac81f 100644 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -309,6 +309,14 @@ public class EventTypes { // Host public static final String EVENT_HOST_RECONNECT = "HOST.RECONNECT"; + // Host Out-of-band management + public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE = "HOST.OOBM.ENABLE"; + public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE = "HOST.OOBM.DISABLE"; + public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_CONFIGURE = "HOST.OOBM.CONFIGURE"; + public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_ACTION = "HOST.OOBM.ACTION"; + public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_CHANGE_PASSWORD = "HOST.OOBM.CHANGEPASSWORD"; + public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_POWERSTATE_TRANSITION = "HOST.OOBM.POWERSTATE.TRANSITION"; + // Maintenance public static final String EVENT_MAINTENANCE_CANCEL = "MAINT.CANCEL"; public static final String EVENT_MAINTENANCE_CANCEL_PRIMARY_STORAGE = "MAINT.CANCEL.PS"; @@ -745,6 +753,14 @@ public class EventTypes { // Host entityEventDetails.put(EVENT_HOST_RECONNECT, Host.class); + // Host Out-of-band management + entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE, Host.class); + entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE, Host.class); + entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_CONFIGURE, Host.class); + entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_ACTION, Host.class); + entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_CHANGE_PASSWORD, Host.class); + entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_POWERSTATE_TRANSITION, Host.class); + // Maintenance entityEventDetails.put(EVENT_MAINTENANCE_CANCEL, Host.class); entityEventDetails.put(EVENT_MAINTENANCE_CANCEL_PRIMARY_STORAGE, Host.class); diff --git a/api/src/com/cloud/resource/ResourceService.java b/api/src/com/cloud/resource/ResourceService.java index 7461455aae..7050b97e0f 100644 --- a/api/src/com/cloud/resource/ResourceService.java +++ b/api/src/com/cloud/resource/ResourceService.java @@ -18,6 +18,7 @@ import java.util.List; +import com.cloud.dc.DataCenter; import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd; import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd; import org.apache.cloudstack.api.command.admin.host.AddHostCmd; @@ -92,6 +93,8 @@ public interface ResourceService { Cluster getCluster(Long clusterId); + DataCenter getZone(Long zoneId); + List getSupportedHypervisorTypes(long zoneId, boolean forVirtualRouter, Long podId); boolean releaseHostReservation(Long hostId); diff --git a/api/src/org/apache/cloudstack/alert/AlertService.java b/api/src/org/apache/cloudstack/alert/AlertService.java index 2b827eb003..ad711ecea4 100644 --- a/api/src/org/apache/cloudstack/alert/AlertService.java +++ b/api/src/org/apache/cloudstack/alert/AlertService.java @@ -66,6 +66,7 @@ private AlertType(short type, String name, boolean isDefault) { public static final AlertType ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED = new AlertType((short)26, "ALERT.RESOURCE.EXCEED", true); public static final AlertType ALERT_TYPE_SYNC = new AlertType((short)27, "ALERT.TYPE.SYNC", true); public static final AlertType ALERT_TYPE_UPLOAD_FAILED = new AlertType((short)28, "ALERT.UPLOAD.FAILED", true); + public static final AlertType ALERT_TYPE_OOBM_AUTH_ERROR = new AlertType((short)29, "ALERT.OOBM.AUTHERROR", true); public short getType() { return type; diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 490492533b..1d0b4a3756 100644 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -21,6 +21,7 @@ public class ApiConstants { public static final String ACCOUNTS = "accounts"; public static final String ACCOUNT_TYPE = "accounttype"; public static final String ACCOUNT_ID = "accountid"; + public static final String ADDRESS = "address"; public static final String ALGORITHM = "algorithm"; public static final String ALLOCATED_ONLY = "allocatedonly"; public static final String API_KEY = "apikey"; @@ -76,6 +77,7 @@ public class ApiConstants { public static final String DEVICE_ID = "deviceid"; public static final String DISK_OFFERING_ID = "diskofferingid"; public static final String DISK_SIZE = "disksize"; + public static final String DRIVER = "driver"; public static final String ROOT_DISK_SIZE = "rootdisksize"; public static final String DISPLAY_NAME = "displayname"; public static final String DISPLAY_NETWORK = "displaynetwork"; @@ -177,6 +179,8 @@ public class ApiConstants { public static final String OS_TYPE_ID = "ostypeid"; public static final String OS_DISPLAY_NAME = "osdisplayname"; public static final String OS_NAME_FOR_HYPERVISOR = "osnameforhypervisor"; + public static final String OUTOFBANDMANAGEMENT_POWERSTATE = "outofbandmanagementpowerstate"; + public static final String OUTOFBANDMANAGEMENT_ENABLED = "outofbandmanagementenabled"; public static final String PARAMS = "params"; public static final String PARENT_DOMAIN_ID = "parentdomainid"; public static final String PASSWORD = "password"; @@ -193,7 +197,7 @@ public class ApiConstants { public static final String PORTABLE_IP_ADDRESS = "portableipaddress"; public static final String PORT_FORWARDING_SERVICE_ID = "portforwardingserviceid"; public static final String POST_URL = "postURL"; - public static final String PARENT = "parent"; + public static final String POWER_STATE = "powerstate"; public static final String PRIVATE_INTERFACE = "privateinterface"; public static final String PRIVATE_IP = "privateip"; public static final String PRIVATE_PORT = "privateport"; diff --git a/api/src/org/apache/cloudstack/api/BaseResponse.java b/api/src/org/apache/cloudstack/api/BaseResponse.java index 05de218763..45016c1a2a 100644 --- a/api/src/org/apache/cloudstack/api/BaseResponse.java +++ b/api/src/org/apache/cloudstack/api/BaseResponse.java @@ -24,23 +24,38 @@ public abstract class BaseResponse implements ResponseObject { private transient String responseName; private transient String objectName; + @SerializedName(ApiConstants.JOB_ID) + @Param(description = "the UUID of the latest async job acting on this object") + protected String jobId; + + @SerializedName(ApiConstants.JOB_STATUS) + @Param(description = "the current status of the latest async job acting on this object") + private Integer jobStatus; + + public BaseResponse() { + } + + public BaseResponse(final String objectName) { + this.objectName = objectName; + } + @Override - public String getResponseName() { + public final String getResponseName() { return responseName; } @Override - public void setResponseName(String responseName) { + public final void setResponseName(String responseName) { this.responseName = responseName; } @Override - public String getObjectName() { + public final String getObjectName() { return objectName; } @Override - public void setObjectName(String objectName) { + public final void setObjectName(String objectName) { this.objectName = objectName; } @@ -49,14 +64,6 @@ public String getObjectId() { return null; } - @SerializedName(ApiConstants.JOB_ID) - @Param(description = "the UUID of the latest async job acting on this object") - protected String jobId; - - @SerializedName(ApiConstants.JOB_STATUS) - @Param(description = "the current status of the latest async job acting on this object") - private Integer jobStatus; - @Override public String getJobId() { return jobId; diff --git a/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java index d7aa18bbfe..424fc05aed 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java @@ -81,9 +81,19 @@ public class ListHostsCmd extends BaseListCmd { description = "lists hosts in the same cluster as this VM and flag hosts with enough CPU/RAm to host this VM") private Long virtualMachineId; + @Parameter(name = ApiConstants.OUTOFBANDMANAGEMENT_ENABLED, + type = CommandType.BOOLEAN, + description = "list hosts for which out-of-band management is enabled") + private Boolean outOfBandManagementEnabled; + + @Parameter(name = ApiConstants.OUTOFBANDMANAGEMENT_POWERSTATE, + type = CommandType.STRING, + description = "list hosts by its out-of-band management interface's power state. Its value can be one of [On, Off, Unknown]") + private String outOfBandManagementPowerState; + @Parameter(name = ApiConstants.RESOURCE_STATE, type = CommandType.STRING, - description = "list hosts by resource state. Resource state represents current state determined by admin of host, valule can be one of [Enabled, Disabled, Unmanaged, PrepareForMaintenance, ErrorInMaintenance, Maintenance, Error]") + description = "list hosts by resource state. Resource state represents current state determined by admin of host, value can be one of [Enabled, Disabled, Unmanaged, PrepareForMaintenance, ErrorInMaintenance, Maintenance, Error]") private String resourceState; @Parameter(name = ApiConstants.DETAILS, @@ -165,6 +175,15 @@ public String getResourceState() { return resourceState; } + + public Boolean isOutOfBandManagementEnabled() { + return outOfBandManagementEnabled; + } + + public String getHostOutOfBandManagementPowerState() { + return outOfBandManagementPowerState; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java new file mode 100644 index 0000000000..ea2e3cdb76 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java @@ -0,0 +1,112 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = ChangeOutOfBandManagementPasswordCmd.APINAME, description = "Changes out-of-band management interface password on the host and updates the interface configuration in CloudStack if the operation succeeds, else reverts the old password", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = true, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class ChangeOutOfBandManagementPasswordCmd extends BaseAsyncCmd { + public static final String APINAME = "changeOutOfBandManagementPassword"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, required = true, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the host") + private Long hostId; + + @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, description = "the new host management interface password of maximum length 16, if none is provided a random password would be used") + private String password; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Host host = _resourceService.getHost(getHostId()); + if (host == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId()); + } + + CallContext.current().setEventDetails("Host Id: " + host.getId() + " Password: " + getPassword().charAt(0) + "****"); + CallContext.current().putContextParameter(Host.class, host.getUuid()); + + final OutOfBandManagementResponse response = outOfBandManagementService.changeOutOfBandManagementPassword(host, getPassword()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + public Long getHostId() { + return hostId; + } + + public String getPassword() { + if (Strings.isNullOrEmpty(password)) { + password = _mgr.generateRandomPassword(); + } + return password; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_CHANGE_PASSWORD; + } + + @Override + public String getEventDescription() { + return "change out-of-band management password for host: " + getHostId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java new file mode 100644 index 0000000000..db224108df --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java @@ -0,0 +1,125 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = ConfigureOutOfBandManagementCmd.APINAME, description = "Configures a host's out-of-band management interface", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = true, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class ConfigureOutOfBandManagementCmd extends BaseCmd { + public static final String APINAME = "configureOutOfBandManagement"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, required = true, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the host") + private Long hostId; + + @Parameter(name = ApiConstants.DRIVER, type = CommandType.STRING, required = true, description = "the host management interface driver, for example: ipmitool") + private String driver; + + @Parameter(name = ApiConstants.ADDRESS, type = CommandType.STRING, required = true, description = "the host management interface IP address") + private String address; + + @Parameter(name = ApiConstants.PORT, type = CommandType.STRING, required = true, description = "the host management interface port") + private String port; + + @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, required = true, description = "the host management interface user") + private String username; + + @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, required = true, description = "the host management interface password") + private String password; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Host host = _resourceService.getHost(getHostId()); + if (host == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId()); + } + CallContext.current().putContextParameter(Host.class, host.getUuid()); + final OutOfBandManagementResponse response = outOfBandManagementService.configureOutOfBandManagement(host, getHostPMOptions()); + response.setId(host.getUuid()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + public Long getHostId() { + return hostId; + } + + public final ImmutableMap getHostPMOptions() { + final ImmutableMap.Builder builder = ImmutableMap.builder(); + if (!Strings.isNullOrEmpty(driver)) { + builder.put(OutOfBandManagement.Option.DRIVER, driver); + } + if (!Strings.isNullOrEmpty(address)) { + builder.put(OutOfBandManagement.Option.ADDRESS, address); + } + if (!Strings.isNullOrEmpty(port)) { + builder.put(OutOfBandManagement.Option.PORT, port); + } + if (!Strings.isNullOrEmpty(username)) { + builder.put(OutOfBandManagement.Option.USERNAME, username); + } + if (!Strings.isNullOrEmpty(password)) { + builder.put(OutOfBandManagement.Option.PASSWORD, password); + } + return builder.build(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForClusterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForClusterCmd.java new file mode 100644 index 0000000000..67d84d5096 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForClusterCmd.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.org.Cluster; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ClusterResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = DisableOutOfBandManagementForClusterCmd.APINAME, description = "Disables out-of-band management for a cluster", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class DisableOutOfBandManagementForClusterCmd extends BaseAsyncCmd { + public static final String APINAME = "disableOutOfBandManagementForCluster"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.CLUSTER_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = ClusterResponse.class, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the cluster") + private Long clusterId; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + final public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Cluster cluster = _resourceService.getCluster(getClusterId()); + if (cluster == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find cluster by ID: " + getClusterId()); + } + + OutOfBandManagementResponse response = outOfBandManagementService.disableOutOfBandManagement(cluster); + + CallContext.current().setEventDetails("Cluster Id:" + cluster.getId() + " out-of-band management enabled: false"); + CallContext.current().putContextParameter(Cluster.class, cluster.getUuid()); + + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + final public Long getClusterId() { + return clusterId; + } + + @Override + final public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE; + } + + @Override + public String getEventDescription() { + return "disable out-of-band management password for cluster: " + getClusterId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java new file mode 100644 index 0000000000..009d0d3fd1 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java @@ -0,0 +1,104 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = DisableOutOfBandManagementForHostCmd.APINAME, description = "Disables out-of-band management for a host", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class DisableOutOfBandManagementForHostCmd extends BaseAsyncCmd { + public static final String APINAME = "disableOutOfBandManagementForHost"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.HOST_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = HostResponse.class, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the host") + private Long hostId; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + final public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Host host = _resourceService.getHost(getHostId()); + if (host == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId()); + } + + OutOfBandManagementResponse response = outOfBandManagementService.disableOutOfBandManagement(host); + + CallContext.current().setEventDetails("Host Id:" + host.getId() + " out-of-band management enabled: false"); + CallContext.current().putContextParameter(Host.class, host.getUuid()); + + response.setId(host.getUuid()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + final public Long getHostId() { + return hostId; + } + + @Override + final public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE; + } + + @Override + public String getEventDescription() { + return "disable out-of-band management password for host: " + getHostId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForZoneCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForZoneCmd.java new file mode 100644 index 0000000000..82e92a75ea --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForZoneCmd.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.dc.DataCenter; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = DisableOutOfBandManagementForZoneCmd.APINAME, description = "Disables out-of-band management for a zone", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class DisableOutOfBandManagementForZoneCmd extends BaseAsyncCmd { + public static final String APINAME = "disableOutOfBandManagementForZone"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = ZoneResponse.class, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the zone") + private Long zoneId; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + final public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final DataCenter zone = _resourceService.getZone(getZoneId()); + if (zone == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find zone by ID: " + getZoneId()); + } + + OutOfBandManagementResponse response = outOfBandManagementService.disableOutOfBandManagement(zone); + + CallContext.current().setEventDetails("Zone Id:" + zone.getId() + " out-of-band management enabled: false"); + CallContext.current().putContextParameter(DataCenter.class, zone.getUuid()); + + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + final public Long getZoneId() { + return zoneId; + } + + @Override + final public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE; + } + + @Override + public String getEventDescription() { + return "disable out-of-band management password for zone: " + getZoneId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForClusterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForClusterCmd.java new file mode 100644 index 0000000000..64279c3a6d --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForClusterCmd.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.org.Cluster; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ClusterResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = EnableOutOfBandManagementForClusterCmd.APINAME, description = "Enables out-of-band management for a cluster", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class EnableOutOfBandManagementForClusterCmd extends BaseAsyncCmd { + public static final String APINAME = "enableOutOfBandManagementForCluster"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.CLUSTER_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = ClusterResponse.class, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the cluster") + private Long clusterId; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + final public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Cluster cluster = _resourceService.getCluster(getClusterId()); + if (cluster == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find cluster by ID: " + getClusterId()); + } + + OutOfBandManagementResponse response = outOfBandManagementService.enableOutOfBandManagement(cluster); + + CallContext.current().setEventDetails("Cluster Id:" + cluster.getId() + " out-of-band management enabled: true"); + CallContext.current().putContextParameter(Cluster.class, cluster.getUuid()); + + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + final public Long getClusterId() { + return clusterId; + } + + @Override + final public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE; + } + + @Override + public String getEventDescription() { + return "enable out-of-band management password for cluster: " + getClusterId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForHostCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForHostCmd.java new file mode 100644 index 0000000000..746725602d --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForHostCmd.java @@ -0,0 +1,104 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = EnableOutOfBandManagementForHostCmd.APINAME, description = "Enables out-of-band management for a host", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class EnableOutOfBandManagementForHostCmd extends BaseAsyncCmd { + public static final String APINAME = "enableOutOfBandManagementForHost"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.HOST_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = HostResponse.class, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the host") + private Long hostId; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + final public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Host host = _resourceService.getHost(getHostId()); + if (host == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId()); + } + + OutOfBandManagementResponse response = outOfBandManagementService.enableOutOfBandManagement(host); + + CallContext.current().setEventDetails("Host Id:" + host.getId() + " out-of-band management enabled: true"); + CallContext.current().putContextParameter(Host.class, host.getUuid()); + + response.setId(host.getUuid()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + final public Long getHostId() { + return hostId; + } + + @Override + final public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE; + } + + @Override + public String getEventDescription() { + return "enable out-of-band management password for host: " + getHostId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForZoneCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForZoneCmd.java new file mode 100644 index 0000000000..cae2181330 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForZoneCmd.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.dc.DataCenter; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = EnableOutOfBandManagementForZoneCmd.APINAME, description = "Enables out-of-band management for a zone", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class EnableOutOfBandManagementForZoneCmd extends BaseAsyncCmd { + public static final String APINAME = "enableOutOfBandManagementForZone"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = ZoneResponse.class, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the zone") + private Long zoneId; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + final public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final DataCenter zone = _resourceService.getZone(getZoneId()); + if (zone == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find zone by ID: " + getZoneId()); + } + + OutOfBandManagementResponse response = outOfBandManagementService.enableOutOfBandManagement(zone); + + CallContext.current().setEventDetails("Zone Id:" + zone.getId() + " out-of-band management enabled: true"); + CallContext.current().putContextParameter(DataCenter.class, zone.getUuid()); + + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + final public Long getZoneId() { + return zoneId; + } + + @Override + final public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE; + } + + @Override + public String getEventDescription() { + return "enable out-of-band management password for zone: " + getZoneId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java new file mode 100644 index 0000000000..8d6bdd350d --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java @@ -0,0 +1,124 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandJobType; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement.PowerOperation; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = IssueOutOfBandManagementPowerActionCmd.APINAME, description = "Initiates the specified power action to the host's out-of-band management interface", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class IssueOutOfBandManagementPowerActionCmd extends BaseAsyncCmd { + public static final String APINAME = "issueOutOfBandManagementPowerAction"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, required = true, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the host") + private Long hostId; + + @Parameter(name = ApiConstants.TIMEOUT, type = CommandType.LONG, description = "optional operation timeout in seconds that overrides the global or cluster-level out-of-band management timeout setting") + private Long actionTimeout; + + @Parameter(name = ApiConstants.ACTION, type = CommandType.STRING, required = true, + validations = {ApiArgValidator.NotNullOrEmpty}, description = "out-of-band management power actions, valid actions are: ON, OFF, CYCLE, RESET, SOFT, STATUS") + private String powerAction; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Host host = _resourceService.getHost(getHostId()); + if (host == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId()); + } + final PowerOperation powerOperation = PowerOperation.valueOf(getPowerAction()); + + CallContext.current().setEventDetails("Host Id: " + host.getId() + " Action: " + powerOperation.toString()); + CallContext.current().putContextParameter(Host.class, host.getUuid()); + + final OutOfBandManagementResponse response = outOfBandManagementService.executeOutOfBandManagementPowerOperation(host, powerOperation, getActionTimeout()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + public Long getHostId() { + return hostId; + } + + public Long getActionTimeout() { + return actionTimeout; + } + + public String getPowerAction() { + return powerAction; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ACTION; + } + + @Override + public String getEventDescription() { + return "issue out-out-band management power action: " + getPowerAction() + " on host: " + getHostId(); + } + + @Override + public ApiCommandJobType getInstanceType() { + return ApiCommandJobType.Host; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/ClusterResponse.java b/api/src/org/apache/cloudstack/api/response/ClusterResponse.java index df01e09595..754baa2677 100644 --- a/api/src/org/apache/cloudstack/api/response/ClusterResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ClusterResponse.java @@ -17,7 +17,9 @@ package org.apache.cloudstack.api.response; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import com.google.gson.annotations.SerializedName; @@ -86,6 +88,10 @@ public class ClusterResponse extends BaseResponse { @Param(description = "Ovm3 VIP to use for pooling and/or clustering") private String ovm3vip; + @SerializedName(ApiConstants.RESOURCE_DETAILS) + @Param(description = "Meta data associated with the zone (key/value pairs)") + private Map resourceDetails; + public String getId() { return id; } @@ -197,4 +203,11 @@ public void setOvm3Vip(String ovm3vip) { public String getOvm3Vip() { return ovm3vip; } + + public void setResourceDetails(Map details) { + if (details == null) { + return; + } + this.resourceDetails = new HashMap<>(details); + } } diff --git a/api/src/org/apache/cloudstack/api/response/HostResponse.java b/api/src/org/apache/cloudstack/api/response/HostResponse.java index c6697fbe30..ab9c8c3767 100644 --- a/api/src/org/apache/cloudstack/api/response/HostResponse.java +++ b/api/src/org/apache/cloudstack/api/response/HostResponse.java @@ -24,6 +24,7 @@ import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; import java.util.Date; import java.util.HashMap; @@ -200,6 +201,10 @@ public class HostResponse extends BaseResponse { @Param(description = "true if this host is suitable(has enough capacity and satisfies all conditions like hosttags, max guests vm limit etc) to migrate a VM to it , false otherwise") private Boolean suitableForMigration; + @SerializedName("outofbandmanagement") + @Param(description = "the host out-of-band management information") + private OutOfBandManagementResponse outOfBandManagementResponse; + @SerializedName("resourcestate") @Param(description = "the resource state of the host") private String resourceState; @@ -403,6 +408,14 @@ public void setSuitableForMigration(Boolean suitableForMigration) { this.suitableForMigration = suitableForMigration; } + public OutOfBandManagementResponse getOutOfBandManagementResponse() { + return outOfBandManagementResponse; + } + + public void setOutOfBandManagementResponse(final OutOfBandManagement outOfBandManagementConfig) { + this.outOfBandManagementResponse = new OutOfBandManagementResponse(outOfBandManagementConfig); + } + public String getResourceState() { return resourceState; } diff --git a/api/src/org/apache/cloudstack/api/response/OutOfBandManagementResponse.java b/api/src/org/apache/cloudstack/api/response/OutOfBandManagementResponse.java new file mode 100644 index 0000000000..19594d2950 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/OutOfBandManagementResponse.java @@ -0,0 +1,189 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response; + +import com.cloud.host.Host; +import com.cloud.serializer.Param; +import com.google.common.base.Strings; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; + +@EntityReference(value = Host.class) +public class OutOfBandManagementResponse extends BaseResponse { + @SerializedName(ApiConstants.HOST_ID) + @Param(description = "the ID of the host") + private String id; + + @SerializedName(ApiConstants.POWER_STATE) + @Param(description = "the out-of-band management interface powerState of the host") + private OutOfBandManagement.PowerState powerState; + + @SerializedName(ApiConstants.ENABLED) + @Param(description = "true if out-of-band management is enabled for the host") + private Boolean enabled; + + @SerializedName(ApiConstants.DRIVER) + @Param(description = "the out-of-band management driver for the host") + private String driver; + + @SerializedName(ApiConstants.ADDRESS) + @Param(description = "the out-of-band management interface address") + private String ipAddress; + + @SerializedName(ApiConstants.PORT) + @Param(description = "the out-of-band management interface port") + private String port; + + @SerializedName(ApiConstants.USERNAME) + @Param(description = "the out-of-band management interface username") + private String username; + + @SerializedName(ApiConstants.PASSWORD) + @Param(description = "the out-of-band management interface password") + private String password; + + @SerializedName(ApiConstants.ACTION) + @Param(description = "the out-of-band management action (if issued)") + private String outOfBandManagementAction; + + @SerializedName(ApiConstants.DESCRIPTION) + @Param(description = "the operation result description") + private String resultDescription; + + @SerializedName(ApiConstants.STATUS) + @Param(description = "the operation result") + private Boolean success; + + public OutOfBandManagementResponse() { + super("outofbandmanagement"); + } + + public OutOfBandManagementResponse(final OutOfBandManagement outOfBandManagementConfig) { + this(); + if (outOfBandManagementConfig == null) { + this.setEnabled(false); + this.setPowerState(OutOfBandManagement.PowerState.Disabled); + return; + } + this.setEnabled(outOfBandManagementConfig.isEnabled()); + if (outOfBandManagementConfig.getPowerState() != null) { + this.setPowerState(outOfBandManagementConfig.getPowerState()); + } else { + this.setPowerState(OutOfBandManagement.PowerState.Unknown); + } + this.setDriver(outOfBandManagementConfig.getDriver()); + this.setIpAddress(outOfBandManagementConfig.getAddress()); + if (outOfBandManagementConfig.getPort() != null) { + this.setPort(String.valueOf(outOfBandManagementConfig.getPort())); + } + this.setUsername(outOfBandManagementConfig.getUsername()); + if (!Strings.isNullOrEmpty(outOfBandManagementConfig.getPassword())) { + this.setPassword(outOfBandManagementConfig.getPassword().substring(0, 1) + "****"); + } + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public OutOfBandManagement.PowerState getPowerState() { + return powerState; + } + + public void setPowerState(OutOfBandManagement.PowerState powerState) { + this.powerState = powerState; + } + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public String getDriver() { + return driver; + } + + public void setDriver(String driver) { + this.driver = driver; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getOutOfBandManagementAction() { + return outOfBandManagementAction; + } + + public void setOutOfBandManagementAction(String outOfBandManagementAction) { + this.outOfBandManagementAction = outOfBandManagementAction; + } + + public String getResultDescription() { + return resultDescription; + } + + public void setResultDescription(String resultDescription) { + this.resultDescription = resultDescription; + } + + public Boolean getSuccess() { + return success; + } + + public void setSuccess(Boolean success) { + this.success = success; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/ZoneResponse.java b/api/src/org/apache/cloudstack/api/response/ZoneResponse.java index 7aee448f6e..4266077e81 100644 --- a/api/src/org/apache/cloudstack/api/response/ZoneResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ZoneResponse.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.api.response; +import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -233,6 +234,9 @@ public void addTag(ResourceTagResponse tag) { } public void setResourceDetails(Map details) { - this.resourceDetails = details; + if (details == null) { + return; + } + this.resourceDetails = new HashMap<>(details); } } diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagement.java b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagement.java new file mode 100644 index 0000000000..1a22328e02 --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagement.java @@ -0,0 +1,150 @@ +// 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.outofbandmanagement; + +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.utils.fsm.StateMachine2; +import com.cloud.utils.fsm.StateObject; +import org.apache.cloudstack.api.InternalIdentity; +import org.apache.cloudstack.utils.identity.ManagementServerNode; + +import java.util.Set; + +public interface OutOfBandManagement extends StateObject, InternalIdentity { + + PowerState getState(); + + Long getHostId(); + + boolean isEnabled(); + + PowerState getPowerState(); + + String getDriver(); + + String getAddress(); + + Integer getPort(); + + String getUsername(); + + String getPassword(); + + Long getManagementServerId(); + + void setEnabled(boolean enabled); + + void setDriver(String driver); + + void setAddress(String address); + + void setPort(Integer port); + + void setUsername(String username); + + void setPassword(String password); + + enum Option { + DRIVER, + ADDRESS, + PORT, + USERNAME, + PASSWORD + } + + enum PowerOperation { + ON, + OFF, + CYCLE, + RESET, + SOFT, + STATUS, + } + + enum PowerState { + On, + Off, + Unknown, + Disabled; + + public enum Event { + On("Chassis Power is On"), + Off("Chassis Power is Off"), + AuthError("Authentication error happened"), + Unknown("An unknown error happened"), + Enabled("Out-of-band management enabled"), + Disabled("Out-of-band management disabled"); + + private String description; + Event(String description) { + this.description = description; + } + public String toString() { + return String.format("%s(%s)", super.toString(), this.getDescription()); + } + public String getDescription() { + return description; + } + public Long getServerId() { + // TODO: change in future if we've better claim & ownership + // Right now the first one to update the db wins + // and mgmt server id would eventually become consistent + return ManagementServerNode.getManagementServerId(); + } + } + + public Event toEvent() { + if (this.equals(On)) { + return Event.On; + } else if (this.equals(Off)) { + return Event.Off; + } else if (this.equals(Disabled)) { + return Event.Disabled; + } + return Event.Unknown; + } + + private static final StateMachine2 FSM = new StateMachine2(); + static { + FSM.addInitialTransition(Event.On, On); + FSM.addInitialTransition(Event.Off, Off); + FSM.addInitialTransition(Event.Unknown, Unknown); + FSM.addInitialTransition(Event.AuthError, Unknown); + FSM.addInitialTransition(Event.Disabled, Disabled); + + FSM.addTransitionFromStates(Event.On, On, On, Off, Unknown, Disabled); + FSM.addTransitionFromStates(Event.Off, Off, On, Off, Unknown, Disabled); + FSM.addTransitionFromStates(Event.Unknown, Unknown, On, Off, Unknown, Disabled); + FSM.addTransitionFromStates(Event.AuthError, Unknown, On, Off, Disabled); + FSM.addTransitionFromStates(Event.Disabled, Disabled, On, Off, Unknown); + } + + public static StateMachine2 getStateMachine() { + return FSM; + } + + public PowerState getNextPowerState(Event e) throws NoTransitionException { + return FSM.getNextState(this, e); + } + + public Set getPossibleEvents() { + return FSM.getPossibleEvents(this); + } + + } +} diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementDriver.java b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementDriver.java new file mode 100644 index 0000000000..38489631f2 --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementDriver.java @@ -0,0 +1,25 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.outofbandmanagement; + +import com.cloud.utils.component.Adapter; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverCommand; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse; + +public interface OutOfBandManagementDriver extends Adapter { + OutOfBandManagementDriverResponse execute(OutOfBandManagementDriverCommand cmd); +} diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementService.java b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementService.java new file mode 100644 index 0000000000..699b2c6a99 --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementService.java @@ -0,0 +1,55 @@ +// 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.outofbandmanagement; + +import com.cloud.dc.DataCenter; +import com.cloud.host.Host; +import com.cloud.org.Cluster; +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.framework.config.ConfigKey; + +import java.util.List; + +public interface OutOfBandManagementService { + + ConfigKey ActionTimeout = new ConfigKey("Advanced", Long.class, "outofbandmanagement.action.timeout", "60", + "The out of band management action timeout in seconds, configurable by cluster", true, ConfigKey.Scope.Cluster); + + ConfigKey SyncThreadInterval = new ConfigKey("Advanced", Long.class, "outofbandmanagement.sync.interval", "300000", + "The interval (in milliseconds) when the out-of-band management background sync are retrieved", true, ConfigKey.Scope.Global); + + ConfigKey SyncThreadPoolSize = new ConfigKey("Advanced", Integer.class, "outofbandmanagement.sync.poolsize", "50", + "The out of band management background sync thread pool size", true, ConfigKey.Scope.Global); + + long getId(); + boolean isOutOfBandManagementEnabled(Host host); + void submitBackgroundPowerSyncTask(Host host); + boolean transitionPowerStateToDisabled(List hosts); + + OutOfBandManagementResponse enableOutOfBandManagement(DataCenter zone); + OutOfBandManagementResponse enableOutOfBandManagement(Cluster cluster); + OutOfBandManagementResponse enableOutOfBandManagement(Host host); + + OutOfBandManagementResponse disableOutOfBandManagement(DataCenter zone); + OutOfBandManagementResponse disableOutOfBandManagement(Cluster cluster); + OutOfBandManagementResponse disableOutOfBandManagement(Host host); + + OutOfBandManagementResponse configureOutOfBandManagement(Host host, ImmutableMap options); + OutOfBandManagementResponse executeOutOfBandManagementPowerOperation(Host host, OutOfBandManagement.PowerOperation operation, Long timeout); + OutOfBandManagementResponse changeOutOfBandManagementPassword(Host host, String password); +} diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverChangePasswordCommand.java b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverChangePasswordCommand.java new file mode 100644 index 0000000000..943339e74e --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverChangePasswordCommand.java @@ -0,0 +1,34 @@ +// 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.outofbandmanagement.driver; + +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; + +public final class OutOfBandManagementDriverChangePasswordCommand extends OutOfBandManagementDriverCommand { + private final String newPassword; + + public OutOfBandManagementDriverChangePasswordCommand(final ImmutableMap options, final Long timeout, final String newPassword) { + super(options, timeout); + this.newPassword = newPassword; + } + + public final String getNewPassword() { + return newPassword; + } + +} diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverCommand.java b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverCommand.java new file mode 100644 index 0000000000..999b10c612 --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverCommand.java @@ -0,0 +1,43 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.outofbandmanagement.driver; + +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.joda.time.Duration; + +public abstract class OutOfBandManagementDriverCommand { + private final ImmutableMap options; + private final Duration timeout; + + public OutOfBandManagementDriverCommand(final ImmutableMap options, final Long timeoutSeconds) { + this.options = options; + if (timeoutSeconds != null && timeoutSeconds > 0) { + this.timeout = new Duration(timeoutSeconds * 1000); + } else { + this.timeout = Duration.ZERO; + } + } + + public final ImmutableMap getOptions() { + return options; + } + + public final Duration getTimeout() { + return timeout; + } +} diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverPowerCommand.java b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverPowerCommand.java new file mode 100644 index 0000000000..406be3b044 --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverPowerCommand.java @@ -0,0 +1,33 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.outofbandmanagement.driver; + +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; + +public final class OutOfBandManagementDriverPowerCommand extends OutOfBandManagementDriverCommand { + private final OutOfBandManagement.PowerOperation powerOperation; + + public OutOfBandManagementDriverPowerCommand(final ImmutableMap options, final Long timeout, final OutOfBandManagement.PowerOperation powerOperation) { + super(options, timeout); + this.powerOperation = powerOperation; + } + + public final OutOfBandManagement.PowerOperation getPowerOperation() { + return powerOperation; + } +} diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverResponse.java b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverResponse.java new file mode 100644 index 0000000000..78a25daee2 --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverResponse.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.outofbandmanagement.driver; + +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; + +public class OutOfBandManagementDriverResponse { + private String result; + private String error; + private boolean success = false; + private boolean hasAuthFailure = false; + private OutOfBandManagement.PowerState powerState; + + public OutOfBandManagementDriverResponse(String result, String error, boolean success) { + this.result = result; + this.error = error; + this.success = success; + } + + public OutOfBandManagement.PowerState.Event toEvent() { + if (hasAuthFailure()) { + return OutOfBandManagement.PowerState.Event.AuthError; + } + + if (!isSuccess() || powerState == null) { + return OutOfBandManagement.PowerState.Event.Unknown; + } + + return powerState.toEvent(); + } + + public boolean isSuccess() { + return success; + } + + public String getResult() { + return result; + } + + public String getError() { + return error; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public void setResult(String result) { + this.result = result; + } + + public void setError(String error) { + this.error = error; + } + + public OutOfBandManagement.PowerState getPowerState() { + return powerState; + } + + public void setPowerState(OutOfBandManagement.PowerState powerState) { + this.powerState = powerState; + } + + public boolean hasAuthFailure() { + return hasAuthFailure; + } + + public void setAuthFailure(boolean hasAuthFailure) { + this.hasAuthFailure = hasAuthFailure; + } +} diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index 5e979074b6..8b8ad1a957 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -876,6 +876,7 @@ label.metrics.num.cpu.cores=Cores label.metrics.property=Property label.metrics.scope=Scope label.metrics.state=State +label.metrics.outofbandmanagementpowerstate=Power State label.metrics.storagepool=Storage Pool label.metrics.vm.name=VM Name label.migrate.instance.to.host=Migrate instance to another host @@ -1004,6 +1005,25 @@ label.pods=Pods label.port.forwarding.policies=Port forwarding policies label.port.forwarding=Port Forwarding label.port.range=Port Range +label.powerstate=Power State +label.outofbandmanagement=Out-of-band Management +label.outofbandmanagement.action.issue=Issue Out-of-band Management Power Action +label.outofbandmanagement.action=Action +label.outofbandmanagement.address=Address +label.outofbandmanagement.changepassword=Change Out-of-band Management Password +label.outofbandmanagement.configure=Configure Out-of-band Management +label.outofbandmanagement.driver=Driver +label.outofbandmanagement.disable=Disable Out-of-band Management +label.outofbandmanagement.enable=Enable Out-of-band Management +label.outofbandmanagement.password=Password +label.outofbandmanagement.port=Port +label.outofbandmanagement.username=Username +message.outofbandmanagement.changepassword=Change Out-of-band Management password +message.outofbandmanagement.configure=Configure Out-of-band Management +message.outofbandmanagement.disable=Disable Out-of-band Management +message.outofbandmanagement.enable=Enable Out-of-band Management +message.outofbandmanagement.issue=Issue Out-of-band Management Power Action +message.outofbandmanagement.action.maintenance=Warning host is in maintenance mode label.PreSetup=PreSetup label.prev=Prev label.previous=Previous diff --git a/client/pom.xml b/client/pom.xml index 9bd80b722c..7310cef4f9 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -241,6 +241,11 @@ cloud-plugin-host-allocator-random ${project.version} + + org.apache.cloudstack + cloud-plugin-outofbandmanagement-driver-ipmitool + ${project.version} + org.apache.cloudstack cloud-mom-rabbitmq diff --git a/core/resources/META-INF/cloudstack/api/spring-core-lifecycle-api-context-inheritable.xml b/core/resources/META-INF/cloudstack/api/spring-core-lifecycle-api-context-inheritable.xml index f1566b1302..1a33fa21f5 100644 --- a/core/resources/META-INF/cloudstack/api/spring-core-lifecycle-api-context-inheritable.xml +++ b/core/resources/META-INF/cloudstack/api/spring-core-lifecycle-api-context-inheritable.xml @@ -61,6 +61,5 @@ - diff --git a/core/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml b/core/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml index 5e2dc7b732..d36f98d404 100644 --- a/core/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml +++ b/core/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml @@ -306,5 +306,10 @@ class="org.apache.cloudstack.spring.lifecycle.registry.ExtensionRegistry"> - + + + + + diff --git a/core/resources/META-INF/cloudstack/outofbandmanagement/module.properties b/core/resources/META-INF/cloudstack/outofbandmanagement/module.properties new file mode 100644 index 0000000000..73d4bec9ce --- /dev/null +++ b/core/resources/META-INF/cloudstack/outofbandmanagement/module.properties @@ -0,0 +1,21 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name=outofbandmanagement +parent=core diff --git a/core/resources/META-INF/cloudstack/outofbandmanagement/spring-core-lifecycle-outofbandmanagement-context-inheritable.xml b/core/resources/META-INF/cloudstack/outofbandmanagement/spring-core-lifecycle-outofbandmanagement-context-inheritable.xml new file mode 100644 index 0000000000..6a25a2e349 --- /dev/null +++ b/core/resources/META-INF/cloudstack/outofbandmanagement/spring-core-lifecycle-outofbandmanagement-context-inheritable.xml @@ -0,0 +1,36 @@ + + + + + + + + diff --git a/debian/control b/debian/control index 6e7881b1bc..6452c03c5d 100644 --- a/debian/control +++ b/debian/control @@ -15,7 +15,7 @@ Description: A common package which contains files which are shared by several C Package: cloudstack-management Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, cloudstack-common (= ${source:Version}), tomcat6 | tomcat7, sudo, jsvc, python-mysql.connector, libmysql-java, augeas-tools, mysql-client, adduser, bzip2 +Depends: ${misc:Depends}, ${python:Depends}, cloudstack-common (= ${source:Version}), tomcat6 | tomcat7, sudo, jsvc, python-mysql.connector, libmysql-java, augeas-tools, mysql-client, adduser, bzip2, ipmitool Conflicts: cloud-server, cloud-client, cloud-client-ui Description: CloudStack server library The CloudStack management server diff --git a/developer/developer-prefill.sql b/developer/developer-prefill.sql index 0dbe1803b9..ab3da96c9f 100644 --- a/developer/developer-prefill.sql +++ b/developer/developer-prefill.sql @@ -106,6 +106,18 @@ INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', 'direct.agent.load.size', '1000'); +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'ping.interval', '10'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'ping.timeout', '1.5'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'outofbandmanagement.sync.interval', '2000'); + -- Enable dynamic RBAC by default for fresh deployments INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'RoleService', diff --git a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java index 45a7dca465..e41a5851d0 100644 --- a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -43,6 +43,7 @@ import org.apache.cloudstack.framework.jobs.AsyncJob; import org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext; import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao; import org.apache.cloudstack.utils.identity.ManagementServerNode; import org.apache.log4j.Logger; import org.slf4j.MDC; @@ -139,6 +140,8 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl @Inject protected HostDao _hostDao = null; @Inject + protected OutOfBandManagementDao outOfBandManagementDao; + @Inject protected DataCenterDao _dcDao = null; @Inject protected HostPodDao _podDao = null; diff --git a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java index 91085bf8d1..9239adc091 100644 --- a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java @@ -736,6 +736,7 @@ public void onManagementNodeLeft(final List node s_logger.info("Marking hosts as disconnected on Management server" + vo.getMsid()); final long lastPing = (System.currentTimeMillis() >> 10) - getTimeout(); _hostDao.markHostsAsDisconnected(vo.getMsid(), lastPing); + outOfBandManagementDao.expireOutOfBandManagementOwnershipByServer(vo.getMsid()); s_logger.info("Deleting entries from op_host_transfer table for Management server " + vo.getMsid()); cleanupTransferMap(vo.getMsid()); } diff --git a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index a3d58fc539..691647829e 100644 --- a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -347,6 +347,6 @@ - + diff --git a/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDao.java b/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDao.java index ed7c494744..1422e3f4d3 100644 --- a/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDao.java +++ b/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDao.java @@ -16,10 +16,10 @@ // under the License. package com.cloud.dc.dao; -import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; - import com.cloud.dc.DataCenterDetailVO; import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; public interface DataCenterDetailsDao extends GenericDao, ResourceDetailsDao { + void persist(long zoneId, String name, String value); } \ No newline at end of file diff --git a/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDaoImpl.java index 8bc9effc7f..e36c8ebd6c 100644 --- a/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDaoImpl.java +++ b/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDaoImpl.java @@ -16,7 +16,6 @@ // under the License. package com.cloud.dc.dao; - import org.apache.cloudstack.api.ResourceDetail; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.ConfigKey.Scope; @@ -24,9 +23,21 @@ import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; import com.cloud.dc.DataCenterDetailVO; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.TransactionLegacy; public class DataCenterDetailsDaoImpl extends ResourceDetailsDaoBase implements DataCenterDetailsDao, ScopedConfigStorage { + private final SearchBuilder DetailSearch; + + DataCenterDetailsDaoImpl() { + DetailSearch = createSearchBuilder(); + DetailSearch.and("zoneId", DetailSearch.entity().getResourceId(), SearchCriteria.Op.EQ); + DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ); + DetailSearch.done(); + } + @Override public Scope getScope() { return ConfigKey.Scope.Zone; @@ -43,4 +54,17 @@ public void addDetail(long resourceId, String key, String value, boolean display super.addDetail(new DataCenterDetailVO(resourceId, key, value, display)); } + @Override + public void persist(long zoneId, String name, String value) { + TransactionLegacy txn = TransactionLegacy.currentTxn(); + txn.start(); + SearchCriteria sc = DetailSearch.create(); + sc.setParameters("zoneId", zoneId); + sc.setParameters("name", name); + expunge(sc); + + DataCenterDetailVO vo = new DataCenterDetailVO(zoneId, name, value, true); + persist(vo); + txn.commit(); + } } diff --git a/engine/schema/src/com/cloud/host/dao/HostDao.java b/engine/schema/src/com/cloud/host/dao/HostDao.java index bd484825c8..26e0644c59 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDao.java +++ b/engine/schema/src/com/cloud/host/dao/HostDao.java @@ -81,6 +81,8 @@ public interface HostDao extends GenericDao, StateDao listAllUpAndEnabledNonHAHosts(Type type, Long clusterId, Long podId, long dcId, String haTag); + List findByDataCenterId(Long zoneId); + List findByPodId(Long podId); List findByClusterId(Long clusterId); @@ -89,5 +91,7 @@ public interface HostDao extends GenericDao, StateDao listAllHosts(long zoneId); + List listAllHostsByType(Host.Type type); + HostVO findByPublicIp(String publicIp); } diff --git a/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java b/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java index 8342f1fcf7..09d9d40cd5 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java +++ b/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java @@ -1048,6 +1048,14 @@ public HostVO findByTypeNameAndZoneId(long zoneId, String name, Host.Type type) return findOneBy(sc); } + @Override + public List findByDataCenterId(Long zoneId) { + SearchCriteria sc = DcSearch.create(); + sc.setParameters("dc", zoneId); + sc.setParameters("type", Type.Routing); + return listBy(sc); + } + @Override public List findByPodId(Long podId) { SearchCriteria sc = PodSearch.create(); @@ -1087,4 +1095,13 @@ public List listAllHosts(long zoneId) { sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, zoneId); return customSearch(sc, null); } + + @Override + public List listAllHostsByType(Host.Type type) { + SearchCriteria sc = TypeSearch.create(); + sc.setParameters("type", type); + sc.setParameters("resourceState", ResourceState.Enabled); + + return listBy(sc); + } } diff --git a/engine/schema/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementVO.java b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementVO.java new file mode 100644 index 0000000000..b5c357c3f8 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementVO.java @@ -0,0 +1,193 @@ +// 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.outofbandmanagement; + +import com.cloud.utils.db.Encrypt; +import com.cloud.utils.db.StateMachine; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import java.util.Date; + +@Entity +@Table(name = "oobm") +public class OutOfBandManagementVO implements OutOfBandManagement { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "host_id") + private Long hostId; + + @Column(name = "enabled") + private boolean enabled = false; + + // There is no setter for status because it has to be set in the dao code + @Enumerated(value = EnumType.STRING) + @StateMachine(state = PowerState.class, event = PowerState.Event.class) + @Column(name = "power_state", updatable = true, nullable = false, length = 32) + private PowerState powerState = null; + + @Column(name = "driver") + private String driver; + + @Column(name = "address") + private String address; + + @Column(name = "port") + private Integer port; + + @Column(name = "username") + private String username; + + @Encrypt + @Column(name = "password") + private String password; + + // This field should be updated every time the state is updated. + // There's no set method in the vo object because it is done with in the dao code. + @Column(name = "update_count", updatable = true, nullable = false) + protected long updateCount; + + @Column(name = "update_time", updatable = true) + @Temporal(value = TemporalType.TIMESTAMP) + protected Date updateTime; + + @Column(name = "mgmt_server_id") + private Long managementServerId; + + public OutOfBandManagementVO(Long hostId) { + this.hostId = hostId; + this.powerState = PowerState.Disabled; + } + + public OutOfBandManagementVO() { + } + + @Override + public long getId() { + return id; + } + + @Override + public PowerState getState() { + return powerState; + } + + public Long getHostId() { + return hostId; + } + + public boolean isEnabled() { + return enabled; + } + + public PowerState getPowerState() { + return powerState; + } + + @Override + public String getDriver() { + return driver; + } + + @Override + public String getAddress() { + return address; + } + + @Override + public Integer getPort() { + return port; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public String getPassword() { + return password; + } + + public long incrUpdateCount() { + updateCount++; + return updateCount; + } + + public long getUpdateCount() { + return updateCount; + } + + public Date getUpdateTime() { + return updateTime; + } + + @Override + public Long getManagementServerId() { + return managementServerId; + } + + public void setHostId(Long hostId) { + this.hostId = hostId; + } + + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public void setDriver(String driver) { + this.driver = driver; + } + + @Override + public void setAddress(String address) { + this.address = address; + } + + @Override + public void setPort(Integer port) { + this.port = port; + } + + @Override + public void setUsername(String username) { + this.username = username; + } + + @Override + public void setPassword(String password) { + this.password = password; + } + + public void setManagementServerId(Long managementServerId) { + this.managementServerId = managementServerId; + } +} diff --git a/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDao.java b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDao.java new file mode 100644 index 0000000000..5985b81625 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDao.java @@ -0,0 +1,31 @@ +// 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.outofbandmanagement.dao; + +import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementVO; + +import java.util.List; + +public interface OutOfBandManagementDao extends GenericDao, StateDao { + OutOfBandManagement findByHost(long hostId); + List findAllByManagementServer(long serverId); + void expireOutOfBandManagementOwnershipByServer(long serverId); +} diff --git a/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDaoImpl.java b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDaoImpl.java new file mode 100644 index 0000000000..b914b6b702 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDaoImpl.java @@ -0,0 +1,158 @@ +// 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.outofbandmanagement.dao; + +import com.cloud.utils.DateUtil; +import com.cloud.utils.db.Attribute; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallbackNoReturn; +import com.cloud.utils.db.TransactionLegacy; +import com.cloud.utils.db.TransactionStatus; +import com.cloud.utils.db.UpdateBuilder; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementVO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.List; + +@DB +@Component +public class OutOfBandManagementDaoImpl extends GenericDaoBase implements OutOfBandManagementDao { + private static final Logger LOG = Logger.getLogger(OutOfBandManagementDaoImpl.class); + + private SearchBuilder HostSearch; + private SearchBuilder ManagementServerSearch; + private SearchBuilder OutOfBandManagementOwnerSearch; + private SearchBuilder StateUpdateSearch; + + private Attribute PowerStateAttr; + private Attribute MsIdAttr; + private Attribute UpdateTimeAttr; + + public OutOfBandManagementDaoImpl() { + super(); + + HostSearch = createSearchBuilder(); + HostSearch.and("hostId", HostSearch.entity().getHostId(), SearchCriteria.Op.EQ); + HostSearch.done(); + + ManagementServerSearch = createSearchBuilder(); + ManagementServerSearch.and("server", ManagementServerSearch.entity().getManagementServerId(), SearchCriteria.Op.EQ); + ManagementServerSearch.done(); + + OutOfBandManagementOwnerSearch = createSearchBuilder(); + OutOfBandManagementOwnerSearch.and("server", OutOfBandManagementOwnerSearch.entity().getManagementServerId(), SearchCriteria.Op.EQ); + OutOfBandManagementOwnerSearch.or("serverNull", OutOfBandManagementOwnerSearch.entity().getManagementServerId(), SearchCriteria.Op.NULL); + OutOfBandManagementOwnerSearch.done(); + + StateUpdateSearch = createSearchBuilder(); + StateUpdateSearch.and("status", StateUpdateSearch.entity().getPowerState(), SearchCriteria.Op.EQ); + StateUpdateSearch.and("id", StateUpdateSearch.entity().getId(), SearchCriteria.Op.EQ); + StateUpdateSearch.and("update", StateUpdateSearch.entity().getUpdateCount(), SearchCriteria.Op.EQ); + StateUpdateSearch.done(); + + PowerStateAttr = _allAttributes.get("powerState"); + MsIdAttr = _allAttributes.get("managementServerId"); + UpdateTimeAttr = _allAttributes.get("updateTime"); + assert (PowerStateAttr != null && MsIdAttr != null && UpdateTimeAttr != null) : "Couldn't find one of these attributes"; + } + + @Override + public OutOfBandManagement findByHost(long hostId) { + SearchCriteria sc = HostSearch.create("hostId", hostId); + return findOneBy(sc); + } + + @Override + public List findAllByManagementServer(long serverId) { + SearchCriteria sc = OutOfBandManagementOwnerSearch.create(); + sc.setParameters("server", serverId); + return listBy(sc, new Filter(OutOfBandManagementVO.class, "updateTime", true, null, null)); + } + + private void executeExpireOwnershipSql(final String sql, final long resource) { + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + TransactionLegacy txn = TransactionLegacy.currentTxn(); + try (final PreparedStatement pstmt = txn.prepareAutoCloseStatement(sql);) { + pstmt.setLong(1, resource); + pstmt.executeUpdate(); + } catch (SQLException e) { + txn.rollback(); + LOG.warn("Failed to expire ownership for out-of-band management server id: " + resource); + } + } + }); + } + + @Override + public void expireOutOfBandManagementOwnershipByServer(long serverId) { + final String resetOwnerSql = "UPDATE oobm set mgmt_server_id=NULL, power_state=NULL where mgmt_server_id=?"; + executeExpireOwnershipSql(resetOwnerSql, serverId); + if (LOG.isDebugEnabled()) { + LOG.debug("Expired out-of-band management ownership for hosts owned by management server id:" + serverId); + } + } + + @Override + public boolean updateState(OutOfBandManagement.PowerState oldStatus, OutOfBandManagement.PowerState.Event event, OutOfBandManagement.PowerState newStatus, OutOfBandManagement vo, Object data) { + OutOfBandManagementVO oobmHost = (OutOfBandManagementVO) vo; + if (oobmHost == null) { + if (LOG.isTraceEnabled()) { + LOG.trace("Invalid out-of-band management host view object provided"); + } + return false; + } + + Long newManagementServerId = event.getServerId(); + // Avoid updates when old ownership and state are same as new + if (oldStatus == newStatus && (oobmHost.getManagementServerId() != null && oobmHost.getManagementServerId().equals(newManagementServerId))) { + return false; + } + + if (event == OutOfBandManagement.PowerState.Event.Disabled) { + newManagementServerId = null; + } + + SearchCriteria sc = StateUpdateSearch.create(); + sc.setParameters("status", oldStatus); + sc.setParameters("id", oobmHost.getId()); + sc.setParameters("update", oobmHost.getUpdateCount()); + + oobmHost.incrUpdateCount(); + UpdateBuilder ub = getUpdateBuilder(oobmHost); + ub.set(oobmHost, PowerStateAttr, newStatus); + ub.set(oobmHost, UpdateTimeAttr, DateUtil.currentGMTTime()); + ub.set(oobmHost, MsIdAttr, newManagementServerId); + + int result = update(ub, sc, null); + if (LOG.isDebugEnabled() && result <= 0) { + LOG.debug(String.format("Failed to update out-of-band management power state from:%s to:%s due to event:%s for the host id:%d", oldStatus, newStatus, event, oobmHost.getHostId())); + } + return result > 0; + } +} diff --git a/plugins/outofbandmanagement-drivers/ipmitool/pom.xml b/plugins/outofbandmanagement-drivers/ipmitool/pom.xml new file mode 100644 index 0000000000..be4cd86bef --- /dev/null +++ b/plugins/outofbandmanagement-drivers/ipmitool/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + cloud-plugin-outofbandmanagement-driver-ipmitool + Apache CloudStack Plugin - Power Management Driver ipmitool + + org.apache.cloudstack + cloudstack-plugins + 4.9.0-SNAPSHOT + ../../pom.xml + + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + org.apache.cloudstack + cloud-api + ${project.version} + + + diff --git a/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/module.properties b/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/module.properties new file mode 100644 index 0000000000..f6499d746b --- /dev/null +++ b/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/module.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +name=ipmitool +parent=outofbandmanagement diff --git a/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/spring-ipmitool-context.xml b/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/spring-ipmitool-context.xml new file mode 100644 index 0000000000..49baa90da3 --- /dev/null +++ b/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/spring-ipmitool-context.xml @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolOutOfBandManagementDriver.java b/plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolOutOfBandManagementDriver.java new file mode 100644 index 0000000000..bad3cb61ac --- /dev/null +++ b/plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolOutOfBandManagementDriver.java @@ -0,0 +1,167 @@ +// 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.outofbandmanagement.driver.ipmitool; + +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementDriver; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverChangePasswordCommand; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverCommand; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverPowerCommand; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse; +import org.apache.log4j.Logger; +import org.joda.time.Duration; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public final class IpmitoolOutOfBandManagementDriver extends AdapterBase implements OutOfBandManagementDriver, Configurable { + public static final Logger LOG = Logger.getLogger(IpmitoolOutOfBandManagementDriver.class); + + private static volatile boolean isDriverEnabled = false; + private static boolean isIpmiToolBinAvailable = false; + + private final ExecutorService ipmitoolExecutor = Executors.newFixedThreadPool(OutOfBandManagementService.SyncThreadPoolSize.value(), new NamedThreadFactory("IpmiToolDriver")); + private final IpmitoolWrapper IPMITOOL = new IpmitoolWrapper(ipmitoolExecutor); + + public final ConfigKey IpmiToolPath = new ConfigKey("Advanced", String.class, "outofbandmanagement.ipmitool.path", "/usr/bin/ipmitool", + "The out of band management ipmitool path used by the IpmiTool driver. Default: /usr/bin/ipmitool.", true, ConfigKey.Scope.Global); + + public final ConfigKey IpmiToolInterface = new ConfigKey("Advanced", String.class, "outofbandmanagement.ipmitool.interface", "lanplus", + "The out of band management IpmiTool driver interface to use. Default: lanplus. Valid values are: lan, lanplus, open etc.", true, ConfigKey.Scope.Global); + + public final ConfigKey IpmiToolRetries = new ConfigKey("Advanced", String.class, "outofbandmanagement.ipmitool.retries", "1", + "The out of band management IpmiTool driver retries option -R. Default 1.", true, ConfigKey.Scope.Global); + + private String getIpmiUserId(ImmutableMap options, final Duration timeOut) { + final String username = options.get(OutOfBandManagement.Option.USERNAME); + if (Strings.isNullOrEmpty(username)) { + throw new CloudRuntimeException("Empty IPMI user configured, cannot proceed to find user's ID"); + } + + final List ipmiToolCommands = IPMITOOL.getIpmiToolCommandArgs(IpmiToolPath.value(), + IpmiToolInterface.value(), + IpmiToolRetries.value(), + options, "user", "list"); + final OutOfBandManagementDriverResponse output = IPMITOOL.executeCommands(ipmiToolCommands, timeOut); + if (!output.isSuccess()) { + throw new CloudRuntimeException("Failed to find IPMI user to change password, error: " + output.getError()); + } + + final String userId = IPMITOOL.findIpmiUser(output.getResult(), username); + if (Strings.isNullOrEmpty(userId)) { + throw new CloudRuntimeException("No IPMI user ID found for the username: " + username); + } + return userId; + } + + public OutOfBandManagementDriverResponse execute(final OutOfBandManagementDriverCommand cmd) { + if (!isIpmiToolBinAvailable) { + initDriver(); + if (!isIpmiToolBinAvailable) { + return new OutOfBandManagementDriverResponse(null, "Aborting operation due to ipmitool binary not available for execution", false); + } + } + + OutOfBandManagementDriverResponse response = new OutOfBandManagementDriverResponse(null, "Unsupported Command", false); + if (!isDriverEnabled) { + response.setError("Driver not enabled or shutdown"); + return response; + } + if (cmd instanceof OutOfBandManagementDriverPowerCommand) { + response = execute((OutOfBandManagementDriverPowerCommand) cmd); + } else if (cmd instanceof OutOfBandManagementDriverChangePasswordCommand) { + response = execute((OutOfBandManagementDriverChangePasswordCommand) cmd); + } + + if (response != null && !response.isSuccess() && response.getError().contains("RAKP 2 HMAC is invalid")) { + response.setAuthFailure(true); + } + return response; + } + + private OutOfBandManagementDriverResponse execute(final OutOfBandManagementDriverPowerCommand cmd) { + List ipmiToolCommands = IPMITOOL.getIpmiToolCommandArgs(IpmiToolPath.value(), + IpmiToolInterface.value(), + IpmiToolRetries.value(), + cmd.getOptions(), "chassis", "power", IPMITOOL.parsePowerCommand(cmd.getPowerOperation())); + + final OutOfBandManagementDriverResponse response = IPMITOOL.executeCommands(ipmiToolCommands, cmd.getTimeout()); + + if (response.isSuccess() && cmd.getPowerOperation().equals(OutOfBandManagement.PowerOperation.STATUS)) { + response.setPowerState(IPMITOOL.parsePowerState(response.getResult().trim())); + } + return response; + } + + private OutOfBandManagementDriverResponse execute(final OutOfBandManagementDriverChangePasswordCommand cmd) { + final String outOfBandManagementUserId = getIpmiUserId(cmd.getOptions(), cmd.getTimeout()); + + final List ipmiToolCommands = IPMITOOL.getIpmiToolCommandArgs(IpmiToolPath.value(), + IpmiToolInterface.value(), IpmiToolRetries.value(), + cmd.getOptions(), "user", "set", "password", outOfBandManagementUserId, cmd.getNewPassword()); + return IPMITOOL.executeCommands(ipmiToolCommands, cmd.getTimeout()); + } + + private void initDriver() { + isDriverEnabled = true; + final OutOfBandManagementDriverResponse output = IPMITOOL.executeCommands(Arrays.asList(IpmiToolPath.value(), "-V")); + if (output.isSuccess() && output.getResult().startsWith("ipmitool version")) { + isIpmiToolBinAvailable = true; + LOG.debug("OutOfBandManagementDriver ipmitool initialized: " + output.getResult()); + } else { + isIpmiToolBinAvailable = false; + LOG.error("OutOfBandManagementDriver ipmitool failed initialization with error: " + output.getError() + "; standard output: " + output.getResult()); + } + } + + private void stopDriver() { + isDriverEnabled = false; + } + + @Override + public boolean start() { + initDriver(); + return true; + } + + @Override + public boolean stop() { + ipmitoolExecutor.shutdown(); + stopDriver(); + return true; + } + + @Override + public String getConfigComponentName() { + return IpmitoolOutOfBandManagementDriver.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[] {IpmiToolPath, IpmiToolInterface, IpmiToolRetries}; + } +} diff --git a/plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapper.java b/plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapper.java new file mode 100644 index 0000000000..f5896b2073 --- /dev/null +++ b/plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapper.java @@ -0,0 +1,181 @@ +// 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.outofbandmanagement.driver.ipmitool; + +import com.cloud.utils.StringUtils; +import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse; +import org.apache.cloudstack.utils.process.ProcessResult; +import org.apache.cloudstack.utils.process.ProcessRunner; +import org.apache.log4j.Logger; +import org.joda.time.Duration; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; + +public final class IpmitoolWrapper { + public static final Logger LOG = Logger.getLogger(IpmitoolWrapper.class); + + private final ProcessRunner RUNNER; + + public IpmitoolWrapper(ExecutorService executor) { + this.RUNNER = new ProcessRunner(executor); + } + + public String parsePowerCommand(OutOfBandManagement.PowerOperation operation) { + if (operation == null) { + throw new IllegalStateException("Invalid power operation requested"); + } + switch (operation) { + case ON: + case OFF: + case CYCLE: + case RESET: + case SOFT: + case STATUS: + break; + default: + throw new IllegalStateException("Invalid power operation requested"); + } + return operation.toString().toLowerCase(); + } + + public OutOfBandManagement.PowerState parsePowerState(final String standardOutput) { + if (Strings.isNullOrEmpty(standardOutput)) { + return OutOfBandManagement.PowerState.Unknown; + } + if (standardOutput.equals("Chassis Power is on")) { + return OutOfBandManagement.PowerState.On; + } else if (standardOutput.equals("Chassis Power is off")) { + return OutOfBandManagement.PowerState.Off; + } + return OutOfBandManagement.PowerState.Unknown; + } + + public List getIpmiToolCommandArgs(final String ipmiToolPath, final String ipmiInterface, final String retries, + final ImmutableMap options, String... commands) { + + final ImmutableList.Builder ipmiToolCommands = ImmutableList.builder() + .add(ipmiToolPath) + .add("-I") + .add(ipmiInterface) + .add("-R") + .add(retries) + .add("-v"); + + if (options != null) { + for (ImmutableMap.Entry option : options.entrySet()) { + switch (option.getKey()) { + case ADDRESS: + ipmiToolCommands.add("-H"); + break; + case PORT: + ipmiToolCommands.add("-p"); + break; + case USERNAME: + ipmiToolCommands.add("-U"); + break; + case PASSWORD: + ipmiToolCommands.add("-P"); + break; + default: + continue; + } + ipmiToolCommands.add(option.getValue()); + } + } + for (String command : commands) { + ipmiToolCommands.add(command); + } + return ipmiToolCommands.build(); + } + + public String findIpmiUser(final String usersList, final String username) { + /** + * Expected usersList string contains legends on first line and users on rest + * ID Name Callin Link Auth IPMI Msg Channel Priv Limit + * 1 admin true true true ADMINISTRATOR + */ + + // Assuming user 'ID' index on 1st position + int idIndex = 0; + + // Assuming user 'Name' index on 2nd position + int usernameIndex = 1; + + final String[] lines = usersList.split("\\r?\\n"); + if (lines.length < 2) { + throw new CloudRuntimeException("Error parsing user ID from ipmi user listing"); + } + // Find user and name indexes from the 1st line if not on default position + final String[] legends = lines[0].split(" +"); + for (int idx = 0; idx < legends.length; idx++) { + if (legends[idx].equals("ID")) { + idIndex = idx; + } + if (legends[idx].equals("Name")) { + usernameIndex = idx; + } + } + // Find user 'ID' based on provided username and ID/Name positions + String userId = null; + for (int idx = 1; idx < lines.length; idx++) { + final String[] words = lines[idx].split(" +"); + if (usernameIndex < words.length && idIndex < words.length) { + if (words[usernameIndex].equals(username)) { + userId = words[idIndex]; + } + } + } + return userId; + } + + public OutOfBandManagementDriverResponse executeCommands(final List commands) { + return executeCommands(commands, ProcessRunner.DEFAULT_MAX_TIMEOUT); + } + + public OutOfBandManagementDriverResponse executeCommands(final List commands, final Duration timeOut) { + final ProcessResult result = RUNNER.executeCommands(commands, timeOut); + if (LOG.isTraceEnabled()) { + List cleanedCommands = new ArrayList(); + int maskNextCommand = 0; + for (String command : commands) { + if (maskNextCommand > 0) { + cleanedCommands.add("**** "); + maskNextCommand--; + continue; + } + if (command.equalsIgnoreCase("-P")) { + maskNextCommand = 1; + } else if (command.toLowerCase().endsWith("password")) { + maskNextCommand = 2; + } + cleanedCommands.add(command); + } + LOG.trace("Executed ipmitool process with commands: " + StringUtils.join(cleanedCommands, ", ") + + "\nIpmitool execution standard output: " + result.getStdOutput() + + "\nIpmitool execution error output: " + result.getStdError()); + } + return new OutOfBandManagementDriverResponse(result.getStdOutput(), result.getStdError(), result.isSuccess()); + } +} \ No newline at end of file diff --git a/plugins/outofbandmanagement-drivers/ipmitool/test/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapperTest.java b/plugins/outofbandmanagement-drivers/ipmitool/test/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapperTest.java new file mode 100644 index 0000000000..86eff86b02 --- /dev/null +++ b/plugins/outofbandmanagement-drivers/ipmitool/test/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapperTest.java @@ -0,0 +1,115 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package org.apache.cloudstack.outofbandmanagement.driver.ipmitool; + +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@RunWith(MockitoJUnitRunner.class) +public class IpmitoolWrapperTest { + + private static final ExecutorService ipmitoolExecutor = Executors.newFixedThreadPool(20, new NamedThreadFactory("IpmiToolDriverTest")); + private static final IpmitoolWrapper IPMITOOL = new IpmitoolWrapper(ipmitoolExecutor); + + @Test + public void testParsePowerCommandValid() { + Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.ON), "on"); + Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.OFF), "off"); + Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.CYCLE), "cycle"); + Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.RESET), "reset"); + Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.SOFT), "soft"); + Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.STATUS), "status"); + } + + @Test(expected = IllegalStateException.class) + public void testParsePowerCommandInvalid() { + IPMITOOL.parsePowerCommand(null); + Assert.fail("IpmitoolWrapper.parsePowerCommand failed to throw exception on invalid power state"); + } + + @Test + public void testParsePowerState() { + Assert.assertEquals(IPMITOOL.parsePowerState(null), OutOfBandManagement.PowerState.Unknown); + Assert.assertEquals(IPMITOOL.parsePowerState(""), OutOfBandManagement.PowerState.Unknown); + Assert.assertEquals(IPMITOOL.parsePowerState(" "), OutOfBandManagement.PowerState.Unknown); + Assert.assertEquals(IPMITOOL.parsePowerState("invalid data"), OutOfBandManagement.PowerState.Unknown); + Assert.assertEquals(IPMITOOL.parsePowerState("Chassis Power is on"), OutOfBandManagement.PowerState.On); + Assert.assertEquals(IPMITOOL.parsePowerState("Chassis Power is off"), OutOfBandManagement.PowerState.Off); + } + + @Test + public void testGetIpmiToolCommandArgs() { + List args = IPMITOOL.getIpmiToolCommandArgs("binpath", "intf", "1", null); + assert args != null; + Assert.assertEquals(args.size(), 6); + Assert.assertArrayEquals(args.toArray(), new String[]{"binpath", "-I", "intf", "-R", "1", "-v"}); + + ImmutableMap.Builder argMap = new ImmutableMap.Builder<>(); + argMap.put(OutOfBandManagement.Option.DRIVER, "ipmitool"); + argMap.put(OutOfBandManagement.Option.ADDRESS, "127.0.0.1"); + List argsWithOpts = IPMITOOL.getIpmiToolCommandArgs("binpath", "intf", "1", argMap.build(), "user", "list"); + assert argsWithOpts != null; + Assert.assertEquals(argsWithOpts.size(), 10); + Assert.assertArrayEquals(argsWithOpts.toArray(), new String[]{"binpath", "-I", "intf", "-R", "1", "-v", "-H", "127.0.0.1", "user", "list"}); + } + + @Test(expected = CloudRuntimeException.class) + public void testFindIpmiUserInvalid() { + IPMITOOL.findIpmiUser("some invalid string\n", "admin"); + Assert.fail("IpmitoolWrapper.findIpmiUser failed to throw exception on invalid data"); + + Assert.assertEquals(IPMITOOL.findIpmiUser("some\ninvalid\ndata\n", "admin"), null); + } + + @Test + public void testFindIpmiUserNull() { + Assert.assertEquals(IPMITOOL.findIpmiUser("some\ninvalid\ndata\n", "admin"), null); + } + + @Test + public void testFindIpmiUserValid() { + String usersList = "ID Name\t Callin Link Auth\tIPMI Msg Channel Priv Limit\n" + + "1 admin true true true ADMINISTRATOR\n" + + "2 operator true false false OPERATOR\n" + + "3 user true true true USER\n"; + Assert.assertEquals(IPMITOOL.findIpmiUser(usersList, "admin"), "1"); + Assert.assertEquals(IPMITOOL.findIpmiUser(usersList, "operator"), "2"); + Assert.assertEquals(IPMITOOL.findIpmiUser(usersList, "user"), "3"); + } + + @Test + public void testExecuteCommands() { + OutOfBandManagementDriverResponse r = IPMITOOL.executeCommands(Arrays.asList("ls", "/tmp")); + Assert.assertTrue(r.isSuccess()); + Assert.assertTrue(r.getResult().length() > 0); + } +} \ No newline at end of file diff --git a/plugins/pom.xml b/plugins/pom.xml index 1a2581972a..25f06876fa 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -80,6 +80,7 @@ network-elements/midonet network-elements/stratosphere-ssp network-elements/opendaylight + outofbandmanagement-drivers/ipmitool storage-allocators/random user-authenticators/ldap user-authenticators/md5 diff --git a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml index 6618e3ee5c..b25c1c3d3a 100644 --- a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml +++ b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml @@ -142,6 +142,10 @@ + + + + diff --git a/server/src/com/cloud/alert/AlertManagerImpl.java b/server/src/com/cloud/alert/AlertManagerImpl.java index 9b9802a095..e18d231e17 100644 --- a/server/src/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/com/cloud/alert/AlertManagerImpl.java @@ -758,7 +758,8 @@ public void sendAlert(AlertType alertType, long dataCenterId, Long podId, Long c (alertType != AlertManager.AlertType.ALERT_TYPE_STORAGE_MISC) && (alertType != AlertManager.AlertType.ALERT_TYPE_MANAGMENT_NODE) && (alertType != AlertManager.AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED) && - (alertType != AlertManager.AlertType.ALERT_TYPE_UPLOAD_FAILED)) { + (alertType != AlertManager.AlertType.ALERT_TYPE_UPLOAD_FAILED) && + (alertType != AlertManager.AlertType.ALERT_TYPE_OOBM_AUTH_ERROR)) { alert = _alertDao.getLastAlert(alertType.getType(), dataCenterId, podId, clusterId); } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 1c256440d4..39ac5c4a20 100644 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -191,6 +191,7 @@ import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.ResourceCount; import com.cloud.configuration.ResourceLimit; +import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; import com.cloud.dc.HostPodVO; @@ -342,6 +343,8 @@ public class ApiResponseHelper implements ResponseGenerator { private SnapshotDataStoreDao _snapshotStoreDao; @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject + private ClusterDetailsDao _clusterDetailsDao; @Override public UserResponse createUserResponse(User user) { @@ -1053,6 +1056,7 @@ public ClusterResponse createClusterResponse(Cluster cluster, Boolean showCapaci String memoryOvercommitRatio = ApiDBUtils.findClusterDetails(cluster.getId(), "memoryOvercommitRatio"); clusterResponse.setCpuOvercommitRatio(cpuOvercommitRatio); clusterResponse.setMemoryOvercommitRatio(memoryOvercommitRatio); + clusterResponse.setResourceDetails(_clusterDetailsDao.findDetails(cluster.getId())); if (showCapacities != null && showCapacities) { List capacities = ApiDBUtils.getCapacityByClusterPodZone(null, null, cluster.getId()); diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 781b1959ad..3cdd4bb791 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -1577,6 +1577,8 @@ public Pair, Integer> searchForServersInternal(ListHostsCmd cmd Object cluster = cmd.getClusterId(); Object id = cmd.getId(); Object keyword = cmd.getKeyword(); + Object outOfBandManagementEnabled = cmd.isOutOfBandManagementEnabled(); + Object powerState = cmd.getHostOutOfBandManagementPowerState(); Object resourceState = cmd.getResourceState(); Object haHosts = cmd.getHaHost(); Long startIndex = cmd.getStartIndex(); @@ -1595,6 +1597,8 @@ public Pair, Integer> searchForServersInternal(ListHostsCmd cmd sb.and("dataCenterId", sb.entity().getZoneId(), SearchCriteria.Op.EQ); sb.and("podId", sb.entity().getPodId(), SearchCriteria.Op.EQ); sb.and("clusterId", sb.entity().getClusterId(), SearchCriteria.Op.EQ); + sb.and("oobmEnabled", sb.entity().isOutOfBandManagementEnabled(), SearchCriteria.Op.EQ); + sb.and("powerState", sb.entity().getOutOfBandManagementPowerState(), SearchCriteria.Op.EQ); sb.and("resourceState", sb.entity().getResourceState(), SearchCriteria.Op.EQ); sb.and("hypervisor_type", sb.entity().getHypervisorType(), SearchCriteria.Op.EQ); @@ -1644,6 +1648,14 @@ public Pair, Integer> searchForServersInternal(ListHostsCmd cmd sc.setParameters("clusterId", cluster); } + if (outOfBandManagementEnabled != null) { + sc.setParameters("oobmEnabled", outOfBandManagementEnabled); + } + + if (powerState != null) { + sc.setParameters("powerState", powerState); + } + if (resourceState != null) { sc.setParameters("resourceState", resourceState); } diff --git a/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java index 970c2b21f1..6c15a8be4d 100644 --- a/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java @@ -22,7 +22,6 @@ import java.util.EnumSet; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; import javax.inject.Inject; @@ -36,6 +35,7 @@ import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.VgpuResponse; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao; import com.cloud.api.ApiDBUtils; import com.cloud.api.query.vo.HostJoinVO; @@ -43,8 +43,7 @@ import com.cloud.gpu.VGPUTypesVO; import com.cloud.host.Host; import com.cloud.host.HostStats; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; +import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor; import com.cloud.storage.StorageStats; import com.cloud.utils.db.GenericDaoBase; @@ -58,7 +57,9 @@ public class HostJoinDaoImpl extends GenericDaoBase implements @Inject private ConfigurationDao _configDao; @Inject - private HostDao hostDao; + private HostDetailsDao hostDetailsDao; + @Inject + private OutOfBandManagementDao outOfBandManagementDao; private final SearchBuilder hostSearch; @@ -189,11 +190,7 @@ public HostResponse newHostResponse(HostJoinVO host, EnumSet detail if (details.contains(HostDetails.all) && host.getHypervisorType() == Hypervisor.HypervisorType.KVM) { //only kvm has the requirement to return host details try { - HostVO h = hostDao.findById(host.getId()); - hostDao.loadDetails(h); - Map hostVoDetails; - hostVoDetails = h.getDetails(); - hostResponse.setDetails(hostVoDetails); + hostResponse.setDetails(hostDetailsDao.findDetails(host.getId())); } catch (Exception e) { s_logger.debug("failed to get host details", e); } @@ -225,6 +222,7 @@ public HostResponse newHostResponse(HostJoinVO host, EnumSet detail } } + hostResponse.setOutOfBandManagementResponse(outOfBandManagementDao.findByHost(host.getId())); hostResponse.setResourceState(host.getResourceState().toString()); // set async job diff --git a/server/src/com/cloud/api/query/vo/HostJoinVO.java b/server/src/com/cloud/api/query/vo/HostJoinVO.java index 48ac531ce8..dcd058fce1 100644 --- a/server/src/com/cloud/api/query/vo/HostJoinVO.java +++ b/server/src/com/cloud/api/query/vo/HostJoinVO.java @@ -36,6 +36,7 @@ import com.cloud.org.Cluster; import com.cloud.resource.ResourceState; import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; /** * Host DB view. @@ -91,6 +92,13 @@ public class HostJoinVO extends BaseViewVO implements InternalIdentity, Identity @Column(name = GenericDao.REMOVED_COLUMN) private Date removed; + @Column(name = "oobm_enabled") + private boolean outOfBandManagementEnabled = false; + + @Column(name = "oobm_power_state") + @Enumerated(value = EnumType.STRING) + private OutOfBandManagement.PowerState outOfBandManagementPowerState; + @Column(name = "resource_state") @Enumerated(value = EnumType.STRING) private ResourceState resourceState; @@ -244,6 +252,14 @@ public Date getRemoved() { return removed; } + public boolean isOutOfBandManagementEnabled() { + return outOfBandManagementEnabled; + } + + public OutOfBandManagement.PowerState getOutOfBandManagementPowerState() { + return outOfBandManagementPowerState; + } + public ResourceState getResourceState() { return resourceState; } diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 8341075b72..4bd30870e4 100644 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -76,6 +76,7 @@ import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterIpAddressVO; import com.cloud.dc.DataCenterVO; @@ -1349,6 +1350,11 @@ public Cluster getCluster(final Long clusterId) { return _clusterDao.findById(clusterId); } + @Override + public DataCenter getZone(Long zoneId) { + return _dcDao.findById(zoneId); + } + @Override public boolean configure(final String name, final Map params) throws ConfigurationException { _defaultSystemVMHypervisor = HypervisorType.getType(_configDao.getValue(Config.SystemVMDefaultHypervisor.toString())); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index e4ae8e1669..60b44d74c2 100644 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -133,6 +133,15 @@ import org.apache.cloudstack.api.command.admin.offering.DeleteServiceOfferingCmd; import org.apache.cloudstack.api.command.admin.offering.UpdateDiskOfferingCmd; import org.apache.cloudstack.api.command.admin.offering.UpdateServiceOfferingCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.DisableOutOfBandManagementForClusterCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.DisableOutOfBandManagementForHostCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.DisableOutOfBandManagementForZoneCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.EnableOutOfBandManagementForClusterCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.EnableOutOfBandManagementForHostCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.EnableOutOfBandManagementForZoneCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.ConfigureOutOfBandManagementCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.IssueOutOfBandManagementPowerActionCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.ChangeOutOfBandManagementPasswordCmd; import org.apache.cloudstack.api.command.admin.pod.CreatePodCmd; import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd; import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd; @@ -3021,6 +3030,17 @@ public List> getCommands() { cmdList.add(UpdateLBHealthCheckPolicyCmd.class); cmdList.add(GetUploadParamsForTemplateCmd.class); cmdList.add(GetUploadParamsForVolumeCmd.class); + // Out-of-band management APIs for admins + cmdList.add(EnableOutOfBandManagementForHostCmd.class); + cmdList.add(DisableOutOfBandManagementForHostCmd.class); + cmdList.add(EnableOutOfBandManagementForClusterCmd.class); + cmdList.add(DisableOutOfBandManagementForClusterCmd.class); + cmdList.add(EnableOutOfBandManagementForZoneCmd.class); + cmdList.add(DisableOutOfBandManagementForZoneCmd.class); + cmdList.add(ConfigureOutOfBandManagementCmd.class); + cmdList.add(IssueOutOfBandManagementPowerActionCmd.class); + cmdList.add(ChangeOutOfBandManagementPasswordCmd.class); + return cmdList; } diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index 0702335308..0d53794585 100644 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -20,6 +20,7 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -33,6 +34,11 @@ import javax.inject.Inject; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementVO; +import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao; +import org.apache.cloudstack.utils.identity.ManagementServerNode; import org.apache.cloudstack.utils.usage.UsageUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -151,6 +157,8 @@ public String toString() { @Inject private HostDao _hostDao; @Inject + private OutOfBandManagementDao outOfBandManagementDao; + @Inject private UserVmDao _userVmDao; @Inject private VolumeDao _volsDao; @@ -167,6 +175,8 @@ public String toString() { @Inject private ResourceManager _resourceMgr; @Inject + private OutOfBandManagementService outOfBandManagementService; + @Inject private ConfigurationDao _configDao; @Inject private EndPointSelector _epSelector; @@ -208,6 +218,7 @@ public String toString() { private ConcurrentHashMap _storagePoolStats = new ConcurrentHashMap(); long hostStatsInterval = -1L; + long hostOutOfBandManagementStatsInterval = -1L; long hostAndVmStatsInterval = -1L; long storageStatsInterval = -1L; long volumeStatsInterval = -1L; @@ -251,8 +262,9 @@ public boolean start() { } private void init(Map configs) { - _executor = Executors.newScheduledThreadPool(4, new NamedThreadFactory("StatsCollector")); + _executor = Executors.newScheduledThreadPool(6, new NamedThreadFactory("StatsCollector")); + hostOutOfBandManagementStatsInterval = OutOfBandManagementService.SyncThreadInterval.value(); hostStatsInterval = NumbersUtil.parseLong(configs.get("host.stats.interval"), 60000L); hostAndVmStatsInterval = NumbersUtil.parseLong(configs.get("vm.stats.interval"), 60000L); storageStatsInterval = NumbersUtil.parseLong(configs.get("storage.stats.interval"), 60000L); @@ -294,6 +306,10 @@ private void init(Map configs) { _executor.scheduleWithFixedDelay(new HostCollector(), 15000L, hostStatsInterval, TimeUnit.MILLISECONDS); } + if (hostOutOfBandManagementStatsInterval > 0) { + _executor.scheduleWithFixedDelay(new HostOutOfBandManagementStatsCollector(), 15000L, hostOutOfBandManagementStatsInterval, TimeUnit.MILLISECONDS); + } + if (hostAndVmStatsInterval > 0) { _executor.scheduleWithFixedDelay(new VmStatsCollector(), 15000L, hostAndVmStatsInterval, TimeUnit.MILLISECONDS); } @@ -412,6 +428,36 @@ protected void runInContext() { } } + class HostOutOfBandManagementStatsCollector extends ManagedContextRunnable { + @Override + protected void runInContext() { + try { + s_logger.debug("HostOutOfBandManagementStatsCollector is running..."); + List outOfBandManagementHosts = outOfBandManagementDao.findAllByManagementServer(ManagementServerNode.getManagementServerId()); + if (outOfBandManagementHosts == null) { + return; + } + for (OutOfBandManagement outOfBandManagementHost : outOfBandManagementHosts) { + Host host = _hostDao.findById(outOfBandManagementHost.getHostId()); + if (host == null) { + continue; + } + if (outOfBandManagementService.isOutOfBandManagementEnabled(host)) { + outOfBandManagementService.submitBackgroundPowerSyncTask(host); + } else if (outOfBandManagementHost.getPowerState() != OutOfBandManagement.PowerState.Disabled) { + if (outOfBandManagementService.transitionPowerStateToDisabled(Collections.singletonList(host))) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Out-of-band management was disabled in zone/cluster/host, disabled power state for host id:" + host.getId()); + } + } + } + } + } catch (Throwable t) { + s_logger.error("Error trying to retrieve host out-of-band management stats", t); + } + } + } + class VmStatsCollector extends ManagedContextRunnable { @Override protected void runInContext() { diff --git a/server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementBackgroundTask.java b/server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementBackgroundTask.java new file mode 100644 index 0000000000..38e139ec61 --- /dev/null +++ b/server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementBackgroundTask.java @@ -0,0 +1,50 @@ +// 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.outofbandmanagement; + +import com.cloud.host.Host; +import org.apache.log4j.Logger; + +public class OutOfBandManagementBackgroundTask implements Runnable { + public static final Logger LOG = Logger.getLogger(OutOfBandManagementBackgroundTask.class); + + final private OutOfBandManagementService service; + final private Host host; + final private OutOfBandManagement.PowerOperation powerOperation; + + public OutOfBandManagementBackgroundTask(OutOfBandManagementService service, Host host, OutOfBandManagement.PowerOperation powerOperation) { + this.service = service; + this.host = host; + this.powerOperation = powerOperation; + } + + @Override + public String toString() { + return String.format("[OOBM Task] Power operation:%s on Host:%d(%s)", powerOperation, host.getId(), host.getName()); + } + + @Override + public void run() { + try { + service.executeOutOfBandManagementPowerOperation(host, powerOperation, null); + } catch (Exception e) { + LOG.warn(String.format("Out-of-band management background task operation=%s for host id=%d failed with: %s", + powerOperation.name(), host.getId(), e.getMessage())); + } + } +} diff --git a/server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceImpl.java b/server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceImpl.java new file mode 100644 index 0000000000..bb099c8908 --- /dev/null +++ b/server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceImpl.java @@ -0,0 +1,555 @@ +// 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.outofbandmanagement; + +import com.cloud.alert.AlertManager; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterDetailVO; +import com.cloud.dc.dao.DataCenterDetailsDao; +import com.cloud.domain.Domain; +import com.cloud.event.ActionEvent; +import com.cloud.event.ActionEventUtils; +import com.cloud.event.EventTypes; +import com.cloud.host.Host; +import com.cloud.host.dao.HostDao; +import com.cloud.org.Cluster; +import com.cloud.utils.component.Manager; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionStatus; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.NoTransitionException; +import com.google.common.base.Strings; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; +import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverChangePasswordCommand; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverPowerCommand; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse; +import org.apache.cloudstack.utils.identity.ManagementServerNode; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +@Component +public class OutOfBandManagementServiceImpl extends ManagerBase implements OutOfBandManagementService, Manager, Configurable { + public static final Logger LOG = Logger.getLogger(OutOfBandManagementServiceImpl.class); + + @Inject + private ClusterDetailsDao clusterDetailsDao; + @Inject + private DataCenterDetailsDao dataCenterDetailsDao; + @Inject + private OutOfBandManagementDao outOfBandManagementDao; + @Inject + private HostDao hostDao; + @Inject + private AlertManager alertMgr; + + private String name; + private long serviceId; + + private List outOfBandManagementDrivers = new ArrayList<>(); + private final Map outOfBandManagementDriversMap = new HashMap(); + + private static final String OOBM_ENABLED_DETAIL = "outOfBandManagementEnabled"; + private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_HOST = 120; + + private static Cache hostAlertCache; + private static ExecutorService backgroundSyncBlockingExecutor; + + private String getOutOfBandManagementHostLock(long id) { + return "oobm.host." + id; + } + + private void initializeDriversMap() { + if (outOfBandManagementDriversMap.isEmpty() && outOfBandManagementDrivers != null && outOfBandManagementDrivers.size() > 0) { + for (final OutOfBandManagementDriver driver : outOfBandManagementDrivers) { + outOfBandManagementDriversMap.put(driver.getName().toLowerCase(), driver); + } + LOG.debug("Discovered out-of-band management drivers configured in the OutOfBandManagementService"); + } + } + + private OutOfBandManagementDriver getDriver(final OutOfBandManagement outOfBandManagementConfig) { + if (!Strings.isNullOrEmpty(outOfBandManagementConfig.getDriver())) { + final OutOfBandManagementDriver driver = outOfBandManagementDriversMap.get(outOfBandManagementConfig.getDriver()); + if (driver != null) { + return driver; + } + } + throw new CloudRuntimeException("Configured out-of-band management driver is not available. Aborting any out-of-band management action."); + } + + protected OutOfBandManagement updateConfig(final OutOfBandManagement outOfBandManagementConfig, final ImmutableMap options) { + if (outOfBandManagementConfig == null) { + throw new CloudRuntimeException("Out-of-band management is not configured for the host. Aborting."); + } + if (options == null) { + return outOfBandManagementConfig; + } + for (OutOfBandManagement.Option option: options.keySet()) { + final String value = options.get(option); + if (Strings.isNullOrEmpty(value)) { + continue; + } + switch (option) { + case DRIVER: + outOfBandManagementConfig.setDriver(value); + break; + case ADDRESS: + outOfBandManagementConfig.setAddress(value); + break; + case PORT: + outOfBandManagementConfig.setPort(Integer.parseInt(value)); + break; + case USERNAME: + outOfBandManagementConfig.setUsername(value); + break; + case PASSWORD: + outOfBandManagementConfig.setPassword(value); + break; + } + } + return outOfBandManagementConfig; + } + + protected ImmutableMap getOptions(final OutOfBandManagement outOfBandManagementConfig) { + final ImmutableMap.Builder optionsBuilder = ImmutableMap.builder(); + if (outOfBandManagementConfig == null) { + throw new CloudRuntimeException("Out-of-band management is not configured for the host. Aborting."); + } + for (OutOfBandManagement.Option option: OutOfBandManagement.Option.values()) { + String value = null; + switch (option) { + case DRIVER: + value = outOfBandManagementConfig.getDriver(); + break; + case ADDRESS: + value = outOfBandManagementConfig.getAddress(); + break; + case PORT: + if (outOfBandManagementConfig.getPort() != null) { + value = String.valueOf(outOfBandManagementConfig.getPort()); + } + break; + case USERNAME: + value = outOfBandManagementConfig.getUsername(); + break; + case PASSWORD: + value = outOfBandManagementConfig.getPassword(); + break; + } + if (value != null) { + optionsBuilder.put(option, value); + } + } + return optionsBuilder.build(); + } + + private void sendAuthError(final Host host, final String message) { + try { + hostAlertCache.asMap().putIfAbsent(host.getId(), 0L); + Long sentCount = hostAlertCache.asMap().get(host.getId()); + if (sentCount != null && sentCount <= 0) { + boolean concurrentUpdateResult = hostAlertCache.asMap().replace(host.getId(), sentCount, sentCount+1L); + if (concurrentUpdateResult) { + final String subject = String.format("Out-of-band management auth-error detected for host:%d in cluster:%d, zone:%d", host.getId(), host.getClusterId(), host.getDataCenterId()); + LOG.error(subject + ": " + message); + alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_OOBM_AUTH_ERROR, host.getDataCenterId(), host.getPodId(), subject, message); + } + } + } catch (Exception ignored) { + } + } + + private boolean transitionPowerState(OutOfBandManagement.PowerState.Event event, OutOfBandManagement outOfBandManagementHost) { + if (outOfBandManagementHost == null) { + return false; + } + OutOfBandManagement.PowerState currentPowerState = outOfBandManagementHost.getPowerState(); + try { + OutOfBandManagement.PowerState newPowerState = OutOfBandManagement.PowerState.getStateMachine().getNextState(currentPowerState, event); + boolean result = outOfBandManagementDao.updateState(currentPowerState, event, newPowerState, outOfBandManagementHost, null); + if (result) { + final String message = String.format("Transitioned out-of-band management power state from:%s to:%s due to event:%s for the host id:%d", currentPowerState, newPowerState, event, outOfBandManagementHost.getHostId()); + LOG.debug(message); + ActionEventUtils.onActionEvent(CallContext.current().getCallingUserId(), CallContext.current().getCallingAccountId(), Domain.ROOT_DOMAIN, + EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_POWERSTATE_TRANSITION, message); + } + return result; + } catch (NoTransitionException ignored) { + LOG.trace(String.format("Unable to transition out-of-band management power state for host id=%s for the event=%s and current power state=%s", outOfBandManagementHost.getHostId(), event, currentPowerState)); + } + return false; + } + + private boolean isOutOfBandManagementEnabledForZone(Long zoneId) { + if (zoneId == null) { + return true; + } + final DataCenterDetailVO zoneDetails = dataCenterDetailsDao.findDetail(zoneId, OOBM_ENABLED_DETAIL); + if (zoneDetails != null && !Strings.isNullOrEmpty(zoneDetails.getValue()) && !Boolean.valueOf(zoneDetails.getValue())) { + return false; + } + return true; + } + + private boolean isOutOfBandManagementEnabledForCluster(Long clusterId) { + if (clusterId == null) { + return true; + } + final ClusterDetailsVO clusterDetails = clusterDetailsDao.findDetail(clusterId, OOBM_ENABLED_DETAIL); + if (clusterDetails != null && !Strings.isNullOrEmpty(clusterDetails.getValue()) && !Boolean.valueOf(clusterDetails.getValue())) { + return false; + } + return true; + } + + private boolean isOutOfBandManagementEnabledForHost(Long hostId) { + if (hostId == null) { + return false; + } + final OutOfBandManagement outOfBandManagementConfig = outOfBandManagementDao.findByHost(hostId); + if (outOfBandManagementConfig == null || !outOfBandManagementConfig.isEnabled()) { + return false; + } + return true; + } + + private void checkOutOfBandManagementEnabledByZoneClusterHost(final Host host) { + if (!isOutOfBandManagementEnabledForZone(host.getDataCenterId())) { + throw new CloudRuntimeException("Out-of-band management is disabled for the host's zone. Aborting Operation."); + } + if (!isOutOfBandManagementEnabledForCluster(host.getClusterId())) { + throw new CloudRuntimeException("Out-of-band management is disabled for the host's cluster. Aborting Operation."); + } + if (!isOutOfBandManagementEnabledForHost(host.getId())) { + throw new CloudRuntimeException("Out-of-band management is disabled or not configured for the host. Aborting Operation."); + } + } + + public boolean isOutOfBandManagementEnabled(final Host host) { + return isOutOfBandManagementEnabledForZone(host.getDataCenterId()) + && isOutOfBandManagementEnabledForCluster(host.getClusterId()) + && isOutOfBandManagementEnabledForHost(host.getId()); + } + + public boolean transitionPowerStateToDisabled(List hosts) { + boolean result = true; + for (Host host : hosts) { + result = result && transitionPowerState(OutOfBandManagement.PowerState.Event.Disabled, + outOfBandManagementDao.findByHost(host.getId())); + } + return result; + } + + public void submitBackgroundPowerSyncTask(final Host host) { + if (host != null) { + backgroundSyncBlockingExecutor.submit(new OutOfBandManagementBackgroundTask(this, host, OutOfBandManagement.PowerOperation.STATUS)); + } + } + + private OutOfBandManagementResponse buildEnableDisableResponse(final boolean enabled) { + final OutOfBandManagementResponse response = new OutOfBandManagementResponse(); + response.setEnabled(enabled); + response.setSuccess(true); + return response; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE, eventDescription = "enabling out-of-band management on a zone") + public OutOfBandManagementResponse enableOutOfBandManagement(final DataCenter zone) { + dataCenterDetailsDao.persist(zone.getId(), OOBM_ENABLED_DETAIL, String.valueOf(true)); + return buildEnableDisableResponse(true); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE, eventDescription = "disabling out-of-band management on a zone") + public OutOfBandManagementResponse disableOutOfBandManagement(final DataCenter zone) { + dataCenterDetailsDao.persist(zone.getId(), OOBM_ENABLED_DETAIL, String.valueOf(false)); + transitionPowerStateToDisabled(hostDao.findByDataCenterId(zone.getId())); + + return buildEnableDisableResponse(false); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE, eventDescription = "enabling out-of-band management on a cluster") + public OutOfBandManagementResponse enableOutOfBandManagement(final Cluster cluster) { + clusterDetailsDao.persist(cluster.getId(), OOBM_ENABLED_DETAIL, String.valueOf(true)); + return buildEnableDisableResponse(true); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE, eventDescription = "disabling out-of-band management on a cluster") + public OutOfBandManagementResponse disableOutOfBandManagement(final Cluster cluster) { + clusterDetailsDao.persist(cluster.getId(), OOBM_ENABLED_DETAIL, String.valueOf(false)); + transitionPowerStateToDisabled(hostDao.findByClusterId(cluster.getId())); + return buildEnableDisableResponse(false); + } + + private OutOfBandManagement getConfigForHost(final Host host) { + final OutOfBandManagement outOfBandManagementConfig = outOfBandManagementDao.findByHost(host.getId()); + if (outOfBandManagementConfig == null) { + throw new CloudRuntimeException("Out-of-band management is not configured for the host. Please configure the host before enabling/disabling it."); + } + return outOfBandManagementConfig; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE, eventDescription = "enabling out-of-band management on a host") + public OutOfBandManagementResponse enableOutOfBandManagement(final Host host) { + final OutOfBandManagement outOfBandManagementConfig = getConfigForHost(host); + hostAlertCache.invalidate(host.getId()); + outOfBandManagementConfig.setEnabled(true); + boolean updateResult = outOfBandManagementDao.update(outOfBandManagementConfig.getId(), (OutOfBandManagementVO) outOfBandManagementConfig); + if (updateResult) { + transitionPowerStateToDisabled(Collections.singletonList(host)); + } + return buildEnableDisableResponse(true); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE, eventDescription = "disabling out-of-band management on a host") + public OutOfBandManagementResponse disableOutOfBandManagement(final Host host) { + final OutOfBandManagement outOfBandManagementConfig = getConfigForHost(host); + hostAlertCache.invalidate(host.getId()); + outOfBandManagementConfig.setEnabled(false); + boolean updateResult = outOfBandManagementDao.update(outOfBandManagementConfig.getId(), (OutOfBandManagementVO) outOfBandManagementConfig); + if (updateResult) { + transitionPowerStateToDisabled(Collections.singletonList(host)); + } + return buildEnableDisableResponse(false); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_CONFIGURE, eventDescription = "updating out-of-band management configuration") + public OutOfBandManagementResponse configureOutOfBandManagement(final Host host, final ImmutableMap options) { + OutOfBandManagement outOfBandManagementConfig = outOfBandManagementDao.findByHost(host.getId()); + if (outOfBandManagementConfig == null) { + outOfBandManagementConfig = outOfBandManagementDao.persist(new OutOfBandManagementVO(host.getId())); + } + outOfBandManagementConfig = updateConfig(outOfBandManagementConfig, options); + if (Strings.isNullOrEmpty(outOfBandManagementConfig.getDriver()) || !outOfBandManagementDriversMap.containsKey(outOfBandManagementConfig.getDriver().toLowerCase())) { + throw new CloudRuntimeException("Out-of-band management driver is not available. Please provide a valid driver name."); + } + + boolean updatedConfig = outOfBandManagementDao.update(outOfBandManagementConfig.getId(), (OutOfBandManagementVO) outOfBandManagementConfig); + CallContext.current().setEventDetails("host id:" + host.getId() + " configuration:" + outOfBandManagementConfig.getAddress() + ":" + outOfBandManagementConfig.getPort()); + + if (!updatedConfig) { + throw new CloudRuntimeException("Failed to update out-of-band management config for the host in the database."); + } + + String result = "Out-of-band management successfully configured for the host"; + LOG.debug(result); + + final OutOfBandManagementResponse response = new OutOfBandManagementResponse(outOfBandManagementDao.findByHost(host.getId())); + response.setResultDescription(result); + response.setSuccess(true); + return response; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ACTION, eventDescription = "issuing host out-of-band management action", async = true) + public OutOfBandManagementResponse executeOutOfBandManagementPowerOperation(final Host host, final OutOfBandManagement.PowerOperation powerOperation, final Long timeout) { + checkOutOfBandManagementEnabledByZoneClusterHost(host); + final OutOfBandManagement outOfBandManagementConfig = getConfigForHost(host); + final ImmutableMap options = getOptions(outOfBandManagementConfig); + final OutOfBandManagementDriver driver = getDriver(outOfBandManagementConfig); + + Long actionTimeOut = timeout; + if (actionTimeOut == null) { + actionTimeOut = ActionTimeout.valueIn(host.getClusterId()); + } + + final OutOfBandManagementDriverPowerCommand cmd = new OutOfBandManagementDriverPowerCommand(options, actionTimeOut, powerOperation); + final OutOfBandManagementDriverResponse driverResponse = driver.execute(cmd); + + if (driverResponse == null) { + throw new CloudRuntimeException(String.format("Out-of-band Management action (%s) on host (%s) failed due to no response from the driver", powerOperation, host.getUuid())); + } + + if (powerOperation.equals(OutOfBandManagement.PowerOperation.STATUS)) { + transitionPowerState(driverResponse.toEvent(), outOfBandManagementConfig); + } + + if (!driverResponse.isSuccess()) { + String errorMessage = String.format("Out-of-band Management action (%s) on host (%s) failed with error: %s", powerOperation, host.getUuid(), driverResponse.getError()); + if (driverResponse.hasAuthFailure()) { + errorMessage = String.format("Out-of-band Management action (%s) on host (%s) failed due to authentication error: %s. Please check configured credentials.", powerOperation, host.getUuid(), driverResponse.getError()); + sendAuthError(host, errorMessage); + } + if (!powerOperation.equals(OutOfBandManagement.PowerOperation.STATUS)) { + LOG.debug(errorMessage); + } + throw new CloudRuntimeException(errorMessage); + } + + final OutOfBandManagementResponse response = new OutOfBandManagementResponse(outOfBandManagementDao.findByHost(host.getId())); + response.setSuccess(driverResponse.isSuccess()); + response.setResultDescription(driverResponse.getResult()); + response.setId(host.getUuid()); + response.setOutOfBandManagementAction(powerOperation.toString()); + return response; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_CHANGE_PASSWORD, eventDescription = "updating out-of-band management password") + public OutOfBandManagementResponse changeOutOfBandManagementPassword(final Host host, final String newPassword) { + checkOutOfBandManagementEnabledByZoneClusterHost(host); + if (Strings.isNullOrEmpty(newPassword)) { + throw new CloudRuntimeException(String.format("Cannot change out-of-band management password as provided new-password is null or empty for the host %s.", host.getUuid())); + } + GlobalLock outOfBandManagementHostLock = GlobalLock.getInternLock(getOutOfBandManagementHostLock(host.getId())); + try { + if (outOfBandManagementHostLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_HOST)) { + try { + final OutOfBandManagement outOfBandManagementConfig = outOfBandManagementDao.findByHost(host.getId()); + + final ImmutableMap options = getOptions(outOfBandManagementConfig); + if (!(options.containsKey(OutOfBandManagement.Option.PASSWORD) && !Strings.isNullOrEmpty(options.get(OutOfBandManagement.Option.PASSWORD)))) { + throw new CloudRuntimeException(String.format("Cannot change out-of-band management password as we've no previously configured password for the host %s.", host.getUuid())); + } + final OutOfBandManagementDriver driver = getDriver(outOfBandManagementConfig); + + final OutOfBandManagementDriverChangePasswordCommand cmd = new OutOfBandManagementDriverChangePasswordCommand(options, ActionTimeout.valueIn(host.getClusterId()), newPassword); + final OutOfBandManagementDriverResponse driverResponse; + try { + driverResponse = driver.execute(cmd); + } catch (Exception e) { + LOG.error("Out-of-band management change password failed due to driver error: " + e.getMessage()); + throw new CloudRuntimeException(String.format("Failed to change out-of-band management password for host (%s) due to driver error: %s", host.getUuid(), e.getMessage())); + } + + if (!driverResponse.isSuccess()) { + throw new CloudRuntimeException(String.format("Failed to change out-of-band management password for host (%s) with error: %s", host.getUuid(), driverResponse.getError())); + } + + final boolean updatedConfigResult = Transaction.execute(new TransactionCallback() { + @Override + public Boolean doInTransaction(TransactionStatus status) { + OutOfBandManagement updatedOutOfBandManagementConfig = outOfBandManagementDao.findByHost(host.getId()); + updatedOutOfBandManagementConfig.setPassword(newPassword); + return outOfBandManagementDao.update(updatedOutOfBandManagementConfig.getId(), (OutOfBandManagementVO) updatedOutOfBandManagementConfig); + } + }); + + if (!updatedConfigResult) { + LOG.error(String.format("Succeeded to change out-of-band management password but failed to updated in database the new password:%s for the host id:%d", newPassword, host.getId())); + } + + final OutOfBandManagementResponse response = new OutOfBandManagementResponse(); + response.setSuccess(updatedConfigResult && driverResponse.isSuccess()); + response.setResultDescription(driverResponse.getResult()); + response.setId(host.getUuid()); + return response; + } finally { + outOfBandManagementHostLock.unlock(); + } + } else { + LOG.error("Unable to acquire synchronization lock to change out-of-band management password for host id: " + host.getId()); + throw new CloudRuntimeException(String.format("Unable to acquire lock to change out-of-band management password for host (%s), please try after some time.", host.getUuid())); + } + } finally { + outOfBandManagementHostLock.releaseRef(); + } + } + + @Override + public String getName() { + return name; + } + + @Override + public long getId() { + return serviceId; + } + + @Override + public boolean configure(final String name, final Map params) throws ConfigurationException { + this.name = name; + this.serviceId = ManagementServerNode.getManagementServerId(); + + final int poolSize = SyncThreadPoolSize.value(); + + hostAlertCache = CacheBuilder.newBuilder() + .concurrencyLevel(4) + .weakKeys() + .maximumSize(100 * poolSize) + .expireAfterWrite(1, TimeUnit.DAYS) + .build(); + + backgroundSyncBlockingExecutor = new ThreadPoolExecutor(poolSize, poolSize, + 0L, TimeUnit.MILLISECONDS, + new ArrayBlockingQueue(10 * poolSize, true), new ThreadPoolExecutor.CallerRunsPolicy()); + + LOG.info("Starting out-of-band management background sync executor with thread pool-size=" + poolSize + " and background sync thread interval=" + SyncThreadInterval.value() + "s"); + return true; + } + + @Override + public boolean start() { + initializeDriversMap(); + return true; + } + + @Override + public boolean stop() { + backgroundSyncBlockingExecutor.shutdown(); + outOfBandManagementDao.expireOutOfBandManagementOwnershipByServer(getId()); + return true; + } + + @Override + public String getConfigComponentName() { + return OutOfBandManagementServiceImpl.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[] {ActionTimeout, SyncThreadInterval, SyncThreadPoolSize}; + } + + public List getOutOfBandManagementDrivers() { + return outOfBandManagementDrivers; + } + + public void setOutOfBandManagementDrivers(List outOfBandManagementDrivers) { + this.outOfBandManagementDrivers = outOfBandManagementDrivers; + } +} diff --git a/server/test/com/cloud/resource/MockResourceManagerImpl.java b/server/test/com/cloud/resource/MockResourceManagerImpl.java index 86de140b97..6e6d66fe18 100644 --- a/server/test/com/cloud/resource/MockResourceManagerImpl.java +++ b/server/test/com/cloud/resource/MockResourceManagerImpl.java @@ -37,6 +37,7 @@ import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.api.VgpuTypesInfo; import com.cloud.agent.api.to.GPUDeviceTO; +import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.PodCluster; @@ -172,6 +173,12 @@ public Cluster getCluster(final Long clusterId) { return null; } + @Override + public DataCenter getZone(Long zoneId) { + // TODO Auto-generated method stub + return null; + } + /* (non-Javadoc) * @see com.cloud.resource.ResourceService#getSupportedHypervisorTypes(long, boolean, java.lang.Long) */ diff --git a/server/test/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceTest.java b/server/test/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceTest.java new file mode 100644 index 0000000000..69f03ff674 --- /dev/null +++ b/server/test/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceTest.java @@ -0,0 +1,116 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.outofbandmanagement; + +import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class OutOfBandManagementServiceTest { + + OutOfBandManagementServiceImpl oobmService = new OutOfBandManagementServiceImpl(); + + @Test + public void testOutOfBandManagementDriverResponseEvent() { + OutOfBandManagementDriverResponse r = new OutOfBandManagementDriverResponse("some result", "some error", false); + + r.setSuccess(false); + r.setAuthFailure(false); + Assert.assertEquals(r.toEvent(), OutOfBandManagement.PowerState.Event.Unknown); + + r.setSuccess(false); + r.setAuthFailure(true); + Assert.assertEquals(r.toEvent(), OutOfBandManagement.PowerState.Event.AuthError); + + r.setAuthFailure(false); + r.setSuccess(true); + r.setPowerState(OutOfBandManagement.PowerState.On); + Assert.assertEquals(r.toEvent(), OutOfBandManagement.PowerState.Event.On); + + r.setPowerState(OutOfBandManagement.PowerState.Off); + Assert.assertEquals(r.toEvent(), OutOfBandManagement.PowerState.Event.Off); + + r.setPowerState(OutOfBandManagement.PowerState.Disabled); + Assert.assertEquals(r.toEvent(), OutOfBandManagement.PowerState.Event.Disabled); + } + + private ImmutableMap buildRandomOptionsMap() { + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + builder.put(OutOfBandManagement.Option.ADDRESS, "localhost"); + builder.put(OutOfBandManagement.Option.DRIVER, "ipmitool"); + return builder.build(); + } + + @Test + public void testUpdateOutOfBandManagementConfigValid() { + OutOfBandManagement config = new OutOfBandManagementVO(123L); + Assert.assertEquals(config.getPowerState(), OutOfBandManagement.PowerState.Disabled); + config = oobmService.updateConfig(config, buildRandomOptionsMap()); + Assert.assertEquals(config.getAddress(), "localhost"); + Assert.assertEquals(config.getDriver(), "ipmitool"); + Assert.assertEquals(config.getPowerState(), OutOfBandManagement.PowerState.Disabled); + } + + @Test(expected = CloudRuntimeException.class) + public void testUpdateOutOfBandManagementNullConfigValidOptions() { + oobmService.updateConfig(null, buildRandomOptionsMap()); + Assert.fail("CloudRuntimeException was expect for out-of-band management not configured for the host"); + } + + @Test(expected = CloudRuntimeException.class) + public void testUpdateOutOfBandManagementNullConfigNullOptions() { + oobmService.updateConfig(null, null); + Assert.fail("CloudRuntimeException was expect for out-of-band management not configured for the host"); + } + + @Test + public void testUpdateOutOfBandManagementValidConfigValidOptions() { + OutOfBandManagement config = new OutOfBandManagementVO(123L); + config.setAddress(null); + config = oobmService.updateConfig(config, null); + Assert.assertEquals(config.getAddress(), null); + Assert.assertEquals(config.getPowerState(), OutOfBandManagement.PowerState.Disabled); + } + + @Test + public void testGetOutOfBandManagementOptionsValid() { + OutOfBandManagement configEmpty = new OutOfBandManagementVO(123L); + ImmutableMap optionsEmpty = oobmService.getOptions(configEmpty); + Assert.assertEquals(optionsEmpty.size(), 0); + + OutOfBandManagement config = new OutOfBandManagementVO(123L); + config.setAddress("localhost"); + config.setDriver("ipmitool"); + config.setPort(1234); + ImmutableMap options = oobmService.getOptions(config); + Assert.assertEquals(options.get(OutOfBandManagement.Option.ADDRESS), "localhost"); + Assert.assertEquals(options.get(OutOfBandManagement.Option.DRIVER), "ipmitool"); + Assert.assertEquals(options.get(OutOfBandManagement.Option.PORT), "1234"); + } + + @Test(expected = CloudRuntimeException.class) + public void testGetOutOfBandManagementOptionsInvalid() { + oobmService.getOptions(null); + Assert.fail("CloudRuntimeException was expected for finding options of host with out-of-band management configuration"); + } +} diff --git a/setup/db/db/schema-481to490-cleanup.sql b/setup/db/db/schema-481to490-cleanup.sql index ba206459f2..0ab02d8308 100644 --- a/setup/db/db/schema-481to490-cleanup.sql +++ b/setup/db/db/schema-481to490-cleanup.sql @@ -271,3 +271,80 @@ CREATE VIEW `cloud`.`user_view` AS `cloud`.`async_job` ON async_job.instance_id = user.id and async_job.instance_type = 'User' and async_job.job_status = 0; + +-- Out-of-band management +DROP VIEW IF EXISTS `cloud`.`host_view`; +CREATE VIEW `cloud`.`host_view` AS + select + host.id, + host.uuid, + host.name, + host.status, + host.disconnected, + host.type, + host.private_ip_address, + host.version, + host.hypervisor_type, + host.hypervisor_version, + host.capabilities, + host.last_ping, + host.created, + host.removed, + host.resource_state, + host.mgmt_server_id, + host.cpu_sockets, + host.cpus, + host.speed, + host.ram, + cluster.id cluster_id, + cluster.uuid cluster_uuid, + cluster.name cluster_name, + cluster.cluster_type, + data_center.id data_center_id, + data_center.uuid data_center_uuid, + data_center.name data_center_name, + data_center.networktype data_center_type, + host_pod_ref.id pod_id, + host_pod_ref.uuid pod_uuid, + host_pod_ref.name pod_name, + host_tags.tag, + guest_os_category.id guest_os_category_id, + guest_os_category.uuid guest_os_category_uuid, + guest_os_category.name guest_os_category_name, + mem_caps.used_capacity memory_used_capacity, + mem_caps.reserved_capacity memory_reserved_capacity, + cpu_caps.used_capacity cpu_used_capacity, + cpu_caps.reserved_capacity cpu_reserved_capacity, + async_job.id job_id, + async_job.uuid job_uuid, + async_job.job_status job_status, + async_job.account_id job_account_id, + oobm.enabled AS `oobm_enabled`, + oobm.power_state AS `oobm_power_state` + from + `cloud`.`host` + left join + `cloud`.`cluster` ON host.cluster_id = cluster.id + left join + `cloud`.`data_center` ON host.data_center_id = data_center.id + left join + `cloud`.`host_pod_ref` ON host.pod_id = host_pod_ref.id + left join + `cloud`.`host_details` ON host.id = host_details.host_id + and host_details.name = 'guest.os.category.id' + left join + `cloud`.`guest_os_category` ON guest_os_category.id = CONVERT( host_details.value , UNSIGNED) + left join + `cloud`.`host_tags` ON host_tags.host_id = host.id + left join + `cloud`.`op_host_capacity` mem_caps ON host.id = mem_caps.host_id + and mem_caps.capacity_type = 0 + left join + `cloud`.`op_host_capacity` cpu_caps ON host.id = cpu_caps.host_id + and cpu_caps.capacity_type = 1 + left join + `cloud`.`async_job` ON async_job.instance_id = host.id + and async_job.instance_type = 'Host' + and async_job.job_status = 0 + left join + `cloud`.`oobm` ON oobm.host_id = host.id; diff --git a/setup/db/db/schema-481to490.sql b/setup/db/db/schema-481to490.sql index a2622ed536..15b0d59ebd 100644 --- a/setup/db/db/schema-481to490.sql +++ b/setup/db/db/schema-481to490.sql @@ -471,3 +471,26 @@ INSERT INTO `cloud`.`roles` (`id`, `uuid`, `name`, `role_type`, `description`) v INSERT INTO `cloud`.`roles` (`id`, `uuid`, `name`, `role_type`, `description`) values (2, UUID(), 'Resource Admin', 'ResourceAdmin', 'Default resource admin role') ON DUPLICATE KEY UPDATE name=name; INSERT INTO `cloud`.`roles` (`id`, `uuid`, `name`, `role_type`, `description`) values (3, UUID(), 'Domain Admin', 'DomainAdmin', 'Default domain admin role') ON DUPLICATE KEY UPDATE name=name; INSERT INTO `cloud`.`roles` (`id`, `uuid`, `name`, `role_type`, `description`) values (4, UUID(), 'User', 'User', 'Default Root Admin role') ON DUPLICATE KEY UPDATE name=name; + +-- Out-of-band management +CREATE TABLE IF NOT EXISTS `cloud`.`oobm` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `host_id` bigint(20) unsigned DEFAULT NULL COMMENT 'foreign key to host', + `enabled` int(1) unsigned DEFAULT '0' COMMENT 'is out-of-band management enabled for host', + `power_state` varchar(32) DEFAULT 'Disabled' COMMENT 'out-of-band management power status', + `driver` varchar(32) DEFAULT NULL COMMENT 'out-of-band management driver', + `address` varchar(255) DEFAULT NULL COMMENT 'out-of-band management interface address', + `port` int(10) unsigned DEFAULT NULL COMMENT 'out-of-band management interface port', + `username` varchar(255) DEFAULT NULL COMMENT 'out-of-band management interface username', + `password` varchar(255) DEFAULT NULL COMMENT 'out-of-band management interface password', + `update_count` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'atomic increase count making status update operation atomical', + `update_time` datetime COMMENT 'last power state update datetime', + `mgmt_server_id` bigint(20) unsigned DEFAULT NULL COMMENT 'management server id which owns out-of-band management for the host', + PRIMARY KEY (`id`), + KEY `fk_oobm__host_id` (`host_id`), + KEY `i_oobm__enabled` (`enabled`), + KEY `i_oobm__power_state` (`power_state`), + KEY `i_oobm__update_time` (`update_time`), + KEY `i_oobm__mgmt_server_id` (`mgmt_server_id`), + CONSTRAINT `fk_oobm__host_id` FOREIGN KEY (`host_id`) REFERENCES `host` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/setup/dev/advanced.cfg b/setup/dev/advanced.cfg index afb9b6a215..5e92028bad 100644 --- a/setup/dev/advanced.cfg +++ b/setup/dev/advanced.cfg @@ -154,7 +154,7 @@ }, { "name": "storage.cleanup.interval", - "value": "150" + "value": "60" }, { "name": "vm.op.wait.interval", @@ -162,7 +162,7 @@ }, { "name": "default.page.size", - "value": "10000" + "value": "500" }, { "name": "network.gc.interval", @@ -215,6 +215,18 @@ { "name": "enable.dynamic.scale.vm", "value": "true" + }, + { + "name": "ping.interval", + "value": "10" + }, + { + "name": "ping.timeout", + "value": "1.5" + }, + { + "name": "outofbandmanagement.sync.interval", + "value": "2000" } ], "mgtSvr": [ diff --git a/test/integration/smoke/test_outofbandmanagement.py b/test/integration/smoke/test_outofbandmanagement.py new file mode 100644 index 0000000000..d1f9840775 --- /dev/null +++ b/test/integration/smoke/test_outofbandmanagement.py @@ -0,0 +1,575 @@ +# 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. + + +import marvin +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.lib.utils import * +from marvin.lib.base import * +from marvin.lib.common import * +from marvin.lib.utils import (random_gen) +from nose.plugins.attrib import attr + +from ipmisim.ipmisim import IpmiServerContext, IpmiServer, ThreadedIpmiServer + +import random +import socket +import sys +import thread +import time + + +class TestOutOfBandManagement(cloudstackTestCase): + """ Test cases for out of band management + """ + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.hypervisor = self.testClient.getHypervisorInfo() + self.dbclient = self.testClient.getDbConnection() + self.services = self.testClient.getParsedTestDataConfig() + self.mgtSvrDetails = self.config.__dict__["mgtSvr"][0].__dict__ + self.fakeMsId = random.randint(10000, 99999) * random.randint(10, 20) + + self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests()) + self.host = None + self.server = None + + # use random port for ipmisim + s = socket.socket() + s.bind(('', 0)) + self.serverPort = s.getsockname()[1] + s.close() + + self.cleanup = [] + + + def tearDown(self): + try: + self.dbclient.execute("delete from oobm where port=%d" % self.getIpmiServerPort()) + self.dbclient.execute("delete from mshost_peer where peer_runid=%s" % self.getFakeMsRunId()) + self.dbclient.execute("delete from mshost where runid=%s" % self.getFakeMsRunId()) + self.dbclient.execute("delete from cluster_details where name='outOfBandManagementEnabled'") + self.dbclient.execute("delete from data_center_details where name='outOfBandManagementEnabled'") + cleanup_resources(self.apiclient, self.cleanup) + if self.server: + self.server.shutdown() + self.server.server_close() + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + + def getFakeMsId(self): + return self.fakeMsId + + + def getFakeMsRunId(self): + return self.fakeMsId * 1000 + + + def getHost(self, hostId=None): + if self.host and hostId is None: + return self.host + + response = list_hosts( + self.apiclient, + zoneid=self.zone.id, + type='Routing', + id=hostId + ) + if len(response) > 0: + self.host = response[0] + return self.host + raise self.skipTest("No hosts found, skipping out-of-band management test") + + + def getIpmiServerIp(self): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect((self.mgtSvrDetails["mgtSvrIp"], self.mgtSvrDetails["port"])) + return s.getsockname()[0] + + + def getIpmiServerPort(self): + return self.serverPort + + + def getOobmConfigCmd(self): + cmd = configureOutOfBandManagement.configureOutOfBandManagementCmd() + cmd.driver = 'ipmitool' # The default available driver + cmd.address = self.getIpmiServerIp() + cmd.port = self.getIpmiServerPort() + cmd.username = 'admin' + cmd.password = 'password' + cmd.hostid = self.getHost().id + return cmd + + + def getOobmEnableCmd(self): + cmd = enableOutOfBandManagementForHost.enableOutOfBandManagementForHostCmd() + cmd.hostid = self.getHost().id + return cmd + + + def getOobmDisableCmd(self): + cmd = disableOutOfBandManagementForHost.disableOutOfBandManagementForHostCmd() + cmd.hostid = self.getHost().id + return cmd + + + def getOobmIssueActionCmd(self): + cmd = issueOutOfBandManagementPowerAction.issueOutOfBandManagementPowerActionCmd() + cmd.hostid = self.getHost().id + cmd.action = 'STATUS' + return cmd + + + def issuePowerActionCmd(self, action, timeout=None): + cmd = self.getOobmIssueActionCmd() + cmd.action = action + if timeout: + cmd.timeout = timeout + return self.apiclient.issueOutOfBandManagementPowerAction(cmd) + + + def configureAndEnableOobm(self): + self.apiclient.configureOutOfBandManagement(self.getOobmConfigCmd()) + response = self.apiclient.enableOutOfBandManagementForHost(self.getOobmEnableCmd()) + self.assertEqual(response.enabled, True) + + + def startIpmiServer(self): + def startIpmiServer(tname, server): + self.debug("Starting ipmisim server") + try: + server.serve_forever() + except Exception: pass + IpmiServerContext('reset') + ThreadedIpmiServer.allow_reuse_address = False + server = ThreadedIpmiServer(('0.0.0.0', self.getIpmiServerPort()), IpmiServer) + thread.start_new_thread(startIpmiServer, ("ipmi-server", server,)) + self.server = server + + + def checkSyncToState(self, state, interval): + self.debug("Waiting for background thread to update powerstate to " + state) + time.sleep(1 + int(interval)*2/1000) # interval is in ms + response = self.getHost(hostId=self.getHost().id).outofbandmanagement + self.assertEqual(response.powerstate, state) + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_configure_invalid_driver(self): + """ + Tests out-of-band management configuration with invalid driver + """ + cmd = self.getOobmConfigCmd() + cmd.driver = 'randomDriverThatDoesNotExist' + try: + response = self.apiclient.configureOutOfBandManagement(cmd) + self.fail("Expected an exception to be thrown, failing") + except Exception: pass + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_configure_default_driver(self): + """ + Tests out-of-band management configuration with valid data + """ + cmd = self.getOobmConfigCmd() + response = self.apiclient.configureOutOfBandManagement(cmd) + self.assertEqual(response.hostid, cmd.hostid) + self.assertEqual(response.driver, cmd.driver) + self.assertEqual(response.address, cmd.address) + self.assertEqual(response.port, str(cmd.port)) + self.assertEqual(response.username, cmd.username) + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_enable_feature_invalid(self): + """ + Tests out-of-band management host enable feature with + invalid options + """ + cmd = self.getOobmEnableCmd() + cmd.hostid = -1 + try: + response = self.apiclient.enableOutOfBandManagementForHost(cmd) + self.fail("Expected an exception to be thrown, failing") + except Exception: pass + + try: + cmd = enableOutOfBandManagementForCluster.enableOutOfBandManagementForClusterCmd() + response = self.apiclient.enableOutOfBandManagementForCluster(cmd) + self.fail("Expected an exception to be thrown, failing") + except Exception: pass + + try: + cmd = enableOutOfBandManagementForZone.enableOutOfBandManagementForZoneCmd() + response = self.apiclient.enableOutOfBandManagementForZone(cmd) + self.fail("Expected an exception to be thrown, failing") + except Exception: pass + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_disable_feature_invalid(self): + """ + Tests out-of-band management host disable feature with + invalid options + """ + cmd = self.getOobmDisableCmd() + cmd.hostid = -1 + try: + response = self.apiclient.disableOutOfBandManagementForHost(cmd) + self.fail("Expected an exception to be thrown, failing") + except Exception: pass + + try: + cmd = disableOutOfBandManagementForCluster.disableOutOfBandManagementForClusterCmd() + response = self.apiclient.disableOutOfBandManagementForCluster(cmd) + self.fail("Expected an exception to be thrown, failing") + except Exception: pass + + try: + cmd = disableOutOfBandManagementForZone.disableOutOfBandManagementForZoneCmd() + response = self.apiclient.disableOutOfBandManagementForZone(cmd) + self.fail("Expected an exception to be thrown, failing") + except Exception: pass + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_enable_feature_valid(self): + """ + Tests out-of-band management host enable feature with + valid options + """ + self.apiclient.configureOutOfBandManagement(self.getOobmConfigCmd()) + cmd = self.getOobmEnableCmd() + response = self.apiclient.enableOutOfBandManagementForHost(cmd) + self.assertEqual(response.hostid, cmd.hostid) + self.assertEqual(response.enabled, True) + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_disable_feature_valid(self): + """ + Tests out-of-band management host disable feature with + valid options + """ + + self.apiclient.configureOutOfBandManagement(self.getOobmConfigCmd()) + cmd = self.getOobmDisableCmd() + response = self.apiclient.disableOutOfBandManagementForHost(cmd) + self.assertEqual(response.hostid, cmd.hostid) + self.assertEqual(response.enabled, False) + + response = self.getHost(hostId=cmd.hostid).outofbandmanagement + self.assertEqual(response.powerstate, 'Disabled') + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_enabledisable_across_clusterzones(self): + """ + Tests out-of-band management enable/disable feature at cluster + and zone level sequentially Zone > Cluster > Host + """ + self.configureAndEnableOobm() + self.startIpmiServer() + bmc = IpmiServerContext().bmc + bmc.powerstate = 'off' + + host = self.getHost() + + # Disable at zone level + cmd = disableOutOfBandManagementForZone.disableOutOfBandManagementForZoneCmd() + cmd.zoneid = host.zoneid + response = self.apiclient.disableOutOfBandManagementForZone(cmd) + + # Disable at cluster level + cmd = disableOutOfBandManagementForCluster.disableOutOfBandManagementForClusterCmd() + cmd.clusterid = host.clusterid + response = self.apiclient.disableOutOfBandManagementForCluster(cmd) + + # Disable at host level + cmd = disableOutOfBandManagementForHost.disableOutOfBandManagementForHostCmd() + cmd.hostid = host.id + response = self.apiclient.disableOutOfBandManagementForHost(cmd) + + try: + self.issuePowerActionCmd('STATUS') + self.fail("Exception was expected, oobm is disabled at zone level") + except Exception: pass + + # Enable at zone level + cmd = enableOutOfBandManagementForZone.enableOutOfBandManagementForZoneCmd() + cmd.zoneid = host.zoneid + response = self.apiclient.enableOutOfBandManagementForZone(cmd) + + try: + self.issuePowerActionCmd('STATUS') + self.fail("Exception was expected, oobm is disabled at cluster level") + except Exception: pass + + # Check background thread syncs state to Disabled + response = self.getHost(hostId=host.id).outofbandmanagement + self.assertEqual(response.powerstate, 'Disabled') + self.dbclient.execute("update oobm set power_state='On' where port=%d" % self.getIpmiServerPort()) + interval = list_configurations( + self.apiclient, + name='outofbandmanagement.sync.interval' + )[0].value + self.checkSyncToState('Disabled', interval) + + # Enable at cluster level + cmd = enableOutOfBandManagementForCluster.enableOutOfBandManagementForClusterCmd() + cmd.clusterid = host.clusterid + response = self.apiclient.enableOutOfBandManagementForCluster(cmd) + + try: + self.issuePowerActionCmd('STATUS') + self.fail("Exception was expected, oobm is disabled at host level") + except Exception: pass + + # Enable at host level + cmd = enableOutOfBandManagementForHost.enableOutOfBandManagementForHostCmd() + cmd.hostid = host.id + response = self.apiclient.enableOutOfBandManagementForHost(cmd) + + response = self.issuePowerActionCmd('STATUS') + self.assertEqual(response.powerstate, 'Off') + + + def configureAndStartIpmiServer(self, power_state=None): + """ + Setup ipmisim and enable out-of-band management for host + """ + self.configureAndEnableOobm() + self.startIpmiServer() + if power_state: + bmc = IpmiServerContext().bmc + bmc.powerstate = power_state + + + def assertIssueCommandState(self, command, expected): + """ + Asserts power action result for a given power command + """ + if command != 'STATUS': + self.issuePowerActionCmd(command) + response = self.issuePowerActionCmd('STATUS') + self.assertEqual(response.powerstate, expected) + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_issue_power_status(self): + """ + Tests out-of-band management issue power action + """ + self.configureAndStartIpmiServer(power_state='on') + self.assertIssueCommandState('STATUS', 'On') + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_issue_power_on(self): + """ + Tests out-of-band management issue power on action + """ + self.configureAndStartIpmiServer() + self.assertIssueCommandState('ON', 'On') + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_issue_power_off(self): + """ + Tests out-of-band management issue power off action + """ + self.configureAndStartIpmiServer() + self.assertIssueCommandState('OFF', 'Off') + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_issue_power_cycle(self): + """ + Tests out-of-band management issue power cycle action + """ + self.configureAndStartIpmiServer() + self.assertIssueCommandState('CYCLE', 'On') + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_issue_power_reset(self): + """ + Tests out-of-band management issue power reset action + """ + self.configureAndStartIpmiServer() + self.assertIssueCommandState('RESET', 'On') + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_issue_power_soft(self): + """ + Tests out-of-band management issue power soft action + """ + self.configureAndStartIpmiServer() + self.assertIssueCommandState('SOFT', 'Off') + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_background_powerstate_sync(self): + """ + Tests out-of-band management background powerstate sync + """ + self.debug("Testing oobm background sync") + interval = list_configurations( + self.apiclient, + name='outofbandmanagement.sync.interval' + )[0].value + + self.configureAndEnableOobm() + self.startIpmiServer() + bmc = IpmiServerContext().bmc + + bmc.powerstate = 'on' + self.checkSyncToState('On', interval) + + bmc.powerstate = 'off' + self.checkSyncToState('Off', interval) + + self.server.shutdown() + self.server.server_close() + + # Check for unknown state (ipmi server not reachable) + self.checkSyncToState('Unknown', interval) + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_multiple_mgmt_server_ownership(self): + """ + Tests out-of-band management ownership expiry across multi-mgmt server + """ + self.configureAndEnableOobm() + + cloudstackVersion = Configurations.listCapabilities(self.apiclient).cloudstackversion + + currentMsHosts = [] + mshosts = self.dbclient.execute("select msid from mshost where version='%s' and removed is NULL and state='Up'" % (cloudstackVersion)) + if len(mshosts) > 0: + currentMsHosts = map(lambda row: row[0], mshosts) + + # Inject fake ms host + self.dbclient.execute("insert into mshost (msid,runid,name,state,version,service_ip,service_port,last_update) values (%s,%s,'oobm-marvin-fakebox', 'Down', '%s', '127.0.0.1', '22', NOW())" % (self.getFakeMsId(), self.getFakeMsRunId(), cloudstackVersion)) + + # Pass ownership to the fake ms id + self.dbclient.execute("update oobm set mgmt_server_id=%d where port=%d" % (self.getFakeMsId(), self.getIpmiServerPort())) + + self.debug("Testing oobm background sync") + pingInterval = float(list_configurations( + self.apiclient, + name='ping.interval' + )[0].value) + + pingTimeout = float(list_configurations( + self.apiclient, + name='ping.timeout' + )[0].value) + + + def removeFakeMgmtServer(fakeMsRunId): + rows = self.dbclient.execute("select * from mshost_peer where peer_runid=%s" % fakeMsRunId) + if len(rows) > 0: + self.debug("Mgmt server is now trying to contact the fake mgmt server") + self.dbclient.execute("update mshost set removed=now() where runid=%s" % fakeMsRunId) + self.dbclient.execute("update mshost_peer set peer_state='Down' where peer_runid=%s" % fakeMsRunId) + return True, None + return False, None + + def checkOobmOwnershipExpiry(serverPort, fakeMsId): + rows = self.dbclient.execute("select mgmt_server_id from oobm where port=%d" % (serverPort)) + if len(rows) > 0 and rows[0][0] != fakeMsId: + self.debug("Out-of-band management ownership expired as node was detected to be gone") + return True, None + return False, None + + retry_interval = 1 + (pingInterval * pingTimeout / 10) + + res, _ = wait_until(retry_interval, 10, removeFakeMgmtServer, self.getFakeMsRunId()) + if not res: + self.fail("Management server failed to turn down or remove fake mgmt server") + + res, _ = wait_until(retry_interval, 100, checkOobmOwnershipExpiry, self.getIpmiServerPort(), self.getFakeMsId()) + if not res: + self.fail("Management server failed to expire ownership of fenced peer") + + self.debug("Testing oobm background sync should claim new ownership") + interval = list_configurations( + self.apiclient, + name='outofbandmanagement.sync.interval' + )[0].value + + self.startIpmiServer() + bmc = IpmiServerContext().bmc + bmc.powerstate = 'on' + + self.checkSyncToState('On', interval) + + result = self.dbclient.execute("select mgmt_server_id from oobm where port=%d" % (self.getIpmiServerPort())) + newOwnerId = result[0][0] + self.assertTrue(newOwnerId in currentMsHosts) + + + @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") + def test_oobm_zchange_password(self): + """ + Tests out-of-band management change password feature + """ + self.configureAndEnableOobm() + self.startIpmiServer() + + self.debug("Testing oobm change password") + + cmd = changeOutOfBandManagementPassword.changeOutOfBandManagementPasswordCmd() + cmd.hostid = self.getHost().id + cmd.password = "Password12345" + response = self.apiclient.changeOutOfBandManagementPassword(cmd) + self.assertEqual(response.status, True) + + bmc = IpmiServerContext().bmc + bmc.powerstate = 'on' + response = self.issuePowerActionCmd('STATUS') + self.assertEqual(response.status, True) + self.assertEqual(response.powerstate, 'On') + + # Reset configuration, resets password + self.apiclient.configureOutOfBandManagement(self.getOobmConfigCmd()) + self.assertEqual(response.status, True) + + alerts = Alert.list(self.apiclient, keyword="auth-error", + listall=True) + alertCount = 0 + if alerts: + alertCount = len(alerts) + + try: + response = self.issuePowerActionCmd('STATUS') + self.fail("Expected an exception to be thrown, failing") + except Exception: pass + + alerts = Alert.list(self.apiclient, keyword="auth-error", + listall=True) + + # At least one alert was sent + self.assertTrue((len(alerts) - alertCount) > 0) diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index b86655e1a9..e6ef674811 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -61,6 +61,7 @@ 'StaticNat': 'NAT', 'IpForwarding': 'NAT', 'Host': 'Host', + 'OutOfBand': 'Out-of-band Management', 'Cluster': 'Cluster', 'Account': 'Account', 'Role': 'Role', diff --git a/tools/marvin/setup.py b/tools/marvin/setup.py index 81fefd829c..7f3d9c8ca3 100644 --- a/tools/marvin/setup.py +++ b/tools/marvin/setup.py @@ -52,7 +52,8 @@ "nose >= 1.3.3", "ddt >= 0.4.0", "pyvmomi >= 5.5.0", - "netaddr >= 0.7.14" + "netaddr >= 0.7.14", + "ipmisim >= 0.7" ], py_modules=['marvin.marvinPlugin'], zip_safe=False, diff --git a/tools/travis/before_install.sh b/tools/travis/before_install.sh index 700ac09d5a..b257e052bd 100755 --- a/tools/travis/before_install.sh +++ b/tools/travis/before_install.sh @@ -86,10 +86,19 @@ sudo service mysql restart echo -e "\nInstalling Development tools: " RETRY_COUNT=3 -sudo apt-get -q -y install uuid-runtime genisoimage netcat > /dev/null +sudo apt-get -q -y install uuid-runtime genisoimage netcat freeipmi-common freeipmi-tools libfreeipmi12 > /dev/null if [[ $? -ne 0 ]]; then echo -e "\napt-get packages failed to install" fi + +# We need version 1.8.15 or above, default installed version is buggy +wget http://mirrors.kernel.org/ubuntu/pool/universe/i/ipmitool/ipmitool_1.8.15-1ubuntu1.1_amd64.deb -O /tmp/ipmitool.deb +if [[ $? -eq 0 ]]; then + sudo dpkg -i /tmp/ipmitool.deb + sudo apt-get install -f -y + ipmitool -V +fi + echo " @@ -107,7 +116,7 @@ pip install --user --upgrade pip for ((i=0;i<$RETRY_COUNT;i++)) do - pip install --user --upgrade lxml paramiko nose texttable > /tmp/piplog + pip install --user --upgrade lxml paramiko nose texttable ipmisim > /tmp/piplog if [[ $? -eq 0 ]]; then echo -e "\npython packages installed successfully" break; diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 17cab9e708..16ee0b7baa 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -12703,6 +12703,54 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it background-position: -137px -614px; } +.blankOutOfBandManagement .icon { + background-position: -266px -31px; +} + +.blankOutOfBandManagement:hover .icon { + background-position: -266px -31px; +} + +.configureOutOfBandManagement .icon { + background-position: -168px -31px; +} + +.configureOutOfBandManagement:hover .icon { + background-position: -168px -613px; +} + +.enableOutOfBandManagement .icon { + background-position: -138px -65px; +} + +.enableOutOfBandManagement:hover .icon { + background-position: -138px -647px; +} + +.disableOutOfBandManagement .icon { + background-position: -138px -123px; +} + +.disableOutOfBandManagement:hover .icon { + background-position: -138px -705px; +} + +.issueOutOfBandManagementPowerAction .icon { + background-position: -266px -3px; +} + +.issueOutOfBandManagementPowerAction:hover .icon { + background-position: -265px -584px; +} + +.changeOutOfBandManagementPassword .icon { + background-position: -68px -30px; +} + +.changeOutOfBandManagementPassword:hover .icon { + background-position: -68px -612px; +} + .enableMaintenanceMode .icon { background-position: -138px -65px; } diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp index ddcd1813b5..b0642997d2 100644 --- a/ui/dictionary.jsp +++ b/ui/dictionary.jsp @@ -871,6 +871,7 @@ dictionary = { 'label.metrics.property': '', 'label.metrics.scope': '', 'label.metrics.state': '', +'label.metrics.outofbandmanagementpowerstate': '', 'label.metrics.storagepool': '', 'label.metrics.vm.name': '', 'label.migrate.instance.to': '', @@ -987,6 +988,26 @@ dictionary = { 'label.port.forwarding': '', 'label.port.forwarding.policies': '', 'label.port.range': '', +'label.powerstate': '', +'label.outofbandmanagement': '', +'label.outofbandmanagement.action.issue': '', +'label.outofbandmanagement.action': '', +'label.outofbandmanagement.address': '', +'label.outofbandmanagement.changepassword': '', +'label.outofbandmanagement.configure': '', +'label.outofbandmanagement.driver': '', +'label.outofbandmanagement.disable': '', +'label.outofbandmanagement.enable': '', +'label.outofbandmanagement.password': '', +'label.outofbandmanagement.port': '', +'label.outofbandmanagement.timeout': '', +'label.outofbandmanagement.username': '', +'message.outofbandmanagement.changepassword': '', +'message.outofbandmanagement.configure': '', +'message.outofbandmanagement.disable': '', +'message.outofbandmanagement.enable': '', +'message.outofbandmanagement.issue': '', +'message.outofbandmanagement.action.maintenance': '', 'label.PreSetup': '', 'label.prev': '', 'label.previous': '', diff --git a/ui/scripts/metrics.js b/ui/scripts/metrics.js index e7b9df8e76..46d6b53bd0 100644 --- a/ui/scripts/metrics.js +++ b/ui/scripts/metrics.js @@ -550,6 +550,19 @@ }, compact: true }, + outofbandmanagementpowerstate: { + label: 'label.metrics.outofbandmanagementpowerstate', + converter: function (str) { + // For localization + return str; + }, + indicator: { + 'On': 'on', + 'Off': 'off', + 'Unknown': 'warning' + }, + compact: true + }, instances: { label: 'label.instances' }, @@ -633,6 +646,9 @@ var items = json.listhostsresponse.host; if (items) { $.each(items, function(idx, host) { + if (host && host.outofbandmanagement) { + items[idx].outofbandmanagementpowerstate = host.outofbandmanagement.powerstate; + } items[idx].cores = host.cpunumber; items[idx].cputotal = (parseFloat(host.cpunumber) * parseFloat(host.cpuspeed) / 1000.0).toFixed(2); if (host.cpuused) { diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 4cb8094add..1d60c12768 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -8241,6 +8241,82 @@ } }); } + }, + enableOutOfBandManagement: { + label: 'label.outofbandmanagement.enable', + action: function (args) { + var data = { + zoneid: args.context.physicalResources[0].id + }; + $.ajax({ + url: createURL("enableOutOfBandManagementForZone"), + data: data, + success: function (json) { + var jid = json.enableoutofbandmanagementforzoneresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return zoneActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.enable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.enable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disableOutOfBandManagement: { + label: 'label.outofbandmanagement.disable', + action: function (args) { + var data = { + zoneid: args.context.physicalResources[0].id + }; + $.ajax({ + url: createURL("disableOutOfBandManagementForZone"), + data: data, + success: function (json) { + var jid = json.disableoutofbandmanagementforzoneresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return zoneActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.disable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.disable'; + } + }, + notification: { + poll: pollAsyncJobResult + } } }, tabs: { @@ -9058,8 +9134,17 @@ url: createURL('listHosts'), data: data, success: function (json) { + var items = json.listhostsresponse.host; + if (items) { + $.each(items, function(idx, host) { + if (host && host.outofbandmanagement) { + items[idx].powerstate = host.outofbandmanagement.powerstate; + } + }); + } + args.response.success({ - data: json.listhostsresponse.host + data: items }); }, error: function (json) { @@ -14970,7 +15055,85 @@ args.complete(); } } + }, + + enableOutOfBandManagement: { + label: 'label.outofbandmanagement.enable', + action: function (args) { + var data = { + clusterid: args.context.clusters[0].id, + }; + $.ajax({ + url: createURL("enableOutOfBandManagementForCluster"), + data: data, + success: function (json) { + var jid = json.enableoutofbandmanagementforclusterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return clusterActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.enable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.enable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + disableOutOfBandManagement: { + label: 'label.outofbandmanagement.disable', + action: function (args) { + var data = { + clusterid: args.context.clusters[0].id, + }; + $.ajax({ + url: createURL("disableOutOfBandManagementForCluster"), + data: data, + success: function (json) { + var jid = json.disableoutofbandmanagementforclusterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return clusterActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.disable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.disable'; + } + }, + notification: { + poll: pollAsyncJobResult + } } + }, tabs: { @@ -15328,7 +15491,15 @@ 'Alert': 'off', 'Error': 'off' } - } + }, + powerstate: { + label: 'label.powerstate', + indicator: { + 'On': 'on', + 'Off': 'off', + 'Unknown': 'warning' + }, + }, }, dataProvider: function (args) { @@ -15355,13 +15526,20 @@ //Instances menu > Instance detailView > View Hosts array1.push("&id=" + args.context.instances[0].hostid); } - $.ajax({ url: createURL("listHosts&type=Routing" + array1.join("") + "&page=" + args.page + "&pagesize=" + pageSize), dataType: "json", async: true, success: function (json) { var items = json.listhostsresponse.host; + if (items) { + $.each(items, function(idx, host) { + if (host && host.outofbandmanagement) { + items[idx].powerstate = host.outofbandmanagement.powerstate; + } + }); + } + args.response.success({ actionFilter: hostActionfilter, data: items @@ -15998,6 +16176,7 @@ } }, + dedicate: { label: 'label.dedicate.host', messages: { @@ -16347,13 +16526,331 @@ args.complete(); } } + }, + + blankOutOfBandManagement: { + label: '', + action: function (args) { + } + }, + + configureOutOfBandManagement: { + label: 'label.outofbandmanagement.configure', + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.configure'; + }, + notification: function (args) { + return 'message.outofbandmanagement.configure'; + } + }, + createForm: { + title: 'label.outofbandmanagement.configure', + fields: { + address: { + label: 'label.outofbandmanagement.address', + validation: { + required: true + } + }, + port: { + label: 'label.outofbandmanagement.port', + validation: { + required: true + } + }, + username: { + label: 'label.outofbandmanagement.username', + validation: { + required: false + } + }, + password: { + label: 'label.outofbandmanagement.password', + isPassword: true, + validation: { + required: false + }, + }, + driver: { + label: 'label.outofbandmanagement.driver', + validation: { + required: true + }, + select: function (args) { + var oobm = args.context.hosts[0].outofbandmanagement; + if (oobm) { + args.$form.find('input[name=address]').val(oobm.address); + args.$form.find('input[name=port]').val(oobm.port); + args.$form.find('input[name=username]').val(oobm.username); + + args.$form.find('input[name=address]').change(function() { + $this.find('input[name=address]').val(oobm.address); + }); + } + + var items = []; + items.push({ + id: 'ipmitool', + description: 'ipmitool - ipmitool based shell driver' + }); + args.response.success({ + data: items + }); + } + } + } + }, + action: function (args) { + var data = args.data; + data.hostid = args.context.hosts[0].id; + + $.ajax({ + url: createURL('configureOutOfBandManagement'), + data: data, + dataType: 'json', + success: function (json) { + var response = json.configureoutofbandmanagementresponse; + args.response.success({ + actionFilter: hostActionfilter, + data: response + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + enableOutOfBandManagement: { + label: 'label.outofbandmanagement.enable', + action: function (args) { + var data = { + hostid: args.context.hosts[0].id, + }; + $.ajax({ + url: createURL("enableOutOfBandManagementForHost"), + data: data, + success: function (json) { + var jid = json.enableoutofbandmanagementforhostresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.enable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.enable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + disableOutOfBandManagement: { + label: 'label.outofbandmanagement.disable', + action: function (args) { + var data = { + hostid: args.context.hosts[0].id, + }; + $.ajax({ + url: createURL("disableOutOfBandManagementForHost"), + data: data, + success: function (json) { + var jid = json.disableoutofbandmanagementforhostresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.disable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.disable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + issueOutOfBandManagementPowerAction: { + label: 'label.outofbandmanagement.action.issue', + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.issue'; + }, + notification: function (args) { + return 'message.outofbandmanagement.issue'; + } + }, + createForm: { + title: 'label.outofbandmanagement.action.issue', + desc: function(args) { + var host = args.context.hosts[0]; + if (host.resourcestate == 'Maintenance' || host.resourcestate == 'PrepareForMaintenance' || host.resourcestate == 'ErrorInMaintenance') { + return _l('message.outofbandmanagement.action.maintenance'); + } + }, + fields: { + action: { + label: 'label.outofbandmanagement.action', + validation: { + required: true + }, + select: function (args) { + var items = []; + items.push({ + id: 'ON', + description: 'ON - turn on host' + }); + items.push({ + id: 'OFF', + description: 'OFF - turn off host' + }); + items.push({ + id: 'CYCLE', + description: 'CYCLE - power cycle the host' + }); + items.push({ + id: 'RESET', + description: 'RESET - power reset the host' + }); + items.push({ + id: 'SOFT', + description: 'SOFT - soft shutdown the host using ACPI etc' + }); + items.push({ + id: 'STATUS', + description: 'STATUS - update power status of the host' + }); + args.response.success({ + data: items + }); + } + }, + } + }, + action: function (args) { + var data = args.data; + data.hostid = args.context.hosts[0].id; + $.ajax({ + url: createURL('issueOutOfBandManagementPowerAction'), + data: data, + dataType: 'json', + success: function (json) { + var jid = json.issueoutofbandmanagementpoweractionresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + changeOutOfBandManagementPassword: { + label: 'label.outofbandmanagement.changepassword', + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.changepassword'; + }, + notification: function (args) { + return 'message.outofbandmanagement.changepassword'; + } + }, + createForm: { + title: 'label.outofbandmanagement.changepassword', + fields: { + password: { + label: 'label.outofbandmanagement.password', + isPassword: true, + validation: { + required: false + }, + }, + } + }, + action: function (args) { + var data = args.data; + data.hostid = args.context.hosts[0].id; + $.ajax({ + url: createURL('changeOutOfBandManagementPassword'), + data: data, + dataType: 'json', + success: function (json) { + var jid = json.changeoutofbandmanagementpasswordresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } } + }, tabFilter: function (args) { var hiddenTabs =[]; - if (args.context.hosts[0].gpugroup == null) { + var host = args.context.hosts[0]; + if (host.gpugroup == null) { hiddenTabs.push("gpu"); } + if (host.outofbandmanagement == null || !host.outofbandmanagement.enabled) { + hiddenTabs.push("outofbandmanagement"); + } return hiddenTabs; }, tabs: { @@ -16390,6 +16887,9 @@ state: { label: 'label.state' }, + powerstate: { + label: 'label.powerstate' + }, type: { label: 'label.type' }, @@ -16501,6 +17001,10 @@ async: true, success: function (json) { var item = json.listhostsresponse.host[0]; + if (item && item.outofbandmanagement) { + item.powerstate = item.outofbandmanagement.powerstate; + } + $.ajax({ url: createURL("listDedicatedHosts&hostid=" + args.context.hosts[0].id), dataType: "json", @@ -16532,6 +17036,44 @@ } }, + outofbandmanagement: { + title: 'label.outofbandmanagement', + fields: { + powerstate: { + label: 'label.powerstate' + }, + driver: { + label: 'label.outofbandmanagement.driver' + }, + username: { + label: 'label.outofbandmanagement.username' + }, + address: { + label: 'label.outofbandmanagement.address' + }, + port: { + label: 'label.outofbandmanagement.port' + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listHosts&id=" + args.context.hosts[0].id), + dataType: "json", + async: true, + success: function (json) { + var host = json.listhostsresponse.host[0]; + var oobm = {}; + if (host && host.outofbandmanagement) { + oobm = host.outofbandmanagement; + } + args.response.success({ + data: oobm + }); + } + }); + } + }, + stats: { title: 'label.statistics', fields: { @@ -20807,6 +21349,13 @@ allowedActions.push("disable"); allowedActions.push("remove"); + + if (jsonObj.hasOwnProperty('resourcedetails') && jsonObj['resourcedetails'].hasOwnProperty('outOfBandManagementEnabled') && jsonObj['resourcedetails']['outOfBandManagementEnabled'] == 'false') { + allowedActions.push("enableOutOfBandManagement"); + } else { + allowedActions.push("disableOutOfBandManagement"); + } + return allowedActions; } @@ -20892,6 +21441,12 @@ allowedActions.push("remove"); + if (jsonObj.hasOwnProperty('resourcedetails') && jsonObj['resourcedetails'].hasOwnProperty('outOfBandManagementEnabled') && jsonObj['resourcedetails']['outOfBandManagementEnabled'] == 'false') { + allowedActions.push("enableOutOfBandManagement"); + } else { + allowedActions.push("disableOutOfBandManagement"); + } + return allowedActions; } @@ -20928,6 +21483,16 @@ allowedActions.push("remove"); } + allowedActions.push("blankOutOfBandManagement"); + allowedActions.push("configureOutOfBandManagement"); + if (jsonObj.hasOwnProperty("outofbandmanagement") && jsonObj.outofbandmanagement.enabled) { + allowedActions.push("issueOutOfBandManagementPowerAction"); + allowedActions.push("changeOutOfBandManagementPassword"); + allowedActions.push("disableOutOfBandManagement"); + } else { + allowedActions.push("enableOutOfBandManagement"); + } + if ((jsonObj.state == "Down" || jsonObj.state == "Alert" || jsonObj.state == "Disconnected") && ($.inArray("remove", allowedActions) == -1)) { allowedActions.push("remove"); } diff --git a/utils/src/main/java/com/cloud/utils/fsm/StateMachine2.java b/utils/src/main/java/com/cloud/utils/fsm/StateMachine2.java index 431d961a41..f03974a00f 100644 --- a/utils/src/main/java/com/cloud/utils/fsm/StateMachine2.java +++ b/utils/src/main/java/com/cloud/utils/fsm/StateMachine2.java @@ -45,10 +45,20 @@ public StateMachine2() { } + public void addInitialTransition(E event, S toState) { + addTransition(null, event, toState); + } + public void addTransition(S currentState, E event, S toState) { addTransition(new Transition(currentState, event, toState, null)); } + @SafeVarargs + public final void addTransitionFromStates(E event, S toState, S... fromStates) { + for (S fromState : fromStates) { + addTransition(fromState, event, toState); + } + } public void addTransition(Transition transition) { S currentState = transition.getCurrentState(); diff --git a/utils/src/main/java/org/apache/cloudstack/utils/process/ProcessResult.java b/utils/src/main/java/org/apache/cloudstack/utils/process/ProcessResult.java new file mode 100644 index 0000000000..b50a7ab8c7 --- /dev/null +++ b/utils/src/main/java/org/apache/cloudstack/utils/process/ProcessResult.java @@ -0,0 +1,46 @@ +// 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.utils.process; + +public final class ProcessResult { + private final String stdOutput; + private final String stdError; + private final int returnCode; + + public ProcessResult(String stdOutput, String stdError, int returnCode) { + this.stdOutput = stdOutput; + this.stdError = stdError; + this.returnCode = returnCode; + } + + public String getStdOutput() { + return stdOutput; + } + + public String getStdError() { + return stdError; + } + + public int getReturnCode() { + return returnCode; + } + + public boolean isSuccess() { + return returnCode == 0; + } +} diff --git a/utils/src/main/java/org/apache/cloudstack/utils/process/ProcessRunner.java b/utils/src/main/java/org/apache/cloudstack/utils/process/ProcessRunner.java new file mode 100644 index 0000000000..c8ea6bf59a --- /dev/null +++ b/utils/src/main/java/org/apache/cloudstack/utils/process/ProcessRunner.java @@ -0,0 +1,115 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package org.apache.cloudstack.utils.process; + +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.io.CharStreams; +import org.apache.log4j.Logger; +import org.joda.time.Duration; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public final class ProcessRunner { + public static final Logger LOG = Logger.getLogger(ProcessRunner.class); + + // Default maximum timeout of 5 minutes for any command + public static final Duration DEFAULT_MAX_TIMEOUT = new Duration(5 * 60 * 1000); + private final ExecutorService executor; + + public ProcessRunner(ExecutorService executor) { + this.executor = executor; + } + + /** + * Executes a process with provided list of commands with a max default timeout + * of 5 minutes + * @param commands list of string commands + * @return returns process result + */ + public ProcessResult executeCommands(final List commands) { + return executeCommands(commands, DEFAULT_MAX_TIMEOUT); + } + + /** + * Executes a process with provided list of commands with a given timeout that is less + * than or equal to DEFAULT_MAX_TIMEOUT + * @param commands list of string commands + * @param timeOut timeout duration + * @return returns process result + */ + public ProcessResult executeCommands(final List commands, final Duration timeOut) { + Preconditions.checkArgument(commands != null && timeOut != null + && timeOut.getStandardSeconds() > 0L + && (timeOut.compareTo(DEFAULT_MAX_TIMEOUT) <= 0) + && executor != null); + + int retVal = -2; + String stdOutput = null; + String stdError = null; + + try { + final Process process = new ProcessBuilder().command(commands).start(); + final Future processFuture = executor.submit(new Callable() { + @Override + public Integer call() throws Exception { + return process.waitFor(); + } + }); + try { + retVal = processFuture.get(timeOut.getStandardSeconds(), TimeUnit.SECONDS); + } catch (ExecutionException e) { + retVal = -2; + stdError = e.getMessage(); + if (LOG.isTraceEnabled()) { + LOG.trace("Failed to complete the requested command due to execution error: " + e.getMessage()); + } + } catch (TimeoutException e) { + retVal = -1; + stdError = "Operation timed out, aborted"; + if (LOG.isTraceEnabled()) { + LOG.trace("Failed to complete the requested command within timeout: " + e.getMessage()); + } + } finally { + if (Strings.isNullOrEmpty(stdError)) { + stdOutput = CharStreams.toString(new InputStreamReader(process.getInputStream())); + stdError = CharStreams.toString(new InputStreamReader(process.getErrorStream())); + } + process.destroy(); + } + if (LOG.isTraceEnabled()) { + LOG.trace("Process standard output: " + stdOutput); + LOG.trace("Process standard error output: " + stdError); + } + } catch (IOException | InterruptedException e) { + stdError = e.getMessage(); + LOG.error("Exception caught error running commands: " + e.getMessage()); + } + return new ProcessResult(stdOutput, stdError, retVal); + } +} \ No newline at end of file diff --git a/utils/src/test/java/org/apache/cloudstack/utils/process/ProcessTest.java b/utils/src/test/java/org/apache/cloudstack/utils/process/ProcessTest.java new file mode 100644 index 0000000000..b5e6e04c31 --- /dev/null +++ b/utils/src/test/java/org/apache/cloudstack/utils/process/ProcessTest.java @@ -0,0 +1,69 @@ +// +// 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.utils.process; + +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.google.common.base.Strings; +import org.joda.time.Duration; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.Arrays; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@RunWith(MockitoJUnitRunner.class) +public class ProcessTest { + + private static final ExecutorService executor = Executors.newFixedThreadPool(10, new NamedThreadFactory("IpmiToolDriverTest")); + private static final ProcessRunner RUNNER = new ProcessRunner(executor); + + @Test + public void testProcessRunner() { + ProcessResult result = RUNNER.executeCommands(Arrays.asList("ls", "/tmp")); + Assert.assertEquals(result.getReturnCode(), 0); + Assert.assertTrue(Strings.isNullOrEmpty(result.getStdError())); + Assert.assertTrue(result.getStdOutput().length() > 0); + } + + @Test + public void testProcessRunnerWithTimeout() { + ProcessResult result = RUNNER.executeCommands(Arrays.asList("sleep", "5"), Duration.standardSeconds(1)); + Assert.assertNotEquals(result.getReturnCode(), 0); + Assert.assertTrue(result.getStdError().length() > 0); + Assert.assertEquals(result.getStdError(), "Operation timed out, aborted"); + } + + @Test + public void testProcessRunnerWithTimeoutAndException() { + ProcessResult result = RUNNER.executeCommands(Arrays.asList("ls", "/some/dir/that/should/not/exist"), Duration.standardSeconds(2)); + Assert.assertNotEquals(result.getReturnCode(), 0); + Assert.assertTrue(result.getStdError().length() > 0); + Assert.assertNotEquals(result.getStdError(), "Operation timed out, aborted"); + } + + @Test(expected = IllegalArgumentException.class) + public void testProcessRunnerWithMoreThanMaxAllowedTimeout() { + RUNNER.executeCommands(Arrays.asList("ls", "/some/dir/that/should/not/exist"), ProcessRunner.DEFAULT_MAX_TIMEOUT.plus(1000)); + Assert.fail("Illegal argument exception was expected"); + } +} From 4d5e8df2f952c4e0594c8fc4d11181f6d3da3811 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Fri, 6 May 2016 05:52:07 +0530 Subject: [PATCH 148/203] travis: Use patched version of ipmitool for tests - For out-of-band management feature (CLOUDSTACK-9299) use patched version of ipmitool that would work on trusty travis machines - The ipmitool used is from xenial/16.04 release with patch from RedHat https://bugzilla.redhat.com/show_bug.cgi?id=1286035 - Installs ipmitool from xenial repositories to get all the dependencies and then install patched deb version - Skip test if the known failure occurs Signed-off-by: Rohit Yadav --- developer/developer-prefill.sql | 2 +- setup/dev/advanced.cfg | 2 +- .../smoke/test_outofbandmanagement.py | 19 +++++++++++++++--- tools/travis/before_install.sh | 20 +++++++++++-------- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/developer/developer-prefill.sql b/developer/developer-prefill.sql index ab3da96c9f..132659e3d9 100644 --- a/developer/developer-prefill.sql +++ b/developer/developer-prefill.sql @@ -116,7 +116,7 @@ INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', - 'outofbandmanagement.sync.interval', '2000'); + 'outofbandmanagement.sync.interval', '1000'); -- Enable dynamic RBAC by default for fresh deployments INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) diff --git a/setup/dev/advanced.cfg b/setup/dev/advanced.cfg index 5e92028bad..48241fa664 100644 --- a/setup/dev/advanced.cfg +++ b/setup/dev/advanced.cfg @@ -226,7 +226,7 @@ }, { "name": "outofbandmanagement.sync.interval", - "value": "2000" + "value": "1000" } ], "mgtSvr": [ diff --git a/test/integration/smoke/test_outofbandmanagement.py b/test/integration/smoke/test_outofbandmanagement.py index d1f9840775..7c2aa6b5da 100644 --- a/test/integration/smoke/test_outofbandmanagement.py +++ b/test/integration/smoke/test_outofbandmanagement.py @@ -70,6 +70,7 @@ def tearDown(self): if self.server: self.server.shutdown() self.server.server_close() + IpmiServerContext('reset') except Exception as e: raise Exception("Warning: Exception during cleanup : %s" % e) @@ -143,7 +144,13 @@ def issuePowerActionCmd(self, action, timeout=None): cmd.action = action if timeout: cmd.timeout = timeout - return self.apiclient.issueOutOfBandManagementPowerAction(cmd) + + try: + return self.apiclient.issueOutOfBandManagementPowerAction(cmd) + except Exception as e: + if "packet session id 0x0 does not match active session" in str(e): + raise self.skipTest("Known ipmitool issue hit, skipping test") + raise e def configureAndEnableOobm(self): @@ -166,8 +173,14 @@ def startIpmiServer(tname, server): def checkSyncToState(self, state, interval): - self.debug("Waiting for background thread to update powerstate to " + state) - time.sleep(1 + int(interval)*2/1000) # interval is in ms + def checkForStateSync(expectedState): + response = self.getHost(hostId=self.getHost().id).outofbandmanagement + return response.powerstate == expectedState, None + + sync_interval = 1 + int(interval)/1000 + res, _ = wait_until(sync_interval, 10, checkForStateSync, state) + if not res: + self.fail("Failed to get host.powerstate synced to expected state:" + state) response = self.getHost(hostId=self.getHost().id).outofbandmanagement self.assertEqual(response.powerstate, state) diff --git a/tools/travis/before_install.sh b/tools/travis/before_install.sh index b257e052bd..44ead5ad56 100755 --- a/tools/travis/before_install.sh +++ b/tools/travis/before_install.sh @@ -86,18 +86,22 @@ sudo service mysql restart echo -e "\nInstalling Development tools: " RETRY_COUNT=3 -sudo apt-get -q -y install uuid-runtime genisoimage netcat freeipmi-common freeipmi-tools libfreeipmi12 > /dev/null +sudo apt-get -q -y install uuid-runtime genisoimage netcat > /dev/null if [[ $? -ne 0 ]]; then echo -e "\napt-get packages failed to install" fi -# We need version 1.8.15 or above, default installed version is buggy -wget http://mirrors.kernel.org/ubuntu/pool/universe/i/ipmitool/ipmitool_1.8.15-1ubuntu1.1_amd64.deb -O /tmp/ipmitool.deb -if [[ $? -eq 0 ]]; then - sudo dpkg -i /tmp/ipmitool.deb - sudo apt-get install -f -y - ipmitool -V -fi +# Use latest ipmitool 1.8.16 dependencies +sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1397BC53640DB551 +sudo sh -c 'echo "deb http://archive.ubuntu.com/ubuntu xenial main universe" >> /etc/apt/sources.list' +sudo apt-get update -q -y > /dev/null +sudo apt-get -q -y -V install freeipmi-common libfreeipmi16 libgcrypt20 libgpg-error-dev libgpg-error0 libopenipmi0 --no-install-recommends > /dev/null + +# Installed version 1.8.16 with patch: https://bugzilla.redhat.com/show_bug.cgi?id=1286035 +wget http://packages.shapeblue.com/contribs/ipmitool_1.8.16_travis_amd64.deb -O ipmitool.deb > /dev/null +sudo dpkg -i ipmitool.deb + +ipmitool -V echo " From e122bbfbfcf13dcec6e4848e8a8b99990047d060 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Wed, 11 May 2016 14:29:22 +0530 Subject: [PATCH 149/203] HypervisorUtilsTest: increate timeout to 8seconds Increases timeout to a larger value to avoid failures in VM environments such as TravisCI. Signed-off-by: Rohit Yadav --- .../apache/cloudstack/utils/hypervisor/HypervisorUtilsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/src/test/java/org/apache/cloudstack/utils/hypervisor/HypervisorUtilsTest.java b/utils/src/test/java/org/apache/cloudstack/utils/hypervisor/HypervisorUtilsTest.java index 54d002f8f8..f68776760d 100644 --- a/utils/src/test/java/org/apache/cloudstack/utils/hypervisor/HypervisorUtilsTest.java +++ b/utils/src/test/java/org/apache/cloudstack/utils/hypervisor/HypervisorUtilsTest.java @@ -57,7 +57,7 @@ public void checkVolumeFileForActivitySmallFileTest() throws IOException { public void checkVolumeFileForActivityTest() throws IOException { System.out.print("Testing block on modified files - "); String filePath = "./testfileinactive"; - int timeoutSeconds = 5; + int timeoutSeconds = 8; long thresholdMilliseconds = 2000; File file = new File(filePath); From 6135f6d98fa6b363b0468c17a8e713aeb5054437 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 12 May 2016 11:04:37 +0530 Subject: [PATCH 150/203] CLOUDSTACK-9378: Fix for #1497 Reorder cleanup items so cleanup won't fail Signed-off-by: Rohit Yadav --- test/integration/smoke/test_list_ids_parameter.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/integration/smoke/test_list_ids_parameter.py b/test/integration/smoke/test_list_ids_parameter.py index be9554bf41..f679aedf37 100755 --- a/test/integration/smoke/test_list_ids_parameter.py +++ b/test/integration/smoke/test_list_ids_parameter.py @@ -192,12 +192,12 @@ def setUpClass(cls): ) cls._cleanup = [ - cls.disk_offering, - cls.account, - cls.service_offering, cls.snapshot_1, cls.snapshot_2, - cls.snapshot_3 + cls.snapshot_3, + cls.account, + cls.disk_offering, + cls.service_offering ] @classmethod From 12fff7d8bda21dfea4324cfac244f96971296cdc Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 12 May 2016 11:16:12 +0530 Subject: [PATCH 151/203] maven: ignore utils/testsmallfileinactive for rat checking This fixes several Jenkins failures as previous runs don't cleanup this file created by one of the unit tests. Signed-off-by: Rohit Yadav --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index b75afd2ed2..b29e6fafb4 100644 --- a/pom.xml +++ b/pom.xml @@ -883,6 +883,7 @@ ui/lib/qunit/qunit.js ui/lib/reset.css ui/lib/require.js + utils/testsmallfileinactive systemvm/conf/agent.properties systemvm/conf/environment.properties systemvm/js/jquery.js From 1ad0da03904fa2ddfdf5016b54ea26dea969795a Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Mon, 2 May 2016 15:23:56 -0600 Subject: [PATCH 152/203] CLOUDSTACK-9373: Removing a few instance methods where there are class methods that are overshadowing them --- tools/marvin/marvin/lib/base.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index f5f53a5d85..1be0a3c209 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -2587,13 +2587,6 @@ def delete(self, apiclient): apiclient.deleteHost(cmd) return - def enableMaintenance(self, apiclient): - """enables maintenance mode Host""" - - cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() - cmd.id = self.id - return apiclient.prepareHostForMaintenance(cmd) - @classmethod def enableMaintenance(cls, apiclient, id): """enables maintenance mode Host""" @@ -2602,13 +2595,6 @@ def enableMaintenance(cls, apiclient, id): cmd.id = id return apiclient.prepareHostForMaintenance(cmd) - def cancelMaintenance(self, apiclient): - """Cancels maintenance mode Host""" - - cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() - cmd.id = self.id - return apiclient.cancelHostMaintenance(cmd) - @classmethod def cancelMaintenance(cls, apiclient, id): """Cancels maintenance mode Host""" @@ -2758,13 +2744,6 @@ def delete(self, apiclient): apiclient.deleteStoragePool(cmd) return - def enableMaintenance(self, apiclient): - """enables maintenance mode Storage pool""" - - cmd = enableStorageMaintenance.enableStorageMaintenanceCmd() - cmd.id = self.id - return apiclient.enableStorageMaintenance(cmd) - @classmethod def enableMaintenance(cls, apiclient, id): """enables maintenance mode Storage pool""" From d4cb05b8f99e2b16e5d8af5656ca64b5cf472b68 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Wed, 19 Jun 2013 17:08:25 -0700 Subject: [PATCH 153/203] utils: Disable NioTest Disable the NioTest, it is far to dependent on the network configuration of the machine running the test. Cherry-picked change from a historic commit where this test was disabled. (cherry picked from commit 881a6e164ece8e34154555b71e97c9f1763674f5) Signed-off-by: Rohit Yadav --- utils/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/pom.xml b/utils/pom.xml index 9e2358680f..206eb1896a 100755 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -208,6 +208,7 @@ com/cloud/utils/testcase/*TestCase* com/cloud/utils/db/*Test* + com/cloud/utils/testcase/NioTest.java From 11e3582fdf2ab94e70591f4603e84db59519f342 Mon Sep 17 00:00:00 2001 From: Paul Angus Date: Tue, 10 May 2016 21:24:29 +0100 Subject: [PATCH 154/203] Remove extraneous log directory and add catalina.out log rotation --- packaging/centos63/cloud.spec | 2 ++ packaging/centos7/cloud.spec | 2 ++ packaging/fedora20/cloud.spec | 2 ++ packaging/fedora21/cloud.spec | 2 ++ python/lib/cloudutils/serviceConfigServer.py | 1 - server/conf/cloudstack-catalina.logrotate | 26 ++++++++++++++++++++ 6 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 server/conf/cloudstack-catalina.logrotate diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index 99e37a3325..25970ea5a3 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -300,6 +300,7 @@ install -D packaging/centos63/cloud-management.rc ${RPM_BUILD_ROOT}%{_initrddir} install -D packaging/centos63/cloud-management.sysconfig ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/%{name}-management install -D server/target/conf/cloudstack-sudoers ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management install -D packaging/centos63/tomcat.sh ${RPM_BUILD_ROOT}%{_initrddir}/tomcat.sh +install -D server/target/conf/cloudstack-catalina.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}-catalina chmod 440 ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management chmod 770 ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management/Catalina @@ -580,6 +581,7 @@ fi %{_defaultdocdir}/%{name}-management-%{version}/LICENSE %{_defaultdocdir}/%{name}-management-%{version}/NOTICE %attr(0644,cloud,cloud) %{_localstatedir}/log/%{name}/management/catalina.out +%attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name}-catalina %files agent %attr(0755,root,root) %{_bindir}/%{name}-setup-agent diff --git a/packaging/centos7/cloud.spec b/packaging/centos7/cloud.spec index ae26c059dd..68cc048a48 100644 --- a/packaging/centos7/cloud.spec +++ b/packaging/centos7/cloud.spec @@ -272,6 +272,7 @@ install -D server/target/conf/cloudstack-sudoers ${RPM_BUILD_ROOT}%{_sysconfdir} install -D packaging/centos7/cloud-management.service ${RPM_BUILD_ROOT}%{_unitdir}/%{name}-management.service install -D packaging/centos7/cloud.limits ${RPM_BUILD_ROOT}%{_sysconfdir}/security/limits.d/cloud touch ${RPM_BUILD_ROOT}%{_localstatedir}/run/%{name}-management.pid +install -D server/target/conf/cloudstack-catalina.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}-catalina chmod 440 ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management chmod 770 ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management/Catalina @@ -476,6 +477,7 @@ fi %{_defaultdocdir}/%{name}-management-%{version}/LICENSE %{_defaultdocdir}/%{name}-management-%{version}/NOTICE %attr(0644,cloud,cloud) %{_localstatedir}/log/%{name}/management/catalina.out +%attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name}-catalina %files agent %attr(0755,root,root) %{_bindir}/%{name}-setup-agent diff --git a/packaging/fedora20/cloud.spec b/packaging/fedora20/cloud.spec index 704e4f79c4..b1d11b13a4 100644 --- a/packaging/fedora20/cloud.spec +++ b/packaging/fedora20/cloud.spec @@ -299,6 +299,7 @@ install -D packaging/centos63/cloud-ipallocator.rc ${RPM_BUILD_ROOT}%{_initrddir install -D packaging/centos63/cloud-management.rc ${RPM_BUILD_ROOT}%{_initrddir}/%{name}-management install -D packaging/centos63/cloud-management.sysconfig ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/%{name}-management install -D packaging/centos63/tomcat.sh ${RPM_BUILD_ROOT}%{_initrddir}/tomcat.sh +install -D server/target/conf/cloudstack-catalina.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}-catalina chmod 440 ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management chmod 770 ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management/Catalina @@ -578,6 +579,7 @@ fi %{_defaultdocdir}/%{name}-management-%{version}/LICENSE %{_defaultdocdir}/%{name}-management-%{version}/NOTICE %attr(0644,cloud,cloud) %{_localstatedir}/log/%{name}/management/catalina.out +%attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name}-catalina %files agent %attr(0755,root,root) %{_bindir}/%{name}-setup-agent diff --git a/packaging/fedora21/cloud.spec b/packaging/fedora21/cloud.spec index 2314ef2fdc..561452e3e9 100644 --- a/packaging/fedora21/cloud.spec +++ b/packaging/fedora21/cloud.spec @@ -299,6 +299,7 @@ install -D packaging/centos63/cloud-ipallocator.rc ${RPM_BUILD_ROOT}%{_initrddir install -D packaging/centos63/cloud-management.rc ${RPM_BUILD_ROOT}%{_initrddir}/%{name}-management install -D packaging/centos63/cloud-management.sysconfig ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/%{name}-management install -D packaging/centos63/tomcat.sh ${RPM_BUILD_ROOT}%{_initrddir}/tomcat.sh +install -D server/target/conf/cloudstack-catalina.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}-catalina chmod 440 ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management chmod 770 ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management/Catalina @@ -578,6 +579,7 @@ fi %{_defaultdocdir}/%{name}-management-%{version}/LICENSE %{_defaultdocdir}/%{name}-management-%{version}/NOTICE %attr(0644,cloud,cloud) %{_localstatedir}/log/%{name}/management/catalina.out +%attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name}-catalina %files agent %attr(0755,root,root) %{_bindir}/%{name}-setup-agent diff --git a/python/lib/cloudutils/serviceConfigServer.py b/python/lib/cloudutils/serviceConfigServer.py index 7812fff4f7..dce85a028e 100644 --- a/python/lib/cloudutils/serviceConfigServer.py +++ b/python/lib/cloudutils/serviceConfigServer.py @@ -120,7 +120,6 @@ def checkHostName(): bash("chown cloud.cloud /var/run/cloudstack-management.pid") #distro like sl 6.1 needs this folder, or tomcat6 failed to start checkHostName() - bash("mkdir /var/log/cloudstack-management/") bash("chown cloud:cloud -R /var/lib/cloudstack/") bash("chmod +x -R /usr/share/cloudstack-management/webapps/client/WEB-INF/classes/scripts/") #set max process per account is unlimited diff --git a/server/conf/cloudstack-catalina.logrotate b/server/conf/cloudstack-catalina.logrotate new file mode 100644 index 0000000000..498f690dd0 --- /dev/null +++ b/server/conf/cloudstack-catalina.logrotate @@ -0,0 +1,26 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +/var/log/cloudstack/management/catalina.out { + copytruncate + daily + rotate 14 + compress + missingok + create 0644 cloud cloud +} \ No newline at end of file From 9b93989032b05567a57a05b0f41a990b1474436e Mon Sep 17 00:00:00 2001 From: Milamber Date: Wed, 27 Jan 2016 16:46:39 +0000 Subject: [PATCH 155/203] Update L10N resource files with 4.9 strings from Transifex (20160511) Force "translator" mode with the transifex client. Update Transifex client config file (regenerated by Tx client) --- .../classes/resources/messages_ar.properties | 2 +- .../resources/messages_de_DE.properties | 2 +- .../classes/resources/messages_es.properties | 570 +++++++++--------- .../resources/messages_fr_FR.properties | 10 +- .../resources/messages_it_IT.properties | 1 + .../resources/messages_ja_JP.properties | 3 +- .../resources/messages_ko_KR.properties | 16 +- .../resources/messages_nb_NO.properties | 6 +- .../resources/messages_nl_NL.properties | 4 +- .../resources/messages_pt_BR.properties | 4 +- .../resources/messages_zh_CN.properties | 2 + tools/transifex/.tx/config | 19 + 12 files changed, 335 insertions(+), 304 deletions(-) diff --git a/client/WEB-INF/classes/resources/messages_ar.properties b/client/WEB-INF/classes/resources/messages_ar.properties index 3ba58ecf14..d1832c456a 100644 --- a/client/WEB-INF/classes/resources/messages_ar.properties +++ b/client/WEB-INF/classes/resources/messages_ar.properties @@ -48,7 +48,7 @@ label.CIDR.list=\u0642\u0627\u0626\u0645\u0629 CIDR label.CIDR.of.destination.network=CIDR \u0627\u0644\u062e\u0627\u0635 \u0628\u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0645\u0648\u062c\u0647\u0629. label.clean.up=\u062a\u0646\u0638\u064a\u0641 label.clear.list=\u0645\u0633\u062d \u0627\u0644\u0642\u0627\u0626\u0645\u0629 -label.configuration=\u0627\u0644\u062a\u0643\u0648\u064a\u0646 +label.configuration=\u062a\u0631\u062a\u064a\u0628 label.configure.network.ACLs=\u0636\u0628\u0637 \u0634\u0628\u0643\u0629 ACLs label.configure=\u0642\u0645 \u0628\u062a\u0643\u0648\u064a\u0646 label.configure.vpc=\u062a\u0643\u0648\u064a\u0646 VPC diff --git a/client/WEB-INF/classes/resources/messages_de_DE.properties b/client/WEB-INF/classes/resources/messages_de_DE.properties index d51598eeb6..3fb4126e00 100644 --- a/client/WEB-INF/classes/resources/messages_de_DE.properties +++ b/client/WEB-INF/classes/resources/messages_de_DE.properties @@ -728,7 +728,7 @@ label.general.alerts=Allgemeine Alarme label.generating.url=Generieren der URL label.globo.dns.configuration=GloboDNS-Konfiguration label.globo.dns=GloboDNS -label.gluster.volume=Volumen +label.gluster.volume=Volume label.go.step.2=Gehe zu Schritt 2 label.go.step.3=Weiter zu Schritt 3 label.go.step.4=Weiter mit Schritt 4 diff --git a/client/WEB-INF/classes/resources/messages_es.properties b/client/WEB-INF/classes/resources/messages_es.properties index 33fee1f846..4c76d2a18f 100644 --- a/client/WEB-INF/classes/resources/messages_es.properties +++ b/client/WEB-INF/classes/resources/messages_es.properties @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -changed.item.properties=Propiedades del elemento cambiadas +changed.item.properties=Propiedades del elemento cambiados confirm.enable.s3=Por favor, complete la siguiente informaci\u00f3n para habilitar el soporte del Almacenamiento Secundario sobre S3 confirm.enable.swift=Por favor, complete la siguiente informaci\u00f3n para habilitar el soporte para Swift error.could.not.change.your.password.because.ldap.is.enabled=Error, no se puede cambiar la contrase\u00f1a porque LDAP esta activado @@ -28,23 +28,23 @@ error.mgmt.server.inaccessible=El Servidor de Gesti\u00f3n es inaccesible. Por f error.password.not.match=Los campos de contrase\u00f1a no coinciden error.please.specify.physical.network.tags=Las Ofertas de Red no est\u00e1n disponibles hasta que se especifique los tags para esta red f\u00edsica. error.session.expired=Su sesi\u00f3n ha caducado. -error.something.went.wrong.please.correct.the.following=Algo sali\u00f3 mal, por favor corrija lo siguiente +error.something.went.wrong.please.correct.the.following=Algo sali\u00f3 mal, pro favor corrija lo siguiente error.unable.to.reach.management.server=No podemos conectar con el Management Server -error.unresolved.internet.name=Su nombre de Internet no se puede resolver. -force.delete.domain.warning=Advertencia\: Si elige esta opci\u00f3n se realizar\u00e1 la supresi\u00f3n de todos los dominios secundarios, todas las cuentas asociadas y sus recursos. -force.delete=Forzar Borrado -force.remove=Forzar la Remoci\u00f3n -force.remove.host.warning=Advertencia\: Si elige esta opci\u00f3n, CloudStack detendra por la fuerza todas las m\u00e1quinas virtuales en ejecuci\u00f3n antes de remover este servidor del cl\u00faster. -force.stop=Forzar la Detenci\u00f3n -force.stop.instance.warning=Advertencia\: Forzar la dertenci\u00f3n de esta instancia deber\u00ed\u00ada ser su \u00faltima opci\u00f3n. Puede conducir a la p\u00e9rdida de datos, as\u00ed\u00ad como un comportamiento inconsistente del estado de la m\u00e1quina virtual. +error.unresolved.internet.name=El nombre de Internet no se puede resolver. +force.delete.domain.warning=Advertencia\: Si elige esta opci\u00f3n, la supresi\u00f3n de todos los dominios secundarios y todas las cuentas asociadas y sus recursos. +force.delete=Forzar el borrado +force.remove=Forzar el retiro +force.remove.host.warning=Advertencia\: Si elige esta opci\u00f3n, CloudStack para detener la fuerza todas las m\u00e1quinas virtuales en ejecuci\u00f3n antes de retirar este host del cl\u00faster. +force.stop=Forzar la detenci\u00f3n +force.stop.instance.warning=Advertencia\: Forzar la dertenci\u00f3n de esta instancia deber\u00ed\u00ada ser su \u00faltima opci\u00f3n. Puede conducir a la p\u00e9rdida de datos, as\u00ed\u00ad como un comportamiento incoherente del Estado de la m\u00e1quina virtual. hint.no.host.tags=No se encontraron las etiquetas de servidor hint.no.storage.tags=No se encontraron las etiquetas de almacenamiento hint.type.part.host.tag=El tipo esta en parte de la etiqueta de servidor hint.type.part.storage.tag=El tipo est\u00e1 en parte de la etiqueta de almacenamiento ICMP.code=C\u00f3digo ICMP ICMP.type=Tipo ICMP -image.directory=Directorio de Im\u00e1genes -inline=Inline +image.directory=Directorio de im\u00e1genes +inline=alineado instances.actions.reboot.label=Reiniciar Instancia label.about=Acerca de label.about.app=Acerca de CloudStack @@ -52,9 +52,9 @@ label.accept.project.invitation=Aceptar invitaci\u00f3n al proyecto label.account.and.security.group=Cuenta, Grupo de seguridad label.account=Cuenta label.account.details=Detalles de la Cuenta -label.account.id=ID de la Cuenta +label.account.id=ID de la cuenta label.account.lower=cuenta -label.account.name=Nombre de la Cuenta +label.account.name=Nombre de cuenta label.accounts=Cuentas label.account.specific=espec\u00edficas de la cuenta label.account.type=Tipo de Cuenta @@ -66,119 +66,119 @@ label.acl.replaced=ACL reemplazada label.acquire.new.ip=Adquirir nueva IP label.acquire.new.secondary.ip=Adquirir nuevo IP secundario label.action=Acci\u00f3n -label.action.attach.disk=Conectar Disco -label.action.attach.disk.processing=Conectando Disco.... +label.action.attach.disk=Conecte el disco +label.action.attach.disk.processing=Conectando el disco.... label.action.attach.iso=Conectar ISO label.action.attach.iso.processing=Conectando el ISO.... -label.action.cancel.maintenance.mode=Cancelar el Modo de Mantenimiento -label.action.cancel.maintenance.mode.processing=Cancelando el Modo de Mantenimiento.... -label.action.change.password=Cambiar la Contrase\u00f1a +label.action.cancel.maintenance.mode=Cancelar el modo de mantenimiento +label.action.cancel.maintenance.mode.processing=Cancelando el modo de mantenimiento.... +label.action.change.password=Cambiar la contrase\u00f1a label.action.change.service=Cambiar el Servicio -label.action.change.service.processing=Cambiando el Servicio.... +label.action.change.service.processing=Cambiando el servicio.... label.action.configure.samlauthorization=Configurar Autorizaci\u00f3n SAML SSO label.action.copy.ISO=Copiar ISO label.action.copy.ISO.processing=Copiando ISO.... -label.action.copy.template=Copiar el Template -label.action.copy.template.processing=Copiando Template.... -label.action.create.template=Crear Template -label.action.create.template.from.vm=Crear Template desde VM -label.action.create.template.from.volume=Crear Template desde Volumen -label.action.create.template.processing=Creando Template.... +label.action.copy.template=Copiear la plantilla +label.action.copy.template.processing=Copiando Plantilla.... +label.action.create.template=Crear plantilla +label.action.create.template.from.vm=Crear plantilla de VM +label.action.create.template.from.volume=Crear plantilla de volumen +label.action.create.template.processing=Creaci\u00f3n de plantillas .... label.action.create.vm=Crear VM -label.action.create.vm.processing=Creando VM.... -label.action.create.volume=Crear Volumen -label.action.create.volume.processing=Creando Volumen.... +label.action.create.vm.processing=Creaci\u00f3n de m\u00e1quina virtual .... +label.action.create.volume=Crear volumen +label.action.create.volume.processing=Crear volumen .... label.action.delete.account=Eliminar cuenta -label.action.delete.account.processing=Eliminando cuenta.... -label.action.delete.cluster.processing=Removiendo Cluster.... -label.action.delete.cluster=Remover Cluster -label.action.delete.disk.offering=Borrar Oferta de Disco -label.action.delete.disk.offering.processing=Borrar Oferta de Disco.... -label.action.delete.domain.processing=Removiendo el Dominio .... -label.action.delete.domain=Remover Dominio -label.action.delete.firewall.processing=Eliminando el Firewall .... -label.action.delete.firewall=Remover regla de firewall -label.action.delete.ingress.rule.processing=Removiendo Regla de ingreso.... -label.action.delete.ingress.rule=Remover Regla de ingreso -label.action.delete.IP.range.processing=Remover Rango de IP.... -label.action.delete.IP.range=Remover Rango de IP -label.action.delete.ISO=Borrar ISO -label.action.delete.ISO.processing=Borrar ISO.... -label.action.delete.load.balancer.processing=Removiendo Load Balancer.... -label.action.delete.load.balancer=Remover regla de load balancer +label.action.delete.account.processing=Eliminar cuentas .... +label.action.delete.cluster=Borrar Grupo +label.action.delete.cluster.processing=Borrar Grupo .... +label.action.delete.disk.offering=Borrar disco Ofrenda +label.action.delete.disk.offering.processing=Borrar disco ofrece .... +label.action.delete.domain=Eliminar de dominio +label.action.delete.domain.processing=Eliminaci\u00f3n de dominio .... +label.action.delete.firewall=Eliminar servidor de seguridad +label.action.delete.firewall.processing=Eliminaci\u00f3n de firewall .... +label.action.delete.ingress.rule=Borrar ingreso Regla +label.action.delete.ingress.rule.processing=Eliminaci\u00f3n de ingreso regla .... +label.action.delete.IP.range=Eliminar Rango de IP +label.action.delete.IP.range.processing=Eliminar Rango de IP .... +label.action.delete.ISO=Eliminar ISO +label.action.delete.ISO.processing=Eliminaci\u00f3n de la norma ISO .... +label.action.delete.load.balancer=Eliminar equilibrador de carga +label.action.delete.load.balancer.processing=Eliminaci\u00f3n del equilibrador de carga .... label.action.delete.network=Eliminar Red -label.action.delete.network.processing=Borrando Red.... +label.action.delete.network.processing=Eliminaci\u00f3n de red .... label.action.delete.nexusVswitch=Eliminar Nexus 1000v label.action.delete.nic=Quitar NIC label.action.delete.physical.network=Eliminar red f\u00edsica label.action.delete.pod=Eliminar Pod -label.action.delete.pod.processing=Eliminando Pod.... -label.action.delete.primary.storage=Eliminar Almacenamiento Primario -label.action.delete.primary.storage.processing=Eliminando Almacenamiento Primario.... -label.action.delete.secondary.storage=Eliminar Almacenamiento Secundario -label.action.delete.secondary.storage.processing=Eliminando Almacenamiento Secundario .... +label.action.delete.pod.processing=Eliminar Pod .... +label.action.delete.primary.storage=Almacenamiento primario Eliminar +label.action.delete.primary.storage.processing=Eliminaci\u00f3n de almacenamiento primaria .... +label.action.delete.secondary.storage.processing=Eliminaci\u00f3n de almacenamiento secundario .... +label.action.delete.secondary.storage=secundaria almacenamiento Eliminar label.action.delete.security.group=Borrar Grupo de Seguridad label.action.delete.security.group.processing=Eliminar grupo de seguridad .... label.action.delete.service.offering=Eliminar Oferta de Servicio -label.action.delete.service.offering.processing=Eliminando Oferta de Servicio .... +label.action.delete.service.offering.processing=Eliminaci\u00f3n de Oferta de Servicio .... label.action.delete.snapshot=Eliminar instant\u00e1nea -label.action.delete.snapshot.processing=Borrando instant\u00e1nea .... +label.action.delete.snapshot.processing=Eliminar instant\u00e1nea .... label.action.delete.system.service.offering=Eliminar Oferta de Servicio de Sistema -label.action.delete.template=Eliminar Template -label.action.delete.template.processing=Borrando Template.... +label.action.delete.template=Eliminar plantilla +label.action.delete.template.processing=Eliminar plantilla .... label.action.delete.user=Eliminar usuario -label.action.delete.user.processing=Eliminando Usuario.... +label.action.delete.user.processing=Eliminar usuario .... label.action.delete.volume=Eliminar volumen -label.action.delete.volume.processing=Eliminando volumen .... +label.action.delete.volume.processing=Eliminar volumen .... label.action.delete.zone=Eliminar Zona -label.action.delete.zone.processing=Eliminando Zona.... +label.action.delete.zone.processing=Eliminaci\u00f3n de la Zona .... label.action.destroy.instance=Destruye Instancia -label.action.destroy.instance.processing=Destruyendo Instancia.... +label.action.destroy.instance.processing=Destrucci\u00f3n Instancia .... label.action.destroy.systemvm=destruir el sistema VM -label.action.destroy.systemvm.processing=Destruyendo VM de Sistema.... -label.action.detach.disk=Desconectar Disco -label.action.detach.disk.processing=Desconectando Disco .... -label.action.detach.iso.processing=Desconectando ISO.... +label.action.destroy.systemvm.processing=Destrucci\u00f3n del sistema VM .... +label.action.detach.disk.processing=Extracci\u00f3n disco .... +label.action.detach.disk=Separar disco +label.action.detach.iso.processing=Extracci\u00f3n ISO .... label.action.detach.iso=Separar ISO label.action.disable.account=Desactivar cuenta -label.action.disable.account.processing=Deshabilitando cuenta.... -label.action.disable.cluster=Deshabilitar Cl\u00faster -label.action.disable.cluster.processing=Deshabilitando el Cluster.... +label.action.disable.account.processing=Deshabilitar cuenta .... +label.action.disable.cluster=Deshabilitar cl\u00faster +label.action.disable.cluster.processing=Desactivaci\u00f3n de Cluster Server .... label.action.disable.nexusVswitch=Deshabilitar Nexus 1000v label.action.disable.physical.network=Desactivar la red f\u00edsica label.action.disable.pod=Deshabilitar Pod -label.action.disable.pod.processing=Deshabilitando el Pod.... +label.action.disable.pod.processing=Deshabilitar Pod .... label.action.disable.static.NAT=Deshabilitar NAT est\u00e1tica -label.action.disable.static.NAT.processing=Deshabilitando el NAT Est\u00e1tico.... +label.action.disable.static.NAT.processing=Deshabilitar NAT est\u00e1tica .... label.action.disable.user=Deshabilitar usuario -label.action.disable.user.processing=Deshabilitando Usuario.... +label.action.disable.user.processing=Desactivaci\u00f3n de usuario .... label.action.disable.zone=Deshabilitar la zona -label.action.disable.zone.processing=Deshabilitando Zona.... +label.action.disable.zone.processing=Desactivaci\u00f3n de la zona .... label.action.download.ISO=ISO Descargar -label.action.download.template=Descargar Template +label.action.download.template=Descargar plantilla label.action.download.volume=Descargar Volumen -label.action.download.volume.processing=Descargando Volumen.... +label.action.download.volume.processing=Volumen Descargar .... label.action.edit.account=Editar cuenta -label.action.edit.disk.offering=Editar Oferta de Disco +label.action.edit.disk.offering=Editar disco Ofrenda label.action.edit.domain=Editar Dominio -label.action.edit.global.setting=Editar la Configuraci\u00f3n Global -label.action.edit.host=Editar Servidor +label.action.edit.global.setting=Editar Mundial Marco +label.action.edit.host=edici\u00f3n Anfitri\u00f3n label.action.edit.instance=Editar Instancia label.action.edit.ISO=Editar ISO label.action.edit.network=Edici\u00f3n de redes label.action.edit.network.offering=Editar Red ofrece label.action.edit.network.processing=Editando Red.... label.action.edit.pod=Editar Pod -label.action.edit.primary.storage=Editar Almacenamiento Primario +label.action.edit.primary.storage=Editar Almacenamiento primario label.action.edit.resource.limits=Editar l\u00edmites de recursos label.action.edit.service.offering=Editar Oferta de Servicio -label.action.edit.template=Editar Template +label.action.edit.template=Editar plantilla label.action.edit.user=Editar usuario label.action.edit.zone=Edici\u00f3n Zona label.action.enable.account=Habilitar cuenta label.action.enable.account.processing=cuenta de Habilitaci\u00f3n .... -label.action.enable.cluster=Habilitar Cl\u00faster -label.action.enable.cluster.processing=Habilitando el Cl\u00faster .... +label.action.enable.cluster=Habilitar cl\u00faster +label.action.enable.cluster.processing=Habilitar cl\u00faster .... label.action.enable.maintenance.mode=Activar el modo de mantenimiento label.action.enable.maintenance.mode.processing=Habilitaci\u00f3n del modo de mantenimiento .... label.action.enable.nexusVswitch=Habilitar Nexus 1000v @@ -200,8 +200,8 @@ label.action.generate.keys.processing=Generar claves .... label.action.list.nexusVswitch=Listar Nexus 1000v label.action.lock.account=Bloqueo de cuenta label.action.lock.account.processing=Bloqueo de cuenta .... -label.action.manage.cluster=Gestionar Cl\u00faster -label.action.manage.cluster.processing=Gestionando Cl\u00faster.... +label.action.manage.cluster=gestionar racimo +label.action.manage.cluster.processing=La gesti\u00f3n de cl\u00fasteres .... label.action.migrate.instance=Migrar Instancia label.action.migrate.instance.processing=Migrar Instancia .... label.action.migrate.router=migrar Router @@ -216,19 +216,19 @@ label.action.reboot.systemvm.processing=reinicio del sistema VM .... label.action.reboot.systemvm=Reiniciar sistema VM label.action.recurring.snapshot=recurrente instant\u00e1neas label.action.register.iso=Registrar ISO -label.action.register.template=Registrar template desde una URL +label.action.register.template=Registrar plantilla desde una URL label.action.release.ip=estreno IP label.action.release.ip.processing=Liberar IP .... -label.action.remove.host.processing=Removiendo el Servidor.... -label.action.remove.host=Quitar el Servidor +label.action.remove.host.processing=Extracci\u00f3n de host .... +label.action.remove.host=Quitar host label.action.reset.password.processing=Restablecimiento de la contrase\u00f1a .... label.action.reset.password=Restablecer contrase\u00f1a label.action.resize.volume=Cambiar el tama\u00f1o del Volumen -label.action.resize.volume.processing=Cambiando el tama\u00f1o del Volumen.... +label.action.resize.volume.processing=Cambiar el tama\u00f1o del Volumen.... label.action.resource.limits=Recursos l\u00edmites label.action.restore.instance.processing=Restaurar Instancia .... label.action.restore.instance=Restaurar Instancia -label.action.revert.snapshot.processing=Revertiendo a Snapshot... +label.action.revert.snapshot.processing=Volviendo a Snapshot... label.action.revert.snapshot=Revertir a Snapshot label.actions=Acciones label.action.start.instance=Iniciar Instancia @@ -239,27 +239,27 @@ label.action.start.systemvm=Inicio del sistema VM label.action.start.systemvm.processing=A partir del sistema VM .... label.action.stop.instance=Detener Instancia label.action.stop.instance.processing=Detener Instancia .... -label.action.stop.router=Parar el Router -label.action.stop.router.processing=Parando el Router.... -label.action.stop.systemvm=Parar VM del Sistema -label.action.stop.systemvm.processing=Deteniendo VM de Sistema.... -label.action.take.snapshot.processing=Tomando instant\u00e1nea.... +label.action.stop.router=Detener router +label.action.stop.router.processing=Detener router .... +label.action.stop.systemvm=parada del sistema VM +label.action.stop.systemvm.processing=Detener sistema VM .... +label.action.take.snapshot.processing=Tomar instant\u00e1neas .... label.action.take.snapshot=Tomar instant\u00e1nea -label.action.unmanage.cluster=Dejar de Gestionar Cl\u00faster -label.action.unmanage.cluster.processing=Dejando de Gestionar Cl\u00faster .... +label.action.unmanage.cluster.processing=Unmanaging Grupo .... +label.action.unmanage.cluster=Unmanage racimo label.action.update.OS.preference=Actualizar OS Preferencia label.action.update.OS.preference.processing=Actualizaci\u00f3n de sistema operativo preferencia .... label.action.update.resource.count=Actualizaci\u00f3n de recursos Conde label.action.update.resource.count.processing=Actualizaci\u00f3n de Conde de recursos .... label.action.vmsnapshot.create=Tomar instant\u00e1nea de VM -label.action.vmsnapshot.delete=Borrar Instant\u00e1nea de VM -label.action.vmsnapshot.revert=Volver VM a la instant\u00e1nea +label.action.vmsnapshot.delete=Borrar Instantanea de VM +label.action.vmsnapshot.revert=Volver VM a la instantanea label.activate.project=Activar Proyecto label.active.sessions=Sesiones activas label.add.account=A\u00f1adir cuenta label.add.accounts=Agregar cuentas label.add.accounts.to=Agregar cuentas a -label.add.account.to.project=Agregar cuenta al proyecto +label.add.account.to.project=Agregar cuenta al projecto label.add.ACL=Agregar ACL label.add.acl.list=Agregar Lista ACL label.add.affinity.group=Agregar un nuevo grupo de afinidad @@ -272,10 +272,10 @@ label.add.by=A\u00f1adir por label.add.by.cidr=A\u00f1adir Por CIDR label.add.by.group=A\u00f1adir Por el Grupo de label.add.ciscoASA1000v=Agregar un Recurso CiscoASA1000v -label.add.cluster=A\u00f1adir Cl\u00faster +label.add.cluster=A\u00f1adir Grupo label.add.compute.offering=Agregar oferta de computo label.add.direct.iprange=A\u00f1adir Direct IP Gama -label.add.disk.offering=A\u00f1adir Oferta de Disco +label.add.disk.offering=A\u00f1adir disco Ofrenda label.add.domain=Agregar dominio label.added.brocade.vcs.switch=Nuevo Switch VCS Brocade agregado label.added.network.offering=Oferta de Red agregada @@ -288,9 +288,9 @@ label.add.firewall=Agregar Servidor de seguridad label.add.globo.dns=Agregar GloboDNS label.add.gslb=Agregar GSLB label.add.guest.network=Agregar red de invitado -label.add.host=Agregar Servidor +label.add.host=Agregar host label.adding=Agregar -label.adding.cluster=Agregando Cl\u00faster +label.adding.cluster=Adici\u00f3n de cl\u00faster label.adding.failed=No se pudo agregar label.adding.pod=Agregar Pod label.adding.processing=A\u00f1adir .... @@ -301,7 +301,7 @@ label.adding.zone=Agregar la zona label.add.intermediate.certificate=Agregar certificado de entidad intermedia label.add.internal.lb=Agregar LB Interno label.add.ip.range=A\u00f1adir Rango de IP -label.add.isolated.guest.network=Agregar red Aislada para Guest +label.add.isolated.guest.network=Agregar red Aislado para Guest label.add.isolated.guest.network.with.sourcenat=Agregar Red Aislada para Guest con SourceNat label.add.isolated.network=Agregar Red Aislada label.additional.networks=Redes adicional @@ -331,20 +331,20 @@ label.add.physical.network=Agregar red f\u00edsica label.add.pod=A\u00f1adir Pod label.add.portable.ip.range=Agregar un Rango IP Port\u00e1til label.add.port.forwarding.rule=Agregar regla port forwarding -label.add.primary.storage=A\u00f1adir Almacenamiento Primario +label.add.primary.storage=A\u00f1adir Almacenamiento primario label.add.private.gateway=Agregar Gateway Privado label.add.region=Agregar Regi\u00f3n label.add.resources=Agregar Recursos label.add.route=Agregar ruta label.add.rule=Agregar regla -label.add.secondary.storage=Agregar Almacenamiento Secundario +label.add.secondary.storage=A\u00f1adir secundaria almacenamiento label.add.security.group=Agregar grupo de seguridad label.add.service.offering=A\u00f1adir Servicio de Oferta label.add.SRX.device=Agregar dispositivo SRX label.add.static.nat.rule=Agregar regla NAT est\u00e1tica label.add.static.route=Agregar ruta est\u00e1tica label.add.system.service.offering=Agregar Oferta de Servicio del Sistema -label.add.template=A\u00f1adir Template +label.add.template=A\u00f1adir plantilla label.add.to.group=Agregar al grupo label.add.ucs.manager=Agregar UCS Manager label.add.user=Agregar usuario @@ -373,7 +373,7 @@ label.advanced.search=B\u00fasqueda Avanzada label.affinity=Afinidad label.affinity.group=Grupo de Afinidad label.affinity.groups=Grupos de Afinidades -label.agent.password=Contrase\u00f1a del Agente +label.agent.password=Password de Agente label.agent.port=Puerto del Agente label.agent.state=Estado del Agente label.agent.username=Usuario de Agente @@ -395,7 +395,7 @@ label.apply=Aplicar label.app.name=CloudStack label.archive.alerts=Archivar alertas label.archive=Archivar -label.archive.events=Archivar eventos +label.archive.events=Archivar sucesos label.assign=Asignar label.assigned.vms=VMs Asignadas label.assign.instance.another=Asignar la instancias a otra Cuenta @@ -423,13 +423,13 @@ label.baremetal.pxe.device=Agregar Proveedor PXE para Baremetal label.baremetal.pxe.devices=Dispositivo Baremetal para PXE label.baremetal.pxe.provider=Proveedor PXE para Baremetal label.baremetal.rack.configuration=Configuraci\u00f3n del Rack Baremetal -label.basic=B\u00e1sic0 +label.basic=B\u00e1sica label.basic.mode=Modo b\u00e1sico -label.bigswitch.bcf.details=Detalles del BigSwitch BCF +label.bigswitch.bcf.details=Detalles del Controlador BigSwitch BCF label.bigswitch.bcf.nat=BigSwitch BCF con NAT habilitado label.bigswitch.controller.address=Direcci\u00f3n del Controlador BigSwitch BCF -label.blade.id=ID de Blade -label.blades=Blades +label.blade.id=ID de Hoja +label.blades=Hojas label.bootable=arranque label.broadcast.domain.range=Rango del dominio de Broadcast label.broadcast.domain.type=Tipo de dominio de difusi\u00f3n @@ -443,9 +443,9 @@ label.by.alert.type=Por tipo de alerta label.by.availability=Por Disponibilidad label.by.date.end=Por fecha (finalizaci\u00f3n) label.by.date.start=Por fecha (inicio) -label.by.domain=Por Dominio +label.by.domain=Por dominio label.by.end.date=Por Fecha de finalizaci\u00f3n -label.by.event.type=Por tipo de evento +label.by.event.type=Por tipo de suceso label.by.level=por Nivel label.by.pod=Por Pod label.by.role=por funci\u00f3n @@ -484,10 +484,10 @@ label.clear.list=Limpiar lista label.close=Cerrar label.cloud.console=Cloud Management Console label.cloud.managed=Cloud.com Gestionado -label.cluster=Cl\u00faster -label.cluster.name=Nombre del Cl\u00faster -label.clusters=Clusters -label.cluster.type=Tipo de Cl\u00faster +label.cluster=Grupo +label.cluster.name=Nombre del Cluster +label.clusters=Cluster +label.cluster.type=Tipo de Cluster Server label.clvm=CLVM label.code=C\u00f3digo label.community=Comunidad @@ -502,7 +502,7 @@ label.configure.network.ACLs=Configurar ACLs de la Red label.configure.sticky.policy=Configurar pol\u00edtica de Sticky label.configure.vpc=Configurar VPC label.confirmation=Confirmation -label.confirm.password=Confirmar la contrase\u00f1a +label.confirm.password=Confirmar password label.congratulations=Felicitaciones \! label.conserve.mode=Conservar modo label.console.proxy=Consola proxy @@ -531,9 +531,9 @@ label.cross.zones=Cruz Zonas label.custom=A Medida label.custom.disk.iops=IOPS personalizadas label.custom.disk.offering=Oferta de Disco Personalizada -label.custom.disk.size=Tama\u00f1o de Disco Personalizado +label.custom.disk.size=Personal Disk Size label.daily=diario -label.data.disk.offering=Oferta para Disco de Datos +label.data.disk.offering=Datos Disco Offering label.date=Fecha label.day=D\u00eda label.day.of.month=D\u00eda del mes @@ -546,9 +546,9 @@ label.dedicated=Dedicado label.dedicate=Dedicar label.dedicated.vlan.vni.ranges=Rangos VLAN/VNI Dedicados label.dedicate.host=Servidor Dedicado -label.dedicate.pod=Dedicar Pod +label.dedicate.pod=Pod Dedicado label.dedicate.vlan.vni.range=Dedicar Rango VLAN/VNI -label.dedicate.zone=Dedicar Zona +label.dedicate.zone=Zona Dedicada label.default.egress.policy=Pol\u00edtica de salida por defecto label.default=Por Defecto label.default.use=Usar por defecto @@ -601,7 +601,7 @@ label.direct.attached.public.ip=IP P\u00fablica Conectada en forma Directa label.direct.ips=IPs de la Red Compartida label.disable.autoscale=Deshabilitar Escalado Autom\u00e1tico label.disabled=personas de movilidad reducida -label.disable.host=Deshabilitar Servidor +label.disable.host=Deshabitar Servidor label.disable.network.offering=Deshabitar oferta de red label.disable.provider=Deshabilitar proveedor label.disable.vnmc.provider=Deshabitar proveedor VNMC @@ -610,14 +610,14 @@ label.disable.vpn=Deshabilitar VPN label.disabling.vpn.access=Desactivaci\u00f3n de VPN de acceso label.disassociate.profile.blade=Remover asociaci\u00f3n entre Perfil y Blade label.disbale.vnmc.device=Deshabitar dispositivo VNMC -label.disk.allocated=Disco Asignado +label.disk.allocated=disco asignado label.disk.bytes.read.rate=Lectura de Disco (BPS) label.disk.bytes.write.rate=Escritura a Disco (BPS) label.disk.iops.max=IOPS m\u00e1ximas label.disk.iops.min=IOPS m\u00ednimas label.disk.iops.read.rate=Lectura de Disco (IOPS) label.disk.iops.total=Total de IOPS -label.disk.iops.write.rate=Escritura a Disco (IOPS) +label.disk.iops.write.rate=Escritura de Disco (IOPS) label.disk.offering.details=Detalles de oferta de disco label.disk.offering=disco Ofrenda label.diskoffering=oferta de disco @@ -639,10 +639,10 @@ label.dns=DNS label.DNS.domain.for.guest.networks=Dominio DNS para las Redes Guest label.domain.admin=Administrador de dominio label.domain.details=Detalles del Dominio -label.domain=Dominio -label.domain.id=ID de Dominio +label.domain=dominio +label.domain.id=ID de dominio label.domain.lower=dominio -label.domain.name=Nombre de Dominio +label.domain.name=Nombre de dominio label.domain.router=Router de Dominio label.domain.suffix=DNS sufijo de dominio (es decir, xyz.com) label.done=Listo @@ -663,7 +663,7 @@ label.edit.secondary.ips=Editar IPs secundarios label.edit.tags=Editar etiquetas label.edit.traffic.type=Edite el tipo de trafico label.edit.vpc=Editar VPC -label.egress.default.policy=Regla de salida predeterminada +label.egress.default.policy=Directiva de salida predeterminada label.egress.rule=Regla de salida label.egress.rules=Reglas de salida label.elastic=El\u00e1stico @@ -673,7 +673,7 @@ label.email=correo electr\u00f3nico label.email.lower=email label.enable.autoscale=Habilitar Escalado Autom\u00e1tico label.enable.host=Habilitar Servidor -label.enable.network.offering=Habilitar oferta de red +label.enable.network.offering=Habilitar oferta de red label.enable.provider=Habilitar proveedor label.enable.s3=Habilitar Almacenamiento Secundario sobre S3 label.enable.swift=Habilitar Swift @@ -698,7 +698,7 @@ label.ESP.encryption=Encriptaci\u00f3n ESP label.ESP.hash=Hash label.ESP.lifetime=Tiempo de vida ESP (en segundos) label.ESP.policy=Pol\u00edtica ESP -label.esx.host=Servidor ESX / ESXi +label.esx.host=ESX / ESXi anfitri\u00f3n label.event.archived=Evento Archivado label.event.deleted=Evento Borrado label.event=Evento @@ -706,7 +706,7 @@ label.every=Cada label.example=Ejemplo label.expunge=Purgar label.external.link=Enlace externo -label.extractable=Extra\u00edble +label.extractable=extra\u00edble label.extractable.lower=extraible label.f5.details=Detalles F5 label.f5=F5 @@ -724,7 +724,7 @@ label.friday=Viernes label.full=completo label.full.path=Path completo label.gateway=puerta de enlace -label.general.alerts=Alertas Generales +label.general.alerts=General de Alertas label.generating.url=Generar URL label.globo.dns.configuration=Configuraci\u00f3n de GloboDNS label.globo.dns=GloboDNS @@ -774,18 +774,18 @@ label.health.check.interval.in.sec=Intervalo de Health Check (en seg) label.health.check.message.desc=Tu load balancer automaticamente har\u00e1 health checks en tus instancias cloudstack y solo pasar\u00e1 el tr\u00e1fico a las instancias que lo cumplan. label.health.check=Verificaci\u00f3n de Salud label.health.check.wizard=Wizard para Health Check -label.healthy.threshold=Umbral Saludable +label.healthy.threshold=Barrera de Salud label.help=Ayuda label.hide.ingress.rule=Ocultar el art\u00edculo ingreso label.hints=Sugerencias label.home=Inicio -label.host.alerts=Alertas de Servidor -label.host.MAC=MAC del Servidor -label.host.name=nombre de servidor -label.host=Servidores -label.hosts=Servidores +label.host.alerts=Host Alertas +label.host=Ej\u00e9rcitos +label.host.MAC=MAC del Host +label.host.name=nombre de host +label.hosts=Ej\u00e9rcitos label.host.tag=Etiqueta del Servidor -label.host.tags=Etiquetas del Servidor +label.host.tags=Etiquetas de Host label.hourly=por hora label.hvm=HVM label.hypervisor.capabilities=Capacidades del Hipervisor @@ -813,9 +813,9 @@ label.installWizard.addHostIntro.title=Agreguemos un servidor label.installWizard.addPodIntro.subtitle=\u00bfQue es un Pod? label.installWizard.addPodIntro.title=Agreguemos un Pod label.installWizard.addPrimaryStorageIntro.subtitle=\u00bfQu\u00e9 es el almacenamiento primario? -label.installWizard.addPrimaryStorageIntro.title=Agreguemos el almacenamiento primario -label.installWizard.addSecondaryStorageIntro.subtitle=Que es el almacenamiento secundario? -label.installWizard.addSecondaryStorageIntro.title=Agreguemos un almacenamiento secundario +label.installWizard.addPrimaryStorageIntro.title=Agreguemos almacenamiento primario +label.installWizard.addSecondaryStorageIntro.subtitle=Que es almacenamiento secundario? +label.installWizard.addSecondaryStorageIntro.title=A\u00f1adir almacenamiento secundario label.installWizard.addZoneIntro.subtitle=\u00bfQu\u00e9 es una zona? label.installWizard.addZoneIntro.title=Agreguemos una zona label.installWizard.addZone.title=Agregar zona @@ -828,7 +828,7 @@ label.instance.name=Nombre de instancia label.instance.port=Puerto de Instancia label.instance.scaled.up=Instancia escalada a lo requerido en la oferta label.instances=Instancias -label.instanciate.template.associate.profile.blade=Instanciar Template y asociar al Perfil del Blade +label.instanciate.template.associate.profile.blade=Instanciar Plantilla y asociar al Perfil del Blade label.intermediate.certificate=Entidad de Certificaci\u00f3n Intermedia {0} label.internal.dns.1=DNS interno una label.internal.dns.2=DNS interno 2 @@ -889,7 +889,7 @@ label.key=Llave label.kvm.traffic.label=Etiqueta de tr\u00e1fico KVM label.label=Etiqueta label.lang.arabic=\u00c1rabe -label.lang.brportugese=Portugu\u00e9s de Brasil +label.lang.brportugese=Portugues de Brasil label.lang.catalan=Catal\u00e1n label.lang.chinese=Chino (simplificado) label.lang.dutch=Holandes @@ -955,7 +955,7 @@ label.max.primary.storage=Primario M\u00e1x. (GiB) label.max.public.ips=IPs p\u00fablicas M\u00e1x. label.max.secondary.storage=Secundario M\u00e1x. (GiB) label.max.snapshots=Instant\u00e1neas M\u00e1x. -label.max.templates=Templates M\u00e1ximos +label.max.templates=Plantillas M\u00e1ximos label.max.vms=VMs de usuario M\u00e1x. label.max.volumes=Maxima cantidad de Volumes label.max.vpcs=VPCs M\u00e1x. @@ -972,16 +972,16 @@ label.menu.alerts=Alertas label.menu.all.accounts=Todas las cuentas label.menu.all.instances=todas las instancias label.menu.community.isos=Comunidad ISOs -label.menu.community.templates=Templates de la Comunidad +label.menu.community.templates=plantillas de la comunidad label.menu.configuration=Configuraci\u00f3n label.menu.dashboard=Interfaz label.menu.destroyed.instances=Destruir instancias -label.menu.disk.offerings=Ofertas de Disco -label.menu.domains=Dominios +label.menu.disk.offerings=disco ofertas +label.menu.domains=dominio label.menu.events=Eventos label.menu.featured.isos=destacados ISO -label.menu.featured.templates=Templates Destacados -label.menu.global.settings=Configuraci\u00f3n Global +label.menu.featured.templates=destacados plantillas +label.menu.global.settings=Configuraci\u00f3n global label.menu.infrastructure=Infraestructura label.menu.instances=Instancias label.menu.ipaddresses=Direcciones IP @@ -989,7 +989,7 @@ label.menu.isos=ISO label.menu.my.accounts=Mis cuentas label.menu.my.instances=Mi instancias label.menu.my.isos=Mi ISOs -label.menu.my.templates=Mis Templates +label.menu.my.templates=Mis plantillas label.menu.network.offerings=Red de ofertas label.menu.network=Red label.menu.physical.resources=Recursos F\u00edsicos @@ -1004,13 +1004,13 @@ label.menu.storage=Almacenamiento label.menu.system.service.offerings=Ofertas de Sistema label.menu.system=Sistema label.menu.system.vms=Sistema de m\u00e1quinas virtuales -label.menu.templates=Templates +label.menu.templates=plantillas label.menu.virtual.appliances=Virtual Appliances label.menu.virtual.resources=Virtual de Recursos label.menu.volumes=Vol\u00famenes label.menu.vpc.offerings=Ofertas de VPC label.metrics.allocated=Asignados -label.metrics.clusters=Clusters +label.metrics.clusters=Cluster label.metrics.cpu.allocated=Asignaci\u00f3n de CPU label.metrics.cpu.max.dev=Desviaci\u00f3n label.metrics.cpu.total=Total @@ -1027,7 +1027,7 @@ label.metrics.disk.unallocated=Sin asignar label.metrics.disk.usage=Uso del Disco label.metrics.disk.used=Usado label.metrics.disk.write=Escritura -label.metrics.hosts=Servidores +label.metrics.hosts=Ej\u00e9rcitos label.metrics.memory.allocated=Asignaci\u00f3n de Memoria label.metrics.memory.max.dev=Desviaci\u00f3n label.metrics.memory.total=Total @@ -1044,13 +1044,13 @@ label.metrics.scope=Alcance label.metrics.state=Estado label.metrics.storagepool=Pool de Almacenamiento label.metrics.vm.name=Nombre de la VM -label.migrate.instance.to.host=Migrar instancia a otro servidor. +label.migrate.instance.to.host=Migrar instancia a otro host. label.migrate.instance.to=Migraci\u00f3n de ejemplo para -label.migrate.instance.to.ps=Migrar instancia a otro almacenamiento primario +label.migrate.instance.to.ps=Migrar instancia a otro primary storage. label.migrate.lb.vm=Migrar LB VM label.migrate.router.to=Router para migrar label.migrate.systemvm.to=Migrar m\u00e1quina virtual del sistema para -label.migrate.to.host=Migrar al server +label.migrate.to.host=Migrar a host label.migrate.to.storage=Migrar a almacenamiento label.migrate.volume=Migrar Volumen label.migrate.volume.to.primary.storage=Migrar volumen a otro almacenamiento primario @@ -1062,14 +1062,14 @@ label.minutes.past.hour=minuto(s) despu\u00e9s de la hora label.mode=modo label.monday=lunes label.monthly=mensual -label.more.templates=M\u00e1s Templates +label.more.templates=plantillas \= M\u00e1s label.move.down.row=Mover abajo una fila label.move.to.bottom=Mover al fondo label.move.to.top=Mover al principio label.move.up.row=Mover una fila arriba label.my.account=Mi Cuenta label.my.network=Mi red -label.my.templates=Mis Templates +label.my.templates=Mis plantillas label.name.lower=Nombre label.name=Nombre label.name.optional=Nombre (Opcional) @@ -1087,7 +1087,7 @@ label.network.desc=Red de Desc label.network.details=Detalles de la Red label.network.device=De dispositivos de red label.network.device.type=Tipo de red de dispositivos -label.network.domain=Red de Dominio +label.network.domain=red de dominio label.network.domain.text=Dominio de Red label.network.id=ID de red label.networking.and.security=Redes y Seguridad @@ -1116,7 +1116,7 @@ label.next=Siguiente label.nexusVswitch=Nexus 1000v label.nfs=NFS label.nfs.server=servidor NFS -label.nfs.storage=Almacenamiento NFS +label.nfs.storage=NFS Almacenamiento label.nic.adapter.type=Tipo de adaptador NIC label.nicira.controller.address=Direcci\u00f3n de Controladora label.nicira.l2gatewayserviceuuid=UUID del Servicio L2 Gateway @@ -1137,18 +1137,18 @@ label.no.security.groups=No hay grupos disponibles de Seguridad label.not.found=No se ha encontrado label.no.thanks=No, gracias label.notifications=Notificaciones -label.number.of.clusters=Cantidad de Clusters +label.number.of.clusters=N\u00famero de Clusters label.number.of.cpu.sockets=Cantidad de Sockets de CPU -label.number.of.hosts=N\u00famero de Servidores +label.number.of.hosts=N\u00famero de Hosts label.number.of.pods=N\u00famero de Pods -label.number.of.system.vms=Cantidad de VM\\\\'s de Sistema +label.number.of.system.vms=N\u00famero de VM\\\\'s del Systema label.number.of.virtual.routers=N\u00famero de Routers Virtuales label.number.of.zones=N\u00famero de Zonas label.num.cpu.cores=n\u00famero de n\u00facleos de CPU label.numretries=N\u00famero de reintentos label.ocfs2=OCFS2 label.offer.ha=Oferta HA -label.of.month=del mes +label.of.month=de mes label.ok=Aceptar label.opendaylight.controller=Controlador OpenDaylight label.opendaylight.controllerdetail=Detalles del Controlador OpenDaylight @@ -1174,11 +1174,11 @@ label.owner.domain=Due\u00f1o del Dominio label.palo.alto.details=Detalles de Palo Alto label.PA.log.profile=Perfil de Palo Alto Log label.PA=Palo Alto -label.parent.domain=Dominio Padre +label.parent.domain=Padres de dominio label.passive=Pasivo label.password=Contrase\u00f1a -label.password.enabled=Contrase\u00f1a Activada -label.password.lower=contraseña +label.password.enabled=Contrase\u00f1a Activado +label.password.lower=contrase\u00f1a label.password.reset.confirm=La Contrase\u00f1a se ha cambiado a label.PA.threat.profile=Perf\u00edl de Amenazas Palo Alto label.path=Ruta @@ -1191,7 +1191,7 @@ label.PING.CIFS.password=PING CIFS contrase\u00f1a label.PING.CIFS.username=PING CIFS nombre de usuario label.PING.dir=PING Directorio label.ping.path=Camino de Ping -label.PING.storage.IP=PING a la IP del almacenamiento +label.PING.storage.IP=PING almacenamiento IP label.planner.mode=Modo planificaci\u00f3n label.please.complete.the.following.fields=Por favor complete los siguientes campos label.please.specify.netscaler.info=Por favor especifique la informaci\u00f3n del Netscaler @@ -1214,12 +1214,12 @@ label.port.range=rango de puertos label.PreSetup=PreSetup label.prev=Anterior label.previous=Previo -label.primary.allocated=Almacenamiento Primario Asignado +label.primary.allocated=primaria asignado de almacenamiento label.primary.network=Red Primaria label.primary.storage=Almacenamiento Primario -label.primary.storage.count=Almacenamiento Primario del Pool +label.primary.storage.count=Pool Almacenamiento Primario label.primary.storage.limits=L\u00edmite del Almacenamiento Primario (GiB) -label.primary.used=Almacenamiento Primario Usado +label.primary.used=Primaria Almacenado label.private.Gateway=Gateway Privado label.private.interface=Interfaz privada label.private.ip=direcci\u00f3n IP privada @@ -1232,11 +1232,11 @@ label.private.port=Puerto privado label.private.zone=Zona Privada label.profile=Perfil label.project.dashboard=Tablero del Proyecto -label.project.id=ID del Proyecto +label.project.id=ID proyecto label.project.invite=Invitar al proyecto label.project.name=Nombre del Proyecto -label.project=Proyecto -label.projects=Proyectos +label.project=proyecto +label.projects=proyectos label.project.view=Vista de Proyecto label.protocol.number=N\u00famero de Protocolo label.protocol=Protocolo @@ -1273,7 +1273,7 @@ label.quota.description=Descripci\u00f3n de Quota label.quota.email.body=Cuerpo label.quota.email.lastupdated=\u00daltima Modificaci\u00f3n label.quota.email.subject=Tema -label.quota.email.template=Template de E-Mail +label.quota.email.template=Plantilla de E-Mail label.quota.enddate=Fecha de F\u00edn label.quota.endquota=Quota Final label.quota.enforcequota=Forzar Quota @@ -1355,7 +1355,7 @@ label.replace.acl=Reemplazar ACL label.required=Requerido label.requires.upgrade=Requiere Actualizaci\u00f3n label.reserved.ip.range=Rango IP Reservado -label.reserved.system.gateway=Gateway de sistema reservado +label.reserved.system.gateway=System gateway reservado label.reserved.system.ip=Reservados sistema de PI label.reserved.system.netmask=M\u00e1scara de red reservada para el sistema label.reset.ssh.key.pair.on.vm=Resetear el Par de Claves SSH en la VM @@ -1382,7 +1382,7 @@ label.revoke.project.invite=Cancelar Invitaci\u00f3n label.role=Papel label.root.certificate=Certificado Ra\u00edz label.root.disk.controller=Controladora de disco ROOT -label.root.disk.offering=Ofertas de Discos Root +label.root.disk.offering=Root Disco Offering label.root.disk.size=Tama\u00f1o del disco Root (GB) label.router.vm.scaled.up=Router VM Escaladas label.routing=Enrutamiento @@ -1416,12 +1416,12 @@ label.secondary.ips=IPs secundarios label.secondary.isolated.vlan.id=VLAN ID de Secundaria Aislada label.secondary.staging.store=Almacenamiento Secundario Temporario label.secondary.staging.store.details=Detalles del Almacenamiento Secundario Temporario -label.secondary.storage=Almacenamiento Secundario +label.secondary.storage=Almacenamiento secundario label.secondary.storage.count=Pools del Almacenamiento Secundario label.secondary.storage.details=Detalles del Almacenamiento Secundario label.secondary.storage.limits=L\u00edmite del Almacenamiento Secundario (GiB) label.secondary.storage.vm=VM de almacenamiento secundario -label.secondary.used=Almacenamiento Secundario Usado +label.secondary.used=Secundaria Almacenado label.secret.key=clave secreta label.security.group=Grupo de Seguridad label.security.group.name=Nombre de grupo de seguridad @@ -1436,7 +1436,7 @@ label.select.offering=Elija oferta label.select.project=Elegir Proyecto label.select.region=Elegir Regi\u00f3n label.select=Seleccione -label.select.template=Elegir Template +label.select.template=Elegir Plantilla label.select.tier=Elija Tier label.select-view=Seleccione vista label.select.vm.for.static.nat=Seleccione VM para NAT est\u00e1tica @@ -1447,13 +1447,13 @@ label.service.offering.details=Detalles de la oferta de servicio label.service.offering=Oferta de Servicio label.services=Servicios label.service.state=Estado del servicio -label.session.expired=Su Sesi\u00f3n a Caducado +label.session.expired=Session Caducado label.set.default.NIC=Definir NIC por defecto -label.settings=Seteos +label.settings=Setos label.setup=Configuraci\u00f3n label.setup.network=Configurar Red label.setup.zone=Configurar Zona -label.set.up.zone.type=Configurar tipo de zona +label.set.up.zone.type=Definir tipo de zona label.shared=compartidas label.SharedMountPoint=SharedMountPoint label.show.advanced.settings=Mostrar setos avanzados @@ -1490,7 +1490,7 @@ label.ssh.key.pair=Par de Claves SSH label.ssh.key.pairs=Par de Claves SSH label.standard.us.keyboard=Teclado Standard (US) label.start.IP=IP inicial -label.start.lb.vm=Arrancar LB VM +label.start.lb.vm=Arrancar VM LB label.start.port=Iniciar Puerto label.start.reserved.system.IP=IP inicial reservada para el sistema label.start.vlan=VLAN inicial @@ -1508,7 +1508,7 @@ label.step.1.title=Paso 1\: Seleccione una plantilla label.step.2=Paso 2 label.step.2.title=Paso 2\: Oferta de Servicio label.step.3=Paso 3 -label.step.3.title=Paso 3\: Seleccione una Oferta de Disco +label.step.3.title=Paso 3\: Seleccione un disco Ofrenda label.step.4=Paso 4 label.step.4.title=Paso 4\: Red label.step.5=Paso 5 @@ -1516,13 +1516,13 @@ label.step.5.title=Paso 5\: Revisi\u00f3n label.stickiness.method=M\u00e9todo de Stickiness label.stickiness=Stickiness label.sticky.cookie-name=Nombre de Cookie -label.sticky.domain=Dominio +label.sticky.domain=dominio label.sticky.expire=Expira label.sticky.holdtime=Tiempo de Retenci\u00f3n label.sticky.indirect=Indirecto label.sticky.length=Longitud label.sticky.mode=modo -label.sticky.name=Nombre de Sticky +label.sticky.name=Nombre Pegajoso label.sticky.nocache=No Cache label.sticky.postonly=Solo Post label.sticky.prefix=Prefijo @@ -1533,9 +1533,9 @@ label.stop.lb.vm=Parar LB VM label.stopped.vms=Detenido m\u00e1quinas virtuales label.storage=Almacenamiento label.storage.pool=Pool de Almacenamiento -label.storage.tags=Etiquetas de Almacenamiento +label.storage.tags=Etiquetas de almacenamiento label.storage.traffic=Tr\u00e1fico de Almacenamiento -label.storage.type=Tipo de Almacenamiento +label.storage.type=Tipo de almacenamiento label.subdomain.access=Acceso al Subdominio label.submit=Enviar label.submitted.by=[Enviado por\: ] @@ -1564,8 +1564,8 @@ label.tags=Etiquetas label.tag.value=Valor de Etiqueta label.target.iqn=Objetivo IQN label.task.completed=Tarea finalizada. -label.template.limits=Templates L\u00edmites -label.template=Template +label.template.limits=Plantilla L\u00edmites +label.template=plantilla label.TFTP.dir=Directorio de TFTP label.tftp.root.directory=Directorio ra\u00edz de TFTP label.theme.default=Tema Por Defecto @@ -1585,7 +1585,7 @@ label.timezone=Zona horaria label.token=Token label.total.cpu=Total CPU label.total.CPU=Total CPU -label.total.hosts=Total de Servidores +label.total.hosts=Total de Hosts label.total.memory=Memoria Total label.total.of.ip=Direcciones IP totales label.total.of.vm=Total de m\u00e1quinas virtuales @@ -1606,21 +1606,21 @@ label.unavailable=no disponible label.unhealthy.threshold=Fuera del Umbral Saludable label.unlimited=Unlimited label.untagged=sin etiquetar -label.update.project.resources=Actualizar recursos del proyecto +label.update.project.resources=Actualizar recurso del proyecto label.update.ssl.cert= Certificado SSL label.update.ssl= Certificado SSL label.updating=Actualizar label.upgrade.required=La Actualizaci\u00f3n es necesaria -label.upgrade.router.newer.template=Actualizar Router para usar el Template M\u00e1s Nuevo +label.upgrade.router.newer.template=Actualizar Router para usar una Plantilla m\u00e1s Nueva label.upload.from.local=Subir desde Local label.upload=Subir -label.upload.template.from.local=Subir Template desde Local +label.upload.template.from.local=Subir Plantilla desde Local label.upload.volume.from.local=Subir un Volumen desde Local label.upload.volume.from.url=Subir un Volumen desde URL label.upload.volume=Subir volumen label.url=URL label.usage.interface=Interfaz de uso -label.usage.sanity.result=Resultado del Uso Correcto +label.usage.sanity.result=Resultado del Uso Sanitizado label.usage.server=Servidor de Uso label.usage.type=Tipo de Uso label.usage.unit=Unidad @@ -1636,11 +1636,11 @@ label.use.vm.ips=Usar las IP de la VM label.use.vm.ip=Usar VM IP\: label.value=Valor label.vcdcname=nombre -label.vcenter.cluster=Cl\u00faster de vCenter +label.vcenter.cluster=vCenter cl\u00faster label.vcenter.datacenter=vCenter de centros de datos label.vcenter.datastore=vCenter almac\u00e9n de datos -label.vcenter.host=Servidor vCenter -label.vcenter.password=Contrase\u00f1a de vCenter +label.vcenter.host=vCenter anfitri\u00f3n +label.vcenter.password=vCenter Contrase\u00f1a label.vcenter.username=vCenter Nombre de usuario label.vcenter=vcenter label.vcipaddress=Direcci\u00f3n IP de vCenter @@ -1661,7 +1661,7 @@ label.virtual.appliance.details=Detalles del Virtual appliance label.virtual.appliances=Virtual Appliances label.virtual.appliance=Virtual Appliance label.virtual.machine=M\u00e1quinas virtuales -label.virtual.machines=M\u00e1quinas virtuales +label.virtual.machines=Maquinas virtuales label.virtual.networking=Red Virtual label.virtual.network=Red Virtual label.virtual.routers.group.account=Routers Virtuales agrupados por cuenta @@ -1705,7 +1705,7 @@ label.vmware.traffic.label=Etiquetas de tr\u00e1fico para VMware label.vnet.id=ID de VLAN label.vnet=VLAN label.vnmc.devices=Dispositivo VNMC -label.vnmc=VNMC +label.vnmc=ID de VM label.volatile=Vol\u00e1til label.volgroup=Volume Group label.volume.details=Detalles del Volumen @@ -1765,22 +1765,22 @@ label.zones=Zona label.zone.type=Tipo de Zona label.zone.wide=Zona para todo el label.zoneWizard.trafficType.guest=Guest\: Tr\u00e1fico entre las m\u00e1quinas virtuales del usuario final -label.zoneWizard.trafficType.management=Management\: Tr\u00e1fico entre los recursos internos de CloudStack\\\\'s, incluyendo cualquier componente que se comunique con el Management Server, tales como servidores y las VMs de sistema de CloudStack +label.zoneWizard.trafficType.management=Management\: Tr\u00e1fico entre los recursos internos de CloudStack\\\\'s, incluyendo cualquier componente que se comunique con el Management Server, tales como hosts y las VMs de systema de CloudStack label.zoneWizard.trafficType.public=Public\: Tr\u00e1fico entre la internet y las m\u00e1quinas virtuales en el cloud. -label.zoneWizard.trafficType.storage=Almacenamiento\: Tr\u00e1fico entre los servidores de almacenamiento primario y secundario, tales como templates de VM e instant\u00e1neas +label.zoneWizard.trafficType.storage=Almacenamiento\: Tr\u00e1fico entre los servidores de almacenamiento primario y secundario, tales como plantillas de VM e instant\u00e1neas label.zone=Zona managed.state=Estado logr\u00f3 message.acquire.ip.nic=Por favor confirme que desea adquirir una IP secundaria nueva para esta NIC.
NOTA\: Las direcciones IP secundarios adquiridas deben ser configuradas manualmente desde la m\u00e1quina virtual. message.acquire.new.ip=Por favor confirme que usted quiere adquirir una nueva IP para esta red message.acquire.new.ip.vpc=Por favor confirme que usted desea adquirir una nueva IP para este VPC. message.acquire.public.ip=Por favor seleccione una zona de la que desea adquirir su nueva IP. -message.action.cancel.maintenance=El servidor ha cancelado con \u00e9xito su entrada al modo mantenimiento. Este proceso puede tardar hasta varios minutos. message.action.cancel.maintenance.mode=Por favor, confirme que desea cancelar el mantenimiento +message.action.cancel.maintenance=Su acogida ha sido cancelado con \u00e9xito para el mantenimiento. Este proceso puede tardar hasta varios minutos. message.action.change.service.warning.for.instance=Su instancia debe estar apagada antes de intentar el cambio de la oferta de servicio activa. message.action.change.service.warning.for.router=Su router debe estar apagado antes de intentar el cambio de la oferta de servicio activa. -message.action.delete.cluster=Por favor, confirme que desea eliminar este cl\u00faster. -message.action.delete.disk.offering=Por favor, confirme que desea eliminar esta oferta de disco. -message.action.delete.domain=Por favor, confirme que desea eliminar este dominio +message.action.delete.cluster=Por favor, confirme que desea eliminar del cl\u00faster +message.action.delete.disk.offering=Por favor, confirme que desea eliminar ofreciendo disco +message.action.delete.domain=Por favor, confirme que desea eliminar de dominio message.action.delete.external.firewall=Por favor, confirme que desea quitar este servidor de seguridad externo. Advertencia\: Si usted est\u00e1 planeando volver a agregar el servidor de seguridad externo mismo, debe restablecer los datos de uso en el dispositivo. message.action.delete.external.load.balancer=Por favor, confirme que desea eliminar este equilibrador de carga externa. Advertencia\: Si usted est\u00e1 planeando volver a agregar la misma equilibrador de carga externo, debe restablecer los datos de uso en el dispositivo. message.action.delete.ingress.rule=Por favor, confirme que desea eliminar la regla de ingreso @@ -1789,30 +1789,30 @@ message.action.delete.ISO=Por favor, confirme que desea eliminar la norma ISO message.action.delete.network=Por favor, confirme que desea eliminar de la red message.action.delete.nexusVswitch=Porfavor confirme que usted quiere eliminar el Nexus 1000v message.action.delete.nic=Por favor, confirme que desea remover esta NIC, lo que har\u00e1 que sea removida la red de esta VM. -message.action.delete.physical.network=Por favor confirme que desea borrar esta red f\u00edsica. +message.action.delete.physical.network=Por favor confirme que desea borrar esta red f\u00edsica message.action.delete.pod=Por favor, confirme que desea eliminar de la vaina message.action.delete.primary.storage=Por favor, confirme que desea eliminar el almacenamiento primario -message.action.delete.secondary.storage=Por favor, confirme que desea eliminar este almacenamiento secundario. +message.action.delete.secondary.storage=Por favor, confirme que desea eliminar de almacenamiento secundario message.action.delete.security.group=Por favor, confirme que desea eliminar el grupo de seguridad message.action.delete.service.offering=Por favor, confirme que desea eliminar oferta de servicios message.action.delete.snapshot=Por favor, confirme que desea eliminar instant\u00e1neas message.action.delete.system.service.offering=Por favor confirme que desea borrar esta oferta de servicio. -message.action.delete.template.for.all.zones=El template es utilizado por todas las zonas. Por favor, confirme que desea eliminarlo de todas las zonas. -message.action.delete.template=Por favor, confirme que desea eliminar este template. +message.action.delete.template.for.all.zones=La plantilla es utilizada por todas las zonas. Por favor, confirme que desea eliminar de todas las zonas. +message.action.delete.template=Por favor, confirme que desea eliminar la plantilla message.action.delete.volume=Por favor, confirme que desea eliminar el volumen message.action.delete.zone=Por favor, confirme que desea eliminar la zona message.action.destroy.instance=Por favor, confirme que desea destruir ejemplo message.action.destroy.systemvm=Por favor, confirme que desea destruir la m\u00e1quina virtual del sistema. -message.action.disable.cluster=Por favor, confirme que desea deshabilitar este cl\u00faster. +message.action.disable.cluster=Por favor, confirme que desea desactivar este grupo. message.action.disable.nexusVswitch=Por favor confirme que usted quiere deshabilitar este nexus 1000v message.action.disable.physical.network=Por favor confirmar que usted quiere deshabilitar esta red f\u00edsica message.action.disable.pod=Por favor, confirme que desea desactivar esta vaina. message.action.disable.static.NAT=Por favor, confirme que desea desactivar NAT est\u00e1tica message.action.disable.zone=Por favor, confirme que desea desactivar esta zona. -message.action.downloading.template=Descargando template. +message.action.downloading.template=Descargando plantilla. message.action.download.iso=Por favor confirme que usted quiere descargar esta ISO message.action.download.template=Por favor confirme que usted quiere descargar este template -message.action.enable.cluster=Por favor, confirme que desea habilitar este cl\u00faster. +message.action.enable.cluster=Por favor, confirme que desea habilitar este grupo. message.action.enable.maintenance=Su acogida ha sido preparado con \u00e9xito para el mantenimiento. Este proceso puede tardar hasta varios minutos o m\u00e1s dependiendo de c\u00f3mo las m\u00e1quinas virtuales se encuentran actualmente en este servidor. message.action.enable.nexusVswitch=por favor confirme que usted quiere habilitar este nexus 1000v message.action.enable.physical.network=Por favor confirmar que usted quiere habilitar esta red f\u00edsica @@ -1830,7 +1830,7 @@ message.action.reboot.systemvm=Por favor, confirme que desea reiniciar el sistem message.action.release.ip=Por favor, confirme que desea liberar IP message.action.remove.host=Por favor confirme que desea borrar este servidor. message.action.reset.password.off=Su ejemplo en la actualidad no es compatible con esta funci\u00f3n. -message.action.reset.password.warning=Su instancia debe ser detenida antes de intentar cambiar la contrase\u00f1a actual. +message.action.reset.password.warning=Su ejemplo debe ser detenido antes de intentar cambiar su contrase\u00f1a actual. message.action.restore.instance=Por favor, confirme que desea restaurar ejemplo message.action.revert.snapshot=Por favor confirme que desea revertir el volumen elegido a esta instant\u00e1nea. message.action.start.instance=Por favor, confirme que desea iniciar la instancia @@ -1846,13 +1846,13 @@ message.action.vmsnapshot.revert=Revertir instant\u00e1nea de VM message.activate.project=Usted esta seguro que quiere activar este proyecto? message.add.cluster=A\u00f1adir un hipervisor administradas por cl\u00faster de zona , la consola de message.add.cluster.zone=A\u00f1adir un hipervisor administradas por cl\u00faster de zona -message.add.disk.offering=Por favor, especifique los par\u00e1metros siguientes para agregar una nueva oferta de disco +message.add.disk.offering=Por favor, especifique los par\u00e1metros siguientes para agregar un nuevo disco que ofrece message.add.domain=por favor especifique el subdominio que usted quiere crear bajo este dominio message.added.new.nuage.vsp.controller=Nuevo Controlador Nuage Vsp agregado message.added.vpc.offering=Oferta VPC agregada message.add.firewall=A\u00f1adir un servidor de seguridad a la zona message.add.guest.network=Por favor confirme que desea agregar una red de guest -message.add.host=Por favor, especifique los par\u00e1metros siguientes para agregar un nuevo servidor +message.add.host=Por favor, especifique los par\u00e1metros siguientes para agregar un nuevo host message.adding.host=Agregando un servidor message.adding.Netscaler.device=Agregando un dispositivo NetScaler message.adding.Netscaler.provider=Agregando un proveedor NetScaler @@ -1872,7 +1872,7 @@ message.add.region=Por favor cargue la informaci\u00f3n requerida para agregar u message.add.secondary.storage=A\u00f1adir un nuevo almacenamiento de zona message.add.service.offering=Por favor, rellene los siguientes datos para agregar una nueva oferta de servicio. message.add.system.service.offering=Por favor complete los siguientes datos para agregar un nueva oferta de servicio. -message.add.template=Por favor ingrese los siguientes datos para crear el nuevo template +message.add.template=Por favor ingrese los siguientes datos para crear la nueva plantilla message.add.volume=Por favor, rellene los siguientes datos para agregar un nuevo volumen. message.add.VPN.gateway=Por favor confirme que usted quiere agregar un VPN Gateway message.admin.guide.read=Para VM basadas en VMware, lea por favor el cap\u00edtulo de escalado din\u00e1mico en la gu\u00eda de administraci\u00f3n.\u00bfDesea continuar? @@ -1885,7 +1885,7 @@ message.alert.state.detected=Estado de Alerta detectado message.allow.vpn.access=Por favor, introduzca un nombre de usuario y la contrase\u00f1a del usuario que desea permitir el acceso de VPN. message.apply.snapshot.policy=Ha actualizado su pol\u00edtica instant\u00e1nea actual. message.attach.iso.confirm=Por favor, confirme que desea conectar el ISO a la instancia virtual -message.attach.volume=Por favor, rellene los siguientes datos para conectar un nuevo volumen. Si est\u00e1 conectando un volumen de disco a una m\u00e1quina virtual basada en Windows, deber\u00e1 reiniciar la instancia para ver el disco conectado. +message.attach.volume=Por favor, rellene los siguientes datos para fijar un nuevo volumen. Si est\u00e1 colocando un volumen de disco a una m\u00e1quina virtual de Windows basado, usted tendr\u00e1 que reiniciar la instancia para ver el disco adjunto. message.basic.mode.desc=Seleccione este modelo de red si lo haces * no * desea habilitar cualquier soporte VLAN. Todas las instancias virtuales creados en virtud de este modelo de red se le asignar\u00e1 una direcci\u00f3n IP directamente desde la red y grupos de seguridad se utilizan para proporcionar la seguridad y la segregaci\u00f3n. message.change.ipaddress=Por favor confirme que desea cambiar la direcci\u00f3n IP de esta NIC en la VM. message.change.offering.confirm=Por favor, confirme que desea cambiar la oferta de servicio de la instancia virtual. @@ -1900,7 +1900,7 @@ message.configuring.guest.traffic=Configurando el tr\u00e1fico de guest message.configuring.physical.networks=Configurando las redes f\u00edsicas message.configuring.public.traffic=Configurando el tr\u00e1fico public message.configuring.storage.traffic=Configurando el tr\u00e1fico de almacenamiento -message.confirm.action.force.reconnect=Por favor confirme que desea forzar la reconexi\u00f3n de este servidor. +message.confirm.action.force.reconnect=Por favor confirme que desea forzar la reconexi\u00f3n de este servidor message.confirm.add.vnmc.provider=Por favor confirme que desea agregar el proveedor VNMC. message.confirm.archive.alert=Por favor confirme que desea archivar esta alerta. message.confirm.archive.event=Por favor confirme que desea archivar este evento. @@ -1910,30 +1910,30 @@ message.confirm.attach.disk=\u00bf Est\u00e1 seguro que desea conectar el disco? message.confirm.create.volume=\u00bfEst\u00e1 seguro que desea crear un volumen? message.confirm.current.guest.CIDR.unchanged=\u00bfDesea mantener el CIDR de la red guest actual sin cambios? message.confirm.dedicate.cluster.domain.account=\u00bfRealmente desea dedicar este cluster al dominio/cuenta? -message.confirm.dedicate.host.domain.account=\u00bfDesea dedicar estos servidores a un dominio/cuenta? -message.confirm.dedicate.pod.domain.account=\u00bfDesea dedicar este pod a un dominio/cuenta? +message.confirm.dedicate.host.domain.account=\u00bfDesea dedicar este hosts a un dominio/cuenta? +message.confirm.dedicate.pod.domain.account=\u00bfDesea dedicar este por a un dominio/cuenta? message.confirm.dedicate.zone=\u00bfRealmente quiere dedicar esta zona a un domino/cuenta? message.confirm.delete.acl.list=\u00bfEsta seguro que desea borrar esta lista de ACL? message.confirm.delete.alert=\u00bfEst\u00e1 seguro que desea borrar esta alerta? -message.confirm.delete.baremetal.rack.configuration=Por favor confirme que desea borrar la Configuraci\u00f3n del Rack Baremetal. -message.confirm.delete.BigSwitchBcf=Por favor confirme que desa borrar este Controlador BigSwitch BCF -message.confirm.delete.BrocadeVcs=Por favor confirme que desa borrar este Switch Brocade Vcs +message.confirm.delete.baremetal.rack.configuration=Por favor confirme que desea borrar la configuraci\u00f3n del Rack Baremetal. +message.confirm.delete.BigSwitchBcf=Por favo confirme que desa borrar este Controlador BigSwitch BCF +message.confirm.delete.BrocadeVcs=Por favo confirme que desa borrar este Switch Brocade Vcs message.confirm.delete.ciscoASA1000v=Por favor confirme que desea borrar CiscoASA1000v message.confirm.delete.ciscovnmc.resource=Por favor confirme que desea borrar el recurso CiscoVNMC message.confirm.delete.F5=Por favor confirme que ud quiere eliminar el F5 message.confirm.delete.internal.lb=Por favor confirme que desea borrar este LB Interno -message.confirm.delete.NetScaler=Por favor confirme que desa borrar este NetScaler -message.confirm.delete.NuageVsp=Por favor confirme que desa borrar este Nuage Virtualized Services Directory +message.confirm.delete.NetScaler=Por favo confirme que desa borrar este NetScaler +message.confirm.delete.NuageVsp=Por favo confirme que desa borrar este Nuage Virtualized Services Directory message.confirm.delete.PA=Por favor confirme que desa borrar este Palo Alto message.confirm.delete.secondary.staging.store=Por favor confirme que desea borrar el Almacenamiento Secundario Temporal. message.confirm.delete.SRX=Por favor confirme que desa borrar este SRX message.confirm.delete.ucs.manager=Por favor confirme que desea borrar el UCS Manager -message.confirm.destroy.router=Por favor confirme que desea destruir este router +message.confirm.destroy.router=Por favor confirme que desa borrar este router message.confirm.disable.host=Por favor confirme que desea deshabitar este servidor message.confirm.disable.network.offering=\u00bfEsta seguro que desea deshabilitar esta oferta de red? -message.confirm.disable.provider=Por favor confirme que desea deshabilitar este proveedor +message.confirm.disable.provider=Por favor confirme que desea deshabitar este proveedor message.confirm.disable.vnmc.provider=Por favor confirme que desea deshabitar el proveedor VNMC. -message.confirm.disable.vpc.offering=\u00bfEsta seguro que desea deshabilitar esta oferta de VPC? +message.confirm.disable.vpc.offering=\u00bfEsta seguro que desea deshabitar esta oferta de VPC? message.confirm.enable.host=Por favor confirme que desea habilitar este servidor message.confirm.enable.network.offering=\u00bfEsta seguro que desea habilitar esta oferta de red? message.confirm.enable.provider=Por favor confirme que desea habilitar este proveedor @@ -1942,7 +1942,7 @@ message.confirm.enable.vpc.offering=\u00bfEsta seguro que desea habilitar esta o message.confirm.join.project=por favor confirme que usted desea unirse a este proyecto. message.confirm.migrate.volume=\u00bfQuiere migrar este volumen? message.confirm.refresh.blades=Por favor confirme que desea refrescar los blades. -message.confirm.release.dedicated.cluster=\u00bfDesea liberar este cl\u00faster dedicado? +message.confirm.release.dedicated.cluster=\u00bf Desea liberar este cl\u00faster dedicado? message.confirm.release.dedicated.host=\u00bfDesea liberar este servidor dedicado? message.confirm.release.dedicated.pod=\u00bfDesea liberar el uso dedicado del pod? message.confirm.release.dedicated.zone=\u00bfDesea liberar esta zona dedicada? @@ -1961,17 +1961,17 @@ message.confirm.scale.up.system.vm=\u00bfDesea escalar esta VM de sistema? message.confirm.shutdown.provider=Por favor confirme que desea apagar ester proveedor message.confirm.start.lb.vm=Por favor confirme que desea iniciar esta VM de LB message.confirm.stop.lb.vm=Por favor confirme que desea parar esta VM de LB -message.confirm.upgrade.router.newer.template=Por favor confirme que desea actualizar el router con un template m\u00e1s nuevo -message.confirm.upgrade.routers.account.newtemplate=Por favor confirme que desea actualizar todos los routers de esta cuenta con un template nuevo -message.confirm.upgrade.routers.cluster.newtemplate=Por favor confirme que desea actualizar todos los routers de este cluster con un template nuevo -message.confirm.upgrade.routers.newtemplate=Por favor confirme que desea actualizar todos los routers de esta zona con un template m\u00e1s nuevo -message.confirm.upgrade.routers.pod.newtemplate=Por favor confirme que desea actualizar todos los routers de este pod con un template nuevo +message.confirm.upgrade.router.newer.template=Por favor confirme que desea actualizar el router con una plantilla nueva +message.confirm.upgrade.routers.account.newtemplate=Por favor confirme que desea actualizar todos los routers de esta cuenta con una plantilla nueva +message.confirm.upgrade.routers.cluster.newtemplate=Por favor confirme que desea actualizar todos los routers de este cluster con una plantilla nueva +message.confirm.upgrade.routers.newtemplate=Por favor confirme que desea actualizar todos los routers de esta zona con una plantilla nueva +message.confirm.upgrade.routers.pod.newtemplate=Por favor confirme que desea actualizar todos los routers de este pod con una plantilla nueva message.copy.iso.confirm=Por favor, confirme que desea copiar el ISO a -message.copy.template.confirm=\u00bfEsta seguro que desea copiar este template? -message.copy.template=Copiar template XXX desde la zona hacia +message.copy.template.confirm=\u00bfDesea copiar esta plantilla? +message.copy.template=Copia plantilla XXX de la zona message.create.template=Esta seguro que quiere crear un template? -message.create.template.vm=Crear VM desde el template -message.create.template.volume=Por favor, especifique la siguiente informaci\u00f3n antes de crear un template desde su volumen de disco\: . El tiempo de creaci\u00f3n del template puede demorar unos minutos o m\u00e1s, dependiendo del tama\u00f1o del volumen. +message.create.template.vm=Crear VM de la plantilla +message.create.template.volume=Por favor, especifique la siguiente informaci\u00f3n antes de crear una plantilla de su volumen de disco\: . Creaci\u00f3n de la plantilla puede oscilar entre varios minutos m\u00e1s, dependiendo del tama\u00f1o del volumen. message.creating.cluster=Creando cluster message.creating.guest.network=Creando red guest message.creating.physical.networks=Creando redes f\u00edsicas @@ -1993,14 +1993,14 @@ message.delete.VPN.customer.gateway=Por favor confirme que desea borrar esta VPN message.delete.VPN.gateway=Por favor confirme que usted quiere eliminar este VPN Gateway message.desc.add.new.lb.sticky.rule=Agregar nueva regla Sticky al LB message.desc.advanced.zone=Para topologia de redes m\u00e1s sofisticadas. Este modelo de red provee la mayor flexibilidad al definir la redes guest y proveyendo ofertas de redes personalizadas tales como firewall, VPN, o soporte de load balancer. -message.desc.basic.zone=Provee una red \u00fanica donde cada instancia de VM se le asigna una IP de esta red. El aislamiento de Guest puede proveerse por medio de productos en layer-3 tales como los security groups (filtrado de direcciones IP por origen). +message.desc.basic.zone=Provee una red \u00fanica donde cada instancia de VM es asignada una IP directamente desde la red. El aislamiento de Guest puede proveerse por medio de layer-3 tales como los security groups (filtrado de direcciones IP por origen). message.desc.cluster=Cada por debe contener uno o m\u00e1s clusters, ahora agregaremos el primero. Un cluster contiene un grupo de servidores. Los servidores en el cluster tiene el mismo hardware, ejecutan el mismo hipervisors, est\u00e1n en la misma subred, y utilizan el mismo almacenamiento compartido. Cada cluster consiste en uno o m\u00e1s servidores y uno o m\u00e1s servidores de almacenamiento primario. message.desc.created.ssh.key.pair=Par de Claves SSH creadas. message.desc.create.ssh.key.pair=Por favor completar los siguientes datos para crear o registrar un par de claves ssh.

1. Si la clave p\u00fablica esta definida, CloudStack la registrar\u00e1. Uds puede usarla por medio de la clave privada.

2. Si la clave p\u00fablica no esta definida, CloudStack crear\u00e1 un nuevo Par de Claves SSH. En este caso, por favor copie y grab\u00e9 la clave privada. CloudStack no la almacenar\u00e1.
-message.desc.host=Cada cluster debe contener por lo menos un servidor (computadora) para que la VMs Guest ejecuten all\u00ed, y se agregara el primero ahora. Para que un servidor funcione en CloudStack, se debe instalar el software del hypervisor, asignarle una IP al host en la red de Management y asegurarse que se conecte al servidores de management de CloudStack.

Indicar el nombre DNS del servidor o su direcci\u00f3n IP, el nombre del usuario (usualmente root), su contrase\u00f1a y las etiquetas necesarias para catalogar los servidores. -message.desc.primary.storage=Cada cl\u00faster debe contener uno o m\u00e1s servidores primarios de almacenamiento, y ahora se agregara el primero. El almacenamiento primario contiene los volumenes de disco para todas las VMSs ejecutandose en los servidores del cl\u00faster. Utilice cualquier protocolo standard que soporte el hipervisor. -message.desc.reset.ssh.key.pair=Por favor especifique el par de claves ssh que desea agregar a esta VM. Tenga en cuenta que la clave de root ser\u00e1 cambiada al realizar esta operaci\u00f3n si la opci\u00f3n de contrase\u00f1a esta habilitada. -message.desc.secondary.storage=Cada zona debe tener al menos un servidor de NFS secundario, y se agregar\u00e1 el primero ahora. El almacenamiento secundario guarda los templates de VM, las im\u00e1genes ISO, y las instant\u00e1neas de volumentes. Este server debe estar disponible a todos los servidores de la zona.

Complete con la direcci\u00f3n IP y el PATH exportado +message.desc.host=Cada cluster debe contener por lo menos un host (servidor) para que la VMs Guest ejecuten all\u00ed, y se agregara el primero ahora. Para que un host funcione en CloudStack, se debe instalar el software del hypervisor, asignarle una IP al host en la red de Management y asegurarse que se conecte al servidores de management de CloudStack.

Indicar el nombre DNS del host o su direcci\u00f3n IP, el nombre del usuario (usualmente root), su contrase\u00f1a y las etiquetas necesarias para catalogar los hosts. +message.desc.primary.storage=Cada cl\u00faster debe contener uno o m\u00e1s servidores primarios de almacenamiento, y ahora se agregara el primero. El almacenamiento primario contiene los volumenes de disco para todas las VMSs ejecutandose en los hosts del cl\u00faster. Utilice cualquier protocolo standard que soporte el hipervisor. +message.desc.reset.ssh.key.pair=Pro favor especifique el par de claves ssh que desea agregar a esta VM. Tenga en cuenta que la clave de root ser\u00e1 cambiada al realizar esta operaci\u00f3n si la opci\u00f3n de contrase\u00f1a esta habilitada. +message.desc.secondary.storage=Cada zona debe tener al menos un servidor de NFS secundario, y se agregar\u00e1 el primero ahora. El almacenamiento secundario guarda las plantillas de VM, las im\u00e1genes ISO, y las instantaneas de volumentes. Este server debe estar disponible a todos los hosts de la zona.

Complete con la direcci\u00f3n IP y el PATH exportado message.desc.zone=Una zona es la unidad organizacional m\u00e1s grande en CloudStack, y t\u00edpicamente se corresponde con un datacenter en particular. Las Zonas proveen aislaci\u00f3n f\u00edsica y redundancia. Una zona consiste de uno o m\u00e1s pode (cada uno conteniendo servidores y almacenamiento primario), junto con el almacenamiento secundario que es compartido entre todos los pods en la zona message.detach.disk=\u00bf Est\u00e1 seguro que desea desconectar este disco? message.detach.iso.confirm=Por favor, confirme que desea quitar el ISO de la instancia virtual @@ -2013,7 +2013,7 @@ message.disabling.network.offering=Deshabilitar oferta de red message.disabling.vpc.offering=Deshabilitando oferta VPC message.disallowed.characters=Caracteres no permitidos\: \\<\\,\\> message.download.ISO=Por favor haga click 00000para descargar el ISO -message.download.template=Por favor haga click 00000para descargar el template +message.download.template=Por favor haga click 00000para descargar la plantilla message.download.volume.confirm=Por favor confirme que desea descargar este volumen. message.download.volume=Por favor, haga clic 00000 para bajar el volumen message.edit.account=Editar ("-1" indica que no hay limite a la cantidad de recursos creados) @@ -2042,24 +2042,24 @@ message.host.dedicated=Servidor Dedicado message.host.dedication.released=Dedicaci\u00f3n de Servidor liberada message.installWizard.click.retry=Haz click en el bot\u00f3n para re-intentar el lanzamiento de la instancia. message.installWizard.copy.whatIsACluster=Un cluster provee una forma de agrupar los servidores. Todos los servidores que componen el cluster tienen un hardware id\u00e9ntico, ejecutan el mismo hipervisor, est\u00e1n en la misma subred y utilizan el mismo almacenamiento compartido. Las instancias de las VMs pueden migrarse en caliente desde un servidor a otro dentro del mismo cluster, sin interrupci\u00f3n del servicio del usuario. Un cluster es la tercera forma organizacional en una instalaci\u00f3n de CloudStack&\#8482; . Los ilustres est\u00e1n contenidos dentro de los podes, los podes estar contenidos en las zonas.

CloudStack&\#8482; permite m\u00faltiple clusters en una instalaci\u00f3n de cloud, pero para realizar una instalaci\u00f3n b\u00e1sica, solo necesitamos uno. -message.installWizard.copy.whatIsAHost=Un servidor es una sola computadora. Los Servidores proveen los recursos de computo necesarios para ejecutar las m\u00e1quinas virtuales. Cada servidor tiene un hipervisor instalado para gestionar las VMs guest (excepto en los servidores baremetal, los cuales son un caso especial que se explaya en la Gu\u00eda de Administraci\u00f3n Avanzada). Por ejemplo, un servidor Linux con KVM habilitado, un servidor con Citrix XenServer o un servidor con ESXi. En una instalaci\u00f3n B\u00e1sica, usaremos un solo servidor ejecutando XenServer o KVM.

El servidor es la m\u00ednima unidad organizacional de CloudStack&\#8482; .Los servidores est\u00e1n contenidos dentro de los ilustres, los ilustres en los pods, y estos \u00faltimos en las zonas. +message.installWizard.copy.whatIsAHost=Un servidor es una sola computadora. Los Servidores proveen los recursos de computo necesarios para ejecutar las m\u00e1quinas virtuales. Cada servidor tiene un hipervisor instalado para gestionar las VMs guest (excepto en los servidores baremetal, los cuales son un caso especial que se explaya en la Gu\u00eda de Administraci\u00f3n Avanzada). Por ejemplo, un servidor Linux con KVM habilitado, un servidor con Citrix XenServer o un servidor con ESXi. En una instalaci\u00f3n Basica, usaremos un solo servidor ejecutando XenServer o KVM.

El servidor es la m\u00ednima unidad organizacional de CloudStack&\#8482; .Los servidores est\u00e1n contenidos dentro de los ilustres, los ilustres en los pods, y estos \u00faltimos en las zonas. message.installWizard.copy.whatIsAPod=Un pod representa generalmente un solo rock. Los servidores en el mismo por estar en la misma subred.

El por es la segunda agrupaci\u00f3n organizacional dentro de CloudStack&\#8482; .Los Pods est\u00e1n contenidos dentro de la zona. Cada zona puede contener uno m\u00e1s pods. En la instalaci\u00f3n B\u00e1sica, solo se necesita tener un por en la zona. message.installWizard.copy.whatIsAZone=Una zona es la unidad organizacional m\u00e1s grande dentro de una instalaci\u00f3n de CloudStack&\#8482;. Una zona tipicamente se corresponde a un solo datacenter, sin embargo esta permitido contar con varias zonas dentro del mismo datacenter. El beneficio de organizar la infraestructura en zonas es que provee aislaci\u00f3n f\u00edsica y redundancia. Por ejemplo, cada zona puede tener su propia fuente de alimentaci\u00f3n y lo mismo con su salida de red, ademas de poder estar separadas geograficamente en grandes distancias (lo cual no es obligatorio). message.installWizard.copy.whatIsCloudStack=CloudStack&\#8482 es una plataforma de software que aglutina recursos computo para poder crear coludas de infraestructuras como Servicio (IaaS), tanto p\u00fablicas como privadas.\nCloudStack&\#8482 gestiona la red, el almacenamiento y los nodos de computo que conforma la infraestructura de cloud. Se puede usar CloudStack&\#8482 para desplegar, gestionar y configurar ambientes de cloud computan.

Extendiendose m\u00e1s all\u00e1 del manejo individual de m\u00e1quinas virtuales en hardware comotidizado, CloudStack&\#8482 provee una soluci\u00f3n llave en mano de un software de infraestructura de red para ofrecer datacenter virtuales como servicio, proveyendo todos los componentes esenciales para construir, desplegar y gestionar aplicaciones cloud multi-tier y multi-tenant. Se ofrecen dos versiones, la open source y la Premium, brindando la primera caracter\u00edsticas casi id\u00e9nticas. message.installWizard.copy.whatIsPrimaryStorage=La infraestrucutra cloud de CloudStack&\#8482 hace uso de dos tipos de almacenamiento, el primario y el secundario. Ambos pueden ser iSCSI, NFS o discos locales.

El Almacenamiento Primario se asocia a un cluster, y almacena los vol\u00famenes de discos de cada VM para todas las VMs en los servidores del cluster. El almacenamiento primario es t\u00edpicamente alojado cerca de los servidores. -message.installWizard.copy.whatIsSecondaryStorage=El almacenamiento secundario est\u00e1 asociado a una zona, y almacena lo siguiente\:
  • Templates - im\u00e1genes del sistema operativo que se pueden utilizar para arrancar VMs, pueden incluir informaci\u00f3n de configuraci\u00f3n adicional, como las aplicaciones instaladas
  • Im\u00e1genes ISO - im\u00e1genes del Sistema Operativo que pueden ser boteables o no boteables
  • Instant\u00e1neas de vol\u00famenes de disco - copias de datos guardadas de VM que se pueden utilizar para la recuperaci\u00f3n de datos o para crear nuevos templates
+message.installWizard.copy.whatIsSecondaryStorage=El almacenamiento secundario est\u00e1 asociado a una zona, y almacena lo siguiente\:
  • Plantillas - im\u00e1genes del sistema operativo que se pueden utilizar para arrancar VMs, pueden incluir informaci\u00f3n de configuraci\u00f3n adicional, como las aplicaciones instaladas
  • Im\u00e1genes ISO - im\u00e1genes del Sistema Operativo que pueden ser boteables o no boteables
  • Disco instant\u00e1neas de vol\u00famenes - copias de datos guardadas de VM que se pueden utilizar para la recuperaci\u00f3n de datos o para crear nuevas plantillas
message.installWizard.now.building=Ahora construyendo su nube... message.installWizard.tooltip.addCluster.name=Nombre del Cluster. Puede ser alfanum\u00e9rico .Este no es usado por CloudStack -message.installWizard.tooltip.addHost.hostname=El nombre DNS o direcci\u00f3n IP del servidor. -message.installWizard.tooltip.addHost.password=Esta es la contrase\u00f1a del usuario mencionado anteriormente (Desde su Instalaci\u00f3n XenServer) +message.installWizard.tooltip.addHost.hostname=El nombre DNS o direcci\u00f3n IP del host +message.installWizard.tooltip.addHost.password=Este es el password para el nombre de usuario mencionado anteriormente (Desde su Instalaci\u00f3n XenServer) message.installWizard.tooltip.addHost.username=Generalmente root message.installWizard.tooltip.addPod.name=Nombre del POD message.installWizard.tooltip.addPod.reservedSystemEndIp=Este es el rango de direcciones IP en la red privada que la CloudStack utiliza para administrar las VMs del Almacenamiento Secundario y consola Proxy. Estas direcciones IP se han tomado de la misma subred que los servidores inform\u00e1ticos. -message.installWizard.tooltip.addPod.reservedSystemGateway=El gateway para los servidores en ese pod. -message.installWizard.tooltip.addPod.reservedSystemNetmask=La m\u00e1scara de red en uso en la subred de los guest ser\u00e1. +message.installWizard.tooltip.addPod.reservedSystemGateway=El gateway ,puerta de enlace, para los host en ese pod. +message.installWizard.tooltip.addPod.reservedSystemNetmask=La m\u00e1scara de red en uso en la subred de los hu\u00e9spedes ser\u00e1. message.installWizard.tooltip.addPod.reservedSystemStartIp=Este es el rango de direcciones IP en la red privada que la CloudStack utiliza para administrar las VMs del Almacenamiento Secundario y consola Proxy. Estas direcciones IP se han tomado de la misma subred que los servidores inform\u00e1ticos. message.installWizard.tooltip.addPrimaryStorage.name=\ Nombre para el storage -message.installWizard.tooltip.addPrimaryStorage.path=(para NFS) En NFS este es el directorio exportado desde el servidor. Directorio (por SharedMountPoint). Con KVM este es el directorio de cada servidor en donde se monta el almacenamiento primario. Por ejemplo, "/mnt/primary". +message.installWizard.tooltip.addPrimaryStorage.path=(para NFS) En NFS este es el directorio exportado desde el servidor. Directorio (por SharedMountPoint). Con KVM este es el directorio de cada host en donde se monta el almacenamiento primario. Por ejemplo, "/mnt/primary". message.installWizard.tooltip.addPrimaryStorage.server=(para NFS, iSCSI, o PreSetup) La direcci\u00f3n IP o el nombre DNS del dispositivo de almacenamiento. message.installWizard.tooltip.addSecondaryStorage.nfsServer=Direcci\u00f3n IP del servidor NFS que contiene el secondary storage message.installWizard.tooltip.addSecondaryStorage.path=El path exportado, ubicado en el servidor especificado anteriormente @@ -2075,7 +2075,7 @@ message.installWizard.tooltip.configureGuestTraffic.guestNetmask=La m\u00e1scara message.installWizard.tooltip.configureGuestTraffic.guestStartIp=El rango de direcciones IP que estar\u00e1 disponible para los guest en esta zona. Si se utiliza una sola NIC, estas IPs estar\u00e1n en el mismo CIDR del pod. message.installWizard.tooltip.configureGuestTraffic.name=Nombre de su RED message.instance.scaled.up.confirm=\u00bfRealmente desea escalar la instancia? -message.instanceWizard.noTemplates=No tienes templates disponibles, por favor agregue uno compatible y re-inicie el asistente de creaci\u00f3n de instancias. +message.instanceWizard.noTemplates=No tienes plantillas disponibles, por favor agregue una plantilla compatible y reinicio el asistente de creaci\u00f3n de instancias. message.ip.address.changed=Su direcci\u00f3n IP pudo haber cambiado. Le gustar\u00eda actualizar el listado? Tenga en cuenta que en este caso el panel de detalles se cerrar\u00e1. message.iso.desc=Disco con la imagen contenedora de los datos o los medios bootables para el SO message.join.project=Ahora estas unido al proyecto. Por favor cambiar a la Vista de Proyecto para verlo. @@ -2086,23 +2086,23 @@ message.link.domain.to.ldap=Habilitar autosync para este dominio en LDAP message.listView.subselect.multi=(Ctrl/Cmd-click) message.lock.account=Por favor, confirme que desea bloquear esta cuenta. Al bloquear la cuenta, todos los usuarios de esta cuenta ya no ser\u00e1 capaz de gestionar sus recursos de la nube. Los recursos existentes todav\u00eda se puede acceder. message.migrate.instance.confirm=Por favor, confirme el anfitri\u00f3n desea migrar la instancia virtual. -message.migrate.instance.to.host=Por favor, confirmar que desea mover la instancia a otro servidor. +message.migrate.instance.to.host=Por favor, confirmar que desea mover la instancia a otro host. message.migrate.instance.to.ps=Por favor, confirmar que desea mover la instancia a otro primary storage. -message.migrate.router.confirm=Por favor, confirme el servidor que desea migrar el router\: -message.migrate.systemvm.confirm=Por favor, confirme el servidor al que desea migrar la m\u00e1quina virtual de sistema\: +message.migrate.router.confirm=Por favor, confirme el hu\u00e9sped que desea migrar el router\: +message.migrate.systemvm.confirm=Por favor, confirme el hu\u00e9sped que desea migrar la m\u00e1quina virtual de sistema\: message.migrate.volume=Por favor confirme que usted quiere migrar el volumen a otro almacenamiento primario message.network.addVM.desc=Por favor indique la red que desea agregar a esta VM. Una NIC nueva se agregar\u00e1 en esta red. message.network.addVMNIC=Por favor confirme que desea agregar una nueva NIC a la VM para esta red. message.network.remote.access.vpn.configuration=Se ha creado la configuraci\u00f3n de acceso remoto por VPN, pero fall\u00f3 su aplicaci\u00f3n. Por favor verifique la conectividad de todos los elementos de red y vuelva a intentarlo. message.new.user=Especifique lo siguiente para agregar un nuevo usuario a la cuenta message.no.affinity.groups=No hay ning\u00fan grupo de afinidad. Por favor continue con el paso siguiente. -message.no.host.available=No hay disponibles Servidores para la Migraci\u00f3n +message.no.host.available=No hay disponibles Hosts para la Migraci\u00f3n message.no.network.support.configuration.not.true=Usted no tiene ninguna zona que ha permitido a grupo de seguridad. Por lo tanto, no hay funciones de red adicionales. Por favor, contin\u00fae con el paso 5. message.no.network.support=El hipervisor seleccionado, vSphere, no tiene funciones de red adicionales. Por favor, contin\u00fae con el paso 5. message.no.projects.adminOnly=No tienes ning\u00fan proyecto.
Por favor dile a tu administrador que cree uno nuevo. -message.no.projects=No tienes ning\u00fan proyecto.
Por favor crea uno nuevo desde la secci\u00f3n de Proyectos. -message.number.clusters=

\# de Clusters

-message.number.hosts=

\# de Servidores

+message.no.projects=No tienes ning\u00fan proyecto.
Pro favor crear uno nuevo desde la secci\u00f3n de Proyectos. +message.number.clusters=

\# de Grupos

+message.number.hosts=

\# de Anfitri\u00f3n

message.number.pods=

\# de Las vainas

message.number.storage=

\# de Almacenamiento primario

message.number.zones=

\# de Zonas

@@ -2115,7 +2115,7 @@ message.please.confirm.remove.ssh.key.pair=Por favor confirme que usted quiere e message.please.proceed=Por favor proceda a el siguiente paso. message.please.select.a.configuration.for.your.zone=Por favor elija una configuraci\u00f3n para su zona. message.please.select.a.different.public.and.management.network.before.removing=Por favor elija una red public y de management diferente antes de remover -message.please.select.networks=Por favor seleccione la red para su m\u00e1quina virtual. +message.please.select.networks=Por favor seleccione la red para su maquina virtual. message.please.select.ssh.key.pair.use.with.this.vm=Por favor elija el par de claves ssh que desea usar en esta VM\: message.please.wait.while.zone.is.being.created=Por favor espere un momento la zona esta siendo creada, puede llegar a demorar unos minutos... message.pod.dedication.released=Dedicaci\u00f3n de Pod liberada @@ -2125,15 +2125,15 @@ message.public.traffic.in.advanced.zone=El tr\u00e1fico p\u00fablico se genera c message.public.traffic.in.basic.zone=El tr\u00e1fico p\u00fablico es generado cuando las VMs en el cloud acceden a Internet o proveen servicios a clientes sobre Internet. Direcciones IPs accesible p\u00fablicamente deben ser asignadas para este cometido. Cuando una instancia es creada, una IP de este conjunto de IPs Publicas es asignada a la instancia ademas de la direcci\u00f3n IP en la red guest. NAT est\u00e1tico 1-1 ser\u00e1 configurado en forma autom\u00e1tica entre la IP p\u00fablica y la IP guest. Los usuarios tambi\u00e9n pueden utilizar la interfaz de CLoudStack para adquirir IPs adicionales para implementar NAT est\u00e1tico entre las instancias y la IP p\u00fablica. message.question.are.you.sure.you.want.to.add=Est\u00e1 seguro que quiere agregar message.read.admin.guide.scaling.up=Por favor les la secci\u00f3n de escalado din\u00e1mico en la gu\u00eda de administraci\u00f3n antes de escalarlo. -message.recover.vm=Por favor confirmar que se quiere recuperar esta VM. +message.recover.vm=Confirme que quiere recuperar esta VM. message.redirecting.region=Redirigiendo a la regi\u00f3n... -message.reinstall.vm=NOTA\: Proceda con precauci\u00f3n. Esta acci\u00f3n har\u00e1 que la VM se vuelva a instalar usando el template. Los datos en el disco de base se perder\u00e1n. Los vol\u00famenes de datos adicionales no se modificar\u00e1n. +message.reinstall.vm=NOTA\: Proceda con precauci\u00f3n. Esta acci\u00f3n har\u00e1 que la VM se vuelva a instalar usando la plantilla. Los datos en el disco de base se perder\u00e1n. Los vol\u00famenes de datos adicionales no se modificar\u00e1n. message.removed.ssh.key.pair=Se removi\u00f3 un Par de Claves SSH message.remove.ldap=\u00bfQuiere borrar la configuraci\u00f3n LDAP? message.remove.region=\u00bfEsta seguro que desea remover esta regi\u00f3n del servidor de management? message.remove.vpc=Por favor confirme que usted quiere eliminar el VPC message.remove.vpn.access=Por favor, confirme que desea eliminar el acceso VPN desde el siguiente usuario -message.reset.password.warning.notPasswordEnabled=El Template de esta instancia fue creado sin la gesti\u00f3n de contrase\u00f1a habilitada +message.reset.password.warning.notPasswordEnabled=El Template de esta instancia fue creado sin gesti\u00f3n de contrase\u00f1a habilitada message.reset.password.warning.notStopped=Su instancia debe ser detenida antes de intentar cambiar la contrase\u00f1a actual. message.reset.VPN.connection=Por favor confirme que desea respetar la conexi\u00f3n de la VPN message.restart.mgmt.server=Por favor, reinicie el servidor de administraci\u00f3n (s) para la nueva configuraci\u00f3n surta efecto. @@ -2150,39 +2150,39 @@ message.select.iso=Por favor seleccione un ISO para su nueva instancia virtual message.select.item=Por favor, seleccionar un item . message.select.security.groups=Por favor elija los security group(s) para su nueva VM message.select.template=Por favor seleccione un template para su nueva instancia virtual -message.select.tier=Por favor elija un Tier -message.set.default.NIC.manual=Por favor ahora actualice manualmente la NIC por defecto en la VM. +message.select.tier=Por favo elija un Tier +message.set.default.NIC.manual=Por favor actualice manualmente la NIC por defecto en la VM. message.set.default.NIC=Por favor que desea que esta NIC sea la por defecto en esta VM. -message.setup.physical.network.during.zone.creation.basic=Cuando se esta agregando un zona b\u00e1sica, puedes setear un red f\u00edsica que se corresponda a una NIC del hipervisor. La red transporta varios tipos de tr\u00e1fico.

Puedes tambi\u00e9n arrastrar y soltar otro tipo de tr\u00e1ficos en la interfaz f\u00edsica. +message.setup.physical.network.during.zone.creation.basic=Cuando se esta agregando un zona b\u00e1sica, puedes sesear un red f\u00edsica que se corresponda a una NIC del hipervisor. La red transporta varios tipos de tr\u00e1fico.

Puedes tambi\u00e9n arrastrar y soltar otro tipo de tr\u00e1ficos en la interfaz f\u00edsica. message.setup.physical.network.during.zone.creation=Cuando se esta agregando una zona avanzada, se necesita setear una o m\u00e1s redes f\u00edsicas. Cada red se corresponder\u00e1 con una NIC del hipervisor. Cada red f\u00edsica puede transportar uno o m\u00e1s tipos de tr\u00e1fico, con ciertas restricciones en como ellos se combinan.

Arrastre y suelte uno o m\u00e1s tipos de tr\u00e1fico sobre cada red f\u00edsica. message.setup.successful=La configuraci\u00f3n de la cloud finalizo satisfactoriamente. message.snapshot.schedule=Puedes definir cronogramas de instant\u00e2neas recurrentes al seleccionar las opciones disponibles debajo y aplicando las pol\u00edticas deseadas message.specifiy.tag.key.value=Por favor especifique una etiqueta con clave y valor message.specify.url=Por favor especifique la URL -message.step.1.continue=Por favor seleccione un template o imagen ISO para continuar -message.step.1.desc=Por favor seleccione un template para la instancia virtual. Tambi\u00e9n puede optar por seleccionar un template en blanco desde el que se pueda instalar una imagen ISO. +message.step.1.continue=Por favor seleccione una plantilla o ISO para continuar +message.step.1.desc=Por favor seleccione una plantilla para la instancia virtual. Tambi\u00e9n puede optar por seleccionar una plantilla en blanco desde el que puede ser una imagen ISO instalado en. message.step.2.continue=Por favor seleccione una oferta de servicio para continuar message.step.3.continue=Por favor seleccione una oferta en disco para continuar message.step.4.continue=Por favor seleccione al menos una red social para continuar message.step.4.desc=Por favor, seleccione la red primaria que la instancia virtual estar\u00e1 conectado. -message.storage.traffic=Tr\u00e1fico entre los recursos internos de CloudStack\\\\'s, incluyendo cualquier componente que se comunique con el Management Server, tales como servidores y las VMs de sistema de CloudStack +message.storage.traffic=Tr\u00e1fico entre los recursos internos de CloudStack\\\\'s, incluyendo cualquier componente que se comunique con el Management Server, tales como hosts y las VMs de systema de CloudStack message.suspend.project=\u00bfEst\u00e1 seguro que desea suspender este proyecto? message.systems.vms.ready=VM de Sistema lista. -message.template.copying=El Template esta siendo copiado. +message.template.copying=La Plantilla esta siendo copiada. message.template.desc=La imagen de OS que puede usarse para iniciar una VM message.tier.required=El Tier es obligatorio. message.tooltip.dns.1=Nombre del servidor DNS que ser\u00e1 usado por las VMs en la zona. Las direcciones IP p\u00fablicas de la zona deber\u00e1n llegar a este servidor. -message.tooltip.dns.2=El nombre del segundo servidor DNS para ser usado por las VMs en esta zona. La direcci\u00f3n IP p\u00fablica para esta zona debe ser accesible desde este servidor. +message.tooltip.dns.2=El nombre del segundo servidor DNS para ser usado por las VMs en esta zona. La direcci\u00f3n IP p\u00fablica para esta zona debe ser accesible desde el servidor. message.tooltip.internal.dns.1=Nombre del servidor DNS que ser\u00e1 usado por las VMs internas de sistema de CloudStack en la zona. Las direcciones IP p\u00fablicas de la zona deber\u00e1n llegar a este servidor. message.tooltip.internal.dns.2=Nombre del servidor DNS que ser\u00e1 usado por las VMs internas de sistema de CloudStack en la zona. Las direcciones IP p\u00fablicas de la zona deber\u00e1n llegar a este servidor. message.tooltip.network.domain=Un subfijo DNS que crear\u00e1 un nombre de dominio personalizado para la red que es acceso da por las VMs guest. message.tooltip.pod.name=Un nombre para este pod. -message.tooltip.reserved.system.gateway=El gateway para los servidores en el pod. +message.tooltip.reserved.system.gateway=El gateway para los hosts en el pod. message.tooltip.reserved.system.netmask=El prefijo de red que define la subred del pod. Use notaci\u00f3n CIDR. message.tooltip.zone.name=Un nombre para la zona. -message.update.os.preference=Por favor seleccione un sistema operativo de preferencia para este servidor. Todas las instancias virtuales con preferencias similares ser\u00e1n los primeros asignados a este servidor antes de elegir otro. +message.update.os.preference=Por favor seleccione un sistema operativo de preferencia para este equipo. Todas las instancias virtuales con preferencias similares ser\u00e1n los primeros asignados a este equipo antes de elegir otro. message.update.resource.count=Por favor confirme que usted quiere actualizar los conteos para esta cuenta -message.update.ssl.failed=Fallo la actualizaci\u00f3n del Certificado SSL. +message.update.ssl.failed=Fallo la actualizaci\u00f3n del Certficado SSL. message.update.ssl=Por favor, env\u00ede una nueva X.509 compatible con certificado SSL que se actualizar\u00e1 a cada instancia virtual de la consola del servidor proxy\: message.update.ssl.succeeded=Actualizaci\u00f3n del Certificado SSL exitosa message.validate.accept=Por favor ingrese un valor con extensi\u00f3n v\u00e1lida. @@ -2190,36 +2190,36 @@ message.validate.creditcard=Por favor ingrese un n\u00famero de tarjeta de cr\u0 message.validate.date.ISO=Por favor ingrese una fecha (ISO) v\u00e1lida. message.validate.date=Por favor ingrese una fecha v\u00e1lida. message.validate.digits=Por favor ingrese solo n\u00fameros. -message.validate.email.address=Por favor ingrese un email v\u00e1lido. +message.validate.email.address=Por favor ingrese i+un email v\u00e1lido. message.validate.equalto=Por favor ingrese el mismo valor nuevamente. message.validate.fieldrequired=Este campo es obligatorio. message.validate.fixfield=Por favor corrija este campo. message.validate.instance.name=El nombre de la instancia no puede ser m\u00e1s largo que 63 caracteres. Solo se permiten letras ASCII tales como a~z, A~Z, n\u00fameros 0~9, los guiones est\u00e1n permitidos. Deben empezar con una letra y finalizar con una letra o un n\u00famero. message.validate.invalid.characters=Se han hallado caracteres no v\u00e1lidos. Por favor, corr\u00edjalos. message.validate.maxlength=Por favor ingrese no m\u00e1s que {0} caracteres. -message.validate.max=Por favor ingrese un valor menor o igual que {0}. +message.validate.max=Por favor ingrese un valor menor o igual que {0}. message.validate.minlength=Por favor ingrese al menos {0} caracteres. message.validate.number=Por favor ingrese un n\u00famero v\u00e1lido. message.validate.range.length=Por favor ingrese un valor entre {0} y {1} caracteres de longitud. message.validate.range=Por favor ingrese un valor entre {0} y {1}. message.validate.URL=Por favor ingrese una URL v\u00e1lida. message.virtual.network.desc=Una red dedicada virtualizados para su cuenta. El dominio de difusi\u00f3n est\u00e1 contenida dentro de una VLAN y todos los acceso a la red p\u00fablica se encamina a cabo por un router virtual. -message.vm.create.template.confirm=Crear el Template reiniciar\u00e1 autom\u00e1ticamente la m\u00e1quina virtual. +message.vm.create.template.confirm=Crear plantilla de la m\u00e1quina virtual se reiniciar\u00e1 autom\u00e1ticamente. message.vm.review.launch=Por favor verifique la siguiente informaci\u00f3n es correcta y confirme antes de lanzarla. message.vnmc.available.list=VNMC no esta disponible en esta lista de proveedores. message.vnmc.not.available.list=VNMC no esta disponible en esta lista de proveedores. -message.volume.create.template.confirm=Por favor, confirme que desea crear un template desde este volumen de disco. El tiempo de creaci\u00f3n del template puede demorar unos minutos o varios m\u00e1s, dependiendo del tama\u00f1o del volumen. -message.waiting.for.builtin.templates.to.load=Esperando que se carguen los templates incorporados... +message.volume.create.template.confirm=Por favor, confirme que desea crear una plantilla para este volumen de disco. Creaci\u00f3n de la plantilla puede oscilar entre varios minutos m\u00e1s, dependiendo del tama\u00f1o del volumen. +message.waiting.for.builtin.templates.to.load=Esperando por las plantillas incorporadas para cargar... message.XSTools61plus.update.failed=La actualizaci\u00f3n fall\u00f3, la versi\u00f3n original de XS es 6.1\\+. Error\: message.you.must.have.at.least.one.physical.network=Debes tener por lo menos una red f\u00edsica -message.your.cloudstack.is.ready=\u00a1Tu CloudStack esta listo\! +message.your.cloudstack.is.ready=Tu CloudStack esta listo\! message.Zone.creation.complete=Creci\u00f3n de la zona completada message.zone.creation.complete.would.you.like.to.enable.this.zone=Creci\u00f3n de la zona completada.\u00bfDesea habilitarla? message.zone.no.network.selection=La zona elegida no tiene ninguna red para seleccionar. message.zone.step.1.desc=Por favor seleccione un modelo de red para su zona. message.zone.step.2.desc=Por favor ingrese la siguiente informaci\u00f3n para agregar una nueva zona -message.zone.step.3.desc=Por favor ingrese la siguiente informaci\u00f3n para agregar un nuevo pod -message.zoneWizard.enable.local.storage=PRECAUCI\u00d3N\: Si habilita el almacenamiento local para esta zona, deber\u00e1 hacer lo siguiente dependiendo de donde se quieran iniciar VMs de sistema\:

1. Si las VMs de sistema deben ser iniciadas sobre el almacenamiento primario compartido, este debe agregarse a la zona despu\u00e9s de creada. Tambi\u00e9n puedes iniciar la zona en estado dshabilitado.

2. Si la VM de sistema necesita ser iniciada en el almacenamiento primario local, el par\u00e1metro system.vm.use.local.storage debe ser puesto en true antes de habilitar la zona.


\u00bfDesea continuar? +message.zone.step.3.desc=Por favor ingrese la siguiente informaci\u00f3n para agregar un nuevo por +message.zoneWizard.enable.local.storage=PRECAUCI\u00d3N\: Si habilita el almacenamiento local para esta zona, debe hacer lo siguiente dependiendo de donde se quieran iniciar las VMs de sistema\:

1. Si las VMs de sistema deben ser iniciadas sobre el almacenamiento primario compartido, este debe agregarse a la zona despu\u00e9s de creada. Tambi\u00e9n puedes iniciar la zona en estado dshabilitado.

2. Si la VM de sistema necesita ser iniciada en el almacenamiento primario local, el par\u00e1metro system.vm.use.local.storage debe ser puesto en true antes de habilitar la zona.


\u00bfDesea continuar? messgae.validate.min=Por favor ingrese un valor mayor o igual que {0}. mode=modo network.rate=Tasa de Red diff --git a/client/WEB-INF/classes/resources/messages_fr_FR.properties b/client/WEB-INF/classes/resources/messages_fr_FR.properties index 17a68c5a38..64c65fd182 100644 --- a/client/WEB-INF/classes/resources/messages_fr_FR.properties +++ b/client/WEB-INF/classes/resources/messages_fr_FR.properties @@ -335,6 +335,7 @@ label.add.primary.storage=Ajouter un stockage primaire label.add.private.gateway=Ajouter Passerelle Priv\u00e9e label.add.region=Ajouter R\u00e9gion label.add.resources=Ajouter ressources +label.add.role=Ajouter R\u00f4le label.add.route=Ajouter route label.add.rule=Ajouter r\u00e8gle label.add.secondary.storage=Ajouter un stockage secondaire @@ -573,6 +574,7 @@ label.delete.PA=Supprimer Palo Alto label.delete.portable.ip.range=Supprimer Plage IP portable label.delete.profile=Supprimer Profil label.delete.project=Supprimer projet +label.delete.role=Supprimer R\u00f4le label.delete.secondary.staging.store=Supprimer Stockage Secondaire Interm\u00e9diaire label.delete.SRX=Supprimer SRX label.delete=Supprimer @@ -658,6 +660,7 @@ label.edit=Modifier label.edit.network.details=Modifier les param\u00e8tres r\u00e9seau label.edit.project.details=Modifier les d\u00e9tails du projet label.edit.region=\u00c9diter R\u00e9gion +label.edit.role=\u00c9diter R\u00f4le label.edit.rule=Modifier r\u00e8gle label.edit.secondary.ips=\u00c9diter IPs secondaires label.edit.tags=Modifier les balises @@ -1183,6 +1186,7 @@ label.password.reset.confirm=Le mot de passe a \u00e9t\u00e9 r\u00e9-initialiser label.path=Chemin label.PA.threat.profile=Profil menace Palo Alto label.perfect.forward.secrecy=Confidentialit\u00e9 persistante +label.permission=Autorisation label.persistent=Persistant label.physical.network.ID=Identifiant du r\u00e9seau physique label.physical.network.name=Nom r\u00e9seau physique @@ -1380,6 +1384,8 @@ label.retry.interval=Interval du nouvel essai label.review=Revoir label.revoke.project.invite=R\u00e9voquer l\\'invitation label.role=R\u00f4le +label.roles=R\u00f4les +label.roletype=Type R\u00f4le label.root.certificate=Certificat racine label.root.disk.controller=Contr\u00f4leur de disque racine label.root.disk.offering=Offre de disque racine @@ -1388,6 +1394,7 @@ label.router.vm.scaled.up=VM Routeur agrandi label.routing.host=H\u00f4te de routage label.routing=Routage label.rule.number=Num\u00e9ro r\u00e8gle +label.rule=R\u00e8gle label.rules=R\u00e8gles label.running.vms=VMs actives label.s3.access_key=Cl\u00e9 d\\'Acc\u00e8s @@ -1583,7 +1590,7 @@ label.timezone.colon=Fuseau horaire \: label.time.zone=Fuseau horaire label.timezone=Fuseau horaire label.token=Jeton unique -label.total.cpu=Capacit\u00e9 Totale en CPU +label.total.cpu=Capacit\u00e9 totale en CPU label.total.CPU=Capacit\u00e9 totale en CPU label.total.hosts=Total H\u00f4tes label.total.memory=Total m\u00e9moire @@ -2142,6 +2149,7 @@ message.restart.network=Tous les services fournit par ce routeur virtuel vont \u message.restart.vpc=Confirmer le red\u00e9marrage du VPC message.restart.vpc.remark=Veuillez confirmer que vous voulez red\u00e9marrer le VPC

Note \: transformer un VPC non-redondant en VPC redondant va forcer un nettoyage du routeur. Le r\u00e9seau associ\u00e9 ne sera pas disponible durant quelques minutes.

message.restoreVM=Voulez-vous restaurer la VM ? +message.role.ordering.fail=La r\u00e9organisation des r\u00e8gles d\\'autorisations a \u00e9t\u00e9 abandonn\u00e9e car la liste a chang\u00e9 pendant que vous apportez des modifications. Veuillez r\u00e9essayer. message.security.group.usage=(Utilisez Ctrl-clic pour s\u00e9lectionner les groupes de s\u00e9curit\u00e9 vis\u00e9s) message.select.affinity.groups=S\u00e9lectionner les groupes d\\'affinit\u00e9 qui appartiendront \u00e0 cette machine virtuelle \: message.select.a.zone=Une zone correspond typiquement \u00e0 un seul centre de donn\u00e9es. Des zones multiples peuvent permettre de rendre votre cloud plus fiable en apportant une isolation physique et de la redondance. diff --git a/client/WEB-INF/classes/resources/messages_it_IT.properties b/client/WEB-INF/classes/resources/messages_it_IT.properties index 45bb43a313..9eddbc1ffd 100644 --- a/client/WEB-INF/classes/resources/messages_it_IT.properties +++ b/client/WEB-INF/classes/resources/messages_it_IT.properties @@ -697,6 +697,7 @@ label.restart.vpc=Riavviare VPC label.restore=Restore label.review=Riesaminare label.revoke.project.invite=Revocare un invit +label.roles=Ruoli label.root.disk.controller=Controller del disco root label.routing=Routing label.rules=Regole diff --git a/client/WEB-INF/classes/resources/messages_ja_JP.properties b/client/WEB-INF/classes/resources/messages_ja_JP.properties index 5fc7adf302..83adc2c618 100644 --- a/client/WEB-INF/classes/resources/messages_ja_JP.properties +++ b/client/WEB-INF/classes/resources/messages_ja_JP.properties @@ -1321,6 +1321,7 @@ label.restore=\u5fa9\u5143 label.retry.interval=\u518d\u8a66\u884c\u9593\u9694 label.review=\u78ba\u8a8d label.revoke.project.invite=\u62db\u5f85\u306e\u53d6\u308a\u6d88\u3057 +label.roles=\u30ed\u30fc\u30eb label.role=\u5f79\u5272 label.root.certificate=\u30eb\u30fc\u30c8\u8a3c\u660e\u66f8 label.root.disk.controller=\u30eb\u30fc\u30c8 \u30c7\u30a3\u30b9\u30af \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc @@ -1642,7 +1643,7 @@ label.vmware.datacenter.name=VMware \u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u label.vmware.datacenter.vcenter=VMware \u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u306e vCenter label.vmware.traffic.label=VMware \u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af \u30e9\u30d9\u30eb label.vnet.id=VLAN/VNI ID -label.vnet=VLAN +label.vnet=VLAN/VNI label.vnmc.devices=VNMC \u30c7\u30d0\u30a4\u30b9 label.vnmc=VNMC label.volatile=\u63ee\u767a\u6027 diff --git a/client/WEB-INF/classes/resources/messages_ko_KR.properties b/client/WEB-INF/classes/resources/messages_ko_KR.properties index 6123623a4a..106cf36387 100644 --- a/client/WEB-INF/classes/resources/messages_ko_KR.properties +++ b/client/WEB-INF/classes/resources/messages_ko_KR.properties @@ -316,7 +316,7 @@ label.agent.username=\uc5d0\uc774\uc804\ud2b8 \uc0ac\uc6a9\uc790\uba85 label.agree=\ub3d9\uc758 label.alert=\uc54c\ub9bc \uccb4\uc81c label.algorithm=\uc54c\uace0\ub9ac\uc998 -label.allocated=\ud560\ub2f9 \ub05d\ub09c \uc0c1\ud0dc +label.allocated=\ud560\ub2f9 \uc644\ub8cc \uc0c1\ud0dc label.allocation.state=\ud560\ub2f9 \uc0c1\ud0dc label.api.key=API \ud0a4 label.apply=\uc801\uc6a9 @@ -705,10 +705,10 @@ label.menu.templates=\ud15c\ud50c\ub9bf label.menu.virtual.appliances=\uac00\uc0c1 \uc544\ud504\ub77c\uc774\uc548\uc2a4 label.menu.virtual.resources=\uac00\uc0c1 \uc790\uc6d0 label.menu.volumes=\ubcfc\ub968 -label.metrics.allocated=\ud560\ub2f9 \ub05d\ub09c \uc0c1\ud0dc +label.metrics.allocated=\ud560\ub2f9 \uc644\ub8cc \uc0c1\ud0dc label.metrics.clusters=\ud074\ub7ec\uc2a4\ud130 label.metrics.cpu.used.avg=\uc0ac\uc6a9 \uc911 -label.metrics.disk.allocated=\ud560\ub2f9 \ub05d\ub09c \uc0c1\ud0dc +label.metrics.disk.allocated=\ud560\ub2f9 \uc644\ub8cc \uc0c1\ud0dc label.metrics.disk.size=\ud06c\uae30 label.metrics.disk.storagetype=\uc885\ub958 label.metrics.disk.used=\uc0ac\uc6a9 \uc911 @@ -1336,7 +1336,7 @@ message.installWizard.tooltip.addHost.hostname=\ud638\uc2a4\ud2b8 DNS \uba85 \ub message.installWizard.tooltip.addHost.password=XenServer \uce21\uc5d0\uc11c \uc9c0\uc815\ud55c \uc704\uc758 \uc0ac\uc6a9\uc790\uba85\uc5d0 \ub300\ud55c \uc554\ud638\uc785\ub2c8\ub2e4. message.installWizard.tooltip.addHost.username=\uc6d0\ub798 root \uc785\ub2c8\ub2e4. message.installWizard.tooltip.addPod.name=Pod \uc774\ub984\uc785\ub2c8\ub2e4. -message.installWizard.tooltip.addPod.reservedSystemEndIp=\uc774\uac83\uc740 2\ucc28 \uc2a4\ud1a0\ub9ac\uc9c0 VM \ubc0f \ucf58\uc194 \ud504\ub85d\uc2dc VM\ub97c \uad00\ub9ac\ud558\uae30 \uc704\ud574\uc11c CloudStack\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \uc0ac\uc124 \ub124\ud2b8\uc6cc\ud06c\ub0b4\uc758 IP \uc8fc\uc18c \ubc94\uc704\uc785\ub2c8\ub2e4. \uc774\ub7ec\ud55c IP \uc8fc\uc18c\ub294 \ucef4\ud4e8\ud305 \uc11c\ubc84\uc640 \uac19\uc740 \uc11c\ube0c\ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \ud560\ub2f9\ud569\ub2c8\ub2e4. +message.installWizard.tooltip.addPod.reservedSystemEndIp=\uc774\uac83\uc740 2\ucc28 \uc2a4\ud1a0\ub9ac\uc9c0 VM \ubc0f \ucf58\uc194 \ud504\ub85d\uc2dc VM\ub97c \uad00\ub9ac\ud558\uae30 \uc704\ud574\uc11c CloudStack\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \uc0ac\uc124 \ub124\ud2b8\uc6cc\ud06c\ub0b4 IP \uc8fc\uc18c \ubc94\uc704\uc785\ub2c8\ub2e4. \uc774\ub7ec\ud55c IP \uc8fc\uc18c\ub294 \ucef4\ud4e8\ud305 \uc11c\ubc84\uc640 \uac19\uc740 \uc11c\ube0c\ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \ud560\ub2f9\ud569\ub2c8\ub2e4. message.installWizard.tooltip.addPod.reservedSystemGateway=\ud604\uc7ac Pod\ub0b4 \ud638\uc2a4\ud2b8 \uac8c\uc774\ud2b8\uc6e8\uc774\uc785\ub2c8\ub2e4. message.installWizard.tooltip.addPod.reservedSystemNetmask=\uac8c\uc2a4\ud2b8\uac00 \uc0ac\uc6a9\ud558\ub294 \uc11c\ube0c\ub124\ud2b8\uc6cc\ud06c\uc0c1\uc5d0\uc11c \uc9c0\uc815\ud55c \ub137 \ub9c8\uc2a4\ud06c\uc785\ub2c8\ub2e4. message.installWizard.tooltip.addPod.reservedSystemStartIp=\uc774\uac83\uc740 2\ucc28 \uc2a4\ud1a0\ub9ac\uc9c0 VM \ubc0f \ucf58\uc194 \ud504\ub85d\uc2dc VM\ub97c \uad00\ub9ac\ud558\uae30 \uc704\ud574\uc11c CloudStack\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \uc0ac\uc124 \ub124\ud2b8\uc6cc\ud06c\ub0b4\uc758 IP \uc8fc\uc18c \ubc94\uc704\uc785\ub2c8\ub2e4. \uc774\ub7ec\ud55c IP \uc8fc\uc18c\ub294 \ucef4\ud4e8\ud305 \uc11c\ubc84\uc640 \uac19\uc740 \uc11c\ube0c\ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \ud560\ub2f9\ud569\ub2c8\ub2e4. @@ -1345,13 +1345,13 @@ message.installWizard.tooltip.addPrimaryStorage.path=(NFS\uc758 \uacbd\uc6b0) \u message.installWizard.tooltip.addPrimaryStorage.server=(NFS, iSCSI \ub610\ub294 PreSetup\uc758 \uacbd\uc6b0) \uc2a4\ud1a0\ub9ac\uc9c0 \uae30\uae30\uc758 IP \uc8fc\uc18c \ub610\ub294 DNS \uba85\uc785\ub2c8\ub2e4. message.installWizard.tooltip.addSecondaryStorage.nfsServer=2\ucc28 \uc2a4\ud1a0\ub9ac\uc9c0\ub97c \ud638\uc2a4\ud2b8 \ud558\ub294 NFS \uc11c\ubc84 IP \uc8fc\uc18c\uc785\ub2c8\ub2e4. message.installWizard.tooltip.addSecondaryStorage.path=\uc704\uc5d0\uc11c \uc9c0\uc815\ud55c \uc11c\ubc84\uc5d0 \uc874\uc7ac\ud558\ub294 \ub0b4\ubcf4\ub0b4\uae30 \uacbd\ub85c\uc785\ub2c8\ub2e4. -message.installWizard.tooltip.addZone.dns1=Zone\ub0b4 \uac8c\uc2a4\ud2b8 VM \ub85c \uc0ac\uc6a9\ud558\ub294 DNS \uc11c\ubc84\uc785\ub2c8\ub2e4. \ud604\uc7ac DNS \uc11c\ubc84\uc5d0\ub294 \ub2e4\uc74c\uc5d0 \ucd94\uac00\ud558\ub294 \uacf5\uac1c \ub124\ud2b8\uc6cc\ud06c \uacbd\uc720\ub85c \uc811\uadfc\ud569\ub2c8\ub2e4. Zone\uc758 \uacf5\uac1c IP \uc8fc\uc18c\uc5d0\uc11c \uc5ec\uae30\uc11c \uc9c0\uc815\ud558\ub294 \uacf5\uac1c DNS \uc11c\ubc84\uc5d0 \ud1b5\uc2e0\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. +message.installWizard.tooltip.addZone.dns1=Zone\ub0b4\uc758 \uac8c\uc2a4\ud2b8 VM\uc73c\ub85c \uc0ac\uc6a9\ud558\ub294 DNS \uc11c\ubc84\uc785\ub2c8\ub2e4. \uc774\ub7ec\ud55c DNS \uc11c\ubc84\uc5d0\ub294 \ub2e4\uc74c\uc5d0 \ucd94\uac00\ud558\ub294 \uacf5\uac1c \ub124\ud2b8\uc6cc\ud06c \uacbd\uc720\ub85c \uc811\uadfc \ud569\ub2c8\ub2e4. Zone\uc758 \uacf5\uac1c IP \uc8fc\uc18c\uc5d0\uc11c \uc5ec\uae30\uc11c \uc9c0\uc815\ud558\ub294 \uacf5\uac1c DNS \uc11c\ubc84\uc5d0 \ud1b5\uc2e0\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. message.installWizard.tooltip.addZone.dns2=Zone\ub0b4 \uac8c\uc2a4\ud2b8 VM \ub85c \uc0ac\uc6a9\ud558\ub294 DNS \uc11c\ubc84\uc785\ub2c8\ub2e4. \ud604\uc7ac DNS \uc11c\ubc84\uc5d0\ub294 \ub2e4\uc74c\uc5d0 \ucd94\uac00\ud558\ub294 \uacf5\uac1c \ub124\ud2b8\uc6cc\ud06c \uacbd\uc720\ub85c \uc811\uadfc\ud569\ub2c8\ub2e4. Zone\uc758 \uacf5\uac1c IP \uc8fc\uc18c\uc5d0\uc11c \uc5ec\uae30\uc11c \uc9c0\uc815\ud558\ub294 \uacf5\uac1c DNS \uc11c\ubc84\uc5d0 \ud1b5\uc2e0\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. -message.installWizard.tooltip.addZone.internaldns1=Zone\ub0b4 \uc2dc\uc2a4\ud15c VM\uc73c\ub85c \uc0ac\uc6a9\ud558\ub294 DNS \uc11c\ubc84\uc785\ub2c8\ub2e4. \ud604\uc7ac DNS \uc11c\ubc84\ub294 \uc2dc\uc2a4\ud15c VM\uc758 \uc0ac\uc124 \ub124\ud2b8\uc6cc\ud06c \uc778\ud130\ud398\uc774\uc2a4\ub97c \uac1c\uc785\uc2dc\ucf1c \uc811\uadfc\ud569\ub2c8\ub2e4. Pod\uc758 \uc0ac\uc124 IP \uc8fc\uc18c\uc5d0\uc11c \uc5ec\uae30\uc11c \uc9c0\uc815\ud558\ub294 DNS \uc11c\ubc84\uc5d0 \ud1b5\uc2e0\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. +message.installWizard.tooltip.addZone.internaldns1=Zone\ub0b4\uc758 \uc2dc\uc2a4\ud15c VM \ub85c \uc0ac\uc6a9\ud558\ub294 DNS \uc11c\ubc84\uc785\ub2c8\ub2e4. \ud604\uc7ac DNS \uc11c\ubc84\ub294 \uc2dc\uc2a4\ud15c VM\uc758 \uc0ac\uc124 \ub124\ud2b8\uc6cc\ud06c \uc778\ud130\ud398\uc774\uc2a4\ub97c \uac1c\uc785\uc2dc\ucf1c \uc811\uadfc\ud569\ub2c8\ub2e4. Pod\uc758 \uc0ac\uc124 IP \uc8fc\uc18c\uc5d0\uc11c \uc5ec\uae30\uc11c \uc9c0\uc815\ud558\ub294 DNS \uc11c\ubc84\uc5d0 \ud1b5\uc2e0\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. message.installWizard.tooltip.addZone.internaldns2=Zone\ub0b4 \uc2dc\uc2a4\ud15c VM\uc73c\ub85c \uc0ac\uc6a9\ud558\ub294 DNS \uc11c\ubc84\uc785\ub2c8\ub2e4. \ud604\uc7ac DNS \uc11c\ubc84\ub294 \uc2dc\uc2a4\ud15c VM\uc758 \uc0ac\uc124 \ub124\ud2b8\uc6cc\ud06c \uc778\ud130\ud398\uc774\uc2a4\ub97c \uac1c\uc785\uc2dc\ucf1c \uc811\uadfc\ud569\ub2c8\ub2e4. Pod\uc758 \uc0ac\uc124 IP \uc8fc\uc18c\uc5d0\uc11c \uc5ec\uae30\uc11c \uc9c0\uc815\ud558\ub294 DNS \uc11c\ubc84\uc5d0 \ud1b5\uc2e0\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. message.installWizard.tooltip.addZone.name=Zone\uc758 \uc774\ub984\uc785\ub2c8\ub2e4. message.installWizard.tooltip.configureGuestTraffic.description=\ub124\ud2b8\uc6cc\ud06c \uc124\uba85\uc785\ub2c8\ub2e4. -message.installWizard.tooltip.configureGuestTraffic.guestEndIp=\ud604\uc7ac Zone\uc758 \uac8c\uc2a4\ud2b8\uc5d0\uac8c \ud560\ub2f9\ud560 \uc218 \uc788\ub294 IP \uc8fc\uc18c \ubc94\uc704\uc785\ub2c8\ub2e4. \uc0ac\uc6a9\ud558\ub294 NIC\uac00 \ud55c \uac00\uc9c0 \uacbd\uc6b0\ub294 \uc774\ub7ec\ud55c IP \uc8fc\uc18c\ub294 Pod\uc758 CIDR\uc640 \uac19\uc740 CIDR\uc5d0 \ud3ec\ud568\ub418\uc5b4 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. +message.installWizard.tooltip.configureGuestTraffic.guestEndIp=\ud604\uc7ac Zone\uc758 \uac8c\uc2a4\ud2b8\uc5d0\uac8c \ud560\ub2f9\ud560 \uc218 \uc788\ub294 IP \uc8fc\uc18c \ubc94\uc704\uc785\ub2c8\ub2e4. \uc0ac\uc6a9\ud558\ub294 NIC\uac00 \ud55c \uac00\uc9c0\uc778 \uacbd\uc6b0\ub294 \uc774\ub7ec\ud55c IP \uc8fc\uc18c\ub294 Pod\uc758 CIDR\uc640 \uac19\uc740 CIDR\uc5d0 \ud3ec\ud568\ub418\uc5b4 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. message.installWizard.tooltip.configureGuestTraffic.guestGateway=\uac8c\uc2a4\ud2b8\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \uac8c\uc774\ud2b8\uc6e8\uc774\uc785\ub2c8\ub2e4. message.installWizard.tooltip.configureGuestTraffic.guestNetmask=\uac8c\uc2a4\ud2b8\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \uc11c\ube0c\ub124\ud2b8\uc6cc\ud06c\uc0c1\uc5d0\uc11c \uc0ac\uc6a9\ub418\ub294 \ub137 \ub9c8\uc2a4\ud06c\uc785\ub2c8\ub2e4. message.installWizard.tooltip.configureGuestTraffic.guestStartIp=\ud604\uc7ac Zone\uc758 \uac8c\uc2a4\ud2b8\uc5d0\uac8c \ud560\ub2f9\ud560 \uc218 \uc788\ub294 IP \uc8fc\uc18c \ubc94\uc704\uc785\ub2c8\ub2e4. \uc0ac\uc6a9\ud558\ub294 NIC\uac00 \ud55c \uac00\uc9c0 \uacbd\uc6b0\ub294 \uc774\ub7ec\ud55c IP \uc8fc\uc18c\ub294 Pod\uc758 CIDR\uc640 \uac19\uc740 CIDR\uc5d0 \ud3ec\ud568\ub418\uc5b4 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. @@ -1459,7 +1459,7 @@ state.Completed=\uc644\ub8cc state.Creating=\uc0dd\uc131 \uc911 state.Declined=\uac70\uc808 state.Destroyed=\ud30c\uae30\ub41c \uc0c1\ud0dc -state.Disabled=\uc0ac\uc6a9 \uc548\ud568 +state.Disabled=\uc720\ud6a8\ud558\uc9c0 \uc54a\uc740 state.Enabled=\uc0ac\uc6a9\ud568 state.Error=\uc624\ub958 state.Expunging=\uc81c\uac70 \uc911 diff --git a/client/WEB-INF/classes/resources/messages_nb_NO.properties b/client/WEB-INF/classes/resources/messages_nb_NO.properties index a4851d033b..98283abdfd 100644 --- a/client/WEB-INF/classes/resources/messages_nb_NO.properties +++ b/client/WEB-INF/classes/resources/messages_nb_NO.properties @@ -1469,8 +1469,8 @@ label.smb.username=SMB Brukernavn label.snapshot.limits=\u00d8yeblikksbildebegrensning label.snapshot.name=\u00d8yeblikksbildenavn label.snapshot.schedule=Sett Opp Gjentagende \u00f8yeblikksbilder -label.snapshot.s=\u00d8yebliksbilder -label.snapshots=\u00d8yebliksbilder +label.snapshot.s=\u00d8yeblikksbilder +label.snapshots=\u00d8yeblikksbilder label.snapshot=\u00d8yeblikksbilde label.SNMP.community=SNMP Community label.SNMP.port=SNM Port @@ -2106,7 +2106,7 @@ message.number.hosts=

\# av Verter

message.number.pods=

\# av Pods

message.number.storage=

\# av Prim\u00e6rlagringsvolumer

message.number.zones=

\# av Soner

-message.password.has.been.reset.to=Passordet har blitt resatt til +message.password.has.been.reset.to=Passordet har blitt endret til message.password.of.the.vm.has.been.reset.to=Passorde for VM har blitt endre til message.pending.projects.1=Du har f\u00f8lgende prosjektinvitasjoner\: message.pending.projects.2=For \u00e5 se, vennligst g\u00e5 til prosjektseksjonen og velg invitasjoner fra nedtrekksmenyen. diff --git a/client/WEB-INF/classes/resources/messages_nl_NL.properties b/client/WEB-INF/classes/resources/messages_nl_NL.properties index 5cb7413ce8..c4dc841b5c 100644 --- a/client/WEB-INF/classes/resources/messages_nl_NL.properties +++ b/client/WEB-INF/classes/resources/messages_nl_NL.properties @@ -435,7 +435,7 @@ label.broadcast.domain.range=Broadcast domain range label.broadcast.domain.type=Broadcast Domain Type label.broadcast.uri=Broadcast URI label.broadcasturi=broadcasturi -label.broadcat.uri=Broadcast URI +label.broadcat.uri=broadcast URI label.brocade.vcs.address=Vcs switch adres label.brocade.vcs.details=Brocade Vcs switch gegevens label.by.account=Op Account @@ -2105,7 +2105,7 @@ message.number.hosts=

Aantal Hosts

message.number.pods=

Aantal Pods

message.number.storage=

Aantal Primaire Opslag Volumes

message.number.zones=

Aantal Zones

-message.password.has.been.reset.to=Het wachtwoord is gereset naar +message.password.has.been.reset.to=Het wachtwoord is veranderd in message.password.of.the.vm.has.been.reset.to=Het wachtwoord van de VM is veranderd in message.pending.projects.1=U heeft openstaande project uitnodigigingen\: message.pending.projects.2=Ga naar de project sectie om deze te zien. Selecteer de uitnodiging vanuit het drop-down menu. diff --git a/client/WEB-INF/classes/resources/messages_pt_BR.properties b/client/WEB-INF/classes/resources/messages_pt_BR.properties index 444bb1568b..8b99b35894 100644 --- a/client/WEB-INF/classes/resources/messages_pt_BR.properties +++ b/client/WEB-INF/classes/resources/messages_pt_BR.properties @@ -1622,7 +1622,7 @@ label.url=URL label.usage.interface=Usage Interface label.usage.sanity.result=Resultado de Sanidade de Uso label.usage.server=Uso do Servidor -label.usage.type=Tipo +label.usage.type=Uso Tipo label.usage.unit=Unidade label.used=Usado label.user.data=Dados de Usu\u00e1rio @@ -2106,7 +2106,7 @@ message.number.hosts=

Hosts

message.number.pods=

PODs

message.number.storage=

Volumes do Storage Prim\u00e1rio

message.number.zones=

Zonas

-message.password.has.been.reset.to=A senha foi recuperada para +message.password.has.been.reset.to=A senha foi redefinida para message.password.of.the.vm.has.been.reset.to=A senha da VM foi redefinida para message.pending.projects.1=Voc\u00ea possui convites de projetos pendentes\: message.pending.projects.2=Para visualizar, por favor acesse a se\u00e7\u00e3o de projetos, depois selecione os convites no menu drop-down. diff --git a/client/WEB-INF/classes/resources/messages_zh_CN.properties b/client/WEB-INF/classes/resources/messages_zh_CN.properties index 66f99b2699..001ccf056d 100644 --- a/client/WEB-INF/classes/resources/messages_zh_CN.properties +++ b/client/WEB-INF/classes/resources/messages_zh_CN.properties @@ -1319,6 +1319,7 @@ label.restore=\u8fd8\u539f label.retry.interval=\u91cd\u8bd5\u65f6\u95f4\u95f4\u9694 label.review=\u6838\u5bf9 label.revoke.project.invite=\u64a4\u9500\u9080\u8bf7 +label.roles=\u89d2\u8272 label.role=\u89d2\u8272 label.root.certificate=\u6839\u8bc1\u4e66 label.root.disk.controller=\u6839\u78c1\u76d8\u63a7\u5236\u5668 @@ -1328,6 +1329,7 @@ label.routing.host=\u6b63\u5728\u8def\u7531\u4e3b\u673a label.routing=\u6b63\u5728\u8def\u7531 label.rule.number=\u89c4\u5219\u7f16\u53f7 label.rules=\u89c4\u5219 +label.rule=\u89c4\u5219 label.running.vms=\u6b63\u5728\u8fd0\u884c\u7684 VM label.s3.access_key=\u8bbf\u95ee\u5bc6\u94a5 label.s3.bucket=\u5b58\u50a8\u6876 diff --git a/tools/transifex/.tx/config b/tools/transifex/.tx/config index 9804e76f86..fa4bc1f4d4 100644 --- a/tools/transifex/.tx/config +++ b/tools/transifex/.tx/config @@ -108,3 +108,22 @@ trans.pt_BR = work-dir/messages_pt_BR.properties trans.ru_RU = work-dir/messages_ru_RU.properties trans.zh_CN = work-dir/messages_zh_CN.properties +[CloudStack_UI.49xmessagesproperties] +source_file = work-dir/messages.properties +source_lang = en +trans.ar = work-dir/messages_ar.properties +trans.ca = work-dir/messages_ca.properties +trans.de_DE = work-dir/messages_de_DE.properties +trans.es = work-dir/messages_es.properties +trans.fr_FR = work-dir/messages_fr_FR.properties +trans.hu = work-dir/messages_hu.properties +trans.it_IT = work-dir/messages_it_IT.properties +trans.ja_JP = work-dir/messages_ja_JP.properties +trans.ko_KR = work-dir/messages_ko_KR.properties +trans.nb_NO = work-dir/messages_nb_NO.properties +trans.nl_NL = work-dir/messages_nl_NL.properties +trans.pl = work-dir/messages_pl.properties +trans.pt_BR = work-dir/messages_pt_BR.properties +trans.ru_RU = work-dir/messages_ru_RU.properties +trans.zh_CN = work-dir/messages_zh_CN.properties + From 540d9572fd491db3ce182d26636fc74ada4e171c Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Fri, 13 May 2016 08:54:24 +0530 Subject: [PATCH 156/203] CLOUDSTACK-9348: Make NioConnectio loop less aggressive - Reverts ea2286 that introduced a wakeup on each connection loop run. - In SSL handshake code removes delegated tasks to be run in separate threads. Signed-off-by: Rohit Yadav --- utils/src/main/java/com/cloud/utils/nio/Link.java | 5 ++++- utils/src/main/java/com/cloud/utils/nio/NioConnection.java | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/utils/src/main/java/com/cloud/utils/nio/Link.java b/utils/src/main/java/com/cloud/utils/nio/Link.java index da2c0d54e8..02ffaab4e0 100644 --- a/utils/src/main/java/com/cloud/utils/nio/Link.java +++ b/utils/src/main/java/com/cloud/utils/nio/Link.java @@ -615,7 +615,10 @@ public static boolean doHandshake(final SocketChannel socketChannel, final SSLEn case NEED_TASK: Runnable task; while ((task = sslEngine.getDelegatedTask()) != null) { - new Thread(task).run(); + if (s_logger.isTraceEnabled()) { + s_logger.trace("SSL: Running delegated task!"); + } + task.run(); } break; case FINISHED: diff --git a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java index 749e552c2c..6fdb4736ac 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java @@ -171,8 +171,6 @@ public Boolean call() throws NioConnectionException { } catch (final IOException e) { s_logger.error("Agent will die due to this IOException!", e); throw new NioConnectionException(e.getMessage(), e); - } finally { - _selector.wakeup(); } } _isStartup = false; From ae0f169123158c23898316a32b413f4647d0c456 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Fri, 13 May 2016 09:09:58 +0530 Subject: [PATCH 157/203] CLOUDSTACK-9299: Fix test failures on CI - Fixes oobm integration test to skip if known ipmitool bug is hit - Fixes ProcessTest unit test case to use sleep - Removes redundant unit test that covers code in ProcessTest Signed-off-by: Rohit Yadav --- .../driver/ipmitool/IpmitoolWrapperTest.java | 11 +---------- test/integration/smoke/test_outofbandmanagement.py | 9 +++++++-- .../apache/cloudstack/utils/process/ProcessTest.java | 3 +-- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/plugins/outofbandmanagement-drivers/ipmitool/test/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapperTest.java b/plugins/outofbandmanagement-drivers/ipmitool/test/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapperTest.java index 86eff86b02..26115f7a8c 100644 --- a/plugins/outofbandmanagement-drivers/ipmitool/test/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapperTest.java +++ b/plugins/outofbandmanagement-drivers/ipmitool/test/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapperTest.java @@ -23,13 +23,11 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.google.common.collect.ImmutableMap; import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; -import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner; -import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -105,11 +103,4 @@ public void testFindIpmiUserValid() { Assert.assertEquals(IPMITOOL.findIpmiUser(usersList, "operator"), "2"); Assert.assertEquals(IPMITOOL.findIpmiUser(usersList, "user"), "3"); } - - @Test - public void testExecuteCommands() { - OutOfBandManagementDriverResponse r = IPMITOOL.executeCommands(Arrays.asList("ls", "/tmp")); - Assert.assertTrue(r.isSuccess()); - Assert.assertTrue(r.getResult().length() > 0); - } -} \ No newline at end of file +} diff --git a/test/integration/smoke/test_outofbandmanagement.py b/test/integration/smoke/test_outofbandmanagement.py index 7c2aa6b5da..0f0f442ac7 100644 --- a/test/integration/smoke/test_outofbandmanagement.py +++ b/test/integration/smoke/test_outofbandmanagement.py @@ -557,8 +557,13 @@ def test_oobm_zchange_password(self): cmd = changeOutOfBandManagementPassword.changeOutOfBandManagementPasswordCmd() cmd.hostid = self.getHost().id cmd.password = "Password12345" - response = self.apiclient.changeOutOfBandManagementPassword(cmd) - self.assertEqual(response.status, True) + try: + response = self.apiclient.changeOutOfBandManagementPassword(cmd) + self.assertEqual(response.status, True) + except Exception as e: + if "packet session id 0x0 does not match active session" in str(e): + raise self.skipTest("Known ipmitool issue hit, skipping test") + raise e bmc = IpmiServerContext().bmc bmc.powerstate = 'on' diff --git a/utils/src/test/java/org/apache/cloudstack/utils/process/ProcessTest.java b/utils/src/test/java/org/apache/cloudstack/utils/process/ProcessTest.java index b5e6e04c31..2c158c800a 100644 --- a/utils/src/test/java/org/apache/cloudstack/utils/process/ProcessTest.java +++ b/utils/src/test/java/org/apache/cloudstack/utils/process/ProcessTest.java @@ -39,10 +39,9 @@ public class ProcessTest { @Test public void testProcessRunner() { - ProcessResult result = RUNNER.executeCommands(Arrays.asList("ls", "/tmp")); + ProcessResult result = RUNNER.executeCommands(Arrays.asList("sleep", "0")); Assert.assertEquals(result.getReturnCode(), 0); Assert.assertTrue(Strings.isNullOrEmpty(result.getStdError())); - Assert.assertTrue(result.getStdOutput().length() > 0); } @Test From 2bd035d1991e97dfd94cc5c9b936c94aed2d3bc4 Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Mon, 16 Nov 2015 12:18:25 -0700 Subject: [PATCH 158/203] Support for backend snapshots with XenServer --- .../agent/api/StartupRoutingCommand.java | 10 +- .../api/storage/ResizeVolumeCommand.java | 37 +- .../storage/resource/StorageProcessor.java | 3 + .../StorageSubsystemCommandHandlerBase.java | 3 + .../storage/command/ResignatureAnswer.java | 60 + .../storage/command/ResignatureCommand.java | 48 + .../storage/to/PrimaryDataStoreTO.java | 1 + .../api/storage/DataStoreCapabilities.java | 18 +- .../api/storage/PrimaryDataStore.java | 2 + .../api/storage/PrimaryDataStoreDriver.java | 35 +- .../api/storage/PrimaryDataStoreInfo.java | 1 + .../api/storage/TemplateService.java | 3 + .../subsystem/api/storage/VolumeService.java | 4 +- .../src/com/cloud/vm/VmWorkResizeVolume.java | 9 +- .../orchestration/VolumeOrchestrator.java | 12 +- .../src/com/cloud/dc/dao/ClusterDao.java | 2 + .../src/com/cloud/dc/dao/ClusterDaoImpl.java | 42 +- .../src/com/cloud/host/dao/HostDao.java | 3 + .../src/com/cloud/host/dao/HostDaoImpl.java | 33 + .../com/cloud/host/dao/HostDetailsDao.java | 2 + .../cloud/host/dao/HostDetailsDaoImpl.java | 30 + .../storage/dao/VMTemplatePoolDaoImpl.java | 4 +- .../StorageSystemDataMotionStrategy.java | 687 ++++++++--- .../storage/image/TemplateServiceImpl.java | 19 + .../storage/image/store/TemplateObject.java | 65 +- .../test/FakePrimaryDataStoreDriver.java | 27 +- .../StorageSystemSnapshotStrategy.java | 213 +++- .../snapshot/XenserverSnapshotStrategy.java | 4 +- .../AbstractStoragePoolAllocator.java | 2 +- engine/storage/volume/pom.xml | 5 + .../datastore/PrimaryDataStoreImpl.java | 30 +- .../storage/volume/VolumeServiceImpl.java | 431 ++++++- plugins/api/solidfire-intg-test/pom.xml | 2 +- .../spring-solidfire-intg-test-context.xml | 4 +- .../admin/solidfire/GetPathForVolumeCmd.java | 67 ++ .../solidfire/GetSolidFireAccountIdCmd.java | 41 +- .../GetSolidFireVolumeAccessGroupIdCmd.java | 29 +- .../solidfire/GetSolidFireVolumeSizeCmd.java | 42 +- .../GetVolumeSnapshotDetailsCmd.java | 73 ++ .../solidfire/GetVolumeiScsiNameCmd.java} | 40 +- .../solidfire/ApiPathForVolumeResponse.java | 33 + .../ApiSolidFireAccountIdResponse.java | 6 +- ...iSolidFireVolumeAccessGroupIdResponse.java | 6 +- .../ApiSolidFireVolumeSizeResponse.java | 6 +- .../ApiVolumeSnapshotDetailsResponse.java | 43 + .../ApiVolumeiScsiNameResponse.java} | 20 +- .../ApiSolidFireIntegrationTestService.java | 22 + ...piSolidFireIntegrationTestServiceImpl.java | 48 + .../solidfire/ApiSolidFireService.java | 37 - .../solidfire/ApiSolidFireServiceImpl.java | 126 -- .../SolidFireIntegrationTestManager.java | 23 + .../SolidFireIntegrationTestManagerImpl.java | 78 ++ .../SolidFireIntegrationTestUtil.java | 112 ++ .../kvm/storage/KVMStorageProcessor.java | 9 + .../ovm3/resources/Ovm3StorageProcessor.java | 16 +- .../resource/SimulatorStorageProcessor.java | 9 + .../resource/VmwareStorageProcessor.java | 9 + .../resource/CitrixResourceBase.java | 119 +- .../resource/XenServerStorageProcessor.java | 61 +- .../Xenserver625StorageProcessor.java | 14 +- .../CitrixResizeVolumeCommandWrapper.java | 70 +- .../xenbase/CitrixStartCommandWrapper.java | 4 +- .../ElastistorPrimaryDataStoreDriver.java | 8 +- .../CloudStackPrimaryDataStoreDriverImpl.java | 13 +- .../driver/NexentaPrimaryDataStoreDriver.java | 13 +- .../SamplePrimaryDataStoreDriverImpl.java | 17 +- .../SolidFirePrimaryDataStoreDriver.java | 1022 +++++++++++++---- .../SolidFirePrimaryDataStoreLifeCycle.java | 67 +- .../provider/SolidFireSharedHostListener.java | 64 +- .../storage/datastore/util/SolidFireUtil.java | 508 ++++---- .../cloud/capacity/CapacityManagerImpl.java | 25 +- .../deploy/DeploymentPlanningManagerImpl.java | 3 +- .../CloudZonesStartupProcessor.java | 23 + .../cloud/resource/ResourceManagerImpl.java | 24 + .../cloud/storage/ResizeVolumePayload.java | 7 +- .../src/com/cloud/storage/StorageManager.java | 24 + .../com/cloud/storage/StorageManagerImpl.java | 75 +- .../cloud/storage/VolumeApiServiceImpl.java | 64 +- .../storage/snapshot/SnapshotManagerImpl.java | 32 +- .../cloud/template/TemplateManagerImpl.java | 52 +- ui/scripts/storage.js | 2 + .../src/main/java/com/cloud/utils/Utils.java | 38 + 82 files changed, 3888 insertions(+), 1207 deletions(-) create mode 100644 core/src/org/apache/cloudstack/storage/command/ResignatureAnswer.java create mode 100644 core/src/org/apache/cloudstack/storage/command/ResignatureCommand.java create mode 100644 plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetPathForVolumeCmd.java rename plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/{user => admin}/solidfire/GetSolidFireAccountIdCmd.java (60%) rename plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/{user => admin}/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java (70%) rename plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/{user => admin}/solidfire/GetSolidFireVolumeSizeCmd.java (57%) create mode 100644 plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeSnapshotDetailsCmd.java rename plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/{user/solidfire/GetSolidFireVolumeIscsiNameCmd.java => admin/solidfire/GetVolumeiScsiNameCmd.java} (55%) create mode 100644 plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiPathForVolumeResponse.java rename plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/{ => solidfire}/ApiSolidFireAccountIdResponse.java (90%) rename plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/{ => solidfire}/ApiSolidFireVolumeAccessGroupIdResponse.java (90%) rename plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/{ => solidfire}/ApiSolidFireVolumeSizeResponse.java (90%) create mode 100644 plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeSnapshotDetailsResponse.java rename plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/{ApiSolidFireVolumeIscsiNameResponse.java => solidfire/ApiVolumeiScsiNameResponse.java} (65%) create mode 100644 plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestService.java create mode 100644 plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestServiceImpl.java delete mode 100644 plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireService.java delete mode 100644 plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireServiceImpl.java create mode 100644 plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.java create mode 100644 plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManagerImpl.java create mode 100644 plugins/api/solidfire-intg-test/src/org/apache/cloudstack/util/solidfire/SolidFireIntegrationTestUtil.java create mode 100644 utils/src/main/java/com/cloud/utils/Utils.java diff --git a/core/src/com/cloud/agent/api/StartupRoutingCommand.java b/core/src/com/cloud/agent/api/StartupRoutingCommand.java index c4138367b7..b459f88496 100644 --- a/core/src/com/cloud/agent/api/StartupRoutingCommand.java +++ b/core/src/com/cloud/agent/api/StartupRoutingCommand.java @@ -35,7 +35,7 @@ public class StartupRoutingCommand extends StartupCommand { long memory; long dom0MinMemory; boolean poolSync; - + private boolean supportsClonedVolumes; String caps; String pool; @@ -180,4 +180,12 @@ public HashMap> getGpuGroupDetails() { public void setGpuGroupDetails(HashMap> groupDetails) { this.groupDetails = groupDetails; } + + public boolean getSupportsClonedVolumes() { + return supportsClonedVolumes; + } + + public void setSupportsClonedVolumes(boolean supportsClonedVolumes) { + this.supportsClonedVolumes = supportsClonedVolumes; + } } diff --git a/core/src/com/cloud/agent/api/storage/ResizeVolumeCommand.java b/core/src/com/cloud/agent/api/storage/ResizeVolumeCommand.java index 3b121e1a54..22cff13de2 100644 --- a/core/src/com/cloud/agent/api/storage/ResizeVolumeCommand.java +++ b/core/src/com/cloud/agent/api/storage/ResizeVolumeCommand.java @@ -25,22 +25,34 @@ public class ResizeVolumeCommand extends Command { private String path; private StorageFilerTO pool; - private String vmInstance; - private Long newSize; private Long currentSize; + private Long newSize; private boolean shrinkOk; + private String vmInstance; - protected ResizeVolumeCommand() { + /* For managed storage */ + private boolean managed; + private String iScsiName; + protected ResizeVolumeCommand() { } public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance) { this.path = path; this.pool = pool; - this.vmInstance = vmInstance; this.currentSize = currentSize; this.newSize = newSize; this.shrinkOk = shrinkOk; + this.vmInstance = vmInstance; + this.managed = false; + } + + public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance, + boolean isManaged, String iScsiName) { + this(path, pool, currentSize, newSize, shrinkOk, vmInstance); + + this.iScsiName = iScsiName; + this.managed = isManaged; } public String getPath() { @@ -55,22 +67,20 @@ public StorageFilerTO getPool() { return pool; } - public long getNewSize() { - return newSize; - } + public long getCurrentSize() { return currentSize; } - public long getCurrentSize() { - return currentSize; - } + public long getNewSize() { return newSize; } - public boolean getShrinkOk() { - return shrinkOk; - } + public boolean getShrinkOk() { return shrinkOk; } public String getInstanceName() { return vmInstance; } + public boolean isManaged() { return managed; } + + public String get_iScsiName() {return iScsiName; } + /** * {@inheritDoc} */ @@ -78,5 +88,4 @@ public String getInstanceName() { public boolean executeInSequence() { return false; } - } diff --git a/core/src/com/cloud/storage/resource/StorageProcessor.java b/core/src/com/cloud/storage/resource/StorageProcessor.java index e2bf1b7877..e5832cc23d 100644 --- a/core/src/com/cloud/storage/resource/StorageProcessor.java +++ b/core/src/com/cloud/storage/resource/StorageProcessor.java @@ -26,6 +26,7 @@ import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import com.cloud.agent.api.Answer; @@ -68,4 +69,6 @@ public interface StorageProcessor { public Answer forgetObject(ForgetObjectCmd cmd); public Answer snapshotAndCopy(SnapshotAndCopyCommand cmd); + + public Answer resignature(ResignatureCommand cmd); } diff --git a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java index fc771e0ff5..d9d2993dba 100644 --- a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java +++ b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java @@ -28,6 +28,7 @@ import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; @@ -64,6 +65,8 @@ public Answer handleStorageCommands(StorageSubSystemCommand command) { return processor.introduceObject((IntroduceObjectCmd)command); } else if (command instanceof SnapshotAndCopyCommand) { return processor.snapshotAndCopy((SnapshotAndCopyCommand)command); + } else if (command instanceof ResignatureCommand) { + return processor.resignature((ResignatureCommand)command); } return new Answer((Command)command, false, "not implemented yet"); diff --git a/core/src/org/apache/cloudstack/storage/command/ResignatureAnswer.java b/core/src/org/apache/cloudstack/storage/command/ResignatureAnswer.java new file mode 100644 index 0000000000..071f6a9cf1 --- /dev/null +++ b/core/src/org/apache/cloudstack/storage/command/ResignatureAnswer.java @@ -0,0 +1,60 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package org.apache.cloudstack.storage.command; + +import com.cloud.agent.api.Answer; +import com.cloud.storage.Storage.ImageFormat; + +public class ResignatureAnswer extends Answer { + private long size; + private String path; + private ImageFormat format; + + public ResignatureAnswer() { + } + + public ResignatureAnswer(String errMsg) { + super(null, false, errMsg); + } + + public void setSize(long size) { + this.size = size; + } + + public long getSize() { + return size; + } + + public void setPath(String path) { + this.path = path; + } + + public String getPath() { + return path; + } + + public void setFormat(ImageFormat format) { + this.format = format; + } + + public ImageFormat getFormat() { + return format; + } +} diff --git a/core/src/org/apache/cloudstack/storage/command/ResignatureCommand.java b/core/src/org/apache/cloudstack/storage/command/ResignatureCommand.java new file mode 100644 index 0000000000..beb4b65748 --- /dev/null +++ b/core/src/org/apache/cloudstack/storage/command/ResignatureCommand.java @@ -0,0 +1,48 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package org.apache.cloudstack.storage.command; + +import com.cloud.utils.Utils; + +import java.util.Map; + +public final class ResignatureCommand extends StorageSubSystemCommand { + private final Map details; + + private boolean executeInSequence = true; + + public ResignatureCommand(final Map details) { + this.details = Utils.getImmutableMap(details); + } + + public Map getDetails() { + return details; + } + + @Override + public void setExecuteInSequence(final boolean executeInSequence) { + this.executeInSequence = executeInSequence; + } + + @Override + public boolean executeInSequence() { + return executeInSequence; + } +} diff --git a/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java b/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java index a69f35706d..9b711bc3b3 100644 --- a/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java +++ b/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java @@ -37,6 +37,7 @@ public class PrimaryDataStoreTO implements DataStoreTO { public static final String CHAP_INITIATOR_SECRET = PrimaryDataStore.CHAP_INITIATOR_SECRET; public static final String CHAP_TARGET_USERNAME = PrimaryDataStore.CHAP_TARGET_USERNAME; public static final String CHAP_TARGET_SECRET = PrimaryDataStore.CHAP_TARGET_SECRET; + public static final String REMOVE_AFTER_COPY = PrimaryDataStore.REMOVE_AFTER_COPY; public static final String VOLUME_SIZE = PrimaryDataStore.VOLUME_SIZE; private final String uuid; diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreCapabilities.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreCapabilities.java index 09883c66ce..2cde5bdc15 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreCapabilities.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreCapabilities.java @@ -18,7 +18,23 @@ */ package org.apache.cloudstack.engine.subsystem.api.storage; +/** + * enumerates different capabilities storage drivers may have + */ public enum DataStoreCapabilities { VOLUME_SNAPSHOT_QUIESCEVM, - STORAGE_SYSTEM_SNAPSHOT // indicates to the StorageSystemSnapshotStrategy that this driver takes snapshots on its own system + /** + * indicates that this driver takes CloudStack volume snapshots on its own system (as either back-end snapshots or back-end clones) + */ + STORAGE_SYSTEM_SNAPSHOT, + /** + * indicates that this driver supports the "cloneOfSnapshot" property of cloud.snapshot_details (for creating a back-end volume + * from a back-end snapshot or a back-end clone) and that it supports the invocation of the createAsync method where a SnapshotInfo is passed in while using + * the "tempVolume" property of snapshot_details + */ + CAN_CREATE_VOLUME_FROM_SNAPSHOT, + /** + * indicates that this driver supports the "cloneOfSnapshot" property of cloud.snapshot_details (for creating a volume from a volume) + */ + CAN_CREATE_VOLUME_FROM_VOLUME } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStore.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStore.java index 465b7eb243..a399758217 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStore.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStore.java @@ -23,6 +23,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; public interface PrimaryDataStore extends DataStore, PrimaryDataStoreInfo { + DataObject create(DataObject dataObject, boolean createEntryInTempSpoolRef); + VolumeInfo getVolume(long id); List getVolumes(); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java index e0c0d28e9d..6dcdf4f0c7 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java @@ -23,27 +23,38 @@ import com.cloud.host.Host; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; public interface PrimaryDataStoreDriver extends DataStoreDriver { - ChapInfo getChapInfo(VolumeInfo volumeInfo); + ChapInfo getChapInfo(DataObject dataObject); boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore); void revokeAccess(DataObject dataObject, Host host, DataStore dataStore); - // intended for managed storage (cloud.storage_pool.managed = true) - // if not managed, return volume.getSize() - long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool storagePool); - - // intended for managed storage (cloud.storage_pool.managed = true) - // if managed storage, return the total number of bytes currently in use for the storage pool in question - // if not managed storage, return 0 + /** + * intended for managed storage (cloud.storage_pool.managed = true) + * if not managed, return volume.getSize() + */ + long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool storagePool); + + /** + * intended for zone-wide primary storage that is capable of storing a template once and using it in multiple clusters + * if not this kind of storage, return 0 + */ + long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool); + + /** + * intended for managed storage (cloud.storage_pool.managed = true) + * if managed storage, return the total number of bytes currently in use for the storage pool in question + * if not managed storage, return 0 + */ long getUsedBytes(StoragePool storagePool); - // intended for managed storage (cloud.storage_pool.managed = true) - // if managed storage, return the total number of IOPS currently in use for the storage pool in question - // if not managed storage, return 0 + /** + * intended for managed storage (cloud.storage_pool.managed = true) + * if managed storage, return the total number of IOPS currently in use for the storage pool in question + * if not managed storage, return 0 + */ long getUsedIops(StoragePool storagePool); void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java index f08d9a4550..7f2f4dc6b8 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java @@ -36,6 +36,7 @@ public interface PrimaryDataStoreInfo extends StoragePool { static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret"; static final String CHAP_TARGET_USERNAME = "chapTargetUsername"; static final String CHAP_TARGET_SECRET = "chapTargetSecret"; + static final String REMOVE_AFTER_COPY = "removeAfterCopy"; static final String VOLUME_SIZE = "volumeSize"; boolean isHypervisorSupported(HypervisorType hypervisor); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java index 88ce932b26..ff204c663c 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java @@ -32,6 +32,7 @@ class TemplateApiResult extends CommandResult { public TemplateApiResult(TemplateInfo template) { super(); + this.template = template; } @@ -52,6 +53,8 @@ public TemplateInfo getTemplate() { AsyncCallFuture prepareTemplateOnPrimary(TemplateInfo srcTemplate, StoragePool pool); + AsyncCallFuture deleteTemplateOnPrimary(TemplateInfo template, StoragePool pool); + void syncTemplateToRegionStore(long templateId, DataStore store); void handleSysTemplateDownload(HypervisorType hostHyper, Long dcId); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java index 8352682ee6..75a7ad96c4 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java @@ -45,7 +45,7 @@ public VolumeInfo getVolume() { } } - ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore); + ChapInfo getChapInfo(DataObject dataObject, DataStore dataStore); boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore); @@ -81,7 +81,7 @@ public VolumeInfo getVolume() { VolumeEntity getVolumeEntity(long volumeId); - AsyncCallFuture createManagedStorageAndVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId, + AsyncCallFuture createManagedStorageVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId, TemplateInfo srcTemplateInfo, long destHostId); AsyncCallFuture createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, diff --git a/engine/components-api/src/com/cloud/vm/VmWorkResizeVolume.java b/engine/components-api/src/com/cloud/vm/VmWorkResizeVolume.java index d269112961..de049b3f0b 100644 --- a/engine/components-api/src/com/cloud/vm/VmWorkResizeVolume.java +++ b/engine/components-api/src/com/cloud/vm/VmWorkResizeVolume.java @@ -24,12 +24,12 @@ public class VmWorkResizeVolume extends VmWork { private long newSize; private Long newMinIops; private Long newMaxIops; + private Integer newHypervisorSnapshotReserve; private Long newServiceOfferingId; private boolean shrinkOk; - public VmWorkResizeVolume(long userId, long accountId, long vmId, String handlerName, - long volumeId, long currentSize, long newSize, Long newMinIops, Long newMaxIops, Long newServiceOfferingId, boolean shrinkOk) { - + public VmWorkResizeVolume(long userId, long accountId, long vmId, String handlerName, long volumeId, long currentSize, long newSize, + Long newMinIops, Long newMaxIops, Integer newHypervisorSnapshotReserve, Long newServiceOfferingId, boolean shrinkOk) { super(userId, accountId, vmId, handlerName); this.volumeId = volumeId; @@ -37,6 +37,7 @@ public VmWorkResizeVolume(long userId, long accountId, long vmId, String handler this.newSize = newSize; this.newMinIops = newMinIops; this.newMaxIops = newMaxIops; + this.newHypervisorSnapshotReserve = newHypervisorSnapshotReserve; this.newServiceOfferingId = newServiceOfferingId; this.shrinkOk = shrinkOk; } @@ -68,4 +69,6 @@ public Long getNewServiceOfferingId() { public boolean isShrinkOk() { return shrinkOk; } + + public Integer getNewHypervisorSnapshotReserve() { return newHypervisorSnapshotReserve; } } diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index d407bb1aff..166210aa31 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -1242,10 +1242,11 @@ private Pair recreateVolume(VolumeVO vol, VirtualMachinePro future = volService.createVolumeAsync(volume, destPool); } else { - TemplateInfo templ = tmplFactory.getReadyTemplateOnImageStore(templateId, dest.getDataCenter().getId()); + if (templ == null) { s_logger.debug("can't find ready template: " + templateId + " for data center " + dest.getDataCenter().getId()); + throw new CloudRuntimeException("can't find ready template: " + templateId + " for data center " + dest.getDataCenter().getId()); } @@ -1260,13 +1261,13 @@ private Pair recreateVolume(VolumeVO vol, VirtualMachinePro long hostId = vm.getVirtualMachine().getHostId(); - future = volService.createManagedStorageAndVolumeFromTemplateAsync(volume, destPool.getId(), templ, hostId); + future = volService.createManagedStorageVolumeFromTemplateAsync(volume, destPool.getId(), templ, hostId); } else { future = volService.createVolumeFromTemplateAsync(volume, destPool.getId(), templ); } } - VolumeApiResult result = null; + VolumeApiResult result; try { result = future.get(); if (result.isFailed()) { @@ -1290,10 +1291,7 @@ private Pair recreateVolume(VolumeVO vol, VirtualMachinePro newVol = _volsDao.findById(newVol.getId()); break; //break out of template-redeploy retry loop - } catch (InterruptedException e) { - s_logger.error("Unable to create " + newVol, e); - throw new StorageUnavailableException("Unable to create " + newVol + ":" + e.toString(), destPool.getId()); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { s_logger.error("Unable to create " + newVol, e); throw new StorageUnavailableException("Unable to create " + newVol + ":" + e.toString(), destPool.getId()); } diff --git a/engine/schema/src/com/cloud/dc/dao/ClusterDao.java b/engine/schema/src/com/cloud/dc/dao/ClusterDao.java index 50c234c915..8e028226d8 100644 --- a/engine/schema/src/com/cloud/dc/dao/ClusterDao.java +++ b/engine/schema/src/com/cloud/dc/dao/ClusterDao.java @@ -45,4 +45,6 @@ public interface ClusterDao extends GenericDao { List listClustersByDcId(long zoneId); List listAllCusters(long zoneId); + + boolean computeWhetherClusterSupportsResigning(long clusterId); } diff --git a/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java index 3459e514b7..aa0b21b49b 100644 --- a/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java +++ b/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java @@ -30,6 +30,9 @@ import com.cloud.dc.ClusterVO; import com.cloud.dc.HostPodVO; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.org.Grouping; import com.cloud.utils.db.GenericDaoBase; @@ -57,7 +60,11 @@ public class ClusterDaoImpl extends GenericDaoBase implements C private static final String GET_POD_CLUSTER_MAP_PREFIX = "SELECT pod_id, id FROM cloud.cluster WHERE cluster.id IN( "; private static final String GET_POD_CLUSTER_MAP_SUFFIX = " )"; @Inject - protected HostPodDao _hostPodDao; + private HostDao hostDao; + @Inject + private HostDetailsDao hostDetailsDao; + @Inject + protected HostPodDao hostPodDao; public ClusterDaoImpl() { super(); @@ -214,7 +221,7 @@ public List listDisabledClusters(long zoneId, Long podId) { @Override public List listClustersWithDisabledPods(long zoneId) { - GenericSearchBuilder disabledPodIdSearch = _hostPodDao.createSearchBuilder(Long.class); + GenericSearchBuilder disabledPodIdSearch = hostPodDao.createSearchBuilder(Long.class); disabledPodIdSearch.selectFields(disabledPodIdSearch.entity().getId()); disabledPodIdSearch.and("dataCenterId", disabledPodIdSearch.entity().getDataCenterId(), Op.EQ); disabledPodIdSearch.and("allocationState", disabledPodIdSearch.entity().getAllocationState(), Op.EQ); @@ -260,4 +267,35 @@ public List listAllCusters(long zoneId) { sc.setParameters("dataCenterId", zoneId); return customSearch(sc, null); } + + @Override + public boolean computeWhetherClusterSupportsResigning(long clusterId) { + ClusterVO cluster = findById(clusterId); + + if (cluster == null || cluster.getAllocationState() != Grouping.AllocationState.Enabled) { + return false; + } + + List hosts = hostDao.findByClusterId(clusterId); + + if (hosts == null) { + return false; + } + + Map mapSupportsResign = hostDetailsDao.findDetails("supportsResign"); + + for (HostVO host : hosts) { + if (host == null) { + return false; + } + + String value = mapSupportsResign.get(host.getId()); + + if (Boolean.parseBoolean(value) == false) { + return false; + } + } + + return true; + } } diff --git a/engine/schema/src/com/cloud/host/dao/HostDao.java b/engine/schema/src/com/cloud/host/dao/HostDao.java index 26e0644c59..3cfdc94af8 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDao.java +++ b/engine/schema/src/com/cloud/host/dao/HostDao.java @@ -23,6 +23,7 @@ import com.cloud.host.Host.Type; import com.cloud.host.HostVO; import com.cloud.host.Status; +import com.cloud.hypervisor.Hypervisor; import com.cloud.info.RunningHostCountInfo; import com.cloud.resource.ResourceState; import com.cloud.utils.db.GenericDao; @@ -89,6 +90,8 @@ public interface HostDao extends GenericDao, StateDao listByDataCenterId(long id); + List listByDataCenterIdAndHypervisorType(long zoneId, Hypervisor.HypervisorType hypervisorType); + List listAllHosts(long zoneId); List listAllHostsByType(Host.Type type); diff --git a/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java b/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java index 09d9d40cd5..54133b90d0 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java +++ b/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java @@ -47,7 +47,9 @@ import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.Status.Event; +import com.cloud.hypervisor.Hypervisor; import com.cloud.info.RunningHostCountInfo; +import com.cloud.org.Grouping; import com.cloud.org.Managed; import com.cloud.resource.ResourceState; import com.cloud.utils.DateUtil; @@ -421,6 +423,37 @@ public List listByDataCenterId(long id) { return listBy(sc); } + @Override + public List listByDataCenterIdAndHypervisorType(long zoneId, Hypervisor.HypervisorType hypervisorType) { + SearchBuilder clusterSearch = _clusterDao.createSearchBuilder(); + + clusterSearch.and("allocationState", clusterSearch.entity().getAllocationState(), SearchCriteria.Op.EQ); + clusterSearch.and("hypervisorType", clusterSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ); + + SearchBuilder hostSearch = createSearchBuilder(); + + hostSearch.and("dc", hostSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); + hostSearch.and("type", hostSearch.entity().getType(), Op.EQ); + hostSearch.and("status", hostSearch.entity().getStatus(), Op.EQ); + hostSearch.and("resourceState", hostSearch.entity().getResourceState(), Op.EQ); + + hostSearch.join("clusterSearch", clusterSearch, hostSearch.entity().getClusterId(), clusterSearch.entity().getId(), JoinBuilder.JoinType.INNER); + + hostSearch.done(); + + SearchCriteria sc = hostSearch.create(); + + sc.setParameters("dc", zoneId); + sc.setParameters("type", Host.Type.Routing); + sc.setParameters("status", Status.Up); + sc.setParameters("resourceState", ResourceState.Enabled); + + sc.setJoinParameters("clusterSearch", "allocationState", Grouping.AllocationState.Enabled); + sc.setJoinParameters("clusterSearch", "hypervisorType", hypervisorType.toString()); + + return listBy(sc); + } + @Override public HostVO findByGuid(String guid) { SearchCriteria sc = GuidSearch.create("guid", guid); diff --git a/engine/schema/src/com/cloud/host/dao/HostDetailsDao.java b/engine/schema/src/com/cloud/host/dao/HostDetailsDao.java index 7f1a6185e6..77e45dd2f4 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDetailsDao.java +++ b/engine/schema/src/com/cloud/host/dao/HostDetailsDao.java @@ -24,6 +24,8 @@ public interface HostDetailsDao extends GenericDao { Map findDetails(long hostId); + Map findDetails(String name); + void persist(long hostId, Map details); DetailVO findDetail(long hostId, String name); diff --git a/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java b/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java index 6a8ff56364..525ee9afb5 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java +++ b/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java @@ -37,6 +37,7 @@ public class HostDetailsDaoImpl extends GenericDaoBase implements HostDetailsDao { protected final SearchBuilder HostSearch; protected final SearchBuilder DetailSearch; + protected final SearchBuilder NameSearch; public HostDetailsDaoImpl() { HostSearch = createSearchBuilder(); @@ -47,6 +48,10 @@ public HostDetailsDaoImpl() { DetailSearch.and("hostId", DetailSearch.entity().getHostId(), SearchCriteria.Op.EQ); DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ); DetailSearch.done(); + + NameSearch = createSearchBuilder(); + NameSearch.and("name", NameSearch.entity().getName(), SearchCriteria.Op.EQ); + NameSearch.done(); } @Override @@ -65,10 +70,13 @@ public DetailVO findDetail(long hostId, String name) { @Override public Map findDetails(long hostId) { SearchCriteria sc = HostSearch.create(); + sc.setParameters("hostId", hostId); List results = search(sc, null); + Map details = new HashMap(results.size()); + for (DetailVO result : results) { if ("password".equals(result.getName())) { details.put(result.getName(), DBEncryptionUtil.decrypt(result.getValue())); @@ -76,6 +84,28 @@ public Map findDetails(long hostId) { details.put(result.getName(), result.getValue()); } } + + return details; + } + + @Override + public Map findDetails(String name) { + SearchCriteria sc = NameSearch.create(); + + sc.setParameters("name", name); + + List results = search(sc, null); + + Map details = new HashMap<>(results.size()); + + for (DetailVO result : results) { + if ("password".equals(result.getName())) { + details.put(result.getHostId(), DBEncryptionUtil.decrypt(result.getValue())); + } else { + details.put(result.getHostId(), result.getValue()); + } + } + return details; } diff --git a/engine/schema/src/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java index 770e673e88..93aad15337 100644 --- a/engine/schema/src/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java +++ b/engine/schema/src/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java @@ -118,9 +118,9 @@ public List listByTemplateId(long templateId) { } @Override - public VMTemplateStoragePoolVO findByPoolTemplate(long hostId, long templateId) { + public VMTemplateStoragePoolVO findByPoolTemplate(long poolId, long templateId) { SearchCriteria sc = PoolTemplateSearch.create(); - sc.setParameters("pool_id", hostId); + sc.setParameters("pool_id", poolId); sc.setParameters("template_id", templateId); return findOneIncludingRemovedBy(sc); } diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java index cdcab754e9..adb1720540 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java @@ -18,18 +18,27 @@ */ package org.apache.cloudstack.storage.motion; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; +import java.util.concurrent.ExecutionException; import javax.inject.Inject; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.OperationTimedoutException; + import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; @@ -43,8 +52,12 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; +import org.apache.cloudstack.storage.command.ResignatureAnswer; +import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -55,65 +68,98 @@ import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; +import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.org.Cluster; -import com.cloud.org.Grouping.AllocationState; -import com.cloud.resource.ResourceState; import com.cloud.server.ManagementService; import com.cloud.storage.DataStoreRole; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.SnapshotVO; import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.VolumeDetailVO; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.SnapshotDetailsDao; import com.cloud.storage.dao.SnapshotDetailsVO; import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeDetailsDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachineManager; +import com.google.common.base.Preconditions; + @Component public class StorageSystemDataMotionStrategy implements DataMotionStrategy { - private static final Logger s_logger = Logger.getLogger(StorageSystemDataMotionStrategy.class); + private static final Logger LOGGER = Logger.getLogger(StorageSystemDataMotionStrategy.class); + private static final Random RANDOM = new Random(System.nanoTime()); @Inject private AgentManager _agentMgr; @Inject private ConfigurationDao _configDao; + @Inject private DataStoreManager dataStoreMgr; @Inject private DiskOfferingDao _diskOfferingDao; + @Inject private ClusterDao clusterDao; @Inject private HostDao _hostDao; + @Inject private HostDetailsDao hostDetailsDao; @Inject private ManagementService _mgr; @Inject private PrimaryDataStoreDao _storagePoolDao; @Inject private SnapshotDao _snapshotDao; @Inject private SnapshotDetailsDao _snapshotDetailsDao; @Inject private VolumeDao _volumeDao; @Inject private VolumeDataFactory _volumeDataFactory; + @Inject private VolumeDetailsDao volumeDetailsDao; @Inject private VolumeService _volumeService; @Override public StrategyPriority canHandle(DataObject srcData, DataObject destData) { if (srcData instanceof SnapshotInfo) { - if (canHandle(srcData.getDataStore()) || canHandle(destData.getDataStore())) { + if (canHandle(srcData) || canHandle(destData)) { return StrategyPriority.HIGHEST; } } + if (srcData instanceof TemplateInfo && destData instanceof VolumeInfo && + (srcData.getDataStore().getId() == destData.getDataStore().getId()) && + (canHandle(srcData) || canHandle(destData))) { + // Both source and dest are on the same storage, so just clone them. + return StrategyPriority.HIGHEST; + } + return StrategyPriority.CANT_HANDLE; } - private boolean canHandle(DataStore dataStore) { + private boolean canHandle(DataObject dataObject) { + Preconditions.checkArgument(dataObject != null, "Passing 'null' to dataObject of canHandle(DataObject) is not supported."); + + DataStore dataStore = dataObject.getDataStore(); + if (dataStore.getRole() == DataStoreRole.Primary) { Map mapCapabilities = dataStore.getDriver().getCapabilities(); - if (mapCapabilities != null) { + if (mapCapabilities == null) { + return false; + } + + if (dataObject instanceof VolumeInfo || dataObject instanceof SnapshotInfo) { String value = mapCapabilities.get(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString()); - Boolean supportsStorageSystemSnapshots = new Boolean(value); + Boolean supportsStorageSystemSnapshots = Boolean.valueOf(value); if (supportsStorageSystemSnapshots) { - s_logger.info("Using 'StorageSystemDataMotionStrategy'"); + LOGGER.info("Using 'StorageSystemDataMotionStrategy' (dataObject is a volume or snapshot and the storage system supports snapshots)"); + + return true; + } + } else if (dataObject instanceof TemplateInfo) { + // If the storage system can clone volumes, we can cache templates on it. + String value = mapCapabilities.get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString()); + Boolean canCloneVolume = Boolean.valueOf(value); + + if (canCloneVolume) { + LOGGER.info("Using 'StorageSystemDataMotionStrategy' (dataObject is a template and the storage system can create a volume from a volume)"); return true; } + } } @@ -132,36 +178,92 @@ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, As validate(snapshotInfo); - boolean canHandleSrc = canHandle(srcData.getDataStore()); + boolean canHandleSrc = canHandle(srcData); if (canHandleSrc && destData instanceof TemplateInfo && (destData.getDataStore().getRole() == DataStoreRole.Image || destData.getDataStore().getRole() == DataStoreRole.ImageCache)) { handleCreateTemplateFromSnapshot(snapshotInfo, (TemplateInfo)destData, callback); + return; } if (destData instanceof VolumeInfo) { VolumeInfo volumeInfo = (VolumeInfo)destData; - boolean canHandleDest = canHandle(destData.getDataStore()); + + boolean canHandleDest = canHandle(destData); if (canHandleSrc && canHandleDest) { - handleCreateVolumeFromSnapshotBothOnStorageSystem(snapshotInfo, volumeInfo, callback); - return; + if (snapshotInfo.getDataStore().getId() == volumeInfo.getDataStore().getId()) { + handleCreateVolumeFromSnapshotBothOnStorageSystem(snapshotInfo, volumeInfo, callback); + return; + } + else { + String errMsg = "This operation is not supported (DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " + + "not supported by source or destination storage plug-in). " + getSrcDestDataStoreMsg(srcData, destData); + + LOGGER.warn(errMsg); + + throw new UnsupportedOperationException(errMsg); + } } + if (canHandleSrc) { - throw new UnsupportedOperationException("This operation is not supported (DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " + - "not supported by destination storage plug-in)."); + String errMsg = "This operation is not supported (DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " + + "not supported by destination storage plug-in). " + getDestDataStoreMsg(destData); + + LOGGER.warn(errMsg); + + throw new UnsupportedOperationException(errMsg); } + if (canHandleDest) { - throw new UnsupportedOperationException("This operation is not supported (DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " + - "not supported by source storage plug-in)."); + String errMsg = "This operation is not supported (DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " + + "not supported by source storage plug-in). " + getSrcDataStoreMsg(srcData); + + LOGGER.warn(errMsg); + + throw new UnsupportedOperationException(errMsg); } } + } else if (srcData instanceof TemplateInfo && destData instanceof VolumeInfo) { + boolean canHandleSrc = canHandle(srcData); + + if (!canHandleSrc) { + String errMsg = "This operation is not supported (DataStoreCapabilities.STORAGE_CAN_CREATE_VOLUME_FROM_VOLUME " + + "not supported by destination storage plug-in). " + getDestDataStoreMsg(destData); + + LOGGER.warn(errMsg); + + throw new UnsupportedOperationException(errMsg); + } + + handleCreateVolumeFromTemplateBothOnStorageSystem((TemplateInfo)srcData, (VolumeInfo)destData, callback); + + return; } throw new UnsupportedOperationException("This operation is not supported."); } + private String getSrcDestDataStoreMsg(DataObject srcData, DataObject destData) { + Preconditions.checkArgument(srcData != null, "Passing 'null' to srcData of getSrcDestDataStoreMsg(DataObject, DataObject) is not supported."); + Preconditions.checkArgument(destData != null, "Passing 'null' to destData of getSrcDestDataStoreMsg(DataObject, DataObject) is not supported."); + + return "Source data store = " + srcData.getDataStore().getName() + "; " + "Destination data store = " + destData.getDataStore().getName() + "."; + } + + private String getSrcDataStoreMsg(DataObject srcData) { + Preconditions.checkArgument(srcData != null, "Passing 'null' to srcData of getSrcDataStoreMsg(DataObject) is not supported."); + + return "Source data store = " + srcData.getDataStore().getName() + "."; + } + + private String getDestDataStoreMsg(DataObject destData) { + Preconditions.checkArgument(destData != null, "Passing 'null' to destData of getDestDataStoreMsg(DataObject) is not supported."); + + return "Destination data store = " + destData.getDataStore().getName() + "."; + } + private void validate(SnapshotInfo snapshotInfo) { long volumeId = snapshotInfo.getVolumeId(); @@ -172,7 +274,13 @@ private void validate(SnapshotInfo snapshotInfo) { } } - private Void handleCreateTemplateFromSnapshot(SnapshotInfo snapshotInfo, TemplateInfo templateInfo, AsyncCompletionCallback callback) { + private boolean usingBackendSnapshotFor(SnapshotInfo snapshotInfo) { + String property = getProperty(snapshotInfo.getId(), "takeSnapshot"); + + return Boolean.parseBoolean(property); + } + + private void handleCreateTemplateFromSnapshot(SnapshotInfo snapshotInfo, TemplateInfo templateInfo, AsyncCompletionCallback callback) { try { snapshotInfo.processEvent(Event.CopyingRequested); } @@ -180,57 +288,168 @@ private Void handleCreateTemplateFromSnapshot(SnapshotInfo snapshotInfo, Templat throw new CloudRuntimeException("This snapshot is not currently in a state where it can be used to create a template."); } - HostVO hostVO = getHost(snapshotInfo.getDataStore().getId()); - DataStore srcDataStore = snapshotInfo.getDataStore(); + HostVO hostVO = getHost(snapshotInfo); - String value = _configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); - int primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); - CopyCommand copyCommand = new CopyCommand(snapshotInfo.getTO(), templateInfo.getTO(), primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); + boolean usingBackendSnapshot = usingBackendSnapshotFor(snapshotInfo); + boolean computeClusterSupportsResign = clusterDao.computeWhetherClusterSupportsResigning(hostVO.getClusterId()); - String errMsg = null; + if (usingBackendSnapshot && !computeClusterSupportsResign) { + String noSupportForResignErrMsg = "Unable to locate an applicable host with which to perform a resignature operation : Cluster ID = " + hostVO.getClusterId(); - CopyCmdAnswer copyCmdAnswer = null; + LOGGER.warn(noSupportForResignErrMsg); + + throw new CloudRuntimeException(noSupportForResignErrMsg); + } try { - _volumeService.grantAccess(snapshotInfo, hostVO, srcDataStore); + if (usingBackendSnapshot) { + createVolumeFromSnapshot(hostVO, snapshotInfo, true); + } - Map srcDetails = getSnapshotDetails(_storagePoolDao.findById(srcDataStore.getId()), snapshotInfo); + DataStore srcDataStore = snapshotInfo.getDataStore(); - copyCommand.setOptions(srcDetails); + String value = _configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); + int primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); + CopyCommand copyCommand = new CopyCommand(snapshotInfo.getTO(), templateInfo.getTO(), primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); + + String errMsg = null; + + CopyCmdAnswer copyCmdAnswer = null; - copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand); - } - catch (Exception ex) { - throw new CloudRuntimeException(ex.getMessage()); - } - finally { try { - _volumeService.revokeAccess(snapshotInfo, hostVO, srcDataStore); + // If we are using a back-end snapshot, then we should still have access to it from the hosts in the cluster that hostVO is in + // (because we passed in true as the third parameter to createVolumeFromSnapshot above). + if (usingBackendSnapshot == false) { + _volumeService.grantAccess(snapshotInfo, hostVO, srcDataStore); + } + + Map srcDetails = getSnapshotDetails(snapshotInfo); + + copyCommand.setOptions(srcDetails); + + copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand); } - catch (Exception ex) { - s_logger.debug(ex.getMessage(), ex); + catch (CloudRuntimeException | AgentUnavailableException | OperationTimedoutException ex) { + String msg = "Failed to create template from snapshot (Snapshot ID = " + snapshotInfo.getId() + ") : "; + + LOGGER.warn(msg, ex); + + throw new CloudRuntimeException(msg + ex.getMessage()); } + finally { + try { + _volumeService.revokeAccess(snapshotInfo, hostVO, srcDataStore); + } + catch (Exception ex) { + LOGGER.warn("Error revoking access to snapshot (Snapshot ID = " + snapshotInfo.getId() + "): " + ex.getMessage(), ex); + } - if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { - if (copyCmdAnswer != null && copyCmdAnswer.getDetails() != null && !copyCmdAnswer.getDetails().isEmpty()) { - errMsg = copyCmdAnswer.getDetails(); + if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { + if (copyCmdAnswer != null && !StringUtils.isEmpty(copyCmdAnswer.getDetails())) { + errMsg = copyCmdAnswer.getDetails(); + } + else { + errMsg = "Unable to create template from snapshot"; + } } - else { - errMsg = "Unable to perform host-side operation"; + + try { + if (StringUtils.isEmpty(errMsg)) { + snapshotInfo.processEvent(Event.OperationSuccessed); + } + else { + snapshotInfo.processEvent(Event.OperationFailed); + } + } + catch (Exception ex) { + LOGGER.warn("Error processing snapshot event: " + ex.getMessage(), ex); } } - try { - if (errMsg == null) { - snapshotInfo.processEvent(Event.OperationSuccessed); + CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer); + + result.setResult(errMsg); + + callback.complete(result); + } + finally { + if (usingBackendSnapshot) { + deleteVolumeFromSnapshot(snapshotInfo); + } + } + } + + /** + * Clones a template present on the storage to a new volume and resignatures it. + * + * @param templateInfo source template + * @param volumeInfo destination ROOT volume + * @param callback for async + */ + private void handleCreateVolumeFromTemplateBothOnStorageSystem(TemplateInfo templateInfo, VolumeInfo volumeInfo, AsyncCompletionCallback callback) { + Preconditions.checkArgument(templateInfo != null, "Passing 'null' to templateInfo of handleCreateVolumeFromTemplateBothOnStorageSystem is not supported."); + Preconditions.checkArgument(volumeInfo != null, "Passing 'null' to volumeInfo of handleCreateVolumeFromTemplateBothOnStorageSystem is not supported."); + + CopyCmdAnswer copyCmdAnswer = null; + String errMsg = null; + + HostVO hostVO = getHost(volumeInfo.getDataCenterId(), true); + + if (hostVO == null) { + throw new CloudRuntimeException("Unable to locate a host capable of resigning in the zone with the following ID: " + volumeInfo.getDataCenterId()); + } + + boolean computeClusterSupportsResign = clusterDao.computeWhetherClusterSupportsResigning(hostVO.getClusterId()); + + if (!computeClusterSupportsResign) { + String noSupportForResignErrMsg = "Unable to locate an applicable host with which to perform a resignature operation : Cluster ID = " + hostVO.getClusterId(); + + LOGGER.warn(noSupportForResignErrMsg); + + throw new CloudRuntimeException(noSupportForResignErrMsg); + } + + try { + VolumeDetailVO volumeDetail = new VolumeDetailVO(volumeInfo.getId(), + "cloneOfTemplate", + String.valueOf(templateInfo.getId()), + false); + + volumeDetail = volumeDetailsDao.persist(volumeDetail); + + AsyncCallFuture future = _volumeService.createVolumeAsync(volumeInfo, volumeInfo.getDataStore()); + VolumeApiResult result = future.get(); + + if (volumeDetail != null) { + volumeDetailsDao.remove(volumeDetail.getId()); + } + + if (result.isFailed()) { + LOGGER.warn("Failed to create a volume: " + result.getResult()); + + throw new CloudRuntimeException(result.getResult()); + } + + volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); + + volumeInfo.processEvent(Event.MigrationRequested); + + volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); + + copyCmdAnswer = performResignature(volumeInfo, hostVO); + + if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { + if (copyCmdAnswer != null && !StringUtils.isEmpty(copyCmdAnswer.getDetails())) { + throw new CloudRuntimeException(copyCmdAnswer.getDetails()); } else { - snapshotInfo.processEvent(Event.OperationFailed); + throw new CloudRuntimeException("Unable to create a volume from a template"); } } - catch (Exception ex) { - s_logger.debug(ex.getMessage(), ex); - } + } catch (InterruptedException | ExecutionException ex) { + volumeInfo.getDataStore().getDriver().deleteAsync(volumeInfo.getDataStore(), volumeInfo, null); + + throw new CloudRuntimeException("Create volume from template (ID = " + templateInfo.getId() + ") failed " + ex.getMessage()); } CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer); @@ -238,12 +457,40 @@ private Void handleCreateTemplateFromSnapshot(SnapshotInfo snapshotInfo, Templat result.setResult(errMsg); callback.complete(result); - - return null; } - private Void handleCreateVolumeFromSnapshotBothOnStorageSystem(SnapshotInfo snapshotInfo, VolumeInfo volumeInfo, AsyncCompletionCallback callback) { + private void handleCreateVolumeFromSnapshotBothOnStorageSystem(SnapshotInfo snapshotInfo, VolumeInfo volumeInfo, AsyncCompletionCallback callback) { + CopyCmdAnswer copyCmdAnswer = null; + String errMsg = null; + try { + HostVO hostVO = getHost(snapshotInfo); + + boolean usingBackendSnapshot = usingBackendSnapshotFor(snapshotInfo); + boolean computeClusterSupportsResign = clusterDao.computeWhetherClusterSupportsResigning(hostVO.getClusterId()); + + if (usingBackendSnapshot && !computeClusterSupportsResign) { + String noSupportForResignErrMsg = "Unable to locate an applicable host with which to perform a resignature operation : Cluster ID = " + hostVO.getClusterId(); + + LOGGER.warn(noSupportForResignErrMsg); + + throw new CloudRuntimeException(noSupportForResignErrMsg); + } + + boolean canStorageSystemCreateVolumeFromVolume = canStorageSystemCreateVolumeFromVolume(snapshotInfo); + boolean useCloning = usingBackendSnapshot || (canStorageSystemCreateVolumeFromVolume && computeClusterSupportsResign); + + VolumeDetailVO volumeDetail = null; + + if (useCloning) { + volumeDetail = new VolumeDetailVO(volumeInfo.getId(), + "cloneOfSnapshot", + String.valueOf(snapshotInfo.getId()), + false); + + volumeDetail = volumeDetailsDao.persist(volumeDetail); + } + // at this point, the snapshotInfo and volumeInfo should have the same disk offering ID (so either one should be OK to get a DiskOfferingVO instance) DiskOfferingVO diskOffering = _diskOfferingDao.findByIdIncludingRemoved(volumeInfo.getDiskOfferingId()); SnapshotVO snapshot = _snapshotDao.findById(snapshotInfo.getId()); @@ -255,99 +502,123 @@ private Void handleCreateVolumeFromSnapshotBothOnStorageSystem(SnapshotInfo snap VolumeApiResult result = future.get(); + if (volumeDetail != null) { + volumeDetailsDao.remove(volumeDetail.getId()); + } + if (result.isFailed()) { - s_logger.debug("Failed to create a volume: " + result.getResult()); + LOGGER.warn("Failed to create a volume: " + result.getResult()); throw new CloudRuntimeException(result.getResult()); } - } - catch (Exception ex) { - throw new CloudRuntimeException(ex.getMessage()); - } - volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); + volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); - volumeInfo.processEvent(Event.MigrationRequested); + volumeInfo.processEvent(Event.MigrationRequested); - volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); + volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); - HostVO hostVO = getHost(snapshotInfo.getDataStore().getId()); - - String value = _configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); - int primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); - CopyCommand copyCommand = new CopyCommand(snapshotInfo.getTO(), volumeInfo.getTO(), primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); + if (useCloning) { + copyCmdAnswer = performResignature(volumeInfo, hostVO); + } + else { + // asking for a XenServer host here so we don't always prefer to use XenServer hosts that support resigning + // even when we don't need those hosts to do this kind of copy work + hostVO = getHost(snapshotInfo.getDataCenterId(), false); - CopyCmdAnswer copyCmdAnswer = null; + copyCmdAnswer = performCopyOfVdi(volumeInfo, snapshotInfo, hostVO); + } - try { - _volumeService.grantAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); - _volumeService.grantAccess(volumeInfo, hostVO, volumeInfo.getDataStore()); + if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { + if (copyCmdAnswer != null && !StringUtils.isEmpty(copyCmdAnswer.getDetails())) { + errMsg = copyCmdAnswer.getDetails(); + } + else { + errMsg = "Unable to create volume from snapshot"; + } + } + } + catch (Exception ex) { + errMsg = ex.getMessage() != null ? ex.getMessage() : "Copy operation failed in 'StorageSystemDataMotionStrategy.handleCreateVolumeFromSnapshotBothOnStorageSystem'"; + } - Map srcDetails = getSnapshotDetails(_storagePoolDao.findById(snapshotInfo.getDataStore().getId()), snapshotInfo); + CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer); - copyCommand.setOptions(srcDetails); + result.setResult(errMsg); - Map destDetails = getVolumeDetails(volumeInfo); + callback.complete(result); + } - copyCommand.setOptions2(destDetails); + /** + * If the underlying storage system is making use of read-only snapshots, this gives the storage system the opportunity to + * create a volume from the snapshot so that we can copy the VHD file that should be inside of the snapshot to secondary storage. + * + * The resultant volume must be writable because we need to resign the SR and the VDI that should be inside of it before we copy + * the VHD file to secondary storage. + * + * If the storage system is using writable snapshots, then nothing need be done by that storage system here because we can just + * resign the SR and the VDI that should be inside of the snapshot before copying the VHD file to secondary storage. + */ + private void createVolumeFromSnapshot(HostVO hostVO, SnapshotInfo snapshotInfo, boolean keepGrantedAccess) { + SnapshotDetailsVO snapshotDetails = handleSnapshotDetails(snapshotInfo.getId(), "tempVolume", "create"); - copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand); - } - catch (Exception ex) { - throw new CloudRuntimeException(ex.getMessage()); + try { + snapshotInfo.getDataStore().getDriver().createAsync(snapshotInfo.getDataStore(), snapshotInfo, null); } finally { - try { - _volumeService.revokeAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); - } - catch (Exception ex) { - s_logger.debug(ex.getMessage(), ex); - } - - try { - _volumeService.revokeAccess(volumeInfo, hostVO, volumeInfo.getDataStore()); - } - catch (Exception ex) { - s_logger.debug(ex.getMessage(), ex); - } + _snapshotDetailsDao.remove(snapshotDetails.getId()); } - String errMsg = null; + CopyCmdAnswer copyCmdAnswer = performResignature(snapshotInfo, hostVO, keepGrantedAccess); if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { - if (copyCmdAnswer != null && copyCmdAnswer.getDetails() != null && !copyCmdAnswer.getDetails().isEmpty()) { - errMsg = copyCmdAnswer.getDetails(); + if (copyCmdAnswer != null && !StringUtils.isEmpty(copyCmdAnswer.getDetails())) { + throw new CloudRuntimeException(copyCmdAnswer.getDetails()); } else { - errMsg = "Unable to perform host-side operation"; + throw new CloudRuntimeException("Unable to create volume from snapshot"); } } + } - CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer); + /** + * If the underlying storage system needed to create a volume from a snapshot for createVolumeFromSnapshot(HostVO, SnapshotInfo), then + * this is its opportunity to delete that temporary volume and restore properties in snapshot_details to the way they were before the + * invocation of createVolumeFromSnapshot(HostVO, SnapshotInfo). + */ + private void deleteVolumeFromSnapshot(SnapshotInfo snapshotInfo) { + SnapshotDetailsVO snapshotDetails = handleSnapshotDetails(snapshotInfo.getId(), "tempVolume", "delete"); - result.setResult(errMsg); + try { + snapshotInfo.getDataStore().getDriver().createAsync(snapshotInfo.getDataStore(), snapshotInfo, null); + } + finally { + _snapshotDetailsDao.remove(snapshotDetails.getId()); + } + } - callback.complete(result); + private SnapshotDetailsVO handleSnapshotDetails(long csSnapshotId, String name, String value) { + _snapshotDetailsDao.removeDetail(csSnapshotId, name); - return null; + SnapshotDetailsVO snapshotDetails = new SnapshotDetailsVO(csSnapshotId, name, value, false); + + return _snapshotDetailsDao.persist(snapshotDetails); } - private Map getSnapshotDetails(StoragePoolVO storagePoolVO, SnapshotInfo snapshotInfo) { - Map details = new HashMap(); + private boolean canStorageSystemCreateVolumeFromVolume(SnapshotInfo snapshotInfo) { + boolean supportsCloningVolumeFromVolume = false; - details.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); - details.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); + DataStore dataStore = dataStoreMgr.getDataStore(snapshotInfo.getDataStore().getId(), DataStoreRole.Primary); - long snapshotId = snapshotInfo.getId(); + Map mapCapabilities = dataStore.getDriver().getCapabilities(); - details.put(DiskTO.IQN, getProperty(snapshotId, DiskTO.IQN)); + if (mapCapabilities != null) { + String value = mapCapabilities.get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString()); - details.put(DiskTO.CHAP_INITIATOR_USERNAME, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_USERNAME)); - details.put(DiskTO.CHAP_INITIATOR_SECRET, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_SECRET)); - details.put(DiskTO.CHAP_TARGET_USERNAME, getProperty(snapshotId, DiskTO.CHAP_TARGET_USERNAME)); - details.put(DiskTO.CHAP_TARGET_SECRET, getProperty(snapshotId, DiskTO.CHAP_TARGET_SECRET)); + supportsCloningVolumeFromVolume = Boolean.valueOf(value); + } - return details; + return supportsCloningVolumeFromVolume; } private String getProperty(long snapshotId, String property) { @@ -361,59 +632,209 @@ private String getProperty(long snapshotId, String property) { } private Map getVolumeDetails(VolumeInfo volumeInfo) { - Map sourceDetails = new HashMap(); + Map volumeDetails = new HashMap(); VolumeVO volumeVO = _volumeDao.findById(volumeInfo.getId()); long storagePoolId = volumeVO.getPoolId(); StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); - sourceDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); - sourceDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); - sourceDetails.put(DiskTO.IQN, volumeVO.get_iScsiName()); + volumeDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); + volumeDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); + volumeDetails.put(DiskTO.IQN, volumeVO.get_iScsiName()); ChapInfo chapInfo = _volumeService.getChapInfo(volumeInfo, volumeInfo.getDataStore()); if (chapInfo != null) { - sourceDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername()); - sourceDetails.put(DiskTO.CHAP_INITIATOR_SECRET, chapInfo.getInitiatorSecret()); - sourceDetails.put(DiskTO.CHAP_TARGET_USERNAME, chapInfo.getTargetUsername()); - sourceDetails.put(DiskTO.CHAP_TARGET_SECRET, chapInfo.getTargetSecret()); + volumeDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername()); + volumeDetails.put(DiskTO.CHAP_INITIATOR_SECRET, chapInfo.getInitiatorSecret()); + volumeDetails.put(DiskTO.CHAP_TARGET_USERNAME, chapInfo.getTargetUsername()); + volumeDetails.put(DiskTO.CHAP_TARGET_SECRET, chapInfo.getTargetSecret()); } - return sourceDetails; + return volumeDetails; } - public HostVO getHost(long dataStoreId) { - StoragePoolVO storagePoolVO = _storagePoolDao.findById(dataStoreId); + private Map getSnapshotDetails(SnapshotInfo snapshotInfo) { + Map snapshotDetails = new HashMap(); + + long storagePoolId = snapshotInfo.getDataStore().getId(); + StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); - List clusters = _mgr.searchForClusters(storagePoolVO.getDataCenterId(), new Long(0), Long.MAX_VALUE, HypervisorType.XenServer.toString()); + snapshotDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); + snapshotDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); - if (clusters == null) { - throw new CloudRuntimeException("Unable to locate an applicable cluster"); + long snapshotId = snapshotInfo.getId(); + + snapshotDetails.put(DiskTO.IQN, getProperty(snapshotId, DiskTO.IQN)); + + snapshotDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_USERNAME)); + snapshotDetails.put(DiskTO.CHAP_INITIATOR_SECRET, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_SECRET)); + snapshotDetails.put(DiskTO.CHAP_TARGET_USERNAME, getProperty(snapshotId, DiskTO.CHAP_TARGET_USERNAME)); + snapshotDetails.put(DiskTO.CHAP_TARGET_SECRET, getProperty(snapshotId, DiskTO.CHAP_TARGET_SECRET)); + + return snapshotDetails; + } + + private HostVO getHost(SnapshotInfo snapshotInfo) { + HostVO hostVO = getHost(snapshotInfo.getDataCenterId(), true); + + if (hostVO == null) { + hostVO = getHost(snapshotInfo.getDataCenterId(), false); + + if (hostVO == null) { + throw new CloudRuntimeException("Unable to locate an applicable host in data center with ID = " + snapshotInfo.getDataCenterId()); + } } - for (Cluster cluster : clusters) { - if (cluster.getAllocationState() == AllocationState.Enabled) { - List hosts = _hostDao.findByClusterId(cluster.getId()); + return hostVO; + } - if (hosts != null) { - for (HostVO host : hosts) { - if (host.getResourceState() == ResourceState.Enabled) { - return host; - } - } + private HostVO getHost(Long zoneId, boolean computeClusterMustSupportResign) { + Preconditions.checkArgument(zoneId != null, "Zone ID cannot be null."); + + List hosts = _hostDao.listByDataCenterIdAndHypervisorType(zoneId, HypervisorType.XenServer); + + if (hosts == null) { + return null; + } + + List clustersToSkip = new ArrayList<>(); + + Collections.shuffle(hosts, RANDOM); + + for (HostVO host : hosts) { + if (computeClusterMustSupportResign) { + long clusterId = host.getClusterId(); + + if (clustersToSkip.contains(clusterId)) { + continue; + } + + if (clusterDao.computeWhetherClusterSupportsResigning(clusterId)) { + return host; + } + else { + clustersToSkip.add(clusterId); } } + else { + return host; + } } - throw new CloudRuntimeException("Unable to locate an applicable cluster"); + return null; } @Override public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { CopyCommandResult result = new CopyCommandResult(null, null); + result.setResult("Unsupported operation requested for copying data."); + callback.complete(result); } + + private Map getDetails(DataObject dataObj) { + if (dataObj instanceof VolumeInfo) { + return getVolumeDetails((VolumeInfo)dataObj); + } + else if (dataObj instanceof SnapshotInfo) { + return getSnapshotDetails((SnapshotInfo)dataObj); + } + + throw new CloudRuntimeException("'dataObj' must be of type 'VolumeInfo' or 'SnapshotInfo'."); + } + + private CopyCmdAnswer performResignature(DataObject dataObj, HostVO hostVO) { + return performResignature(dataObj, hostVO, false); + } + + private CopyCmdAnswer performResignature(DataObject dataObj, HostVO hostVO, boolean keepGrantedAccess) { + long storagePoolId = dataObj.getDataStore().getId(); + DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + + Map details = getDetails(dataObj); + + ResignatureCommand command = new ResignatureCommand(details); + + ResignatureAnswer answer = null; + + try { + _volumeService.grantAccess(dataObj, hostVO, dataStore); + + answer = (ResignatureAnswer)_agentMgr.send(hostVO.getId(), command); + } + catch (CloudRuntimeException | AgentUnavailableException | OperationTimedoutException ex) { + keepGrantedAccess = false; + + String msg = "Failed to resign the DataObject with the following ID: " + dataObj.getId(); + + LOGGER.warn(msg, ex); + + throw new CloudRuntimeException(msg + ex.getMessage()); + } + finally { + if (keepGrantedAccess == false) { + _volumeService.revokeAccess(dataObj, hostVO, dataStore); + } + } + + if (answer == null || !answer.getResult()) { + final String errMsg; + + if (answer != null && answer.getDetails() != null && !answer.getDetails().isEmpty()) { + errMsg = answer.getDetails(); + } + else { + errMsg = "Unable to perform resignature operation in 'StorageSystemDataMotionStrategy.performResignature'"; + } + + throw new CloudRuntimeException(errMsg); + } + + VolumeObjectTO newVolume = new VolumeObjectTO(); + + newVolume.setSize(answer.getSize()); + newVolume.setPath(answer.getPath()); + newVolume.setFormat(answer.getFormat()); + + return new CopyCmdAnswer(newVolume); + } + + private CopyCmdAnswer performCopyOfVdi(VolumeInfo volumeInfo, SnapshotInfo snapshotInfo, HostVO hostVO) { + String value = _configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); + int primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); + CopyCommand copyCommand = new CopyCommand(snapshotInfo.getTO(), volumeInfo.getTO(), primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); + + CopyCmdAnswer copyCmdAnswer = null; + + try { + _volumeService.grantAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); + _volumeService.grantAccess(volumeInfo, hostVO, volumeInfo.getDataStore()); + + Map srcDetails = getSnapshotDetails(snapshotInfo); + + copyCommand.setOptions(srcDetails); + + Map destDetails = getVolumeDetails(volumeInfo); + + copyCommand.setOptions2(destDetails); + + copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand); + } + catch (CloudRuntimeException | AgentUnavailableException | OperationTimedoutException ex) { + String msg = "Failed to perform VDI copy : "; + + LOGGER.warn(msg, ex); + + throw new CloudRuntimeException(msg + ex.getMessage()); + } + finally { + _volumeService.revokeAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); + _volumeService.revokeAccess(volumeInfo, hostVO, volumeInfo.getDataStore()); + } + + return copyCmdAnswer; + } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index df2d37f05b..0d96660d58 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -918,6 +918,25 @@ public AsyncCallFuture prepareTemplateOnPrimary(TemplateInfo return copyAsync(srcTemplate, srcTemplate, (DataStore)pool); } + @Override + public AsyncCallFuture deleteTemplateOnPrimary(TemplateInfo template, StoragePool pool) { + TemplateObject templateObject = (TemplateObject)_templateFactory.getTemplate(template.getId(), (DataStore)pool); + + templateObject.processEvent(ObjectInDataStoreStateMachine.Event.DestroyRequested); + + DataStore dataStore = _storeMgr.getPrimaryDataStore(pool.getId()); + + AsyncCallFuture future = new AsyncCallFuture<>(); + TemplateOpContext context = new TemplateOpContext<>(null, templateObject, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + + caller.setCallback(caller.getTarget().deleteTemplateCallback(null, null)).setContext(context); + + dataStore.getDriver().deleteAsync(dataStore, templateObject, caller); + + return future; + } + protected Void copyTemplateCallBack(AsyncCallbackDispatcher callback, TemplateOpContext context) { TemplateInfo destTemplate = context.getTemplate(); CopyCommandResult result = callback.getResult(); diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java index 473959b081..6e78f190d5 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java @@ -28,7 +28,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; @@ -54,6 +53,9 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; +import com.google.common.base.Strings; + +@SuppressWarnings("serial") public class TemplateObject implements TemplateInfo { private static final Logger s_logger = Logger.getLogger(TemplateObject.class); private VMTemplateVO imageVO; @@ -189,12 +191,15 @@ public void processEvent(ObjectInDataStoreStateMachine.Event event, Answer answe TemplateObjectTO newTemplate = (TemplateObjectTO)cpyAnswer.getNewData(); VMTemplateStoragePoolVO templatePoolRef = templatePoolDao.findByPoolTemplate(getDataStore().getId(), getId()); templatePoolRef.setDownloadPercent(100); - if (newTemplate.getSize() != null) { - templatePoolRef.setTemplateSize(newTemplate.getSize()); - } + + setTemplateSizeIfNeeded(newTemplate, templatePoolRef); + templatePoolRef.setDownloadState(Status.DOWNLOADED); - templatePoolRef.setLocalDownloadPath(newTemplate.getPath()); - templatePoolRef.setInstallPath(newTemplate.getPath()); + + setDownloadPathIfNeeded(newTemplate, templatePoolRef); + + setInstallPathIfNeeded(newTemplate, templatePoolRef); + templatePoolDao.update(templatePoolRef.getId(), templatePoolRef); } } else if (getDataStore().getRole() == DataStoreRole.Image || getDataStore().getRole() == DataStoreRole.ImageCache) { @@ -243,6 +248,33 @@ public void processEvent(ObjectInDataStoreStateMachine.Event event, Answer answe } } + /** + * In the case of managed storage, the install path may already be specified (by the storage plug-in), so do not overwrite it. + */ + private void setInstallPathIfNeeded(TemplateObjectTO template, VMTemplateStoragePoolVO templatePoolRef) { + if (Strings.isNullOrEmpty(templatePoolRef.getInstallPath())) { + templatePoolRef.setInstallPath(template.getPath()); + } + } + + /** + * In the case of managed storage, the local download path may already be specified (by the storage plug-in), so do not overwrite it. + */ + private void setDownloadPathIfNeeded(TemplateObjectTO template, VMTemplateStoragePoolVO templatePoolRef) { + if (Strings.isNullOrEmpty(templatePoolRef.getLocalDownloadPath())) { + templatePoolRef.setLocalDownloadPath(template.getPath()); + } + } + + /** + * In the case of managed storage, the template size may already be specified (by the storage plug-in), so do not overwrite it. + */ + private void setTemplateSizeIfNeeded(TemplateObjectTO template, VMTemplateStoragePoolVO templatePoolRef) { + if (templatePoolRef.getTemplateSize() == 0 && template.getSize() != null) { + templatePoolRef.setTemplateSize(template.getSize()); + } + } + @Override public void incRefCount() { if (dataStore == null) { @@ -299,28 +331,17 @@ public DataTO getTO() { @Override public String getInstallPath() { - if (installPath != null) + if (installPath != null) { return installPath; + } if (dataStore == null) { return null; } - // managed primary data stores should not have an install path - if (dataStore instanceof PrimaryDataStore) { - PrimaryDataStore primaryDataStore = (PrimaryDataStore)dataStore; - - Map details = primaryDataStore.getDetails(); - - boolean managed = details != null && Boolean.parseBoolean(details.get(PrimaryDataStore.MANAGED)); - - if (managed) { - return null; - } - } - DataObjectInStore obj = objectInStoreMgr.findObject(this, dataStore); - return obj.getInstallPath(); + + return obj != null ? obj.getInstallPath() : null; } public void setInstallPath(String installPath) { @@ -435,7 +456,7 @@ public String getTemplateTag() { } @Override - public Map getDetails() { + public Map getDetails() { return imageVO.getDetails(); } diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java index 1f1ba24b6b..a86b3219ee 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java @@ -28,6 +28,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.command.CommandResult; @@ -44,8 +45,8 @@ public class FakePrimaryDataStoreDriver implements PrimaryDataStoreDriver { boolean snapshotResult = true; @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo) { - return null; // To change body of implemented methods, use File | Settings | File Templates. + public ChapInfo getChapInfo(DataObject dataObject) { + return null; } @Override @@ -65,8 +66,13 @@ public long getUsedIops(StoragePool storagePool) { } @Override - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { - return volume.getSize(); + public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) { + return dataObject.getSize(); + } + + @Override + public long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool) { + return 0L; } @Override @@ -90,23 +96,21 @@ public void makeTakeSnapshotSucceed(boolean success) { } @Override - public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback) { - //To change body of implemented methods use File | Settings | File Templates. + public void revertSnapshot(SnapshotInfo snapshotOnImageStore, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback callback) { } @Override public DataTO getTO(DataObject data) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } @Override public DataStoreTO getStoreTO(DataStore store) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } @Override public void createAsync(DataStore store, DataObject data, AsyncCompletionCallback callback) { - //To change body of implemented methods use File | Settings | File Templates. } @Override @@ -119,22 +123,19 @@ public void deleteAsync(DataStore store, DataObject data, AsyncCompletionCallbac @Override public void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback callback) { - //To change body of implemented methods use File | Settings | File Templates. } @Override public boolean canCopy(DataObject srcData, DataObject destData) { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } @Override public void resize(DataObject data, AsyncCompletionCallback callback) { - //To change body of implemented methods use File | Settings | File Templates. } @Override public Map getCapabilities() { - // TODO Auto-generated method stub return null; } } diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java index c6960eb4a1..d74ee57dda 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java @@ -16,14 +16,16 @@ // under the License. package org.apache.cloudstack.storage.snapshot; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import javax.inject.Inject; import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; @@ -38,11 +40,15 @@ import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.springframework.stereotype.Component; + +import com.google.common.base.Optional; + import com.cloud.agent.AgentManager; import com.cloud.agent.api.to.DiskTO; +import com.cloud.dc.dao.ClusterDao; import com.cloud.exception.InvalidParameterValueException; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; @@ -71,18 +77,18 @@ public class StorageSystemSnapshotStrategy extends SnapshotStrategyBase { private static final Logger s_logger = Logger.getLogger(StorageSystemSnapshotStrategy.class); - @Inject private AgentManager _agentMgr; - @Inject private DataStoreManager _dataStoreMgr; - @Inject private HostDao _hostDao; - @Inject private ManagementService _mgr; - @Inject private PrimaryDataStoreDao _storagePoolDao; - @Inject private SnapshotDao _snapshotDao; - @Inject private SnapshotDataFactory _snapshotDataFactory; - @Inject private SnapshotDataStoreDao _snapshotStoreDao; - @Inject private SnapshotDetailsDao _snapshotDetailsDao; - @Inject private VMInstanceDao _vmInstanceDao; - @Inject private VolumeDao _volumeDao; - @Inject private VolumeService _volService; + @Inject private AgentManager agentMgr; + @Inject private ClusterDao clusterDao; + @Inject private DataStoreManager dataStoreMgr; + @Inject private HostDao hostDao; + @Inject private ManagementService mgr; + @Inject private PrimaryDataStoreDao storagePoolDao; + @Inject private SnapshotDao snapshotDao; + @Inject private SnapshotDataFactory snapshotDataFactory; + @Inject private SnapshotDetailsDao snapshotDetailsDao; + @Inject private VMInstanceDao vmInstanceDao; + @Inject private VolumeDao volumeDao; + @Inject private VolumeService volService; @Override public SnapshotInfo backupSnapshot(SnapshotInfo snapshotInfo) { @@ -91,14 +97,14 @@ public SnapshotInfo backupSnapshot(SnapshotInfo snapshotInfo) { @Override public boolean deleteSnapshot(Long snapshotId) { - SnapshotVO snapshotVO = _snapshotDao.findById(snapshotId); + SnapshotVO snapshotVO = snapshotDao.findById(snapshotId); if (Snapshot.State.Destroyed.equals(snapshotVO.getState())) { return true; } if (Snapshot.State.Error.equals(snapshotVO.getState())) { - _snapshotDao.remove(snapshotId); + snapshotDao.remove(snapshotId); return true; } @@ -107,12 +113,12 @@ public boolean deleteSnapshot(Long snapshotId) { throw new InvalidParameterValueException("Unable to delete snapshotshot " + snapshotId + " because it is in the following state: " + snapshotVO.getState()); } - SnapshotObject snapshotObj = (SnapshotObject)_snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary); + SnapshotObject snapshotObj = (SnapshotObject)snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary); if (snapshotObj == null) { s_logger.debug("Can't find snapshot; deleting it in DB"); - _snapshotDao.remove(snapshotId); + snapshotDao.remove(snapshotId); return true; } @@ -165,7 +171,7 @@ public SnapshotInfo takeSnapshot(SnapshotInfo snapshotInfo) { throw new CloudRuntimeException("Only the " + ImageFormat.VHD.toString() + " image type is currently supported."); } - SnapshotVO snapshotVO = _snapshotDao.acquireInLockTable(snapshotInfo.getId()); + SnapshotVO snapshotVO = snapshotDao.acquireInLockTable(snapshotInfo.getId()); if (snapshotVO == null) { throw new CloudRuntimeException("Failed to acquire lock on the following snapshot: " + snapshotInfo.getId()); @@ -176,7 +182,24 @@ public SnapshotInfo takeSnapshot(SnapshotInfo snapshotInfo) { try { volumeInfo.stateTransit(Volume.Event.SnapshotRequested); - // tell the storage driver to create a back-end volume (eventually used to create a new SR on and to copy the VM snapshot VDI to) + // only XenServer is currently supported + HostVO hostVO = getHost(volumeInfo.getId()); + + boolean canStorageSystemCreateVolumeFromSnapshot = canStorageSystemCreateVolumeFromSnapshot(volumeInfo.getPoolId()); + boolean computeClusterSupportsResign = clusterDao.computeWhetherClusterSupportsResigning(hostVO.getClusterId()); + + // if canStorageSystemCreateVolumeFromSnapshot && computeClusterSupportsResign, then take a back-end snapshot or create a back-end clone; + // else, just create a new back-end volume (eventually used to create a new SR on and to copy a VDI to) + + if (canStorageSystemCreateVolumeFromSnapshot && computeClusterSupportsResign) { + SnapshotDetailsVO snapshotDetail = new SnapshotDetailsVO(snapshotInfo.getId(), + "takeSnapshot", + Boolean.TRUE.toString(), + false); + + snapshotDetailsDao.persist(snapshotDetail); + } + result = snapshotSvr.takeSnapshot(snapshotInfo); if (result.isFailed()) { @@ -185,9 +208,9 @@ public SnapshotInfo takeSnapshot(SnapshotInfo snapshotInfo) { throw new CloudRuntimeException(result.getResult()); } - // send a command to XenServer to create a VM snapshot on the applicable SR (get back the VDI UUID of the VM snapshot) - - performSnapshotAndCopyOnHostSide(volumeInfo, snapshotInfo); + if (!canStorageSystemCreateVolumeFromSnapshot || !computeClusterSupportsResign) { + performSnapshotAndCopyOnHostSide(volumeInfo, snapshotInfo); + } markAsBackedUp((SnapshotObject)result.getSnashot()); } @@ -199,19 +222,35 @@ public SnapshotInfo takeSnapshot(SnapshotInfo snapshotInfo) { volumeInfo.stateTransit(Volume.Event.OperationFailed); } - _snapshotDao.releaseFromLockTable(snapshotInfo.getId()); + snapshotDao.releaseFromLockTable(snapshotInfo.getId()); } return snapshotInfo; } + private boolean canStorageSystemCreateVolumeFromSnapshot(long storagePoolId) { + boolean supportsCloningVolumeFromSnapshot = false; + + DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + + Map mapCapabilities = dataStore.getDriver().getCapabilities(); + + if (mapCapabilities != null) { + String value = mapCapabilities.get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_SNAPSHOT.toString()); + + supportsCloningVolumeFromSnapshot = Boolean.valueOf(value); + } + + return supportsCloningVolumeFromSnapshot; + } + private void performSnapshotAndCopyOnHostSide(VolumeInfo volumeInfo, SnapshotInfo snapshotInfo) { Map sourceDetails = null; - VolumeVO volumeVO = _volumeDao.findById(volumeInfo.getId()); + VolumeVO volumeVO = volumeDao.findById(volumeInfo.getId()); Long vmInstanceId = volumeVO.getInstanceId(); - VMInstanceVO vmInstanceVO = _vmInstanceDao.findById(vmInstanceId); + VMInstanceVO vmInstanceVO = vmInstanceDao.findById(vmInstanceId); Long hostId = null; @@ -233,11 +272,30 @@ private void performSnapshotAndCopyOnHostSide(VolumeInfo volumeInfo, SnapshotInf sourceDetails = getSourceDetails(volumeInfo); } - HostVO hostVO = getHost(hostId, volumeVO); + HostVO hostVO = null; + + if (hostId != null) { + hostVO = hostDao.findById(hostId); + } + else { + Optional optHostVO = getHost(volumeInfo.getDataCenterId(), false); + + if (optHostVO.isPresent()) { + hostVO = optHostVO.get(); + } + } + + if (hostVO == null) { + final String errMsg = "Unable to locate an applicable host"; + + s_logger.error("performSnapshotAndCopyOnHostSide: " + errMsg); + + throw new CloudRuntimeException(errMsg); + } long storagePoolId = volumeVO.getPoolId(); - StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); - DataStore dataStore = _dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + StoragePoolVO storagePoolVO = storagePoolDao.findById(storagePoolId); + DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); Map destDetails = getDestDetails(storagePoolVO, snapshotInfo); @@ -248,23 +306,23 @@ private void performSnapshotAndCopyOnHostSide(VolumeInfo volumeInfo, SnapshotInf try { // if sourceDetails != null, we need to connect the host(s) to the volume if (sourceDetails != null) { - _volService.grantAccess(volumeInfo, hostVO, dataStore); + volService.grantAccess(volumeInfo, hostVO, dataStore); } - _volService.grantAccess(snapshotInfo, hostVO, dataStore); + volService.grantAccess(snapshotInfo, hostVO, dataStore); - snapshotAndCopyAnswer = (SnapshotAndCopyAnswer)_agentMgr.send(hostVO.getId(), snapshotAndCopyCommand); + snapshotAndCopyAnswer = (SnapshotAndCopyAnswer)agentMgr.send(hostVO.getId(), snapshotAndCopyCommand); } catch (Exception ex) { throw new CloudRuntimeException(ex.getMessage()); } finally { try { - _volService.revokeAccess(snapshotInfo, hostVO, dataStore); + volService.revokeAccess(snapshotInfo, hostVO, dataStore); // if sourceDetails != null, we need to disconnect the host(s) from the volume if (sourceDetails != null) { - _volService.revokeAccess(volumeInfo, hostVO, dataStore); + volService.revokeAccess(volumeInfo, hostVO, dataStore); } } catch (Exception ex) { @@ -292,22 +350,22 @@ private void performSnapshotAndCopyOnHostSide(VolumeInfo volumeInfo, SnapshotInf path, false); - _snapshotDetailsDao.persist(snapshotDetail); + snapshotDetailsDao.persist(snapshotDetail); } private Map getSourceDetails(VolumeInfo volumeInfo) { - Map sourceDetails = new HashMap(); + Map sourceDetails = new HashMap<>(); - VolumeVO volumeVO = _volumeDao.findById(volumeInfo.getId()); + VolumeVO volumeVO = volumeDao.findById(volumeInfo.getId()); long storagePoolId = volumeVO.getPoolId(); - StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); + StoragePoolVO storagePoolVO = storagePoolDao.findById(storagePoolId); sourceDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); sourceDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); sourceDetails.put(DiskTO.IQN, volumeVO.get_iScsiName()); - ChapInfo chapInfo = _volService.getChapInfo(volumeInfo, volumeInfo.getDataStore()); + ChapInfo chapInfo = volService.getChapInfo(volumeInfo, volumeInfo.getDataStore()); if (chapInfo != null) { sourceDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername()); @@ -320,7 +378,7 @@ private Map getSourceDetails(VolumeInfo volumeInfo) { } private Map getDestDetails(StoragePoolVO storagePoolVO, SnapshotInfo snapshotInfo) { - Map destDetails = new HashMap(); + Map destDetails = new HashMap<>(); destDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); destDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); @@ -338,7 +396,7 @@ private Map getDestDetails(StoragePoolVO storagePoolVO, Snapshot } private String getProperty(long snapshotId, String property) { - SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshotId, property); + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshotId, property); if (snapshotDetails != null) { return snapshotDetails.getValue(); @@ -347,38 +405,87 @@ private String getProperty(long snapshotId, String property) { return null; } - private HostVO getHost(Long hostId, VolumeVO volumeVO) { - HostVO hostVO = _hostDao.findById(hostId); + private HostVO getHost(long volumeId) { + VolumeVO volumeVO = volumeDao.findById(volumeId); + + Long vmInstanceId = volumeVO.getInstanceId(); + VMInstanceVO vmInstanceVO = vmInstanceDao.findById(vmInstanceId); + + Long hostId = null; + + // if the volume to snapshot is associated with a VM + if (vmInstanceVO != null) { + hostId = vmInstanceVO.getHostId(); + + // if the VM is not associated with a host + if (hostId == null) { + hostId = vmInstanceVO.getLastHostId(); + } + } + + return getHost(volumeVO.getDataCenterId(), hostId); + } + + private HostVO getHost(long zoneId, Long hostId) { + Optional optHostVO = getHost(zoneId, true); + + if (optHostVO.isPresent()) { + return optHostVO.get(); + } + + HostVO hostVO = hostDao.findById(hostId); if (hostVO != null) { return hostVO; } - // pick a host in any XenServer cluster that's in the applicable zone + optHostVO = getHost(zoneId, false); - long zoneId = volumeVO.getDataCenterId(); + if (optHostVO.isPresent()) { + return optHostVO.get(); + } - List clusters = _mgr.searchForClusters(zoneId, new Long(0), Long.MAX_VALUE, HypervisorType.XenServer.toString()); + throw new CloudRuntimeException("Unable to locate an applicable host"); + } + + private Optional getHost(long zoneId, boolean computeClusterMustSupportResign) { + List clusters = mgr.searchForClusters(zoneId, 0L, Long.MAX_VALUE, HypervisorType.XenServer.toString()); if (clusters == null) { - throw new CloudRuntimeException("Unable to locate an applicable cluster"); + clusters = new ArrayList<>(); } + Collections.shuffle(clusters, new Random(System.nanoTime())); + + clusters: for (Cluster cluster : clusters) { if (cluster.getAllocationState() == AllocationState.Enabled) { - List hosts = _hostDao.findByClusterId(cluster.getId()); + List hosts = hostDao.findByClusterId(cluster.getId()); if (hosts != null) { + Collections.shuffle(hosts, new Random(System.nanoTime())); + for (HostVO host : hosts) { if (host.getResourceState() == ResourceState.Enabled) { - return host; + if (computeClusterMustSupportResign) { + if (clusterDao.computeWhetherClusterSupportsResigning(cluster.getId())) { + return Optional.of(host); + } + else { + // no other host in the cluster in question should be able to satisfy our requirements here, so move on to the next cluster + continue clusters; + } + } + else { + return Optional.of(host); + } } } } } } - throw new CloudRuntimeException("Unable to locate an applicable cluster"); + return Optional.absent(); } private void markAsBackedUp(SnapshotObject snapshotObj) { @@ -406,18 +513,18 @@ public StrategyPriority canHandle(Snapshot snapshot, SnapshotOperation op) { long volumeId = snapshot.getVolumeId(); - VolumeVO volumeVO = _volumeDao.findByIdIncludingRemoved(volumeId); + VolumeVO volumeVO = volumeDao.findByIdIncludingRemoved(volumeId); long storagePoolId = volumeVO.getPoolId(); - DataStore dataStore = _dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); if (dataStore != null) { Map mapCapabilities = dataStore.getDriver().getCapabilities(); if (mapCapabilities != null) { String value = mapCapabilities.get(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString()); - Boolean supportsStorageSystemSnapshots = new Boolean(value); + Boolean supportsStorageSystemSnapshots = Boolean.valueOf(value); if (supportsStorageSystemSnapshots) { return StrategyPriority.HIGHEST; diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java index 99fc1612fa..25444843fe 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java @@ -78,6 +78,8 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase { VolumeDao volumeDao; @Inject SnapshotDataFactory snapshotDataFactory; + @Inject + private SnapshotDao _snapshotDao; @Override public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) { @@ -289,7 +291,7 @@ public boolean deleteSnapshot(Long snapshotId) { @Override public boolean revertSnapshot(SnapshotInfo snapshot) { if (canHandle(snapshot,SnapshotOperation.REVERT) == StrategyPriority.CANT_HANDLE) { - throw new UnsupportedOperationException("Reverting not supported. Create a template or volume based on the snapshot instead."); + throw new CloudRuntimeException("Reverting not supported. Create a template or volume based on the snapshot instead."); } SnapshotVO snapshotVO = snapshotDao.acquireInLockTable(snapshot.getId()); diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java index 73a8544f51..194f7bd857 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java @@ -223,7 +223,7 @@ protected boolean filter(ExcludeList avoid, StoragePool pool, DiskProfile dskCh, Volume volume = _volumeDao.findById(dskCh.getVolumeId()); List requestVolumes = new ArrayList(); requestVolumes.add(volume); - return storageMgr.storagePoolHasEnoughIops(requestVolumes, pool) && storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool); + return storageMgr.storagePoolHasEnoughIops(requestVolumes, pool) && storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool, plan.getClusterId()); } /* diff --git a/engine/storage/volume/pom.xml b/engine/storage/volume/pom.xml index e790df12dd..340010ba34 100644 --- a/engine/storage/volume/pom.xml +++ b/engine/storage/volume/pom.xml @@ -25,6 +25,11 @@ cloud-engine-storage ${project.version}
+ + org.apache.cloudstack + cloud-engine-storage-image + ${project.version} + diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java index f3c9e79027..81966784be 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java @@ -26,6 +26,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; @@ -65,6 +66,7 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.storage.encoding.EncodingType; +@SuppressWarnings("serial") public class PrimaryDataStoreImpl implements PrimaryDataStore { private static final Logger s_logger = Logger.getLogger(PrimaryDataStoreImpl.class); @@ -239,10 +241,34 @@ public boolean isManaged() { return pdsv.isManaged(); } + private boolean canCloneVolume() { + return Boolean.valueOf(getDriver().getCapabilities().get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString())); + } + + /** + * The parameter createEntryInTempSpoolRef in the overloaded create(DataObject, boolean) method only applies to managed storage. We pass + * in "true" here. + * + * In the case of managed storage that can create a volume from a volume (clone), if the DataObject passed in is a TemplateInfo, + * we do want to create an entry in the cloud.template_spool_ref table (so that multiple uses of the template can be leveraged from + * the one copy on managed storage). + * + * In cases where UUID resigning is not available, then the code calling "create" should invoke the overloaded "create" method whose second + * parameter is a boolean. This code can pass in "false" so that an entry in the cloud.template_spool_ref table is not created (no template to share + * on the primary storage). + */ + @Override + public DataObject create(DataObject dataObject) { + return create(dataObject, true); + } + + /** + * Please read the comment for the create(DataObject) method if you are planning on passing in "false" for createEntryInTempSpoolRef. + */ @Override - public DataObject create(DataObject obj) { + public DataObject create(DataObject obj, boolean createEntryInTempSpoolRef) { // create template on primary storage - if (obj.getType() == DataObjectType.TEMPLATE && !isManaged()) { + if (obj.getType() == DataObjectType.TEMPLATE && (!isManaged() || (createEntryInTempSpoolRef && canCloneVolume()))) { try { String templateIdPoolIdString = "templateId:" + obj.getId() + "poolId:" + getId(); VMTemplateStoragePoolVO templateStoragePoolRef; diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index a2fd656d4b..54e5105491 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -19,14 +19,21 @@ package org.apache.cloudstack.storage.volume; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import javax.inject.Inject; +import com.cloud.dc.dao.ClusterDao; import com.cloud.offering.DiskOffering; +import com.cloud.org.Cluster; +import com.cloud.org.Grouping.AllocationState; +import com.cloud.resource.ResourceState; +import com.cloud.server.ManagementService; import com.cloud.storage.RegisterVolumePayload; import com.cloud.utils.Pair; import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; @@ -36,6 +43,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionService; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; @@ -59,8 +67,10 @@ import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO; +import org.apache.cloudstack.storage.image.store.TemplateObject; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.log4j.Logger; @@ -80,7 +90,9 @@ import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ResourceAllocationException; import com.cloud.host.Host; +import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; +import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.DataStoreRole; import com.cloud.storage.ScopeType; @@ -134,6 +146,14 @@ public class VolumeServiceImpl implements VolumeService { EndPointSelector _epSelector; @Inject HostDao _hostDao; + @Inject + private PrimaryDataStoreDao storagePoolDao; + @Inject + private HostDetailsDao hostDetailsDao; + @Inject + private ManagementService mgr; + @Inject + private ClusterDao clusterDao; public VolumeServiceImpl() { } @@ -160,11 +180,11 @@ public AsyncCallFuture getFuture() { } @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore) { + public ChapInfo getChapInfo(DataObject dataObject, DataStore dataStore) { DataStoreDriver dataStoreDriver = dataStore.getDriver(); if (dataStoreDriver instanceof PrimaryDataStoreDriver) { - return ((PrimaryDataStoreDriver)dataStoreDriver).getChapInfo(volumeInfo); + return ((PrimaryDataStoreDriver)dataStoreDriver).getChapInfo(dataObject); } return null; @@ -554,6 +574,49 @@ protected Void managedCopyBaseImageCallback(AsyncCallbackDispatcher callback, CreateVolumeContext context) { + CreateCmdResult result = callback.getResult(); + VolumeApiResult res = new VolumeApiResult(null); + + res.setResult(result.getResult()); + + AsyncCallFuture future = context.getFuture(); + DataObject templateOnPrimaryStoreObj = context.getVolume(); + + if (result.isSuccess()) { + ((TemplateObject)templateOnPrimaryStoreObj).setInstallPath(result.getPath()); + templateOnPrimaryStoreObj.processEvent(Event.OperationSuccessed, result.getAnswer()); + } + else { + templateOnPrimaryStoreObj.processEvent(Event.OperationFailed); + } + + future.complete(res); + + return null; + } + + protected Void copyManagedTemplateCallback(AsyncCallbackDispatcher callback, CreateBaseImageContext context) { + CopyCommandResult result = callback.getResult(); + VolumeApiResult res = new VolumeApiResult(context.getVolume()); + + res.setResult(result.getResult()); + + AsyncCallFuture future = context.getFuture(); + DataObject templateOnPrimaryStoreObj = context.destObj; + + if (result.isSuccess()) { + templateOnPrimaryStoreObj.processEvent(Event.OperationSuccessed, result.getAnswer()); + } + else { + templateOnPrimaryStoreObj.processEvent(Event.OperationFailed); + } + + future.complete(res); + + return null; + } + @DB protected Void copyBaseImageCallback(AsyncCallbackDispatcher callback, CreateBaseImageContext context) { CopyCommandResult result = callback.getResult(); @@ -636,8 +699,10 @@ protected Void createVolumeFromBaseImageCallBack(AsyncCallbackDispatcher createManagedStorageAndVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId, - TemplateInfo srcTemplateInfo, long destHostId) { - PrimaryDataStore destPrimaryDataStore = dataStoreMgr.getPrimaryDataStore(destDataStoreId); - TemplateInfo destTemplateInfo = (TemplateInfo)destPrimaryDataStore.create(srcTemplateInfo); - Host destHost = _hostDao.findById(destHostId); + /** + * Creates a template volume on managed storage, which will be used for creating ROOT volumes by cloning. + * + * @param srcTemplateInfo Source template on secondary storage + * @param destPrimaryDataStore Managed storage on which we need to create the volume + */ + private TemplateInfo createManagedTemplateVolume(TemplateInfo srcTemplateInfo, PrimaryDataStore destPrimaryDataStore) { + // create a template volume on primary storage + AsyncCallFuture createTemplateFuture = new AsyncCallFuture<>(); + TemplateInfo templateOnPrimary = (TemplateInfo)destPrimaryDataStore.create(srcTemplateInfo); - if (destHost == null) { - throw new CloudRuntimeException("Destinatin host should not be null."); + VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId()); + + if (templatePoolRef == null) { + throw new CloudRuntimeException("Failed to find template " + srcTemplateInfo.getUniqueName() + " in storage pool " + destPrimaryDataStore.getId()); } - AsyncCallFuture future = new AsyncCallFuture(); + // At this point, we have an entry in the DB that points to our cached template. + // We need to lock it as there may be other VMs that may get started using the same template. + // We want to avoid having to create multiple cache copies of the same template. + + int storagePoolMaxWaitSeconds = NumbersUtil.parseInt(configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600); + long templatePoolRefId = templatePoolRef.getId(); + + templatePoolRef = _tmpltPoolDao.acquireInLockTable(templatePoolRefId, storagePoolMaxWaitSeconds); + + if (templatePoolRef == null) { + throw new CloudRuntimeException("Unable to acquire lock on VMTemplateStoragePool: " + templatePoolRefId); + } + + // Template already exists + if (templatePoolRef.getState() == ObjectInDataStoreStateMachine.State.Ready) { + _tmpltPoolDao.releaseFromLockTable(templatePoolRefId); + + return templateOnPrimary; + } try { - // must call driver to have a volume created - AsyncCallFuture createVolumeFuture = createVolumeAsync(volumeInfo, destPrimaryDataStore); + // create a cache volume on the back-end + + templateOnPrimary.processEvent(Event.CreateOnlyRequested); + + CreateVolumeContext createContext = new CreateVolumeContext<>(null, templateOnPrimary, createTemplateFuture); + AsyncCallbackDispatcher createCaller = AsyncCallbackDispatcher.create(this); + + createCaller.setCallback(createCaller.getTarget().createManagedTemplateImageCallback(null, null)).setContext(createContext); + + destPrimaryDataStore.getDriver().createAsync(destPrimaryDataStore, templateOnPrimary, createCaller); + + VolumeApiResult result = createTemplateFuture.get(); + + if (result.isFailed()) { + String errMesg = result.getResult(); + + throw new CloudRuntimeException("Unable to create template " + templateOnPrimary.getId() + + " on primary storage " + destPrimaryDataStore.getId() + ":" + errMesg); + } + } catch (Throwable e) { + s_logger.debug("Failed to create template volume on storage", e); + + templateOnPrimary.processEvent(Event.OperationFailed); + + throw new CloudRuntimeException(e.getMessage()); + } + finally { + _tmpltPoolDao.releaseFromLockTable(templatePoolRefId); + } + + return templateOnPrimary; + } + + /** + * This function copies a template from secondary storage to a template volume + * created on managed storage. This template volume will be used as a cache. + * Instead of copying the template to a ROOT volume every time, a clone is performed instead. + * + * @param srcTemplateInfo Source from which to copy the template + * @param templateOnPrimary Dest to copy to + * @param templatePoolRef Template reference on primary storage (entry in the template_spool_ref) + * @param destPrimaryDataStore The managed primary storage + * @param destHost The host that we will use for the copy + */ + private void copyTemplateToManagedTemplateVolume(TemplateInfo srcTemplateInfo, TemplateInfo templateOnPrimary, VMTemplateStoragePoolVO templatePoolRef, + PrimaryDataStore destPrimaryDataStore, Host destHost) + { + AsyncCallFuture copyTemplateFuture = new AsyncCallFuture<>(); + int storagePoolMaxWaitSeconds = NumbersUtil.parseInt(configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600); + long templatePoolRefId = templatePoolRef.getId(); + templatePoolRef = _tmpltPoolDao.acquireInLockTable(templatePoolRefId, storagePoolMaxWaitSeconds); + + if (templatePoolRef == null) { + throw new CloudRuntimeException("Unable to acquire lock on VMTemplateStoragePool: " + templatePoolRefId); + } + + if (templatePoolRef.getDownloadState() == Status.DOWNLOADED) { + // There can be cases where we acquired the lock, but the template + // was already copied by a previous thread. Just return in that case. + + s_logger.debug("Template already downloaded, nothing to do"); + + return; + } + + try { + // copy the template from sec storage to the created volume + CreateBaseImageContext copyContext = new CreateBaseImageContext<>( + null, null, destPrimaryDataStore, srcTemplateInfo, + copyTemplateFuture, templateOnPrimary, templatePoolRefId + ); + + AsyncCallbackDispatcher copyCaller = AsyncCallbackDispatcher.create(this); + copyCaller.setCallback(copyCaller.getTarget().copyManagedTemplateCallback(null, null)).setContext(copyContext); + + // Populate details which will be later read by the storage subsystem. + Map details = new HashMap(); + + details.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString()); + details.put(PrimaryDataStore.STORAGE_HOST, destPrimaryDataStore.getHostAddress()); + details.put(PrimaryDataStore.STORAGE_PORT, String.valueOf(destPrimaryDataStore.getPort())); + details.put(PrimaryDataStore.MANAGED_STORE_TARGET, ((TemplateObject)templateOnPrimary).getInstallPath()); + details.put(PrimaryDataStore.MANAGED_STORE_TARGET_ROOT_VOLUME, srcTemplateInfo.getUniqueName()); + details.put(PrimaryDataStore.REMOVE_AFTER_COPY, Boolean.TRUE.toString()); + details.put(PrimaryDataStore.VOLUME_SIZE, String.valueOf(templateOnPrimary.getSize())); + + ChapInfo chapInfo = getChapInfo(templateOnPrimary, destPrimaryDataStore); + + if (chapInfo != null) { + details.put(PrimaryDataStore.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername()); + details.put(PrimaryDataStore.CHAP_INITIATOR_SECRET, chapInfo.getInitiatorSecret()); + details.put(PrimaryDataStore.CHAP_TARGET_USERNAME, chapInfo.getTargetUsername()); + details.put(PrimaryDataStore.CHAP_TARGET_SECRET, chapInfo.getTargetSecret()); + } + + templateOnPrimary.processEvent(Event.CopyingRequested); + + destPrimaryDataStore.setDetails(details); + + grantAccess(templateOnPrimary, destHost, destPrimaryDataStore); + + VolumeApiResult result = null; + + try { + motionSrv.copyAsync(srcTemplateInfo, templateOnPrimary, destHost, copyCaller); + + result = copyTemplateFuture.get(); + } + finally { + revokeAccess(templateOnPrimary, destHost, destPrimaryDataStore); + } + + if (result.isFailed()) { + throw new CloudRuntimeException("Failed to copy template " + templateOnPrimary.getId() + + " to primary storage " + destPrimaryDataStore.getId() + ": " + result.getResult()); + // XXX: I find it is useful to destroy the volume on primary storage instead of another thread trying the copy again because I've seen + // something weird happens to the volume (XenServer creates an SR, but the VDI copy can fail). + // For now, I just retry the copy. + } + } + catch (Throwable e) { + s_logger.debug("Failed to create a template on primary storage", e); + + templateOnPrimary.processEvent(Event.OperationFailed); + + throw new CloudRuntimeException(e.getMessage()); + } + finally { + _tmpltPoolDao.releaseFromLockTable(templatePoolRefId); + } + } + + /** + * Clones the template volume on managed storage to the ROOT volume + * + * @param volumeInfo ROOT volume to create + * @param templateOnPrimary Template from which to clone the ROOT volume + * @param destPrimaryDataStore Primary storage of the volume + * @param future For async + */ + private void createManagedVolumeCloneTemplateAsync(VolumeInfo volumeInfo, TemplateInfo templateOnPrimary, PrimaryDataStore destPrimaryDataStore, + AsyncCallFuture future) { + VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId()); + + if (templatePoolRef == null) { + throw new CloudRuntimeException("Failed to find template " + templateOnPrimary.getUniqueName() + " in storage pool " + destPrimaryDataStore.getId()); + } + + //XXX: not sure if this the right thing to do here. We can always fallback to the "copy from sec storage" + if (templatePoolRef.getDownloadState() == Status.NOT_DOWNLOADED) { + throw new CloudRuntimeException("Template " + templateOnPrimary.getUniqueName() + " has not been downloaded to primary storage."); + } + + try { + volumeInfo.processEvent(Event.CreateOnlyRequested); + + CreateVolumeFromBaseImageContext context = + new CreateVolumeFromBaseImageContext<>(null, volumeInfo, destPrimaryDataStore, templateOnPrimary, future, null); + + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + + caller.setCallback(caller.getTarget().createVolumeFromBaseImageCallBack(null, null)); + caller.setContext(context); + + motionSrv.copyAsync(templateOnPrimary, volumeInfo, caller); + } catch (Throwable e) { + s_logger.debug("Failed to clone template on primary storage", e); + + volumeInfo.processEvent(Event.OperationFailed); + + throw new CloudRuntimeException(e.getMessage()); + } + } + + private void createManagedVolumeCopyTemplateAsync(VolumeInfo volumeInfo, PrimaryDataStore primaryDataStore, TemplateInfo srcTemplateInfo, Host destHost, + AsyncCallFuture future) { + try { + // Create a volume on managed storage. + + TemplateInfo destTemplateInfo = (TemplateInfo)primaryDataStore.create(srcTemplateInfo, false); + + AsyncCallFuture createVolumeFuture = createVolumeAsync(volumeInfo, primaryDataStore); VolumeApiResult createVolumeResult = createVolumeFuture.get(); if (createVolumeResult.isFailed()) { throw new CloudRuntimeException("Creation of a volume failed: " + createVolumeResult.getResult()); } - // refresh the volume from the DB - volumeInfo = volFactory.getVolume(volumeInfo.getId(), destPrimaryDataStore); - - grantAccess(volumeInfo, destHost, destPrimaryDataStore); + // Refresh the volume info from the DB. + volumeInfo = volFactory.getVolume(volumeInfo.getId(), primaryDataStore); ManagedCreateBaseImageContext context = new ManagedCreateBaseImageContext(null, volumeInfo, - destPrimaryDataStore, srcTemplateInfo, future); + primaryDataStore, srcTemplateInfo, future); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().managedCopyBaseImageCallback(null, null)).setContext(context); Map details = new HashMap(); details.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString()); - details.put(PrimaryDataStore.STORAGE_HOST, destPrimaryDataStore.getHostAddress()); - details.put(PrimaryDataStore.STORAGE_PORT, String.valueOf(destPrimaryDataStore.getPort())); + details.put(PrimaryDataStore.STORAGE_HOST, primaryDataStore.getHostAddress()); + details.put(PrimaryDataStore.STORAGE_PORT, String.valueOf(primaryDataStore.getPort())); // for managed storage, the storage repository (XenServer) or datastore (ESX) name is based off of the iScsiName property of a volume details.put(PrimaryDataStore.MANAGED_STORE_TARGET, volumeInfo.get_iScsiName()); details.put(PrimaryDataStore.MANAGED_STORE_TARGET_ROOT_VOLUME, volumeInfo.getName()); details.put(PrimaryDataStore.VOLUME_SIZE, String.valueOf(volumeInfo.getSize())); - ChapInfo chapInfo = getChapInfo(volumeInfo, destPrimaryDataStore); + ChapInfo chapInfo = getChapInfo(volumeInfo, primaryDataStore); if (chapInfo != null) { details.put(PrimaryDataStore.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername()); @@ -705,17 +973,21 @@ public AsyncCallFuture createManagedStorageAndVolumeFromTemplat details.put(PrimaryDataStore.CHAP_TARGET_SECRET, chapInfo.getTargetSecret()); } - destPrimaryDataStore.setDetails(details); + primaryDataStore.setDetails(details); - motionSrv.copyAsync(srcTemplateInfo, destTemplateInfo, destHost, caller); - } - catch (Throwable t) { + grantAccess(volumeInfo, destHost, primaryDataStore); + + try { + motionSrv.copyAsync(srcTemplateInfo, destTemplateInfo, destHost, caller); + } + finally { + revokeAccess(volumeInfo, destHost, primaryDataStore); + } + } catch (Throwable t) { String errMsg = t.toString(); volumeInfo.processEvent(Event.DestroyRequested); - revokeAccess(volumeInfo, destHost, destPrimaryDataStore); - try { AsyncCallFuture expungeVolumeFuture = expungeVolumeAsync(volumeInfo); @@ -735,10 +1007,112 @@ public AsyncCallFuture createManagedStorageAndVolumeFromTemplat future.complete(result); } + } + + @Override + public AsyncCallFuture createManagedStorageVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId, + TemplateInfo srcTemplateInfo, long destHostId) { + PrimaryDataStore destPrimaryDataStore = dataStoreMgr.getPrimaryDataStore(destDataStoreId); + Host destHost = _hostDao.findById(destHostId); + + if (destHost == null) { + throw new CloudRuntimeException("Destination host should not be null."); + } + + Boolean storageCanCloneVolume = new Boolean( + destPrimaryDataStore.getDriver().getCapabilities().get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString()) + ); + + boolean computeZoneSupportsResign = computeZoneSupportsResign(destHost.getDataCenterId(), destHost.getHypervisorType()); + + AsyncCallFuture future = new AsyncCallFuture<>(); + + if (storageCanCloneVolume && computeZoneSupportsResign) { + s_logger.debug("Storage " + destDataStoreId + " can support cloning using a cached template and host cluster can perform UUID resigning."); + + TemplateInfo templateOnPrimary = destPrimaryDataStore.getTemplate(srcTemplateInfo.getId()); + + if (templateOnPrimary == null) { + templateOnPrimary = createManagedTemplateVolume(srcTemplateInfo, destPrimaryDataStore); + + if (templateOnPrimary == null) { + throw new CloudRuntimeException("Failed to create template " + srcTemplateInfo.getUniqueName() + " on primary storage: " + destDataStoreId); + } + } + + // Copy the template to the template volume. + VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId()); + + if (templatePoolRef == null) { + throw new CloudRuntimeException("Failed to find template " + + srcTemplateInfo.getUniqueName() + " in storage pool " + + destPrimaryDataStore.getId() + ); + } + + if (templatePoolRef.getDownloadState() == Status.NOT_DOWNLOADED) { + copyTemplateToManagedTemplateVolume(srcTemplateInfo, templateOnPrimary, templatePoolRef, destPrimaryDataStore, destHost); + } + + // We have a template on primary storage. Clone it to new volume. + s_logger.debug("Creating a clone from template on primary storage " + destDataStoreId); + createManagedVolumeCloneTemplateAsync(volumeInfo, templateOnPrimary, destPrimaryDataStore, future); + } else { + s_logger.debug("Primary storage does not support cloning or no support for UUID resigning on the host side; copying the template normally"); + createManagedVolumeCopyTemplateAsync(volumeInfo, destPrimaryDataStore, srcTemplateInfo, destHost, future); + } return future; } + private boolean computeZoneSupportsResign(long zoneId, HypervisorType hypervisorType) { + return getHost(zoneId, hypervisorType, true) != null; + } + + private HostVO getHost(Long zoneId, HypervisorType hypervisorType, boolean computeClusterMustSupportResign) { + if (zoneId == null) { + throw new CloudRuntimeException("Zone ID cannot be null."); + } + + List clusters = mgr.searchForClusters(zoneId, new Long(0), Long.MAX_VALUE, hypervisorType.toString()); + + if (clusters == null) { + clusters = new ArrayList<>(); + } + + Collections.shuffle(clusters, new Random(System.nanoTime())); + + clusters: + for (Cluster cluster : clusters) { + if (cluster.getAllocationState() == AllocationState.Enabled) { + List hosts = _hostDao.findByClusterId(cluster.getId()); + + if (hosts != null) { + Collections.shuffle(hosts, new Random(System.nanoTime())); + + for (HostVO host : hosts) { + if (host.getResourceState() == ResourceState.Enabled) { + if (computeClusterMustSupportResign) { + if (clusterDao.computeWhetherClusterSupportsResigning(cluster.getId())) { + return host; + } + else { + // no other host in the cluster in question should be able to satisfy our requirements here, so move on to the next cluster + continue clusters; + } + } + else { + return host; + } + } + } + } + } + } + + return null; + } + @DB @Override public AsyncCallFuture createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, TemplateInfo template) { @@ -1332,7 +1706,8 @@ public void resizeVolumeOnHypervisor(long volumeId, long newSize, long destHostI if (ep != null) { VolumeVO volume = volDao.findById(volumeId); PrimaryDataStore primaryDataStore = this.dataStoreMgr.getPrimaryDataStore(volume.getPoolId()); - ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(volume.getPath(), new StorageFilerTO(primaryDataStore), volume.getSize(), newSize, true, instanceName); + ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(volume.getPath(), new StorageFilerTO(primaryDataStore), + volume.getSize(), newSize, true, instanceName, primaryDataStore.isManaged(), volume.get_iScsiName()); answer = ep.sendMessage(resizeCmd); } else { diff --git a/plugins/api/solidfire-intg-test/pom.xml b/plugins/api/solidfire-intg-test/pom.xml index a15d7b3e85..fa5302b14b 100644 --- a/plugins/api/solidfire-intg-test/pom.xml +++ b/plugins/api/solidfire-intg-test/pom.xml @@ -19,7 +19,7 @@ 4.0.0 cloud-plugin-api-solidfire-intg-test - Apache CloudStack Plugin - API SolidFire + Apache CloudStack Plugin - API SolidFire Integration Testing org.apache.cloudstack cloudstack-plugins diff --git a/plugins/api/solidfire-intg-test/resources/META-INF/cloudstack/solidfire-intg-test/spring-solidfire-intg-test-context.xml b/plugins/api/solidfire-intg-test/resources/META-INF/cloudstack/solidfire-intg-test/spring-solidfire-intg-test-context.xml index 1bab7349ca..2fe875af69 100644 --- a/plugins/api/solidfire-intg-test/resources/META-INF/cloudstack/solidfire-intg-test/spring-solidfire-intg-test-context.xml +++ b/plugins/api/solidfire-intg-test/resources/META-INF/cloudstack/solidfire-intg-test/spring-solidfire-intg-test-context.xml @@ -27,6 +27,8 @@ http://www.springframework.org/schema/context/spring-context-3.0.xsd" > - + + + diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetPathForVolumeCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetPathForVolumeCmd.java new file mode 100644 index 0000000000..5ff178a2e9 --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetPathForVolumeCmd.java @@ -0,0 +1,67 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.solidfire; + +import javax.inject.Inject; + +import org.apache.log4j.Logger; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.solidfire.ApiPathForVolumeResponse; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; + +@APICommand(name = "getPathForVolume", responseObject = ApiPathForVolumeResponse.class, description = "Get the path associated with the provided volume UUID", + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class GetPathForVolumeCmd extends BaseCmd { + private static final Logger LOGGER = Logger.getLogger(GetPathForVolumeCmd.class.getName()); + private static final String NAME = "getpathforvolumeresponse"; + + @Parameter(name = ApiConstants.VOLUME_ID, type = CommandType.STRING, description = "CloudStack Volume UUID", required = true) + private String _volumeUuid; + + @Inject private SolidFireIntegrationTestUtil _util; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return NAME; + } + + @Override + public long getEntityOwnerId() { + return _util.getAccountIdForVolumeUuid(_volumeUuid); + } + + @Override + public void execute() { + LOGGER.info("'GetPathForVolumeIdCmd.execute' method invoked"); + + String pathForVolume = _util.getPathForVolumeUuid(_volumeUuid); + + ApiPathForVolumeResponse response = new ApiPathForVolumeResponse(pathForVolume); + + response.setResponseName(getCommandName()); + response.setObjectName("apipathforvolume"); + + setResponseObject(response); + } +} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireAccountIdCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireAccountIdCmd.java similarity index 60% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireAccountIdCmd.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireAccountIdCmd.java index f4c0076f86..9bb8481c3c 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireAccountIdCmd.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireAccountIdCmd.java @@ -14,10 +14,7 @@ // 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.solidfire; - -import com.cloud.user.Account; -import com.cloud.user.dao.AccountDao; +package org.apache.cloudstack.api.command.admin.solidfire; import javax.inject.Inject; @@ -27,26 +24,23 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.response.ApiSolidFireAccountIdResponse; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.solidfire.ApiSolidFireService; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.api.response.solidfire.ApiSolidFireAccountIdResponse; +import org.apache.cloudstack.solidfire.SolidFireIntegrationTestManager; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; @APICommand(name = "getSolidFireAccountId", responseObject = ApiSolidFireAccountIdResponse.class, description = "Get SolidFire Account ID", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class GetSolidFireAccountIdCmd extends BaseCmd { - private static final Logger s_logger = Logger.getLogger(GetSolidFireAccountIdCmd.class.getName()); - private static final String s_name = "getsolidfireaccountidresponse"; + private static final Logger LOGGER = Logger.getLogger(GetSolidFireAccountIdCmd.class.getName()); + private static final String NAME = "getsolidfireaccountidresponse"; @Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.STRING, description = "CloudStack Account UUID", required = true) - private String accountUuid; + private String csAccountUuid; @Parameter(name = ApiConstants.STORAGE_ID, type = CommandType.STRING, description = "Storage Pool UUID", required = true) private String storagePoolUuid; - @Inject private ApiSolidFireService _apiSolidFireService; - @Inject private AccountDao _accountDao; - @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private SolidFireIntegrationTestManager manager; + @Inject private SolidFireIntegrationTestUtil util; ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -54,26 +48,21 @@ public class GetSolidFireAccountIdCmd extends BaseCmd { @Override public String getCommandName() { - return s_name; + return NAME; } @Override public long getEntityOwnerId() { - Account account = CallContext.current().getCallingAccount(); - - if (account != null) { - return account.getId(); - } - - return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked + return util.getAccountIdForAccountUuid(csAccountUuid); } @Override public void execute() { - Account account = _accountDao.findByUuid(accountUuid); - StoragePoolVO storagePool = _storagePoolDao.findByUuid(storagePoolUuid); + LOGGER.info("'GetSolidFireAccountIdCmd.execute' method invoked"); + + long sfAccountId = manager.getSolidFireAccountId(csAccountUuid, storagePoolUuid); - ApiSolidFireAccountIdResponse response = _apiSolidFireService.getSolidFireAccountId(account.getId(), storagePool.getId()); + ApiSolidFireAccountIdResponse response = new ApiSolidFireAccountIdResponse(sfAccountId); response.setResponseName(getCommandName()); response.setObjectName("apisolidfireaccountid"); diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java similarity index 70% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java index c432fb1109..5c15e01a30 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java @@ -14,12 +14,9 @@ // 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.solidfire; +package org.apache.cloudstack.api.command.admin.solidfire; import com.cloud.user.Account; -import com.cloud.org.Cluster; -import com.cloud.storage.StoragePool; -import com.cloud.dc.dao.ClusterDao; import javax.inject.Inject; @@ -29,25 +26,24 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeAccessGroupIdResponse; +import org.apache.cloudstack.api.response.solidfire.ApiSolidFireVolumeAccessGroupIdResponse; import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.solidfire.ApiSolidFireService; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.solidfire.SolidFireIntegrationTestManager; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; @APICommand(name = "getSolidFireVolumeAccessGroupId", responseObject = ApiSolidFireVolumeAccessGroupIdResponse.class, description = "Get the SF Volume Access Group ID", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class GetSolidFireVolumeAccessGroupIdCmd extends BaseCmd { - private static final Logger s_logger = Logger.getLogger(GetSolidFireVolumeAccessGroupIdCmd.class.getName()); - private static final String s_name = "getsolidfirevolumeaccessgroupidresponse"; + private static final Logger LOGGER = Logger.getLogger(GetSolidFireVolumeAccessGroupIdCmd.class.getName()); + private static final String NAME = "getsolidfirevolumeaccessgroupidresponse"; @Parameter(name = ApiConstants.CLUSTER_ID, type = CommandType.STRING, description = "Cluster UUID", required = true) private String clusterUuid; @Parameter(name = ApiConstants.STORAGE_ID, type = CommandType.STRING, description = "Storage Pool UUID", required = true) private String storagePoolUuid; - @Inject private ApiSolidFireService _apiSolidFireService; - @Inject private ClusterDao _clusterDao; - @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private SolidFireIntegrationTestManager manager; + @Inject private SolidFireIntegrationTestUtil util; ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -55,7 +51,7 @@ public class GetSolidFireVolumeAccessGroupIdCmd extends BaseCmd { @Override public String getCommandName() { - return s_name; + return NAME; } @Override @@ -71,10 +67,11 @@ public long getEntityOwnerId() { @Override public void execute() { - Cluster cluster = _clusterDao.findByUuid(clusterUuid); - StoragePool storagePool = _storagePoolDao.findByUuid(storagePoolUuid); + LOGGER.info("'GetSolidFireVolumeAccessGroupIdCmd.execute' method invoked"); - ApiSolidFireVolumeAccessGroupIdResponse response = _apiSolidFireService.getSolidFireVolumeAccessGroupId(cluster.getId(), storagePool.getId()); + long sfVagId = manager.getSolidFireVolumeAccessGroupId(clusterUuid, storagePoolUuid); + + ApiSolidFireVolumeAccessGroupIdResponse response = new ApiSolidFireVolumeAccessGroupIdResponse(sfVagId); response.setResponseName(getCommandName()); response.setObjectName("apisolidfirevolumeaccessgroupid"); diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeSizeCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeSizeCmd.java similarity index 57% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeSizeCmd.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeSizeCmd.java index 3a27a66811..d7c8acfe37 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeSizeCmd.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeSizeCmd.java @@ -14,12 +14,7 @@ // 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.solidfire; - -import com.cloud.storage.Volume; -import com.cloud.user.Account; -import com.cloud.storage.dao.VolumeDao; -import com.cloud.storage.StoragePool; +package org.apache.cloudstack.api.command.admin.solidfire; import javax.inject.Inject; @@ -29,25 +24,21 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeSizeResponse; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.solidfire.ApiSolidFireService; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.api.response.solidfire.ApiSolidFireVolumeSizeResponse; +import org.apache.cloudstack.solidfire.SolidFireIntegrationTestManager; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; @APICommand(name = "getSolidFireVolumeSize", responseObject = ApiSolidFireVolumeSizeResponse.class, description = "Get the SF volume size including Hypervisor Snapshot Reserve", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class GetSolidFireVolumeSizeCmd extends BaseCmd { - private static final Logger s_logger = Logger.getLogger(GetSolidFireVolumeSizeCmd.class.getName()); - private static final String s_name = "getsolidfirevolumesizeresponse"; + private static final Logger LOGGER = Logger.getLogger(GetSolidFireVolumeSizeCmd.class.getName()); + private static final String NAME = "getsolidfirevolumesizeresponse"; @Parameter(name = ApiConstants.VOLUME_ID, type = CommandType.STRING, description = "Volume UUID", required = true) private String volumeUuid; - @Parameter(name = ApiConstants.STORAGE_ID, type = CommandType.STRING, description = "Storage Pool UUID", required = true) - private String storagePoolUuid; - @Inject private ApiSolidFireService _apiSolidFireService; - @Inject private VolumeDao _volumeDao; - @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private SolidFireIntegrationTestManager manager; + @Inject private SolidFireIntegrationTestUtil util; ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -55,26 +46,21 @@ public class GetSolidFireVolumeSizeCmd extends BaseCmd { @Override public String getCommandName() { - return s_name; + return NAME; } @Override public long getEntityOwnerId() { - Account account = CallContext.current().getCallingAccount(); - - if (account != null) { - return account.getId(); - } - - return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked + return util.getAccountIdForVolumeUuid(volumeUuid); } @Override public void execute() { - Volume volume = _volumeDao.findByUuid(volumeUuid); - StoragePool storagePool = _storagePoolDao.findByUuid(storagePoolUuid); + LOGGER.info("'GetSolidFireVolumeSizeCmd.execute' method invoked"); + + long sfVolumeSize = manager.getSolidFireVolumeSize(volumeUuid); - ApiSolidFireVolumeSizeResponse response = _apiSolidFireService.getSolidFireVolumeSize(volume, storagePool); + ApiSolidFireVolumeSizeResponse response = new ApiSolidFireVolumeSizeResponse(sfVolumeSize); response.setResponseName(getCommandName()); response.setObjectName("apisolidfirevolumesize"); diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeSnapshotDetailsCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeSnapshotDetailsCmd.java new file mode 100644 index 0000000000..5b9ce37332 --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeSnapshotDetailsCmd.java @@ -0,0 +1,73 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.solidfire; + +import java.util.List; + +import javax.inject.Inject; + +import org.apache.log4j.Logger; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.solidfire.ApiVolumeSnapshotDetailsResponse; +import org.apache.cloudstack.api.response.solidfire.ApiVolumeiScsiNameResponse; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; + +@APICommand(name = "getVolumeSnapshotDetails", responseObject = ApiVolumeiScsiNameResponse.class, description = "Get Volume Snapshot Details", + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) + +public class GetVolumeSnapshotDetailsCmd extends BaseCmd { + private static final Logger LOGGER = Logger.getLogger(GetVolumeSnapshotDetailsCmd.class.getName()); + private static final String NAME = "getvolumesnapshotdetailsresponse"; + + @Parameter(name = ApiConstants.SNAPSHOT_ID, type = CommandType.STRING, description = "CloudStack Snapshot UUID", required = true) + private String snapshotUuid; + + @Inject private SolidFireIntegrationTestUtil util; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return NAME; + } + + @Override + public long getEntityOwnerId() { + return util.getAccountIdForSnapshotUuid(snapshotUuid); + } + + @Override + public void execute() { + LOGGER.info("'" + GetVolumeSnapshotDetailsCmd.class.getSimpleName() + ".execute' method invoked"); + + List responses = util.getSnapshotDetails(snapshotUuid); + + ListResponse listReponse = new ListResponse<>(); + + listReponse.setResponses(responses); + listReponse.setResponseName(getCommandName()); + listReponse.setObjectName("apivolumesnapshotdetails"); + + this.setResponseObject(listReponse); + } +} \ No newline at end of file diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeIscsiNameCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeiScsiNameCmd.java similarity index 55% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeIscsiNameCmd.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeiScsiNameCmd.java index 7afa301403..dd6992caf3 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeIscsiNameCmd.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeiScsiNameCmd.java @@ -14,11 +14,7 @@ // 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.solidfire; - -import com.cloud.storage.dao.VolumeDao; -import com.cloud.storage.Volume; -import com.cloud.user.Account; +package org.apache.cloudstack.api.command.admin.solidfire; import javax.inject.Inject; @@ -27,22 +23,20 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeIscsiNameResponse; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.solidfire.ApiSolidFireService; +import org.apache.cloudstack.api.response.solidfire.ApiVolumeiScsiNameResponse; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; -@APICommand(name = "getSolidFireVolumeIscsiName", responseObject = ApiSolidFireVolumeIscsiNameResponse.class, description = "Get SolidFire Volume's Iscsi Name", +@APICommand(name = "getVolumeiScsiName", responseObject = ApiVolumeiScsiNameResponse.class, description = "Get Volume's iSCSI Name", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) -public class GetSolidFireVolumeIscsiNameCmd extends BaseCmd { - private static final Logger s_logger = Logger.getLogger(GetSolidFireVolumeIscsiNameCmd.class.getName()); - private static final String s_name = "getsolidfirevolumeiscsinameresponse"; +public class GetVolumeiScsiNameCmd extends BaseCmd { + private static final Logger LOGGER = Logger.getLogger(GetVolumeiScsiNameCmd.class.getName()); + private static final String NAME = "getvolumeiscsinameresponse"; @Parameter(name = ApiConstants.VOLUME_ID, type = CommandType.STRING, description = "CloudStack Volume UUID", required = true) private String volumeUuid; - @Inject private ApiSolidFireService _apiSolidFireService; - @Inject private VolumeDao _volumeDao; + @Inject private SolidFireIntegrationTestUtil _util; ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -50,28 +44,24 @@ public class GetSolidFireVolumeIscsiNameCmd extends BaseCmd { @Override public String getCommandName() { - return s_name; + return NAME; } @Override public long getEntityOwnerId() { - Account account = CallContext.current().getCallingAccount(); - - if (account != null) { - return account.getId(); - } - - return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked + return _util.getAccountIdForVolumeUuid(volumeUuid); } @Override public void execute() { - Volume volume = _volumeDao.findByUuid(volumeUuid); + LOGGER.info("'GetVolumeiScsiNameCmd.execute' method invoked"); + + String volume_iScsiName = _util.getVolume_iScsiName(volumeUuid); - ApiSolidFireVolumeIscsiNameResponse response = _apiSolidFireService.getSolidFireVolumeIscsiName(volume); + ApiVolumeiScsiNameResponse response = new ApiVolumeiScsiNameResponse(volume_iScsiName); response.setResponseName(getCommandName()); - response.setObjectName("apisolidfirevolumeiscsiname"); + response.setObjectName("apivolumeiscsiname"); this.setResponseObject(response); } diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiPathForVolumeResponse.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiPathForVolumeResponse.java new file mode 100644 index 0000000000..3e0f820aea --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiPathForVolumeResponse.java @@ -0,0 +1,33 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response.solidfire; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public class ApiPathForVolumeResponse extends BaseResponse { + @SerializedName(ApiConstants.PATH) + @Param(description = "The path field for the volume") + private String path; + + public ApiPathForVolumeResponse(String path) { + this.path = path; + } +} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireAccountIdResponse.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireAccountIdResponse.java similarity index 90% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireAccountIdResponse.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireAccountIdResponse.java index ad77c7495d..a1c2a4c32d 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireAccountIdResponse.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireAccountIdResponse.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.api.response; +package org.apache.cloudstack.api.response.solidfire; import com.cloud.serializer.Param; @@ -30,8 +30,4 @@ public class ApiSolidFireAccountIdResponse extends BaseResponse { public ApiSolidFireAccountIdResponse(long sfAccountId) { solidFireAccountId = sfAccountId; } - - public long getSolidFireAccountId() { - return solidFireAccountId; - } } diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeAccessGroupIdResponse.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeAccessGroupIdResponse.java similarity index 90% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeAccessGroupIdResponse.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeAccessGroupIdResponse.java index 8b63192b7c..202a7e9ebb 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeAccessGroupIdResponse.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeAccessGroupIdResponse.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.api.response; +package org.apache.cloudstack.api.response.solidfire; import com.cloud.serializer.Param; @@ -30,8 +30,4 @@ public class ApiSolidFireVolumeAccessGroupIdResponse extends BaseResponse { public ApiSolidFireVolumeAccessGroupIdResponse(long sfVolumeAccessGroupId) { solidFireVolumeAccessGroupId = sfVolumeAccessGroupId; } - - public long getSolidFireAccessGroupId() { - return solidFireVolumeAccessGroupId; - } } \ No newline at end of file diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeSizeResponse.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeSizeResponse.java similarity index 90% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeSizeResponse.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeSizeResponse.java index b320adab87..d8a7d0407c 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeSizeResponse.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeSizeResponse.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.api.response; +package org.apache.cloudstack.api.response.solidfire; import com.cloud.serializer.Param; @@ -30,8 +30,4 @@ public class ApiSolidFireVolumeSizeResponse extends BaseResponse { public ApiSolidFireVolumeSizeResponse(long sfVolumeSize) { solidFireVolumeSize = sfVolumeSize; } - - public long getSolidFireVolumeSize() { - return solidFireVolumeSize; - } } \ No newline at end of file diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeSnapshotDetailsResponse.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeSnapshotDetailsResponse.java new file mode 100644 index 0000000000..364ded8dce --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeSnapshotDetailsResponse.java @@ -0,0 +1,43 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response.solidfire; + +import com.cloud.serializer.Param; + +import com.google.gson.annotations.SerializedName; + +import org.apache.cloudstack.api.BaseResponse; + +public class ApiVolumeSnapshotDetailsResponse extends BaseResponse { + @SerializedName("volumeSnapshotId") + @Param(description = "CloudStack Volume Snapshot ID") + private long volumeSnapshotId; + + @SerializedName("snapshotDetailsName") + @Param(description = "Snapshot Details Name") + private String volumeSnapshotDetailsName; + + @SerializedName("snapshotDetailsValue") + @Param(description = "Snapshot Details Value") + private String volumeSnapshotDetailsValue; + + public ApiVolumeSnapshotDetailsResponse(long volumeSnapshotId, String volumeSnapshotDetailsName, String volumeSnapshotDetailsValue) { + this.volumeSnapshotId = volumeSnapshotId; + this.volumeSnapshotDetailsName = volumeSnapshotDetailsName; + this.volumeSnapshotDetailsValue = volumeSnapshotDetailsValue; + } +} \ No newline at end of file diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeIscsiNameResponse.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeiScsiNameResponse.java similarity index 65% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeIscsiNameResponse.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeiScsiNameResponse.java index 517cba93ec..f43e53352a 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeIscsiNameResponse.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeiScsiNameResponse.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.api.response; +package org.apache.cloudstack.api.response.solidfire; import com.cloud.serializer.Param; @@ -22,16 +22,12 @@ import org.apache.cloudstack.api.BaseResponse; -public class ApiSolidFireVolumeIscsiNameResponse extends BaseResponse { - @SerializedName("solidFireVolumeIscsiName") - @Param(description = "SolidFire Volume Iscsi Name") - private String solidFireVolumeIscsiName; +public class ApiVolumeiScsiNameResponse extends BaseResponse { + @SerializedName("volumeiScsiName") + @Param(description = "Volume iSCSI Name") + private String volumeiScsiName; - public ApiSolidFireVolumeIscsiNameResponse(String sfVolumeIscsiName) { - solidFireVolumeIscsiName = sfVolumeIscsiName; + public ApiVolumeiScsiNameResponse(String volumeiScsiName) { + this.volumeiScsiName = volumeiScsiName; } - - public String getSolidFireVolumeIscsiName() { - return solidFireVolumeIscsiName; - } -} \ No newline at end of file +} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestService.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestService.java new file mode 100644 index 0000000000..ff206d3a3b --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestService.java @@ -0,0 +1,22 @@ +// 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.solidfire; + +import com.cloud.utils.component.PluggableService; + +public interface ApiSolidFireIntegrationTestService extends PluggableService { +} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestServiceImpl.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestServiceImpl.java new file mode 100644 index 0000000000..04589038d3 --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestServiceImpl.java @@ -0,0 +1,48 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.solidfire; + +import java.util.List; +import java.util.ArrayList; + +import org.apache.cloudstack.api.command.admin.solidfire.GetPathForVolumeCmd; +// import org.apache.log4j.Logger; +import org.apache.cloudstack.api.command.admin.solidfire.GetSolidFireAccountIdCmd; +import org.apache.cloudstack.api.command.admin.solidfire.GetSolidFireVolumeAccessGroupIdCmd; +import org.apache.cloudstack.api.command.admin.solidfire.GetVolumeSnapshotDetailsCmd; +import org.apache.cloudstack.api.command.admin.solidfire.GetVolumeiScsiNameCmd; +import org.apache.cloudstack.api.command.admin.solidfire.GetSolidFireVolumeSizeCmd; +import org.springframework.stereotype.Component; + +import com.cloud.utils.component.AdapterBase; + +@Component +public class ApiSolidFireIntegrationTestServiceImpl extends AdapterBase implements ApiSolidFireIntegrationTestService { + @Override + public List> getCommands() { + List> cmdList = new ArrayList>(); + + cmdList.add(GetPathForVolumeCmd.class); + cmdList.add(GetSolidFireAccountIdCmd.class); + cmdList.add(GetSolidFireVolumeAccessGroupIdCmd.class); + cmdList.add(GetVolumeiScsiNameCmd.class); + cmdList.add(GetSolidFireVolumeSizeCmd.class); + cmdList.add(GetVolumeSnapshotDetailsCmd.class); + + return cmdList; + } +} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireService.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireService.java deleted file mode 100644 index 92828d4b81..0000000000 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireService.java +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.solidfire; - -import com.cloud.utils.component.PluggableService; -import com.cloud.storage.Volume; -import com.cloud.storage.StoragePool; - -import org.apache.cloudstack.api.response.ApiSolidFireAccountIdResponse; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeSizeResponse; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeAccessGroupIdResponse; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeIscsiNameResponse; - -/** - * Provide API for SolidFire integration tests - * - */ -public interface ApiSolidFireService extends PluggableService { - public ApiSolidFireAccountIdResponse getSolidFireAccountId(Long csAccountId, Long storagePoolId); - public ApiSolidFireVolumeSizeResponse getSolidFireVolumeSize(Volume volume, StoragePool storagePool); - public ApiSolidFireVolumeAccessGroupIdResponse getSolidFireVolumeAccessGroupId(Long csClusterId, Long storagePoolId); - public ApiSolidFireVolumeIscsiNameResponse getSolidFireVolumeIscsiName(Volume volume); -} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireServiceImpl.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireServiceImpl.java deleted file mode 100644 index fbda65433a..0000000000 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireServiceImpl.java +++ /dev/null @@ -1,126 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.solidfire; - -import java.util.Map; -import java.util.List; -import java.util.ArrayList; - -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -// import org.apache.log4j.Logger; -import org.apache.cloudstack.acl.APIChecker; -import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; -import org.apache.cloudstack.api.command.user.solidfire.GetSolidFireAccountIdCmd; -import org.apache.cloudstack.api.command.user.solidfire.GetSolidFireVolumeAccessGroupIdCmd; -import org.apache.cloudstack.api.command.user.solidfire.GetSolidFireVolumeIscsiNameCmd; -import org.apache.cloudstack.api.command.user.solidfire.GetSolidFireVolumeSizeCmd; -import org.apache.cloudstack.api.response.ApiSolidFireAccountIdResponse; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeAccessGroupIdResponse; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeIscsiNameResponse; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeSizeResponse; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; -import org.springframework.stereotype.Component; - -import com.cloud.dc.ClusterDetailsDao; -import com.cloud.dc.ClusterDetailsVO; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; -import com.cloud.user.AccountDetailsDao; -import com.cloud.user.AccountDetailVO; -import com.cloud.user.User; -import com.cloud.utils.component.AdapterBase; - -@Component -public class ApiSolidFireServiceImpl extends AdapterBase implements APIChecker, ApiSolidFireService { - // private static final Logger s_logger = Logger.getLogger(ApiSolidFireServiceImpl.class); - - @Inject private AccountDetailsDao _accountDetailsDao; - @Inject private DataStoreProviderManager _dataStoreProviderMgr; - @Inject private ClusterDetailsDao _clusterDetailsDao; - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - super.configure(name, params); - - return true; - } - - @Override - public ApiSolidFireAccountIdResponse getSolidFireAccountId(Long csAccountId, Long storagePoolId) { - AccountDetailVO accountDetail = _accountDetailsDao.findDetail(csAccountId, SolidFireUtil.getAccountKey(storagePoolId)); - String sfAccountId = accountDetail.getValue(); - - return new ApiSolidFireAccountIdResponse(Long.parseLong(sfAccountId)); - } - - @Override - public ApiSolidFireVolumeSizeResponse getSolidFireVolumeSize(Volume volume, StoragePool storagePool) { - PrimaryDataStoreDriver primaryStoreDriver = null; - - try { - DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(storagePool.getStorageProviderName()); - DataStoreDriver storeDriver = storeProvider.getDataStoreDriver(); - - if (storeDriver instanceof PrimaryDataStoreDriver) { - primaryStoreDriver = (PrimaryDataStoreDriver)storeDriver; - } - } - catch (InvalidParameterValueException e) { - throw new InvalidParameterValueException("Invalid Storage Driver Type"); - } - - return new ApiSolidFireVolumeSizeResponse(primaryStoreDriver.getVolumeSizeIncludingHypervisorSnapshotReserve(volume, storagePool)); - } - - @Override - public ApiSolidFireVolumeAccessGroupIdResponse getSolidFireVolumeAccessGroupId(Long csClusterId, Long storagePoolId) { - ClusterDetailsVO clusterDetails = _clusterDetailsDao.findDetail(csClusterId, SolidFireUtil.getVagKey(storagePoolId)); - String sfVagId = clusterDetails.getValue(); - - return new ApiSolidFireVolumeAccessGroupIdResponse(Long.parseLong(sfVagId)); - } - - @Override - public ApiSolidFireVolumeIscsiNameResponse getSolidFireVolumeIscsiName(Volume volume) { - return new ApiSolidFireVolumeIscsiNameResponse(volume.get_iScsiName()); - } - - - @Override - public boolean checkAccess(User user, String apiCommandName) throws PermissionDeniedException { - return true; - } - - @Override - public List> getCommands() { - List> cmdList = new ArrayList>(); - - cmdList.add(GetSolidFireAccountIdCmd.class); - cmdList.add(GetSolidFireVolumeSizeCmd.class); - cmdList.add(GetSolidFireVolumeAccessGroupIdCmd.class); - cmdList.add(GetSolidFireVolumeIscsiNameCmd.class); - - return cmdList; - } -} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.java new file mode 100644 index 0000000000..bdc11807ef --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.java @@ -0,0 +1,23 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.solidfire; + +public interface SolidFireIntegrationTestManager { + long getSolidFireAccountId(String csAccountUuid, String storagePoolUuid); + long getSolidFireVolumeAccessGroupId(String csClusterUuid, String storagePoolUuid); + long getSolidFireVolumeSize(String volumeUuid); +} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManagerImpl.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManagerImpl.java new file mode 100644 index 0000000000..ff6e72cb29 --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManagerImpl.java @@ -0,0 +1,78 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.solidfire; + +import javax.inject.Inject; + +import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; +import org.springframework.stereotype.Component; + +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; +import com.cloud.storage.VolumeDetailVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeDetailsDao; +import com.cloud.user.AccountDetailsDao; +import com.cloud.user.AccountDetailVO; +import com.cloud.utils.exception.CloudRuntimeException; + +@Component +public class SolidFireIntegrationTestManagerImpl implements SolidFireIntegrationTestManager { + + @Inject private AccountDetailsDao accountDetailsDao; + @Inject private ClusterDetailsDao clusterDetailsDao; + @Inject private SolidFireIntegrationTestUtil util; + @Inject private VolumeDao volumeDao; + @Inject private VolumeDetailsDao volumeDetailsDao; + + @Override + public long getSolidFireAccountId(String csAccountUuid, String storagePoolUuid) { + long csAccountId = util.getAccountIdForAccountUuid(csAccountUuid); + long storagePoolId = util.getStoragePoolIdForStoragePoolUuid(storagePoolUuid); + + AccountDetailVO accountDetail = accountDetailsDao.findDetail(csAccountId, SolidFireUtil.getAccountKey(storagePoolId)); + String sfAccountId = accountDetail.getValue(); + + return Long.parseLong(sfAccountId); + } + + @Override + public long getSolidFireVolumeAccessGroupId(String csClusterUuid, String storagePoolUuid) { + long csClusterId = util.getClusterIdForClusterUuid(csClusterUuid); + long storagePoolId = util.getStoragePoolIdForStoragePoolUuid(storagePoolUuid); + + ClusterDetailsVO clusterDetails = clusterDetailsDao.findDetail(csClusterId, SolidFireUtil.getVagKey(storagePoolId)); + String sfVagId = clusterDetails.getValue(); + + return Long.parseLong(sfVagId); + } + + @Override + public long getSolidFireVolumeSize(String volumeUuid) { + VolumeVO volume = volumeDao.findByUuid(volumeUuid); + + VolumeDetailVO volumeDetail = volumeDetailsDao.findDetail(volume.getId(), SolidFireUtil.VOLUME_SIZE); + + if (volumeDetail != null && volumeDetail.getValue() != null) { + return Long.parseLong(volumeDetail.getValue()); + } + + throw new CloudRuntimeException("Unable to determine the size of the SolidFire volume"); + } +} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/util/solidfire/SolidFireIntegrationTestUtil.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/util/solidfire/SolidFireIntegrationTestUtil.java new file mode 100644 index 0000000000..307e8c5969 --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/util/solidfire/SolidFireIntegrationTestUtil.java @@ -0,0 +1,112 @@ +// 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.util.solidfire; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.response.solidfire.ApiVolumeSnapshotDetailsResponse; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + +import com.cloud.dc.ClusterVO; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.SnapshotDetailsDao; +import com.cloud.storage.dao.SnapshotDetailsVO; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.user.Account; +import com.cloud.user.dao.AccountDao; + +public class SolidFireIntegrationTestUtil { + @Inject private AccountDao accountDao; + @Inject private ClusterDao clusterDao; + @Inject private PrimaryDataStoreDao storagePoolDao; + @Inject private SnapshotDao snapshotDao; + @Inject private SnapshotDetailsDao snapshotDetailsDao; + @Inject private VolumeDao volumeDao; + + private SolidFireIntegrationTestUtil() {} + + public long getAccountIdForAccountUuid(String accountUuid) { + Account account = accountDao.findByUuid(accountUuid); + + return account.getAccountId(); + } + + public long getAccountIdForVolumeUuid(String volumeUuid) { + VolumeVO volume = volumeDao.findByUuid(volumeUuid); + + return volume.getAccountId(); + } + + public long getAccountIdForSnapshotUuid(String snapshotUuid) { + SnapshotVO snapshot = snapshotDao.findByUuid(snapshotUuid); + + return snapshot.getAccountId(); + } + + public long getClusterIdForClusterUuid(String clusterUuid) { + ClusterVO cluster = clusterDao.findByUuid(clusterUuid); + + return cluster.getId(); + } + + public long getStoragePoolIdForStoragePoolUuid(String storagePoolUuid) { + StoragePoolVO storagePool = storagePoolDao.findByUuid(storagePoolUuid); + + return storagePool.getId(); + } + + public String getPathForVolumeUuid(String volumeUuid) { + VolumeVO volume = volumeDao.findByUuid(volumeUuid); + + return volume.getPath(); + } + + public String getVolume_iScsiName(String volumeUuid) { + VolumeVO volume = volumeDao.findByUuid(volumeUuid); + + return volume.get_iScsiName(); + } + + public List getSnapshotDetails(String snapshotUuid) { + SnapshotVO snapshot = snapshotDao.findByUuid(snapshotUuid); + + List snapshotDetails = snapshotDetailsDao.listDetails(snapshot.getId()); + + List responses = new ArrayList<>(); + + if (snapshotDetails != null) { + for (SnapshotDetailsVO snapshotDetail : snapshotDetails) { + ApiVolumeSnapshotDetailsResponse response = new ApiVolumeSnapshotDetailsResponse( + snapshotDetail.getResourceId(), + snapshotDetail.getName(), + snapshotDetail.getValue() + ); + + responses.add(response); + } + } + + return responses; + } +} diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index 92e985e023..ad87469f68 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -47,6 +47,8 @@ import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.ResignatureAnswer; +import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; @@ -147,6 +149,13 @@ public SnapshotAndCopyAnswer snapshotAndCopy(final SnapshotAndCopyCommand cmd) { return new SnapshotAndCopyAnswer(); } + @Override + public ResignatureAnswer resignature(final ResignatureCommand cmd) { + s_logger.info("'ResignatureAnswer resignature(ResignatureCommand)' not currently used for KVMStorageProcessor"); + + return new ResignatureAnswer(); + } + @Override public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { final DataTO srcData = cmd.getSrcTO(); diff --git a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3StorageProcessor.java b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3StorageProcessor.java index 3c28f1fde3..7c89921936 100644 --- a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3StorageProcessor.java +++ b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3StorageProcessor.java @@ -31,6 +31,8 @@ import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.ResignatureAnswer; +import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.to.SnapshotObjectTO; @@ -805,9 +807,17 @@ public Answer forgetObject(ForgetObjectCmd cmd) { * iSCSI? */ @Override - public Answer snapshotAndCopy(SnapshotAndCopyCommand cmd) { - LOGGER.debug("execute snapshotAndCopy: "+ cmd.getClass()); - return new SnapshotAndCopyAnswer("not implemented yet"); + public SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand cmd) { + LOGGER.info("'SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand)' not currently used for Ovm3StorageProcessor"); + + return new SnapshotAndCopyAnswer("Not implemented"); + } + + @Override + public ResignatureAnswer resignature(final ResignatureCommand cmd) { + LOGGER.info("'ResignatureAnswer resignature(ResignatureCommand)' not currently used for Ovm3StorageProcessor"); + + return new ResignatureAnswer("Not implemented"); } /** diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java index cae926179f..9d86bc31b7 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java @@ -35,6 +35,8 @@ import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.ResignatureAnswer; +import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.to.SnapshotObjectTO; @@ -66,6 +68,13 @@ public SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand cmd) { return new SnapshotAndCopyAnswer(); } + @Override + public ResignatureAnswer resignature(ResignatureCommand cmd) { + s_logger.info("'ResignatureAnswer resignature(ResignatureCommand)' not currently used for SimulatorStorageProcessor"); + + return new ResignatureAnswer(); + } + @Override public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { TemplateObjectTO template = new TemplateObjectTO(); diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index 21f79f983e..b2766e666d 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -62,6 +62,8 @@ import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.ResignatureAnswer; +import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; @@ -144,6 +146,13 @@ public SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand cmd) { return new SnapshotAndCopyAnswer(); } + @Override + public ResignatureAnswer resignature(ResignatureCommand cmd) { + s_logger.info("'ResignatureAnswer resignature(ResignatureCommand)' not currently used for VmwareStorageProcessor"); + + return new ResignatureAnswer(); + } + private String getOVFFilePath(String srcOVAFileName) { File file = new File(srcOVAFileName); assert (_storage != null); diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index efc3f81ed1..026d0c18cd 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -37,6 +37,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Properties; import java.util.Queue; import java.util.Random; @@ -164,9 +165,16 @@ * */ public abstract class CitrixResourceBase implements ServerResource, HypervisorResource, VirtualRouterDeployer { - + /** + * used to describe what type of resource a storage device is of + */ public enum SRType { - EXT, FILE, ISCSI, ISO, LVM, LVMOHBA, LVMOISCSI, NFS; + EXT, FILE, ISCSI, ISO, LVM, LVMOHBA, LVMOISCSI, + /** + * used for resigning metadata (like SR UUID and VDI UUID when a + * particular storage manager is installed on a XenServer host (for back-end snapshots to work)) + */ + RELVMOISCSI, NFS; String _str; @@ -1794,10 +1802,26 @@ protected void fillHostInfo(final Connection conn, final StartupRoutingCommand c cmd.setPod(_pod); cmd.setVersion(CitrixResourceBase.class.getPackage().getImplementationVersion()); + try { + final String cmdLine = "xe sm-list | grep \"resigning of duplicates\""; + + final XenServerUtilitiesHelper xenServerUtilitiesHelper = getXenServerUtilitiesHelper(); + + Pair result = xenServerUtilitiesHelper.executeSshWrapper(_host.getIp(), 22, _username, null, getPwdFromQueue(), cmdLine); + + boolean supportsClonedVolumes = result != null && result.first() != null && result.first() && + result.second() != null && result.second().length() > 0; + + cmd.setSupportsClonedVolumes(supportsClonedVolumes); + } catch (NumberFormatException ex) { + s_logger.warn("Issue sending 'xe sm-list' via SSH to XenServer host: " + ex.getMessage()); + } } catch (final XmlRpcException e) { - throw new CloudRuntimeException("XML RPC Exception" + e.getMessage(), e); + throw new CloudRuntimeException("XML RPC Exception: " + e.getMessage(), e); } catch (final XenAPIException e) { - throw new CloudRuntimeException("XenAPIException" + e.toString(), e); + throw new CloudRuntimeException("XenAPIException: " + e.toString(), e); + } catch (final Exception e) { + throw new CloudRuntimeException("Exception: " + e.toString(), e); } } @@ -2264,6 +2288,11 @@ protected HashMap getHostVmStateReport(final Con public SR getIscsiSR(final Connection conn, final String srNameLabel, final String target, String path, final String chapInitiatorUsername, final String chapInitiatorPassword, final boolean ignoreIntroduceException) { + return getIscsiSR(conn, srNameLabel, target, path, chapInitiatorUsername, chapInitiatorPassword, false, ignoreIntroduceException); + } + + public SR getIscsiSR(final Connection conn, final String srNameLabel, final String target, String path, final String chapInitiatorUsername, + final String chapInitiatorPassword, final boolean resignature, final boolean ignoreIntroduceException) { synchronized (srNameLabel.intern()) { final Map deviceConfig = new HashMap(); try { @@ -2353,17 +2382,52 @@ public SR getIscsiSR(final Connection conn, final String srNameLabel, final Stri throw new CloudRuntimeException(msg, e); } } + deviceConfig.put("SCSIid", scsiid); - final String result = SR.probe(conn, host, deviceConfig, type, smConfig); + String result = SR.probe(conn, host, deviceConfig, type, smConfig); + String pooluuid = null; + if (result.indexOf("") != -1) { pooluuid = result.substring(result.indexOf("") + 6, result.indexOf("")).trim(); } if (pooluuid == null || pooluuid.length() != 36) { sr = SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, type, "user", true, smConfig); - } else { + } + else { + if (resignature) { + try { + SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, SRType.RELVMOISCSI.toString(), "user", true, smConfig); + + // The successful outcome of SR.create (right above) is to throw an exception of type XenAPIException (with expected + // toString() text) after resigning the metadata (we indicated to perform a resign by passing in SRType.RELVMOISCSI.toString()). + // That being the case, if this CloudRuntimeException statement is executed, there appears to have been some kind + // of failure in the execution of the above SR.create (resign) method. + throw new CloudRuntimeException("Problem resigning the metadata"); + } + catch (XenAPIException ex) { + String msg = ex.toString(); + + if (!msg.contains("successfully resigned")) { + throw ex; + } + + result = SR.probe(conn, host, deviceConfig, type, smConfig); + + pooluuid = null; + + if (result.indexOf("") != -1) { + pooluuid = result.substring(result.indexOf("") + 6, result.indexOf("")).trim(); + } + + if (pooluuid == null || pooluuid.length() != 36) { + throw new CloudRuntimeException("Non-existent or invalid SR UUID"); + } + } + } + try { sr = SR.introduce(conn, pooluuid, srNameLabel, srNameLabel, type, "user", true, smConfig); } catch (final XenAPIException ex) { @@ -2375,11 +2439,15 @@ public SR getIscsiSR(final Connection conn, final String srNameLabel, final Stri } final Set setHosts = Host.getAll(conn); + if (setHosts == null) { - final String msg = "Unable to create Iscsi SR " + deviceConfig + " due to hosts not available."; + final String msg = "Unable to create iSCSI SR " + deviceConfig + " due to hosts not available."; + s_logger.warn(msg); + throw new CloudRuntimeException(msg); } + for (final Host currentHost : setHosts) { final PBD.Record rec = new PBD.Record(); @@ -2392,7 +2460,9 @@ public SR getIscsiSR(final Connection conn, final String srNameLabel, final Stri pbd.plug(conn); } } + sr.scan(conn); + return sr; } catch (final XenAPIException e) { final String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e.toString(); @@ -3969,11 +4039,9 @@ public void prepareISO(final Connection conn, final String vmName, List details = disk.getDetails(); if (details == null) { @@ -3994,7 +4062,7 @@ public VDI prepareManagedDisk(final Connection conn, final DiskTO disk, final St return null; } - final String vdiNameLabel = vmName + "-DATA"; + final String vdiNameLabel = Volume.Type.ROOT.equals(disk.getType()) ? ("ROOT-" + vmId) : (vmName + "-DATA"); return prepareManagedStorage(conn, details, null, vdiNameLabel); } @@ -4024,19 +4092,25 @@ protected VDI prepareManagedStorage(final Connection conn, final Map vdisInSr = sr.getVDIs(conn); + + // If a VDI already exists in the SR (in case we cloned from a template cache), use that. + if (vdisInSr.size() == 1) { + vdi = vdisInSr.iterator().next(); + } + if (vdi == null) { vdi = createVdi(sr, vdiNameLabel, volumeSize); } else { - // if VDI is not null, it must have already been created, so check - // whether a resize of the volume was performed - // if true, resize the VDI to the volume size + // If vdi is not null, it must have already been created, so check whether a resize of the volume was performed. + // If true, resize the VDI to the volume size. - s_logger.info("checking for the resize of the datadisk"); + s_logger.info("Checking for the resize of the datadisk"); final long vdiVirtualSize = vdi.getVirtualSize(conn); if (vdiVirtualSize != volumeSize) { - s_logger.info("resizing the data disk (vdi) from vdiVirtualsize: " + vdiVirtualSize + " to volumeSize: " + volumeSize); + s_logger.info("Resizing the data disk (VDI) from vdiVirtualSize: " + vdiVirtualSize + " to volumeSize: " + volumeSize); try { vdi.resize(conn, volumeSize); @@ -4044,6 +4118,15 @@ protected VDI prepareManagedStorage(final Connection conn, final Map details = cmd.getDetails(); + + final String iScsiName = details.get(DiskTO.IQN); + final String storageHost = details.get(DiskTO.STORAGE_HOST); + final String chapInitiatorUsername = details.get(DiskTO.CHAP_INITIATOR_USERNAME); + final String chapInitiatorSecret = details.get(DiskTO.CHAP_INITIATOR_SECRET); + + newSr = hypervisorResource.getIscsiSR(conn, iScsiName, storageHost, iScsiName, chapInitiatorUsername, chapInitiatorSecret, true, false); + + Set vdis = newSr.getVDIs(conn); + + if (vdis.size() != 1) { + throw new RuntimeException("There were " + vdis.size() + " VDIs in the SR."); + } + + VDI vdi = vdis.iterator().next(); + + final ResignatureAnswer resignatureAnswer = new ResignatureAnswer(); + + resignatureAnswer.setSize(vdi.getVirtualSize(conn)); + resignatureAnswer.setPath(vdi.getUuid(conn)); + resignatureAnswer.setFormat(ImageFormat.VHD); + + return resignatureAnswer; + } + catch (final Exception ex) { + s_logger.warn("Failed to resignature: " + ex.toString(), ex); + + return new ResignatureAnswer(ex.getMessage()); + } + finally { + if (newSr != null) { + hypervisorResource.removeSR(conn, newSr); + } + } + } + @Override public AttachAnswer attachIso(final AttachCommand cmd) { final DiskTO disk = cmd.getDisk(); @@ -763,6 +809,9 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { final DataTO destDataTo = cmd.getDestTO(); final int wait = cmd.getWait(); final DataStoreTO srcDataStoreTo = srcDataTo.getDataStore(); + final Connection conn = hypervisorResource.getConnection(); + SR sr = null; + boolean removeSrAfterCopy = false; try { if (srcDataStoreTo instanceof NfsTO && srcDataTo.getObjectType() == DataObjectType.TEMPLATE) { @@ -796,14 +845,11 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { managedStoragePoolRootVolumeSize = details.get(PrimaryDataStoreTO.VOLUME_SIZE); chapInitiatorUsername = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_USERNAME); chapInitiatorSecret = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_SECRET); + removeSrAfterCopy = Boolean.parseBoolean(details.get(PrimaryDataStoreTO.REMOVE_AFTER_COPY)); } } } - final Connection conn = hypervisorResource.getConnection(); - - final SR sr; - if (managed) { final Map details = new HashMap(); @@ -861,9 +907,11 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { newVol.setUuid(uuidToReturn); newVol.setPath(uuidToReturn); + if (physicalSize != null) { newVol.setSize(physicalSize); } + newVol.setFormat(ImageFormat.VHD); return new CopyCmdAnswer(newVol); @@ -875,6 +923,11 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { return new CopyCmdAnswer(msg); } + finally { + if (removeSrAfterCopy && sr != null) { + hypervisorResource.removeSR(conn, sr); + } + } return new CopyCmdAnswer("not implemented yet"); } diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java index e58bade2c4..02c3197e51 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java @@ -171,6 +171,8 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { final DataStoreTO srcStore = srcData.getDataStore(); final Connection conn = hypervisorResource.getConnection(); SR srcSr = null; + SR destSr = null; + boolean removeSrAfterCopy = false; Task task = null; try { @@ -198,7 +200,8 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { final Set setVdis = srcSr.getVDIs(conn); if (setVdis.size() != 1) { - return new CopyCmdAnswer("Expected 1 VDI template but found " + setVdis.size() + " VDI template(s) on: " + uri.getHost() + ":" + uri.getPath() + "/" + volumeDirectory); + return new CopyCmdAnswer("Expected 1 VDI template, but found " + setVdis.size() + " VDI templates on: " + + uri.getHost() + ":" + uri.getPath() + "/" + volumeDirectory); } final VDI srcVdi = setVdis.iterator().next(); @@ -225,11 +228,10 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { managedStoragePoolRootVolumeSize = details.get(PrimaryDataStoreTO.VOLUME_SIZE); chapInitiatorUsername = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_USERNAME); chapInitiatorSecret = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_SECRET); + removeSrAfterCopy = Boolean.parseBoolean(details.get(PrimaryDataStoreTO.REMOVE_AFTER_COPY)); } } - final SR destSr; - if (managed) { details = new HashMap(); @@ -291,9 +293,11 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { newVol.setUuid(uuidToReturn); newVol.setPath(uuidToReturn); + if (physicalSize != null) { newVol.setSize(physicalSize); } + newVol.setFormat(Storage.ImageFormat.VHD); return new CopyCmdAnswer(newVol); @@ -316,6 +320,10 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { if (srcSr != null) { hypervisorResource.removeSR(conn, srcSr); } + + if (removeSrAfterCopy && destSr != null) { + hypervisorResource.removeSR(conn, destSr); + } } return new CopyCmdAnswer("not implemented yet"); diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixResizeVolumeCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixResizeVolumeCommandWrapper.java index 0206939725..b8e0f565df 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixResizeVolumeCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixResizeVolumeCommandWrapper.java @@ -27,28 +27,80 @@ import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase; import com.cloud.resource.CommandWrapper; import com.cloud.resource.ResourceWrapper; +import com.cloud.utils.exception.CloudRuntimeException; import com.xensource.xenapi.Connection; +import com.xensource.xenapi.PBD; +import com.xensource.xenapi.SR; import com.xensource.xenapi.VDI; +import java.util.HashSet; +import java.util.Set; + @ResourceWrapper(handles = ResizeVolumeCommand.class) public final class CitrixResizeVolumeCommandWrapper extends CommandWrapper { - private static final Logger s_logger = Logger.getLogger(CitrixResizeVolumeCommandWrapper.class); @Override public Answer execute(final ResizeVolumeCommand command, final CitrixResourceBase citrixResourceBase) { - final Connection conn = citrixResourceBase.getConnection(); - final String volid = command.getPath(); - final long newSize = command.getNewSize(); + Connection conn = citrixResourceBase.getConnection(); + + String volId = command.getPath(); + long newSize = command.getNewSize(); try { - final VDI vdi = citrixResourceBase.getVDIbyUuid(conn, volid); + if (command.isManaged()) { + resizeSr(conn, command); + } + + VDI vdi = citrixResourceBase.getVDIbyUuid(conn, volId); + vdi.resize(conn, newSize); + return new ResizeVolumeAnswer(command, true, "success", newSize); - } catch (final Exception e) { - s_logger.warn("Unable to resize volume", e); - final String error = "failed to resize volume:" + e; + } catch (Exception ex) { + s_logger.warn("Unable to resize volume", ex); + + String error = "Failed to resize volume: " + ex; + return new ResizeVolumeAnswer(command, false, error); } } -} \ No newline at end of file + + private void resizeSr(Connection conn, ResizeVolumeCommand command) { + // If this is managed storage, re-size the SR, too. + // The logical unit/volume has already been re-sized, so the SR needs to fill up the new space. + + String iScsiName = command.get_iScsiName(); + + try { + Set srs = SR.getByNameLabel(conn, iScsiName); + Set allPbds = new HashSet<>(); + + for (SR sr : srs) { + if (!CitrixResourceBase.SRType.LVMOISCSI.equals(sr.getType(conn))) { + continue; + } + + Set pbds = sr.getPBDs(conn); + + if (pbds.size() <= 0) { + s_logger.debug("No PBDs found for the following SR: " + sr.getNameLabel(conn)); + } + + allPbds.addAll(pbds); + } + + for (PBD pbd: allPbds) { + PBD.Record pbdr = pbd.getRecord(conn); + + if (pbdr.currentlyAttached) { + pbd.unplug(conn); + pbd.plug(conn); + } + } + } + catch (Throwable ex) { + throw new CloudRuntimeException("Unable to resize volume: " + ex.getMessage()); + } + } +} diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java index 241110253c..073f00096b 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java @@ -108,11 +108,13 @@ public Answer execute(final StartCommand command, final CitrixResourceBase citri } index++; } + for (DiskTO disk : disks) { - final VDI newVdi = citrixResourceBase.prepareManagedDisk(conn, disk, vmName); + final VDI newVdi = citrixResourceBase.prepareManagedDisk(conn, disk, vmSpec.getId(), vmSpec.getName()); if (newVdi != null) { final String path = newVdi.getUuid(conn); + iqnToPath.put(disk.getDetails().get(DiskTO.IQN), path); } diff --git a/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java b/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java index b7ae4d43ff..74fbde5273 100644 --- a/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java +++ b/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java @@ -53,7 +53,6 @@ import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; import com.cloud.storage.VolumeDetailVO; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; @@ -110,7 +109,7 @@ public void createAsync(DataStore dataStore, DataObject dataObject, AsyncComplet String volumeName = volumeInfo.getName(); Long Iops = volumeInfo.getMaxIops(); // quota size of the cloudbyte volume will be increased with the given HypervisorSnapshotReserve - Long quotaSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volumeInfo, _storagePoolDao.findById(storagePoolId)); + Long quotaSize = getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, _storagePoolDao.findById(storagePoolId)); StoragePoolVO storagePool = _storagePoolDao.findById(dataStore.getId()); VolumeVO volume = _volumeDao.findById(volumeInfo.getId()); @@ -337,7 +336,8 @@ public void updateVolumeDetails(VolumeVO volume, FileSystem esvolume) { } @Override - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { + public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) { + VolumeInfo volume = (VolumeInfo)dataObject; long volumeSize = volume.getSize(); Integer hypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve(); @@ -353,7 +353,7 @@ public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, Stora } @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + public ChapInfo getChapInfo(DataObject dataObject) { return null; } diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java index e92e8f6e04..b5aee543e4 100644 --- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java @@ -38,6 +38,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.StorageAction; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -70,7 +71,6 @@ import com.cloud.storage.Storage; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.VMTemplateDao; @@ -145,7 +145,7 @@ public Answer createVolume(VolumeInfo volume) throws StorageUnavailableException } @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + public ChapInfo getChapInfo(DataObject dataObject) { return null; } @@ -169,8 +169,13 @@ public long getUsedIops(StoragePool storagePool) { } @Override - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { - return volume.getSize(); + public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) { + return dataObject.getSize(); + } + + @Override + public long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool) { + return 0; } @Override diff --git a/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java b/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java index 752470316d..c6ae3ed7f6 100644 --- a/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java +++ b/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java @@ -31,6 +31,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.command.CommandResult; @@ -49,7 +50,6 @@ import com.cloud.host.Host; import com.cloud.storage.Storage; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.VolumeDao; import com.cloud.user.dao.AccountDao; @@ -78,8 +78,13 @@ public long getUsedIops(StoragePool storagePool) { } @Override - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { - return 0; //To change body of implemented methods use File | Settings | File Templates. + public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) { + return 0; + } + + @Override + public long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool) { + return 0; } @Inject @@ -97,7 +102,7 @@ public Map getCapabilities() { } @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + public ChapInfo getChapInfo(DataObject dataObject) { return null; } diff --git a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java index 0a4cfd6c08..343b08a11a 100644 --- a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java @@ -31,7 +31,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.async.AsyncRpcContext; @@ -44,7 +44,6 @@ import com.cloud.agent.api.to.DataTO; import com.cloud.host.Host; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.utils.exception.CloudRuntimeException; @@ -77,7 +76,7 @@ public DataStoreTO getStoreTO(DataStore store) { } @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + public ChapInfo getChapInfo(DataObject dataObject) { return null; } @@ -98,16 +97,18 @@ public long getUsedIops(StoragePool storagePool) { } @Override - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { - return volume.getSize(); + public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) { + return dataObject.getSize(); } - private class CreateVolumeContext extends AsyncRpcContext { - private final DataObject volume; + @Override + public long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool) { + return 0; + } + private class CreateVolumeContext extends AsyncRpcContext { public CreateVolumeContext(AsyncCompletionCallback callback, DataObject volume) { super(callback); - this.volume = volume; } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java index 5f647db110..af969e168a 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java @@ -17,32 +17,13 @@ package org.apache.cloudstack.storage.datastore.driver; import java.text.NumberFormat; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; -import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; -import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; -import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; -import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; -import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.storage.command.CommandResult; -import org.apache.cloudstack.storage.command.CreateObjectAnswer; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; -import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; -import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; -import org.apache.cloudstack.storage.to.SnapshotObjectTO; -import org.apache.log4j.Logger; - import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataStoreTO; @@ -55,16 +36,19 @@ import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; -import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.DataStoreRole; import com.cloud.storage.ResizeVolumePayload; +import com.cloud.storage.Snapshot.State; +import com.cloud.storage.SnapshotVO; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; +import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VolumeDetailVO; import com.cloud.storage.VolumeVO; -import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.SnapshotDetailsDao; import com.cloud.storage.dao.SnapshotDetailsVO; +import com.cloud.storage.dao.VMTemplatePoolDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.dao.VolumeDetailsDao; import com.cloud.user.AccountDetailVO; @@ -74,27 +58,64 @@ import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.base.Preconditions; + +import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.command.CommandResult; +import org.apache.cloudstack.storage.command.CreateObjectAnswer; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; +import org.apache.cloudstack.storage.to.SnapshotObjectTO; +import org.apache.log4j.Logger; + public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { - private static final Logger s_logger = Logger.getLogger(SolidFirePrimaryDataStoreDriver.class); - private static final int s_lowestHypervisorSnapshotReserve = 10; - - @Inject private AccountDao _accountDao; - @Inject private AccountDetailsDao _accountDetailsDao; - @Inject private ClusterDao _clusterDao; - @Inject private ClusterDetailsDao _clusterDetailsDao; - @Inject private HostDao _hostDao; - @Inject private SnapshotDao _snapshotDao; - @Inject private SnapshotDetailsDao _snapshotDetailsDao; - @Inject private PrimaryDataStoreDao _storagePoolDao; - @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; - @Inject private VolumeDao _volumeDao; - @Inject private VolumeDetailsDao _volumeDetailsDao; + private static final Logger LOGGER = Logger.getLogger(SolidFirePrimaryDataStoreDriver.class); + private static final int LOCK_TIME_IN_SECONDS = 300; + private static final int LOWEST_HYPERVISOR_SNAPSHOT_RESERVE = 10; + private static final long MIN_IOPS_FOR_TEMPLATE_VOLUME = 100L; + private static final long MAX_IOPS_FOR_TEMPLATE_VOLUME = 20000L; + private static final long MIN_IOPS_FOR_TEMP_VOLUME = 100L; + private static final long MAX_IOPS_FOR_TEMP_VOLUME = 20000L; + private static final long MIN_IOPS_FOR_SNAPSHOT_VOLUME = 100L; + private static final long MAX_IOPS_FOR_SNAPSHOT_VOLUME = 20000L; + + @Inject private AccountDao accountDao; + @Inject private AccountDetailsDao accountDetailsDao; + @Inject private ClusterDao clusterDao; + @Inject private ClusterDetailsDao clusterDetailsDao; + @Inject private DataStoreManager dataStoreMgr; + @Inject private HostDao hostDao; + @Inject private SnapshotDao snapshotDao; + @Inject private SnapshotDetailsDao snapshotDetailsDao; + @Inject private PrimaryDataStoreDao storagePoolDao; + @Inject private StoragePoolDetailsDao storagePoolDetailsDao; + @Inject private VMTemplatePoolDao tmpltPoolDao; + @Inject private VolumeDao volumeDao; + @Inject private VolumeDetailsDao volumeDetailsDao; + @Inject private VolumeDataFactory volumeFactory; @Override public Map getCapabilities() { - Map mapCapabilities = new HashMap(); + Map mapCapabilities = new HashMap<>(); mapCapabilities.put(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString(), Boolean.TRUE.toString()); + mapCapabilities.put(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_SNAPSHOT.toString(), Boolean.TRUE.toString()); + mapCapabilities.put(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString(), Boolean.TRUE.toString()); return mapCapabilities; } @@ -116,7 +137,7 @@ private SolidFireUtil.SolidFireAccount createSolidFireAccount(SolidFireUtil.Soli } @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + public ChapInfo getChapInfo(DataObject dataObject) { return null; } @@ -128,38 +149,42 @@ public ChapInfo getChapInfo(VolumeInfo volumeInfo) { @Override public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore) { - if (dataObject == null || host == null || dataStore == null) { - return false; - } + Preconditions.checkArgument(dataObject != null, "'dataObject' should not be 'null'"); + Preconditions.checkArgument(host != null, "'host' should not be 'null'"); + Preconditions.checkArgument(dataStore != null, "'dataStore' should not be 'null'"); long sfVolumeId = getSolidFireVolumeId(dataObject); long clusterId = host.getClusterId(); long storagePoolId = dataStore.getId(); - ClusterVO cluster = _clusterDao.findById(clusterId); + ClusterVO cluster = clusterDao.findById(clusterId); GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); - if (!lock.lock(SolidFireUtil.s_lockTimeInSeconds)) { + if (!lock.lock(LOCK_TIME_IN_SECONDS)) { String errMsg = "Couldn't lock the DB (in grantAccess) on the following string: " + cluster.getUuid(); - s_logger.debug(errMsg); + LOGGER.warn(errMsg); throw new CloudRuntimeException(errMsg); } try { - ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId)); + ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId)); String vagId = clusterDetail != null ? clusterDetail.getValue() : null; - List hosts = _hostDao.findByClusterId(clusterId); + List hosts = hostDao.findByClusterId(clusterId); if (!SolidFireUtil.hostsSupport_iScsi(hosts)) { - return false; + String errMsg = "Not all hosts in the compute cluster support iSCSI."; + + LOGGER.warn(errMsg); + + throw new CloudRuntimeException(errMsg); } - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); if (vagId != null) { SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); @@ -169,7 +194,7 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); } else { - SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolumeId, storagePoolId, cluster.getUuid(), hosts, _clusterDetailsDao); + SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolumeId, storagePoolId, cluster.getUuid(), hosts, clusterDetailsDao); } return true; @@ -194,25 +219,25 @@ public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore) long clusterId = host.getClusterId(); long storagePoolId = dataStore.getId(); - ClusterVO cluster = _clusterDao.findById(clusterId); + ClusterVO cluster = clusterDao.findById(clusterId); GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); - if (!lock.lock(SolidFireUtil.s_lockTimeInSeconds)) { + if (!lock.lock(LOCK_TIME_IN_SECONDS)) { String errMsg = "Couldn't lock the DB (in revokeAccess) on the following string: " + cluster.getUuid(); - s_logger.debug(errMsg); + LOGGER.debug(errMsg); throw new CloudRuntimeException(errMsg); } try { - ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId)); + ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId)); String vagId = clusterDetail != null ? clusterDetail.getValue() : null; if (vagId != null) { - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); @@ -233,7 +258,7 @@ private long getSolidFireVolumeId(DataObject dataObject) { } if (dataObject.getType() == DataObjectType.SNAPSHOT) { - SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(dataObject.getId(), SolidFireUtil.VOLUME_ID); + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(dataObject.getId(), SolidFireUtil.VOLUME_ID); if (snapshotDetails == null || snapshotDetails.getValue() == null) { throw new CloudRuntimeException("Unable to locate the volume ID associated with the following snapshot ID: " + dataObject.getId()); @@ -242,11 +267,26 @@ private long getSolidFireVolumeId(DataObject dataObject) { return Long.parseLong(snapshotDetails.getValue()); } + if (dataObject.getType() == DataObjectType.TEMPLATE) { + return getVolumeIdFrom_iScsiPath(((TemplateInfo)dataObject).getInstallPath()); + } + throw new CloudRuntimeException("Invalid DataObjectType (" + dataObject.getType() + ") passed to getSolidFireVolumeId(DataObject)"); } + private long getVolumeIdFrom_iScsiPath(String iScsiPath) { + String[] splits = iScsiPath.split("/"); + String iqn = splits[1]; + + String sequenceToSearchFor = "."; + int lastIndexOf = iqn.lastIndexOf(sequenceToSearchFor); + String volumeIdAsString = iqn.substring(lastIndexOf + sequenceToSearchFor.length()); + + return Long.parseLong(volumeIdAsString); + } + private long getDefaultMinIops(long storagePoolId) { - StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS); + StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS); String clusterDefaultMinIops = storagePoolDetail.getValue(); @@ -254,7 +294,7 @@ private long getDefaultMinIops(long storagePoolId) { } private long getDefaultMaxIops(long storagePoolId) { - StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS); + StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS); String clusterDefaultMaxIops = storagePoolDetail.getValue(); @@ -262,7 +302,7 @@ private long getDefaultMaxIops(long storagePoolId) { } private long getDefaultBurstIops(long storagePoolId, long maxIops) { - StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS); + StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS); String clusterDefaultBurstIopsPercentOfMaxIops = storagePoolDetail.getValue(); @@ -271,30 +311,56 @@ private long getDefaultBurstIops(long storagePoolId, long maxIops) { return (long)(maxIops * fClusterDefaultBurstIopsPercentOfMaxIops); } - private SolidFireUtil.SolidFireVolume createSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, VolumeInfo volumeInfo, long sfAccountId) { - long storagePoolId = volumeInfo.getDataStore().getId(); + private SolidFireUtil.SolidFireVolume createSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, DataObject dataObject, long sfAccountId) { + long storagePoolId = dataObject.getDataStore().getId(); + Long minIops = null; + Long maxIops = null; + Long volumeSize = dataObject.getSize(); + String volumeName = null; - final Iops iops; + final Map mapAttributes; - Long minIops = volumeInfo.getMinIops(); - Long maxIops = volumeInfo.getMaxIops(); + if (dataObject.getType() == DataObjectType.VOLUME) { + VolumeInfo volumeInfo = (VolumeInfo)dataObject; - if (minIops == null || minIops <= 0 || maxIops == null || maxIops <= 0) { - long defaultMaxIops = getDefaultMaxIops(storagePoolId); + minIops = volumeInfo.getMinIops(); + maxIops = volumeInfo.getMaxIops(); + volumeSize = getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, storagePoolDao.findById(storagePoolId)); + volumeName = volumeInfo.getName(); - iops = new Iops(getDefaultMinIops(storagePoolId), defaultMaxIops, getDefaultBurstIops(storagePoolId, defaultMaxIops)); - } else { - iops = new Iops(volumeInfo.getMinIops(), volumeInfo.getMaxIops(), getDefaultBurstIops(storagePoolId, volumeInfo.getMaxIops())); + mapAttributes = getVolumeAttributes(volumeInfo); + } else if (dataObject.getType() == DataObjectType.TEMPLATE) { + TemplateInfo templateInfo = (TemplateInfo)dataObject; + + minIops = MIN_IOPS_FOR_TEMPLATE_VOLUME; + maxIops = MAX_IOPS_FOR_TEMPLATE_VOLUME; + volumeSize = getDataObjectSizeIncludingHypervisorSnapshotReserve(templateInfo, storagePoolDao.findById(storagePoolId)); + volumeName = templateInfo.getUniqueName(); + + mapAttributes = getTemplateAttributes(templateInfo); + } + else { + throw new CloudRuntimeException("Invalid type passed to createSolidFireVolume: " + dataObject.getType()); } - long volumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volumeInfo, _storagePoolDao.findById(storagePoolId)); + final Iops iops = getIops(minIops, maxIops, storagePoolId); - long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeInfo.getName()), sfAccountId, volumeSize, true, - NumberFormat.getInstance().format(volumeInfo.getSize()), iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); + long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeName), sfAccountId, + volumeSize, true, mapAttributes, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); return SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId); } + private Iops getIops(Long minIops, Long maxIops, long storagePoolId) { + if (minIops == null || minIops <= 0 || maxIops == null || maxIops <= 0) { + long defaultMaxIops = getDefaultMaxIops(storagePoolId); + + return new Iops(getDefaultMinIops(storagePoolId), defaultMaxIops, getDefaultBurstIops(storagePoolId, defaultMaxIops)); + } + + return new Iops(minIops, maxIops, getDefaultBurstIops(storagePoolId, maxIops)); + } + @Override public long getUsedBytes(StoragePool storagePool) { return getUsedBytes(storagePool, Long.MIN_VALUE); @@ -303,7 +369,7 @@ public long getUsedBytes(StoragePool storagePool) { private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) { long usedSpace = 0; - List lstVolumes = _volumeDao.findByPoolId(storagePool.getId(), null); + List lstVolumes = volumeDao.findByPoolId(storagePool.getId(), null); if (lstVolumes != null) { for (VolumeVO volume : lstVolumes) { @@ -311,7 +377,7 @@ private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) { continue; } - VolumeDetailVO volumeDetail = _volumeDetailsDao.findDetail(volume.getId(), SolidFireUtil.VOLUME_SIZE); + VolumeDetailVO volumeDetail = volumeDetailsDao.findDetail(volume.getId(), SolidFireUtil.VOLUME_SIZE); if (volumeDetail != null && volumeDetail.getValue() != null) { long volumeSize = Long.parseLong(volumeDetail.getValue()); @@ -319,18 +385,22 @@ private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) { usedSpace += volumeSize; } else { - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), _storagePoolDetailsDao); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), storagePoolDetailsDao); try { long lVolumeId = Long.parseLong(volume.getFolder()); SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, lVolumeId); + long volumeSize = sfVolume.getTotalSize(); + // SolidFireUtil.VOLUME_SIZE was introduced in 4.5. // To be backward compatible with releases prior to 4.5, call updateVolumeDetails here. // That way if SolidFireUtil.VOLUME_SIZE wasn't put in the volume_details table when the // volume was initially created, it can be placed in volume_details here. - updateVolumeDetails(volume.getId(), sfVolume.getTotalSize()); + updateVolumeDetails(volume.getId(), volumeSize); + + usedSpace += volumeSize; } catch (NumberFormatException ex) { // can be ignored (the "folder" column didn't have a valid "long" in it (hasn't been placed there yet)) @@ -339,15 +409,15 @@ private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) { } } - List lstSnapshots = _snapshotDao.listAll(); + List lstSnapshots = snapshotDao.listAll(); if (lstSnapshots != null) { for (SnapshotVO snapshot : lstSnapshots) { - SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.STORAGE_POOL_ID); + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.STORAGE_POOL_ID); // if this snapshot belongs to the storagePool that was passed in if (snapshotDetails != null && snapshotDetails.getValue() != null && Long.parseLong(snapshotDetails.getValue()) == storagePool.getId()) { - snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.VOLUME_SIZE); + snapshotDetails = snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.VOLUME_SIZE); if (snapshotDetails != null && snapshotDetails.getValue() != null) { long snapshotSize = Long.parseLong(snapshotDetails.getValue()); @@ -358,6 +428,14 @@ private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) { } } + List lstTemplatePoolRefs = tmpltPoolDao.listByPoolId(storagePool.getId()); + + if (lstTemplatePoolRefs != null) { + for (VMTemplateStoragePoolVO templatePoolRef : lstTemplatePoolRefs) { + usedSpace += templatePoolRef.getTemplateSize(); + } + } + return usedSpace; } @@ -365,7 +443,7 @@ private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) { public long getUsedIops(StoragePool storagePool) { long usedIops = 0; - List volumes = _volumeDao.findByPoolId(storagePool.getId(), null); + List volumes = volumeDao.findByPoolId(storagePool.getId(), null); if (volumes != null) { for (VolumeVO volume : volumes) { @@ -377,12 +455,25 @@ public long getUsedIops(StoragePool storagePool) { } @Override - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { - long volumeSize = volume.getSize(); - Integer hypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve(); + public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) { + long volumeSize = 0; + + if (dataObject.getType() == DataObjectType.VOLUME) { + VolumeInfo volume = (VolumeInfo)dataObject; + + volumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volume.getSize(), volume.getHypervisorSnapshotReserve()); + } else if (dataObject.getType() == DataObjectType.TEMPLATE) { + TemplateInfo templateInfo = (TemplateInfo)dataObject; + + volumeSize = (long)(templateInfo.getSize() + templateInfo.getSize() * (LOWEST_HYPERVISOR_SNAPSHOT_RESERVE / 100f)); + } + return volumeSize; + } + + private long getVolumeSizeIncludingHypervisorSnapshotReserve(long volumeSize, Integer hypervisorSnapshotReserve) { if (hypervisorSnapshotReserve != null) { - hypervisorSnapshotReserve = Math.max(hypervisorSnapshotReserve, s_lowestHypervisorSnapshotReserve); + hypervisorSnapshotReserve = Math.max(hypervisorSnapshotReserve, LOWEST_HYPERVISOR_SNAPSHOT_RESERVE); volumeSize += volumeSize * (hypervisorSnapshotReserve / 100f); } @@ -390,6 +481,29 @@ public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, Stora return volumeSize; } + /** + * This method is only relevant when storagePool is being used with a compute cluster that supports UUID resigning. + */ + @Override + public long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool) { + List lstTemplatePoolRefs = tmpltPoolDao.listByPoolId(storagePool.getId()); + + if (lstTemplatePoolRefs != null) { + for (VMTemplateStoragePoolVO templatePoolRef : lstTemplatePoolRefs) { + if (templatePoolRef.getTemplateId() == templateInfo.getId()) { + // This indicates that we already have this template stored on this primary storage, so + // we do not require additional space. + return 0; + } + } + } + + // This indicates that we do not have a copy of this template on this primary storage, so + // we need to take it into consideration from a space standpoint (ex. when a new VM is spun + // up and wants to use this particular template for its root disk). + return getDataObjectSizeIncludingHypervisorSnapshotReserve(templateInfo, storagePool); + } + private static class Iops { private final long _minIops; private final long _maxIops; @@ -436,7 +550,7 @@ private void deleteSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnectio long sfVolumeId = Long.parseLong(volumeInfo.getFolder()); - SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId); + deleteSolidFireVolume(sfConnection, volumeInfo.getId(), sfVolumeId); } @Override @@ -444,114 +558,234 @@ public void createAsync(DataStore dataStore, DataObject dataObject, AsyncComplet String iqn = null; String errMsg = null; - if (dataObject.getType() == DataObjectType.VOLUME) { - VolumeInfo volumeInfo = (VolumeInfo)dataObject; + try { + if (dataObject.getType() == DataObjectType.VOLUME) { + iqn = createVolume((VolumeInfo)dataObject, dataStore.getId()); + } else if (dataObject.getType() == DataObjectType.SNAPSHOT) { + createTempVolume((SnapshotInfo)dataObject, dataStore.getId()); + } else if (dataObject.getType() == DataObjectType.TEMPLATE) { + iqn = createTemplateVolume((TemplateInfo)dataObject, dataStore.getId()); + } else { + errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync"; + + LOGGER.error(errMsg); + } + } + catch (Exception ex) { + errMsg = ex.getMessage(); - long storagePoolId = dataStore.getId(); + LOGGER.error(errMsg); - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + if (callback == null) { + throw ex; + } + } - AccountDetailVO accountDetail = SolidFireUtil.getAccountDetail(volumeInfo.getAccountId(), storagePoolId, _accountDetailsDao); + if (callback != null) { + // path = iqn + // size is pulled from DataObject instance, if errMsg is null + CreateCmdResult result = new CreateCmdResult(iqn, new Answer(null, errMsg == null, errMsg)); - if (accountDetail == null || accountDetail.getValue() == null) { - AccountVO account = _accountDao.findById(volumeInfo.getAccountId()); - String sfAccountName = SolidFireUtil.getSolidFireAccountName(account.getUuid(), account.getAccountId()); - SolidFireUtil.SolidFireAccount sfAccount = SolidFireUtil.getSolidFireAccount(sfConnection, sfAccountName); + result.setResult(errMsg); - if (sfAccount == null) { - sfAccount = createSolidFireAccount(sfConnection, sfAccountName); - } + callback.complete(result); + } + } + + private long getCreateSolidFireAccountId(SolidFireUtil.SolidFireConnection sfConnection, long csAccountId, long storagePoolId) { + AccountDetailVO accountDetail = SolidFireUtil.getAccountDetail(csAccountId, storagePoolId, accountDetailsDao); - SolidFireUtil.updateCsDbWithSolidFireAccountInfo(account.getId(), sfAccount, storagePoolId, _accountDetailsDao); + if (accountDetail == null || accountDetail.getValue() == null) { + AccountVO account = accountDao.findById(csAccountId); + String sfAccountName = SolidFireUtil.getSolidFireAccountName(account.getUuid(), account.getAccountId()); + SolidFireUtil.SolidFireAccount sfAccount = SolidFireUtil.getSolidFireAccount(sfConnection, sfAccountName); - accountDetail = SolidFireUtil.getAccountDetail(volumeInfo.getAccountId(), storagePoolId, _accountDetailsDao); + if (sfAccount == null) { + sfAccount = createSolidFireAccount(sfConnection, sfAccountName); } - long sfAccountId = Long.parseLong(accountDetail.getValue()); + SolidFireUtil.updateCsDbWithSolidFireAccountInfo(account.getId(), sfAccount, storagePoolId, accountDetailsDao); - SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(sfConnection, volumeInfo, sfAccountId); + accountDetail = SolidFireUtil.getAccountDetail(csAccountId, storagePoolId, accountDetailsDao); + } - iqn = sfVolume.getIqn(); + return Long.parseLong(accountDetail.getValue()); + } - VolumeVO volume = _volumeDao.findById(volumeInfo.getId()); + private void handleSnapshotDetails(long csSnapshotId, String name, String value) { + snapshotDetailsDao.removeDetail(csSnapshotId, name); - volume.set_iScsiName(iqn); - volume.setFolder(String.valueOf(sfVolume.getId())); - volume.setPoolType(StoragePoolType.IscsiLUN); - volume.setPoolId(storagePoolId); + SnapshotDetailsVO snapshotDetails = new SnapshotDetailsVO(csSnapshotId, name, value, false); - _volumeDao.update(volume.getId(), volume); + snapshotDetailsDao.persist(snapshotDetails); + } - updateVolumeDetails(volume.getId(), sfVolume.getTotalSize()); + private void addTempVolumeId(long csSnapshotId, String tempVolumeId) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID); - StoragePoolVO storagePool = _storagePoolDao.findById(dataStore.getId()); + if (snapshotDetails == null || snapshotDetails.getValue() == null) { + throw new CloudRuntimeException("'addTempVolumeId' should not be invoked unless " + SolidFireUtil.VOLUME_ID + " exists."); + } - long capacityBytes = storagePool.getCapacityBytes(); - // getUsedBytes(StoragePool) will include the bytes of the newly created volume because - // updateVolumeDetails(long, long) has already been called for this volume - long usedBytes = getUsedBytes(storagePool); + String originalVolumeId = snapshotDetails.getValue(); - storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes); + handleSnapshotDetails(csSnapshotId, SolidFireUtil.TEMP_VOLUME_ID, originalVolumeId); + handleSnapshotDetails(csSnapshotId, SolidFireUtil.VOLUME_ID, tempVolumeId); + } - _storagePoolDao.update(storagePoolId, storagePool); - } else { - errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync"; + private void removeTempVolumeId(long csSnapshotId) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.TEMP_VOLUME_ID); + + if (snapshotDetails == null || snapshotDetails.getValue() == null) { + throw new CloudRuntimeException("'removeTempVolumeId' should not be invoked unless " + SolidFireUtil.TEMP_VOLUME_ID + " exists."); } - // path = iqn - // size is pulled from DataObject instance, if errMsg is null - CreateCmdResult result = new CreateCmdResult(iqn, new Answer(null, errMsg == null, errMsg)); + String originalVolumeId = snapshotDetails.getValue(); - result.setResult(errMsg); + handleSnapshotDetails(csSnapshotId, SolidFireUtil.VOLUME_ID, originalVolumeId); - callback.complete(result); + snapshotDetailsDao.remove(snapshotDetails.getId()); } - private void updateVolumeDetails(long volumeId, long sfVolumeSize) { - VolumeDetailVO volumeDetailVo = _volumeDetailsDao.findDetail(volumeId, SolidFireUtil.VOLUME_SIZE); - - if (volumeDetailVo == null || volumeDetailVo.getValue() == null) { - volumeDetailVo = new VolumeDetailVO(volumeId, SolidFireUtil.VOLUME_SIZE, String.valueOf(sfVolumeSize), false); + private long getCsIdForCloning(long volumeId, String cloneOf) { + VolumeDetailVO volumeDetail = volumeDetailsDao.findDetail(volumeId, cloneOf); - _volumeDetailsDao.persist(volumeDetailVo); + if (volumeDetail != null && volumeDetail.getValue() != null) { + return new Long(volumeDetail.getValue()); } + + return Long.MIN_VALUE; } - @Override - public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback callback) { - String errMsg = null; + private boolean shouldTakeSnapshot(long snapshotId) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshotId, "takeSnapshot"); - if (dataObject.getType() == DataObjectType.VOLUME) { - try { - VolumeInfo volumeInfo = (VolumeInfo)dataObject; - long volumeId = volumeInfo.getId(); + if (snapshotDetails != null && snapshotDetails.getValue() != null) { + return new Boolean(snapshotDetails.getValue()); + } - long storagePoolId = dataStore.getId(); + return false; + } - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + private SolidFireUtil.SolidFireVolume createClone(SolidFireUtil.SolidFireConnection sfConnection, long dataObjectId, VolumeInfo volumeInfo, long sfAccountId, + long storagePoolId, DataObjectType dataObjectType) { + String sfNewVolumeName = volumeInfo.getName(); - deleteSolidFireVolume(sfConnection, volumeInfo); + long sfVolumeId = Long.MIN_VALUE; + long sfSnapshotId = Long.MIN_VALUE; - _volumeDetailsDao.removeDetails(volumeId); + if (dataObjectType == DataObjectType.SNAPSHOT) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(dataObjectId, SolidFireUtil.SNAPSHOT_ID); - StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); + if (snapshotDetails != null && snapshotDetails.getValue() != null) { + sfSnapshotId = Long.parseLong(snapshotDetails.getValue()); + } - long usedBytes = getUsedBytes(storagePool, volumeId); + snapshotDetails = snapshotDetailsDao.findDetail(dataObjectId, SolidFireUtil.VOLUME_ID); - storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes); + sfVolumeId = Long.parseLong(snapshotDetails.getValue()); + } else if (dataObjectType == DataObjectType.TEMPLATE) { + // get the cached template on this storage + VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId, dataObjectId); - _storagePoolDao.update(storagePoolId, storagePool); + if (templatePoolRef != null) { + sfVolumeId = Long.parseLong(templatePoolRef.getLocalDownloadPath()); } - catch (Exception ex) { - s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire volume", ex); + } + + if (sfVolumeId <= 0) { + throw new CloudRuntimeException("Unable to find SolidFire volume for the following data-object ID: " + dataObjectId + + " and data-object type: " + dataObjectType); + } + + final long newSfVolumeId = SolidFireUtil.createSolidFireClone(sfConnection, sfVolumeId, sfSnapshotId, sfAccountId, sfNewVolumeName, + getVolumeAttributes(volumeInfo)); + + final Iops iops = getIops(volumeInfo.getMinIops(), volumeInfo.getMaxIops(), storagePoolId); + + SolidFireUtil.modifySolidFireVolume(sfConnection, newSfVolumeId, null, null, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); + + return SolidFireUtil.getSolidFireVolume(sfConnection, newSfVolumeId); + } + + private Map getVolumeAttributes(VolumeInfo volumeInfo) { + Map mapAttributes = new HashMap<>(); + + mapAttributes.put(SolidFireUtil.CloudStackVolumeId, String.valueOf(volumeInfo.getId())); + mapAttributes.put(SolidFireUtil.CloudStackVolumeSize, NumberFormat.getInstance().format(volumeInfo.getSize())); + + return mapAttributes; + } + + private Map getSnapshotAttributes(SnapshotInfo snapshotInfo) { + Map mapAttributes = new HashMap<>(); + + mapAttributes.put(SolidFireUtil.CloudStackSnapshotId, String.valueOf(snapshotInfo.getId())); + mapAttributes.put(SolidFireUtil.CloudStackSnapshotSize, NumberFormat.getInstance().format(snapshotInfo.getSize())); + + return mapAttributes; + } + + private Map getTemplateAttributes(TemplateInfo templateInfo) { + Map mapAttributes = new HashMap<>(); + + mapAttributes.put(SolidFireUtil.CloudStackTemplateId, String.valueOf(templateInfo.getId())); + mapAttributes.put(SolidFireUtil.CloudStackTemplateSize, NumberFormat.getInstance().format(templateInfo.getSize())); + + return mapAttributes; + } + + private SolidFireUtil.SolidFireVolume createCloneFromSnapshot(SolidFireUtil.SolidFireConnection sfConnection, long csSnapshotId, long sfAccountId) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID); + + long sfVolumeId = Long.parseLong(snapshotDetails.getValue()); + + snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.SNAPSHOT_ID); + + long sfSnapshotId = Long.parseLong(snapshotDetails.getValue()); + + SolidFireUtil.SolidFireSnapshot sfSnapshot = SolidFireUtil.getSolidFireSnapshot(sfConnection, sfVolumeId, sfSnapshotId); + + long newSfVolumeId = SolidFireUtil.createSolidFireClone(sfConnection, sfVolumeId, sfSnapshotId, sfAccountId, sfSnapshot.getName(), null); + + snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.STORAGE_POOL_ID); + + long storagePoolId = Long.parseLong(snapshotDetails.getValue()); + + final Iops iops = getIops(MIN_IOPS_FOR_TEMP_VOLUME, MAX_IOPS_FOR_TEMP_VOLUME, storagePoolId); + + SolidFireUtil.modifySolidFireVolume(sfConnection, newSfVolumeId, null, null, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); + + return SolidFireUtil.getSolidFireVolume(sfConnection, newSfVolumeId); + } + + private void updateVolumeDetails(long volumeId, long sfVolumeSize) { + volumeDetailsDao.removeDetail(volumeId, SolidFireUtil.VOLUME_SIZE); - errMsg = ex.getMessage(); + VolumeDetailVO volumeDetailVo = new VolumeDetailVO(volumeId, SolidFireUtil.VOLUME_SIZE, String.valueOf(sfVolumeSize), false); + + volumeDetailsDao.persist(volumeDetailVo); + } + + @Override + public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback callback) { + String errMsg = null; + + try { + if (dataObject.getType() == DataObjectType.VOLUME) { + deleteVolume((VolumeInfo)dataObject, dataStore.getId()); + } else if (dataObject.getType() == DataObjectType.SNAPSHOT) { + deleteSnapshot((SnapshotInfo)dataObject, dataStore.getId()); + } else if (dataObject.getType() == DataObjectType.TEMPLATE) { + deleteTemplate((TemplateInfo)dataObject, dataStore.getId()); + } else { + errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to deleteAsync"; } - } else if (dataObject.getType() == DataObjectType.SNAPSHOT) { - // should return null when no error message - errMsg = deleteSnapshot((SnapshotInfo)dataObject, dataStore.getId()); - } else { - errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to deleteAsync"; + } + catch (Exception ex) { + errMsg = ex.getMessage(); + + LOGGER.error(errMsg); } CommandResult result = new CommandResult(); @@ -577,49 +811,67 @@ public void takeSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback capacityBytes) { throw new CloudRuntimeException("Insufficient amount of space remains in this primary storage to take a snapshot"); } storagePool.setUsedBytes(usedBytes); - String volumeName = volumeInfo.getName() + "-" + snapshotInfo.getUuid(); + SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshotInfo.getTO(); - long sfNewVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, volumeName, sfVolume.getAccountId(), sfVolumeSize, - sfVolume.isEnable512e(), NumberFormat.getInstance().format(volumeInfo.getSize()), sfVolume.getMinIops(), 50000, 75000); + if (shouldTakeSnapshot(snapshotInfo.getId())) { + // We are supposed to take a SolidFire snapshot to serve as the back-end for our CloudStack volume snapshot. - // Now that we have successfully created a volume, update the space usage in the storage_pool table - // (even though storage_pool.used_bytes is likely no longer in use). - _storagePoolDao.update(storagePoolId, storagePool); + String sfNewSnapshotName = volumeInfo.getName() + "-" + snapshotInfo.getUuid(); - SolidFireUtil.SolidFireVolume sfNewVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfNewVolumeId); + long sfNewSnapshotId = SolidFireUtil.createSolidFireSnapshot(sfConnection, sfVolumeId, sfNewSnapshotName, getSnapshotAttributes(snapshotInfo)); - updateSnapshotDetails(snapshotInfo.getId(), sfNewVolumeId, storagePoolId, sfVolumeSize, sfNewVolume.getIqn()); + updateSnapshotDetails(snapshotInfo.getId(), sfVolumeId, sfNewSnapshotId, storagePoolId, sfVolumeSize); - SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshotInfo.getTO(); + snapshotObjectTo.setPath("SfSnapshotId=" + sfNewSnapshotId); + } + else { + // We are supposed to create a new SolidFire volume to serve as the back-end for our CloudStack volume snapshot. + + String sfNewVolumeName = volumeInfo.getName() + "-" + snapshotInfo.getUuid(); - snapshotObjectTo.setPath(String.valueOf(sfNewVolumeId)); + final Iops iops = getIops(MIN_IOPS_FOR_SNAPSHOT_VOLUME, MAX_IOPS_FOR_SNAPSHOT_VOLUME, storagePoolId); + + long sfNewVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, sfNewVolumeName, sfVolume.getAccountId(), sfVolumeSize, + sfVolume.isEnable512e(), getSnapshotAttributes(snapshotInfo), iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); + + SolidFireUtil.SolidFireVolume sfNewVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfNewVolumeId); + + updateSnapshotDetails(snapshotInfo.getId(), sfNewVolumeId, storagePoolId, sfVolumeSize, sfNewVolume.getIqn()); + + snapshotObjectTo.setPath("SfVolumeId=" + sfNewVolumeId); + } + + // Now that we have successfully created a volume or a snapshot, update the space usage in the cloud.storage_pool table + // (even though cloud.storage_pool.used_bytes is likely no longer in use). + storagePoolDao.update(storagePoolId, storagePool); CreateObjectAnswer createObjectAnswer = new CreateObjectAnswer(snapshotObjectTo); @@ -628,7 +880,7 @@ public void takeSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback 0) { + // We are supposed to create a clone of the underlying volume or snapshot that supports the CloudStack snapshot. + sfVolume = createClone(sfConnection, csSnapshotId, volumeInfo, sfAccountId, storagePoolId, DataObjectType.SNAPSHOT); + } else if (csTemplateId > 0) { + // Clone from template. + sfVolume = createClone(sfConnection, csTemplateId, volumeInfo, sfAccountId, storagePoolId, DataObjectType.TEMPLATE); + + long volumeSize = getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, storagePoolDao.findById(storagePoolId)); + + if (volumeSize > sfVolume.getTotalSize()) { + // Expand the volume to include HSR. + SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolume.getId(), volumeSize, getVolumeAttributes(volumeInfo), + sfVolume.getMinIops(), sfVolume.getMaxIops(), sfVolume.getBurstIops()); + + // Get the SolidFire volume from the SAN again because we just updated its size. + sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolume.getId()); + } + } + else { + sfVolume = createSolidFireVolume(sfConnection, volumeInfo, sfAccountId); + } + + String iqn = sfVolume.getIqn(); + + VolumeVO volume = volumeDao.findById(volumeInfo.getId()); + + volume.set_iScsiName(iqn); + volume.setFolder(String.valueOf(sfVolume.getId())); + volume.setPoolType(StoragePoolType.IscsiLUN); + volume.setPoolId(storagePoolId); + + volumeDao.update(volume.getId(), volume); + + updateVolumeDetails(volume.getId(), sfVolume.getTotalSize()); + + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); + + long capacityBytes = storagePool.getCapacityBytes(); + // getUsedBytes(StoragePool) will include the bytes of the newly created volume because + // updateVolumeDetails(long, long) has already been called for this volume + long usedBytes = getUsedBytes(storagePool); + + storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes); + + storagePoolDao.update(storagePoolId, storagePool); + + return iqn; + } - long snapshotId = snapshotInfo.getId(); + private void createTempVolume(SnapshotInfo snapshotInfo, long storagePoolId) { + long csSnapshotId = snapshotInfo.getId(); + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.SNAPSHOT_ID); + + if (snapshotDetails == null || snapshotDetails.getValue() == null) { + throw new CloudRuntimeException("'createTempVolume(SnapshotInfo, long)' should not be invoked unless " + SolidFireUtil.SNAPSHOT_ID + " exists."); + } + + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); + + snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, "tempVolume"); + + if (snapshotDetails != null && snapshotDetails.getValue() != null && snapshotDetails.getValue().equalsIgnoreCase("create")) { + long sfAccountId = getCreateSolidFireAccountId(sfConnection, snapshotInfo.getAccountId(), storagePoolId); + + SolidFireUtil.SolidFireVolume sfVolume = createCloneFromSnapshot(sfConnection, csSnapshotId, sfAccountId); + + addTempVolumeId(csSnapshotId, String.valueOf(sfVolume.getId())); + + handleSnapshotDetails(csSnapshotId, DiskTO.IQN, sfVolume.getIqn()); + } + else if (snapshotDetails != null && snapshotDetails.getValue() != null && snapshotDetails.getValue().equalsIgnoreCase("delete")) { + snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID); + + SolidFireUtil.deleteSolidFireVolume(sfConnection, Long.parseLong(snapshotDetails.getValue())); + + removeTempVolumeId(csSnapshotId); + + snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, DiskTO.IQN); + + snapshotDetailsDao.remove(snapshotDetails.getId()); + } + else { + throw new CloudRuntimeException("Invalid state in 'createTempVolume(SnapshotInfo, long)'"); + } + } + + private String createTemplateVolume(TemplateInfo templateInfo, long storagePoolId) { + verifySufficientBytesForStoragePool(templateInfo, storagePoolId); + + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); + + long sfAccountId = getCreateSolidFireAccountId(sfConnection, templateInfo.getAccountId(), storagePoolId); + + SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(sfConnection, templateInfo, sfAccountId); + + String iqn = sfVolume.getIqn(); + + VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId, templateInfo.getId()); + + templatePoolRef.setInstallPath(iqn); + templatePoolRef.setLocalDownloadPath(Long.toString(sfVolume.getId())); + templatePoolRef.setTemplateSize(sfVolume.getTotalSize()); + + tmpltPoolDao.update(templatePoolRef.getId(), templatePoolRef); + + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); + + long capacityBytes = storagePool.getCapacityBytes(); + // getUsedBytes(StoragePool) will include the bytes of the newly created template volume because + // _tmpltPoolDao.update(Long, VMTemplateStoragePoolVO) has already been invoked + long usedBytes = getUsedBytes(storagePool); + + storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes); + + storagePoolDao.update(storagePoolId, storagePool); + + return iqn; + } + + private void deleteVolume(VolumeInfo volumeInfo, long storagePoolId) { try { - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + long volumeId = volumeInfo.getId(); + + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); - SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshotId, SolidFireUtil.VOLUME_ID); + deleteSolidFireVolume(sfConnection, volumeInfo); - long volumeId = Long.parseLong(snapshotDetails.getValue()); + volumeDetailsDao.removeDetails(volumeId); - SolidFireUtil.deleteSolidFireVolume(sfConnection, volumeId); + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); - _snapshotDetailsDao.removeDetails(snapshotId); + long usedBytes = getUsedBytes(storagePool, volumeId); - StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); + storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes); + + storagePoolDao.update(storagePoolId, storagePool); + } + catch (Exception ex) { + LOGGER.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire volume. CloudStack volume ID: " + volumeInfo.getId(), ex); + + throw ex; + } + } + + private void deleteSnapshot(SnapshotInfo snapshotInfo, long storagePoolId) { + long csSnapshotId = snapshotInfo.getId(); + + try { + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); + + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.SNAPSHOT_ID); + + if (snapshotDetails != null && snapshotDetails.getValue() != null) { + // A SolidFire snapshot is being used to support the CloudStack volume snapshot. + + long sfSnapshotId = Long.parseLong(snapshotDetails.getValue()); + + deleteSolidFireSnapshot(sfConnection, csSnapshotId, sfSnapshotId); + } + else { + // A SolidFire volume is being used to support the CloudStack volume snapshot. + + snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID); + + long sfVolumeId = Long.parseLong(snapshotDetails.getValue()); + + SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId); + } + + snapshotDetailsDao.removeDetails(csSnapshotId); + + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); // getUsedBytes(StoragePool) will not include the snapshot to delete because it has already been deleted by this point long usedBytes = getUsedBytes(storagePool); storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes); - _storagePoolDao.update(storagePoolId, storagePool); + storagePoolDao.update(storagePoolId, storagePool); } catch (Exception ex) { - s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire volume. CloudStack snapshot ID: " + snapshotId, ex); + LOGGER.debug(SolidFireUtil.LOG_PREFIX + "Issue in 'deleteSnapshot(SnapshotInfo, long)'. CloudStack snapshot ID: " + csSnapshotId, ex); - errMsg = ex.getMessage(); + throw ex; + } + } + + private void deleteTemplate(TemplateInfo template, long storagePoolId) { + try { + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); + + long sfTemplateVolumeId = getVolumeIdFrom_iScsiPath(template.getInstallPath()); + + SolidFireUtil.deleteSolidFireVolume(sfConnection, sfTemplateVolumeId); + + VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId, template.getId()); + + tmpltPoolDao.remove(templatePoolRef.getId()); + + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); + + // getUsedBytes(StoragePool) will not include the template to delete because the "template_spool_ref" table has already been updated by this point + long usedBytes = getUsedBytes(storagePool); + + storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes); + + storagePoolDao.update(storagePoolId, storagePool); } + catch (Exception ex) { + LOGGER.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire template volume. CloudStack template ID: " + template.getId(), ex); - return errMsg; + throw ex; + } } @Override @@ -720,26 +1196,49 @@ public void resize(DataObject dataObject, AsyncCompletionCallback hsr) { + hsr = payload.newHypervisorSnapshotReserve; + } + } + else { + hsr = payload.newHypervisorSnapshotReserve; + } + } + + sfNewVolumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(payload.newSize, hsr); + } + + Map mapAttributes = new HashMap<>(); + + mapAttributes.put(SolidFireUtil.CloudStackVolumeId, String.valueOf(volumeInfo.getId())); + mapAttributes.put(SolidFireUtil.CloudStackVolumeSize, NumberFormat.getInstance().format(payload.newSize)); - SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolumeId, sfVolume.getTotalSize(), NumberFormat.getInstance().format(payload.newSize), + SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolumeId, sfNewVolumeSize, mapAttributes, payload.newMinIops, payload.newMaxIops, getDefaultBurstIops(storagePoolId, payload.newMaxIops)); - VolumeVO volume = _volumeDao.findById(volumeInfo.getId()); + VolumeVO volume = volumeDao.findById(volumeInfo.getId()); volume.setMinIops(payload.newMinIops); volume.setMaxIops(payload.newMaxIops); + volume.setHypervisorSnapshotReserve(hsr); - _volumeDao.update(volume.getId(), volume); + volumeDao.update(volume.getId(), volume); // SolidFireUtil.VOLUME_SIZE was introduced in 4.5. - // To be backward compatible with releases prior to 4.5, call updateVolumeDetails here. - // That way if SolidFireUtil.VOLUME_SIZE wasn't put in the volume_details table when the - // volume was initially created, it can be placed in volume_details if the volume is resized. - updateVolumeDetails(volume.getId(), sfVolume.getTotalSize()); + updateVolumeDetails(volume.getId(), sfNewVolumeSize); } else { errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to resize"; } @@ -751,21 +1250,140 @@ public void resize(DataObject dataObject, AsyncCompletionCallback capacityBytes) { + throw new CloudRuntimeException("Insufficient amount of space remains in this primary storage"); + } + } + + private void verifySufficientBytesForStoragePool(DataObject dataObject, long storagePoolId) { + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); + + long requestedBytes = getDataObjectSizeIncludingHypervisorSnapshotReserve(dataObject, storagePool); + + verifySufficientBytesForStoragePool(requestedBytes, storagePoolId); + } + + private void verifySufficientBytesForStoragePool(long storagePoolId, long volumeId, long newSize, Integer newHypervisorSnapshotReserve) { + DataStore primaryDataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + VolumeInfo volumeInfo = volumeFactory.getVolume(volumeId, primaryDataStore); + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); + long currentSizeWithHsr = getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, storagePool); + + newHypervisorSnapshotReserve = newHypervisorSnapshotReserve == null ? LOWEST_HYPERVISOR_SNAPSHOT_RESERVE : + Math.max(newHypervisorSnapshotReserve, LOWEST_HYPERVISOR_SNAPSHOT_RESERVE); + + long newSizeWithHsr = (long)(newSize + newSize * (newHypervisorSnapshotReserve / 100f)); + + if (newSizeWithHsr < currentSizeWithHsr) { + throw new CloudRuntimeException("Storage pool " + storagePoolId + " does not support shrinking a volume."); + } + + long availableBytes = storagePool.getCapacityBytes() - getUsedBytes(storagePool); + + if ((newSizeWithHsr - currentSizeWithHsr) > availableBytes) { + throw new CloudRuntimeException("Storage pool " + storagePoolId + " does not have enough space to expand the volume."); + } + } + + private void verifySufficientIopsForStoragePool(long requestedIops, long storagePoolId) { + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); + + long usedIops = getUsedIops(storagePool); + long capacityIops = storagePool.getCapacityIops(); + + if (usedIops + requestedIops > capacityIops) { + throw new CloudRuntimeException("Insufficient number of IOPS available in this storage pool"); + } + } + private void verifySufficientIopsForStoragePool(long storagePoolId, long volumeId, long newMinIops) { - StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); - VolumeVO volume = _volumeDao.findById(volumeId); + VolumeVO volume = volumeDao.findById(volumeId); long currentMinIops = volume.getMinIops(); long diffInMinIops = newMinIops - currentMinIops; // if the desire is for more IOPS if (diffInMinIops > 0) { - long usedIops = getUsedIops(storagePool); - long capacityIops = storagePool.getCapacityIops(); + verifySufficientIopsForStoragePool(diffInMinIops, storagePoolId); + } + } + + private void deleteSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, long csVolumeId, long sfVolumeId) { + List lstSnapshots = getNonDestroyedSnapshots(csVolumeId); + + boolean deleteVolume = true; + + for (SnapshotVO snapshot : lstSnapshots) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.SNAPSHOT_ID); - if (usedIops + diffInMinIops > capacityIops) { - throw new CloudRuntimeException("Insufficient number of IOPS available in this storage pool"); + if (snapshotDetails != null && snapshotDetails.getValue() != null) { + deleteVolume = false; + + break; } } + + if (deleteVolume) { + SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId); + } + } + + private void deleteSolidFireSnapshot(SolidFireUtil.SolidFireConnection sfConnection, long csSnapshotId, long sfSnapshotId) { + SolidFireUtil.deleteSolidFireSnapshot(sfConnection, sfSnapshotId); + + SnapshotVO snapshot = snapshotDao.findById(csSnapshotId); + VolumeVO volume = volumeDao.findById(snapshot.getVolumeId()); + + if (volume == null) { // if the CloudStack volume has been deleted + List lstSnapshots = getNonDestroyedSnapshots(snapshot.getVolumeId()); + + List lstSnapshots2 = new ArrayList<>(); + + for (SnapshotVO snapshotVo : lstSnapshots) { + // The CloudStack volume snapshot has not yet been set to the DESTROYED state, so check to make + // sure snapshotVo.getId() != csSnapshotId when determining if any volume snapshots remain for the given CloudStack volume. + if (snapshotVo.getId() != csSnapshotId) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshotVo.getId(), SolidFireUtil.SNAPSHOT_ID); + + // We are only interested here in volume snapshots that make use of SolidFire snapshots (as opposed to ones + // that make use of SolidFire volumes). + if (snapshotDetails != null && snapshotDetails.getValue() != null) { + lstSnapshots2.add(snapshotVo); + } + } + } + + if (lstSnapshots2.isEmpty()) { + volume = volumeDao.findByIdIncludingRemoved(snapshot.getVolumeId()); + + SolidFireUtil.deleteSolidFireVolume(sfConnection, Long.parseLong(volume.getFolder())); + } + } + } + + private List getNonDestroyedSnapshots(long csVolumeId) { + List lstSnapshots = snapshotDao.listByVolumeId(csVolumeId); + + if (lstSnapshots == null) { + lstSnapshots = new ArrayList<>(); + } + + List lstSnapshots2 = new ArrayList<>(); + + for (SnapshotVO snapshot : lstSnapshots) { + if (!State.Destroyed.equals(snapshot.getState())) { + lstSnapshots2.add(snapshot); + } + } + + return lstSnapshots2; } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java index f89c97a899..c47411e39a 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java @@ -33,6 +33,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper; @@ -49,23 +50,27 @@ import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.SnapshotDetailsDao; import com.cloud.storage.dao.SnapshotDetailsVO; +import com.cloud.storage.dao.VMTemplatePoolDao; import com.cloud.storage.SnapshotVO; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolAutomation; +import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.utils.exception.CloudRuntimeException; public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle { private static final Logger s_logger = Logger.getLogger(SolidFirePrimaryDataStoreLifeCycle.class); @Inject private CapacityManager _capacityMgr; - @Inject private DataCenterDao zoneDao; - @Inject private PrimaryDataStoreDao storagePoolDao; - @Inject private PrimaryDataStoreHelper dataStoreHelper; + @Inject private DataCenterDao _zoneDao; + @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private PrimaryDataStoreHelper _dataStoreHelper; @Inject private ResourceManager _resourceMgr; @Inject private SnapshotDao _snapshotDao; @Inject private SnapshotDetailsDao _snapshotDetailsDao; @Inject private StorageManager _storageMgr; - @Inject private StoragePoolAutomation storagePoolAutomation; + @Inject private StoragePoolAutomation _storagePoolAutomation; + @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; + @Inject private VMTemplatePoolDao _tmpltPoolDao; // invoked to add primary storage that is based on the SolidFire plug-in @Override @@ -83,7 +88,7 @@ public DataStore initialize(Map dsInfos) { String storageVip = SolidFireUtil.getStorageVip(url); int storagePort = SolidFireUtil.getStoragePort(url); - DataCenterVO zone = zoneDao.findById(zoneId); + DataCenterVO zone = _zoneDao.findById(zoneId); String uuid = SolidFireUtil.PROVIDER_NAME + "_" + zone.getUuid() + "_" + storageVip; @@ -179,7 +184,7 @@ public DataStore initialize(Map dsInfos) { details.put(SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS, String.valueOf(fClusterDefaultBurstIopsPercentOfMaxIops)); // this adds a row in the cloud.storage_pool table for this SolidFire cluster - return dataStoreHelper.createPrimaryDataStore(parameters); + return _dataStoreHelper.createPrimaryDataStore(parameters); } // do not implement this method for SolidFire's plug-in @@ -196,7 +201,7 @@ public boolean attachCluster(DataStore store, ClusterScope scope) { @Override public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) { - dataStoreHelper.attachZone(dataStore); + _dataStoreHelper.attachZone(dataStore); List xenServerHosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType.XenServer, scope.getScopeId()); List vmWareServerHosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType.VMware, scope.getScopeId()); @@ -220,23 +225,25 @@ public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType h @Override public boolean maintain(DataStore dataStore) { - storagePoolAutomation.maintain(dataStore); - dataStoreHelper.maintain(dataStore); + _storagePoolAutomation.maintain(dataStore); + _dataStoreHelper.maintain(dataStore); return true; } @Override public boolean cancelMaintain(DataStore store) { - dataStoreHelper.cancelMaintain(store); - storagePoolAutomation.cancelMaintain(store); + _dataStoreHelper.cancelMaintain(store); + _storagePoolAutomation.cancelMaintain(store); return true; } // invoked to delete primary storage that is based on the SolidFire plug-in @Override - public boolean deleteDataStore(DataStore store) { + public boolean deleteDataStore(DataStore dataStore) { + long storagePoolId = dataStore.getId(); + List lstSnapshots = _snapshotDao.listAll(); if (lstSnapshots != null) { @@ -244,13 +251,39 @@ public boolean deleteDataStore(DataStore store) { SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.STORAGE_POOL_ID); // if this snapshot belongs to the storagePool that was passed in - if (snapshotDetails != null && snapshotDetails.getValue() != null && Long.parseLong(snapshotDetails.getValue()) == store.getId()) { + if (snapshotDetails != null && snapshotDetails.getValue() != null && Long.parseLong(snapshotDetails.getValue()) == storagePoolId) { throw new CloudRuntimeException("This primary storage cannot be deleted because it currently contains one or more snapshots."); } } } - return dataStoreHelper.deletePrimaryDataStore(store); + List lstTemplatePoolRefs = _tmpltPoolDao.listByPoolId(storagePoolId); + + if (lstTemplatePoolRefs != null) { + for (VMTemplateStoragePoolVO templatePoolRef : lstTemplatePoolRefs) { + try { + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + long sfTemplateVolumeId = Long.parseLong(templatePoolRef.getLocalDownloadPath()); + + SolidFireUtil.deleteSolidFireVolume(sfConnection, sfTemplateVolumeId); + } + catch (Exception ex) { + s_logger.error(ex.getMessage() != null ? ex.getMessage() : "Error deleting SolidFire template volume"); + } + + _tmpltPoolDao.remove(templatePoolRef.getId()); + } + } + + StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); + + storagePool.setUsedBytes(0); + + _storagePoolDao.update(storagePoolId, storagePool); + + _storagePoolDetailsDao.removeDetails(storagePoolId); + + return _dataStoreHelper.deletePrimaryDataStore(dataStore); } /* (non-Javadoc) @@ -263,7 +296,7 @@ public boolean migrateToObjectStore(DataStore store) { @Override public void updateStoragePool(StoragePool storagePool, Map details) { - StoragePoolVO storagePoolVo = storagePoolDao.findById(storagePool.getId()); + StoragePoolVO storagePoolVo = _storagePoolDao.findById(storagePool.getId()); String strCapacityBytes = details.get(PrimaryDataStoreLifeCycle.CAPACITY_BYTES); Long capacityBytes = strCapacityBytes != null ? Long.parseLong(strCapacityBytes) : null; @@ -290,11 +323,11 @@ public void updateStoragePool(StoragePool storagePool, Map detai @Override public void enableStoragePool(DataStore dataStore) { - dataStoreHelper.enable(dataStore); + _dataStoreHelper.enable(dataStore); } @Override public void disableStoragePool(DataStore dataStore) { - dataStoreHelper.disable(dataStore); + _dataStoreHelper.disable(dataStore); } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java index e505cd07ba..f88041a3c4 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java @@ -52,24 +52,24 @@ import com.cloud.utils.exception.CloudRuntimeException; public class SolidFireSharedHostListener implements HypervisorHostListener { - private static final Logger s_logger = Logger.getLogger(SolidFireSharedHostListener.class); - - @Inject private AgentManager _agentMgr; - @Inject private AlertManager _alertMgr; - @Inject private ClusterDao _clusterDao; - @Inject private ClusterDetailsDao _clusterDetailsDao; - @Inject private DataStoreManager _dataStoreMgr; - @Inject private HostDao _hostDao; - @Inject private PrimaryDataStoreDao _storagePoolDao; - @Inject private StoragePoolHostDao _storagePoolHostDao; - @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; + private static final Logger LOGGER = Logger.getLogger(SolidFireSharedHostListener.class); + + @Inject private AgentManager agentMgr; + @Inject private AlertManager alertMgr; + @Inject private ClusterDao clusterDao; + @Inject private ClusterDetailsDao clusterDetailsDao; + @Inject private DataStoreManager dataStoreMgr; + @Inject private HostDao hostDao; + @Inject private PrimaryDataStoreDao storagePoolDao; + @Inject private StoragePoolHostDao storagePoolHostDao; + @Inject private StoragePoolDetailsDao storagePoolDetailsDao; @Override public boolean hostAdded(long hostId) { - HostVO host = _hostDao.findById(hostId); + HostVO host = hostDao.findById(hostId); SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, host.getClusterId(), true, SolidFireUtil.SHARED_PROVIDER_NAME, - _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao); + clusterDao, clusterDetailsDao, storagePoolDao, storagePoolDetailsDao, hostDao); handleVMware(hostId, true); @@ -78,37 +78,37 @@ public boolean hostAdded(long hostId) { @Override public boolean hostConnect(long hostId, long storagePoolId) { - StoragePool storagePool = (StoragePool)_dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + StoragePool storagePool = (StoragePool) dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool); ModifyStoragePoolAnswer answer = sendModifyStoragePoolCommand(cmd, storagePool, hostId); - StoragePoolHostVO storagePoolHost = _storagePoolHostDao.findByPoolHost(storagePoolId, hostId); + StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId); if (storagePoolHost != null) { storagePoolHost.setLocalPath(answer.getPoolInfo().getLocalPath().replaceAll("//", "/")); } else { storagePoolHost = new StoragePoolHostVO(storagePoolId, hostId, answer.getPoolInfo().getLocalPath().replaceAll("//", "/")); - _storagePoolHostDao.persist(storagePoolHost); + storagePoolHostDao.persist(storagePoolHost); } - StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); + StoragePoolVO storagePoolVO = storagePoolDao.findById(storagePoolId); storagePoolVO.setCapacityBytes(answer.getPoolInfo().getCapacityBytes()); storagePoolVO.setUsedBytes(answer.getPoolInfo().getCapacityBytes() - answer.getPoolInfo().getAvailableBytes()); - _storagePoolDao.update(storagePoolId, storagePoolVO); + storagePoolDao.update(storagePoolId, storagePoolVO); return true; } @Override public boolean hostDisconnected(long hostId, long storagePoolId) { - StoragePoolHostVO storagePoolHost = _storagePoolHostDao.findByPoolHost(storagePoolId, hostId); + StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId); if (storagePoolHost != null) { - _storagePoolHostDao.deleteStoragePoolHostDetails(hostId, storagePoolId); + storagePoolHostDao.deleteStoragePoolHostDetails(hostId, storagePoolId); } return true; @@ -124,16 +124,16 @@ public boolean hostAboutToBeRemoved(long hostId) { @Override public boolean hostRemoved(long hostId, long clusterId) { SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, clusterId, false, SolidFireUtil.SHARED_PROVIDER_NAME, - _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao); + clusterDao, clusterDetailsDao, storagePoolDao, storagePoolDetailsDao, hostDao); return true; } private void handleVMware(long hostId, boolean add) { - HostVO host = _hostDao.findById(hostId); + HostVO host = hostDao.findById(hostId); if (HypervisorType.VMware.equals(host.getHypervisorType())) { - List storagePools = _storagePoolDao.findPoolsByProvider(SolidFireUtil.SHARED_PROVIDER_NAME); + List storagePools = storagePoolDao.findPoolsByProvider(SolidFireUtil.SHARED_PROVIDER_NAME); if (storagePools != null && storagePools.size() > 0) { List> targets = new ArrayList<>(); @@ -142,15 +142,15 @@ private void handleVMware(long hostId, boolean add) { if (storagePool.getClusterId().equals(host.getClusterId())) { long storagePoolId = storagePool.getId(); - StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.IQN); + StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.IQN); String iqn = storagePoolDetail.getValue(); - storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_VIP); + storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_VIP); String sVip = storagePoolDetail.getValue(); - storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_PORT); + storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_PORT); String sPort = storagePoolDetail.getValue(); @@ -177,7 +177,7 @@ private void handleVMware(long hostId, boolean add) { } private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { - Answer answer = _agentMgr.easySend(hostId, cmd); + Answer answer = agentMgr.easySend(hostId, cmd); if (answer == null) { throw new CloudRuntimeException("Unable to get an answer to the modify targets command"); @@ -186,16 +186,16 @@ private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { if (!answer.getResult()) { String msg = "Unable to modify targets on the following host: " + hostId; - HostVO host = _hostDao.findById(hostId); + HostVO host = hostDao.findById(hostId); - _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), msg, msg); + alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), msg, msg); throw new CloudRuntimeException(msg); } } private ModifyStoragePoolAnswer sendModifyStoragePoolCommand(ModifyStoragePoolCommand cmd, StoragePool storagePool, long hostId) { - Answer answer = _agentMgr.easySend(hostId, cmd); + Answer answer = agentMgr.easySend(hostId, cmd); if (answer == null) { throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command for storage pool: " + storagePool.getId()); @@ -204,7 +204,7 @@ private ModifyStoragePoolAnswer sendModifyStoragePoolCommand(ModifyStoragePoolCo if (!answer.getResult()) { String msg = "Unable to attach storage pool " + storagePool.getId() + " to the host " + hostId; - _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg); + alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg); throw new CloudRuntimeException(msg); } @@ -212,7 +212,7 @@ private ModifyStoragePoolAnswer sendModifyStoragePoolCommand(ModifyStoragePoolCo assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer not returned from ModifyStoragePoolCommand; Storage pool = " + storagePool.getId() + "; Host = " + hostId; - s_logger.info("Connection established between storage pool " + storagePool + " and host " + hostId); + LOGGER.info("Connection established between storage pool " + storagePool + " and host " + hostId); return (ModifyStoragePoolAnswer)answer; } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java index 7268e72914..a9c1227120 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -55,6 +56,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; @@ -104,6 +106,15 @@ public class SolidFireUtil { public static final String ACCOUNT_ID = "accountId"; public static final String VOLUME_ID = "volumeId"; + public static final String TEMP_VOLUME_ID = "tempVolumeId"; + public static final String SNAPSHOT_ID = "snapshotId"; + + public static final String CloudStackVolumeId = "CloudStackVolumeId"; + public static final String CloudStackVolumeSize = "CloudStackVolumeSize"; + public static final String CloudStackSnapshotId = "CloudStackSnapshotId"; + public static final String CloudStackSnapshotSize = "CloudStackSnapshotSize"; + public static final String CloudStackTemplateId = "CloudStackTemplateId"; + public static final String CloudStackTemplateSize = "CloudStackTemplateSize"; public static final String VOLUME_SIZE = "sfVolumeSize"; @@ -562,13 +573,44 @@ public static String getSolidFireVolumeName(String strCloudStackVolumeName) { } public static long createSolidFireVolume(SolidFireConnection sfConnection, String strSfVolumeName, long lSfAccountId, long lTotalSize, - boolean bEnable512e, String strCloudStackVolumeSize, long minIops, long maxIops, long burstIops) + boolean bEnable512e, Map mapAttributes, long minIops, long maxIops, long burstIops) { - final Gson gson = new GsonBuilder().create(); + JsonObject volumeToCreate = new JsonObject(); + + volumeToCreate.addProperty("method", "CreateVolume"); + + JsonObject params = new JsonObject(); + + volumeToCreate.add("params", params); + + params.addProperty("name", strSfVolumeName); + params.addProperty("accountID", lSfAccountId); + params.addProperty("totalSize", lTotalSize); + params.addProperty("enable512e", bEnable512e); + + JsonObject qos = new JsonObject(); + + params.add("qos", qos); + + qos.addProperty("minIOPS", minIops); + qos.addProperty("maxIOPS", maxIops); + qos.addProperty("burstIOPS", burstIops); + + if (mapAttributes != null && mapAttributes.size() > 0) { + JsonObject attributes = new JsonObject(); + + params.add("attributes", attributes); + + Iterator> itr = mapAttributes.entrySet().iterator(); + + while (itr.hasNext()) { + Map.Entry pair = itr.next(); + + attributes.addProperty(pair.getKey(), pair.getValue()); + } + } - Object volumeToCreate = strCloudStackVolumeSize != null && strCloudStackVolumeSize.trim().length() > 0 ? - new VolumeToCreateWithCloudStackVolumeSize(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, strCloudStackVolumeSize, minIops, maxIops, burstIops) : - new VolumeToCreate(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, minIops, maxIops, burstIops); + final Gson gson = new GsonBuilder().create(); String strVolumeToCreateJson = gson.toJson(volumeToCreate); @@ -581,14 +623,46 @@ public static long createSolidFireVolume(SolidFireConnection sfConnection, Strin return volumeCreateResult.result.volumeID; } - public static void modifySolidFireVolume(SolidFireConnection sfConnection, long volumeId, long totalSize, String strCloudStackVolumeSize, + public static void modifySolidFireVolume(SolidFireConnection sfConnection, long volumeId, Long totalSize, Map mapAttributes, long minIops, long maxIops, long burstIops) { - final Gson gson = new GsonBuilder().create(); + JsonObject volumeToModify = new JsonObject(); + + volumeToModify.addProperty("method", "ModifyVolume"); + + JsonObject params = new JsonObject(); + + volumeToModify.add("params", params); + + params.addProperty("volumeID", volumeId); + + if (totalSize != null) { + params.addProperty("totalSize", totalSize); + } + + JsonObject qos = new JsonObject(); + + params.add("qos", qos); + + qos.addProperty("minIOPS", minIops); + qos.addProperty("maxIOPS", maxIops); + qos.addProperty("burstIOPS", burstIops); + + if (mapAttributes != null && mapAttributes.size() > 0) { + JsonObject attributes = new JsonObject(); + + params.add("attributes", attributes); + + Iterator> itr = mapAttributes.entrySet().iterator(); - Object volumeToModify = strCloudStackVolumeSize != null && strCloudStackVolumeSize.trim().length() > 0 ? - new VolumeToModifyWithCloudStackVolumeSize(volumeId, totalSize, strCloudStackVolumeSize, minIops, maxIops, burstIops) : - new VolumeToModify(volumeId, totalSize, minIops, maxIops, burstIops); + while (itr.hasNext()) { + Map.Entry pair = itr.next(); + + attributes.addProperty(pair.getKey(), pair.getValue()); + } + } + + final Gson gson = new GsonBuilder().create(); String strVolumeToModifyJson = gson.toJson(volumeToModify); @@ -687,7 +761,7 @@ public static void deleteSolidFireVolume(SolidFireConnection sfConnection, long executeJsonRpc(sfConnection, strVolumeToDeleteJson); } - public static void purgeSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId) + public static void purgeSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId) { final Gson gson = new GsonBuilder().create(); @@ -800,10 +874,51 @@ public boolean equals(Object obj) { } } - public static long createSolidFireSnapshot(SolidFireConnection sfConnection, long lVolumeId, String snapshotName) { - final Gson gson = new GsonBuilder().create(); + public static class SolidFireSnapshot { + private final long _id; + private final String _name; + + public SolidFireSnapshot(long id, String name) { + _id = id; + _name = name; + } + + public long getId() { + return _id; + } + + public String getName() { + return _name; + } + } + + public static long createSolidFireSnapshot(SolidFireConnection sfConnection, long lVolumeId, String snapshotName, Map mapAttributes) { + JsonObject snapshotToCreate = new JsonObject(); + + snapshotToCreate.addProperty("method", "CreateSnapshot"); - SnapshotToCreate snapshotToCreate = new SnapshotToCreate(lVolumeId, snapshotName); + JsonObject params = new JsonObject(); + + snapshotToCreate.add("params", params); + + params.addProperty("volumeID", lVolumeId); + params.addProperty("name", snapshotName); + + if (mapAttributes != null && mapAttributes.size() > 0) { + JsonObject attributes = new JsonObject(); + + params.add("attributes", attributes); + + Iterator> itr = mapAttributes.entrySet().iterator(); + + while (itr.hasNext()) { + Map.Entry pair = itr.next(); + + attributes.addProperty(pair.getKey(), pair.getValue()); + } + } + + final Gson gson = new GsonBuilder().create(); String strSnapshotToCreateJson = gson.toJson(snapshotToCreate); @@ -816,6 +931,38 @@ public static long createSolidFireSnapshot(SolidFireConnection sfConnection, lon return snapshotCreateResult.result.snapshotID; } + public static SolidFireSnapshot getSolidFireSnapshot(SolidFireConnection sfConnection, long lVolumeId, long lSnapshotId) { + final Gson gson = new GsonBuilder().create(); + + SnapshotsToGet snapshotsToGet = new SnapshotsToGet(lVolumeId); + + String strSnapshotsToGetJson = gson.toJson(snapshotsToGet); + + String strSnapshotsGetResultJson = executeJsonRpc(sfConnection, strSnapshotsToGetJson); + + SnapshotsGetResult snapshotsGetResult = gson.fromJson(strSnapshotsGetResultJson, SnapshotsGetResult.class); + + verifyResult(snapshotsGetResult.result, strSnapshotsGetResultJson, gson); + + String snapshotName = null; + + if (snapshotsGetResult.result.snapshots != null) { + for (SnapshotsGetResult.Result.Snapshot snapshot : snapshotsGetResult.result.snapshots) { + if (snapshot.snapshotID == lSnapshotId) { + snapshotName = snapshot.name; + + break; + } + } + } + + if (snapshotName == null) { + throw new CloudRuntimeException("Could not find SolidFire snapshot ID: " + lSnapshotId + " for the following SolidFire volume ID: " + lVolumeId); + } + + return new SolidFireSnapshot(lSnapshotId, snapshotName); + } + public static void deleteSolidFireSnapshot(SolidFireConnection sfConnection, long lSnapshotId) { final Gson gson = new GsonBuilder().create(); @@ -841,10 +988,40 @@ public static void rollBackVolumeToSnapshot(SolidFireConnection sfConnection, lo verifyResult(rollbackInitiatedResult.result, strRollbackInitiatedResultJson, gson); } - public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId, long lSnapshotId, String cloneName) { - final Gson gson = new GsonBuilder().create(); + public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId, long lSnapshotId, long sfAccountId, + String cloneName, Map mapAttributes) { + JsonObject cloneToCreate = new JsonObject(); + + cloneToCreate.addProperty("method", "CloneVolume"); + + JsonObject params = new JsonObject(); + + cloneToCreate.add("params", params); + + params.addProperty("volumeID", lVolumeId); + + if (lSnapshotId > 0) { + params.addProperty("snapshotID", lSnapshotId); + } + + params.addProperty("newAccountID", sfAccountId); + params.addProperty("name", cloneName); + + if (mapAttributes != null && mapAttributes.size() > 0) { + JsonObject attributes = new JsonObject(); - CloneToCreate cloneToCreate = new CloneToCreate(lVolumeId, lSnapshotId, cloneName); + params.add("attributes", attributes); + + Iterator> itr = mapAttributes.entrySet().iterator(); + + while (itr.hasNext()) { + Map.Entry pair = itr.next(); + + attributes.addProperty(pair.getKey(), pair.getValue()); + } + } + + final Gson gson = new GsonBuilder().create(); String strCloneToCreateJson = gson.toJson(cloneToCreate); @@ -854,7 +1031,33 @@ public static long createSolidFireClone(SolidFireConnection sfConnection, long l verifyResult(cloneCreateResult.result, strCloneCreateResultJson, gson); - return cloneCreateResult.result.cloneID; + // Clone is an async operation. Poll until we get data. + + AsyncJobToPoll asyncJobToPoll = new AsyncJobToPoll(cloneCreateResult.result.asyncHandle); + + String strAsyncJobToPollJson = gson.toJson(asyncJobToPoll); + + do { + String strAsyncJobResultJson = executeJsonRpc(sfConnection, strAsyncJobToPollJson); + + AsyncJobResult asyncJobResult = gson.fromJson(strAsyncJobResultJson, AsyncJobResult.class); + + verifyResult(asyncJobResult.result, strAsyncJobResultJson, gson); + + if (asyncJobResult.result.status.equals("complete")) { + break; + } + + try { + Thread.sleep(500); // sleep for 1/2 of a second + } + catch (Exception ex) { + // ignore + } + } + while (true); + + return cloneCreateResult.result.volumeID; } public static long createSolidFireAccount(SolidFireConnection sfConnection, String strAccountName) @@ -1134,189 +1337,6 @@ public boolean equals(Object obj) { } } - @SuppressWarnings("unused") - private static final class VolumeToCreateWithCloudStackVolumeSize { - private final String method = "CreateVolume"; - private final VolumeToCreateParams params; - - private VolumeToCreateWithCloudStackVolumeSize(final String strVolumeName, final long lAccountId, final long lTotalSize, - final boolean bEnable512e, final String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - params = new VolumeToCreateParams(strVolumeName, lAccountId, lTotalSize, bEnable512e, strCloudStackVolumeSize, lMinIOPS, lMaxIOPS, lBurstIOPS); - } - - private static final class VolumeToCreateParams { - private final String name; - private final long accountID; - private final long totalSize; - private final boolean enable512e; - private final VolumeToCreateParamsAttributes attributes; - private final VolumeToCreateParamsQoS qos; - - private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e, - final String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - name = strVolumeName; - accountID = lAccountId; - totalSize = lTotalSize; - enable512e = bEnable512e; - - attributes = new VolumeToCreateParamsAttributes(strCloudStackVolumeSize); - qos = new VolumeToCreateParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS); - } - - private static final class VolumeToCreateParamsAttributes { - private final String CloudStackVolumeSize; - - private VolumeToCreateParamsAttributes(final String strCloudStackVolumeSize) { - CloudStackVolumeSize = strCloudStackVolumeSize; - } - } - - private static final class VolumeToCreateParamsQoS { - private final long minIOPS; - private final long maxIOPS; - private final long burstIOPS; - - private VolumeToCreateParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - minIOPS = lMinIOPS; - maxIOPS = lMaxIOPS; - burstIOPS = lBurstIOPS; - } - } - } - } - - @SuppressWarnings("unused") - private static final class VolumeToCreate { - private final String method = "CreateVolume"; - private final VolumeToCreateParams params; - - private VolumeToCreate(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e, - final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - params = new VolumeToCreateParams(strVolumeName, lAccountId, lTotalSize, bEnable512e, lMinIOPS, lMaxIOPS, lBurstIOPS); - } - - private static final class VolumeToCreateParams { - private final String name; - private final long accountID; - private final long totalSize; - private final boolean enable512e; - private final VolumeToCreateParamsQoS qos; - - private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e, - final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - name = strVolumeName; - accountID = lAccountId; - totalSize = lTotalSize; - enable512e = bEnable512e; - - qos = new VolumeToCreateParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS); - } - - private static final class VolumeToCreateParamsQoS { - private final long minIOPS; - private final long maxIOPS; - private final long burstIOPS; - - private VolumeToCreateParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - minIOPS = lMinIOPS; - maxIOPS = lMaxIOPS; - burstIOPS = lBurstIOPS; - } - } - } - } - - @SuppressWarnings("unused") - private static final class VolumeToModifyWithCloudStackVolumeSize - { - private final String method = "ModifyVolume"; - private final VolumeToModifyParams params; - - private VolumeToModifyWithCloudStackVolumeSize(final long lVolumeId, final long lTotalSize, final String strCloudStackVolumeSize, - final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) - { - params = new VolumeToModifyParams(lVolumeId, lTotalSize, strCloudStackVolumeSize, lMinIOPS, lMaxIOPS, lBurstIOPS); - } - - private static final class VolumeToModifyParams - { - private final long volumeID; - private final long totalSize; - private final VolumeToModifyParamsAttributes attributes; - private final VolumeToModifyParamsQoS qos; - - private VolumeToModifyParams(final long lVolumeId, final long lTotalSize, String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) - { - volumeID = lVolumeId; - - totalSize = lTotalSize; - - attributes = new VolumeToModifyParamsAttributes(strCloudStackVolumeSize); - qos = new VolumeToModifyParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS); - } - } - - private static final class VolumeToModifyParamsAttributes { - private final String CloudStackVolumeSize; - - private VolumeToModifyParamsAttributes(final String strCloudStackVolumeSize) { - CloudStackVolumeSize = strCloudStackVolumeSize; - } - } - - private static final class VolumeToModifyParamsQoS { - private final long minIOPS; - private final long maxIOPS; - private final long burstIOPS; - - private VolumeToModifyParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - minIOPS = lMinIOPS; - maxIOPS = lMaxIOPS; - burstIOPS = lBurstIOPS; - } - } - } - - @SuppressWarnings("unused") - private static final class VolumeToModify - { - private final String method = "ModifyVolume"; - private final VolumeToModifyParams params; - - private VolumeToModify(final long lVolumeId, final long lTotalSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) - { - params = new VolumeToModifyParams(lVolumeId, lTotalSize, lMinIOPS, lMaxIOPS, lBurstIOPS); - } - - private static final class VolumeToModifyParams - { - private final long volumeID; - private final long totalSize; - private final VolumeToModifyParamsQoS qos; - - private VolumeToModifyParams(final long lVolumeId, final long lTotalSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) - { - volumeID = lVolumeId; - - totalSize = lTotalSize; - - qos = new VolumeToModifyParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS); - } - } - - private static final class VolumeToModifyParamsQoS { - private final long minIOPS; - private final long maxIOPS; - private final long burstIOPS; - - private VolumeToModifyParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - minIOPS = lMinIOPS; - maxIOPS = lMaxIOPS; - burstIOPS = lBurstIOPS; - } - } - } - @SuppressWarnings("unused") private static final class VolumeToGet { @@ -1407,21 +1427,20 @@ private VolumeToPurgeParams(final long lVolumeId) { } @SuppressWarnings("unused") - private static final class SnapshotToCreate { - private final String method = "CreateSnapshot"; - private final SnapshotToCreateParams params; + private static final class SnapshotsToGet + { + private final String method = "ListSnapshots"; + private final SnapshotsToGetParams params; - private SnapshotToCreate(final long lVolumeId, final String snapshotName) { - params = new SnapshotToCreateParams(lVolumeId, snapshotName); + private SnapshotsToGet(final long lVolumeId) { + params = new SnapshotsToGetParams(lVolumeId); } - private static final class SnapshotToCreateParams { + private static final class SnapshotsToGetParams { private final long volumeID; - private final String name; - private SnapshotToCreateParams(final long lVolumeId, final String snapshotName) { + private SnapshotsToGetParams(final long lVolumeId) { volumeID = lVolumeId; - name = snapshotName; } } } @@ -1465,28 +1484,6 @@ private RollbackToInitiateParams(final long lVolumeId, final long lSnapshotId) { } } - @SuppressWarnings("unused") - private static final class CloneToCreate { - private final String method = "CloneVolume"; - private final CloneToCreateParams params; - - private CloneToCreate(final long lVolumeId, final long lSnapshotId, final String cloneName) { - params = new CloneToCreateParams(lVolumeId, lSnapshotId, cloneName); - } - - private static final class CloneToCreateParams { - private final long volumeID; - private final long snapshotID; - private final String name; - - private CloneToCreateParams(final long lVolumeId, final long lSnapshotId, final String cloneName) { - volumeID = lVolumeId; - snapshotID = lSnapshotId; - name = cloneName; - } - } - } - @SuppressWarnings("unused") private static final class AccountToAdd { @@ -1680,6 +1677,28 @@ private VagToDeleteParams(final long lVagId) { } } + @SuppressWarnings("unused") + private static final class AsyncJobToPoll + { + private final String method = "GetAsyncResult"; + private final AsyncJobToPollParams params; + + private AsyncJobToPoll(final long asyncHandle) + { + params = new AsyncJobToPollParams(asyncHandle); + } + + private static final class AsyncJobToPollParams + { + private final long asyncHandle; + + private AsyncJobToPollParams(final long asyncHandle) + { + this.asyncHandle = asyncHandle; + } + } + } + private static final class VolumeCreateResult { private Result result; @@ -1721,6 +1740,19 @@ private static final class Result { } } + private static final class SnapshotsGetResult { + private Result result; + + private static final class Result { + private Snapshot[] snapshots; + + private static final class Snapshot { + private long snapshotID; + private String name; + } + } + } + @SuppressWarnings("unused") private static final class RollbackInitiatedResult { private Result result; @@ -1734,7 +1766,8 @@ private static final class CloneCreateResult { private Result result; private static final class Result { - private long cloneID; + private long volumeID; + private long asyncHandle; } } @@ -1786,6 +1819,15 @@ private static final class Vag } } + private static final class AsyncJobResult { + private AsyncResult result; + + private static final class AsyncResult + { + private String status; + } + } + private static final class JsonError { private Error error; diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index 13794c7636..d0ae3e9969 100644 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -549,28 +549,35 @@ public long getAllocatedPoolCapacity(StoragePoolVO pool, VMTemplateVO templateFo return getUsedBytes(pool); } else { - // Get size for all the non-destroyed volumes + // Get size for all the non-destroyed volumes. Pair sizes = _volumeDao.getNonDestroyedCountAndTotalByPool(pool.getId()); totalAllocatedSize = sizes.second() + sizes.first() * _extraBytesPerVolume; } - // Get size for VM Snapshots - totalAllocatedSize = totalAllocatedSize + _volumeDao.getVMSnapshotSizeByPool(pool.getId()); + // Get size for VM Snapshots. + totalAllocatedSize += _volumeDao.getVMSnapshotSizeByPool(pool.getId()); - // Iterate through all templates on this storage pool - boolean tmpinstalled = false; - List templatePoolVOs; - templatePoolVOs = _templatePoolDao.listByPoolId(pool.getId()); + boolean tmpInstalled = false; + // Iterate through all templates on this storage pool. + List templatePoolVOs = _templatePoolDao.listByPoolId(pool.getId()); for (VMTemplateStoragePoolVO templatePoolVO : templatePoolVOs) { - if ((templateForVmCreation != null) && !tmpinstalled && (templatePoolVO.getTemplateId() == templateForVmCreation.getId())) { - tmpinstalled = true; + if ((templateForVmCreation != null) && !tmpInstalled && (templatePoolVO.getTemplateId() == templateForVmCreation.getId())) { + tmpInstalled = true; } + long templateSize = templatePoolVO.getTemplateSize(); + totalAllocatedSize += templateSize + _extraBytesPerVolume; } + if ((templateForVmCreation != null) && !tmpInstalled) { + long templateForVmCreationSize = templateForVmCreation.getSize() != null ? templateForVmCreation.getSize() : 0; + + totalAllocatedSize += templateForVmCreationSize + _extraBytesPerVolume; + } + return totalAllocatedSize; } diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index 2b3358aee8..ef0ad19079 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -1234,7 +1234,8 @@ public int compare(Volume v1, Volume v2) { requestVolumes = new ArrayList(); requestVolumes.add(vol); - if (!_storageMgr.storagePoolHasEnoughSpace(requestVolumes, potentialSPool)) + if (!_storageMgr.storagePoolHasEnoughIops(requestVolumes, potentialSPool) || + !_storageMgr.storagePoolHasEnoughSpace(requestVolumes, potentialSPool, potentialHost.getClusterId())) continue; volumeAllocationMap.put(potentialSPool, requestVolumes); } diff --git a/server/src/com/cloud/hypervisor/CloudZonesStartupProcessor.java b/server/src/com/cloud/hypervisor/CloudZonesStartupProcessor.java index 4bdb2bc1d4..2aa9b04b2a 100644 --- a/server/src/com/cloud/hypervisor/CloudZonesStartupProcessor.java +++ b/server/src/com/cloud/hypervisor/CloudZonesStartupProcessor.java @@ -44,9 +44,11 @@ import com.cloud.dc.dao.DataCenterDetailsDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.exception.ConnectionException; +import com.cloud.host.DetailVO; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; +import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.exception.CloudRuntimeException; @@ -69,6 +71,8 @@ public class CloudZonesStartupProcessor extends AdapterBase implements StartupCo @Inject HostDao _hostDao = null; @Inject + private HostDetailsDao hostDetailsDao; + @Inject HostPodDao _podDao = null; @Inject DataCenterDetailsDao _zoneDetailsDao = null; @@ -319,6 +323,25 @@ protected void updateComputeHost(final HostVO host, final StartupCommand startup host.setHypervisorType(hyType); host.setHypervisorVersion(scc.getHypervisorVersion()); + updateHostDetails(host, scc); + } + + private void updateHostDetails(HostVO host, StartupRoutingCommand startupRoutingCmd) { + final String name = "supportsResign"; + final String value = String.valueOf(startupRoutingCmd.getSupportsClonedVolumes()); + + DetailVO hostDetail = hostDetailsDao.findDetail(host.getId(), name); + + if (hostDetail != null) { + hostDetail.setValue(value); + + hostDetailsDao.update(hostDetail.getId(), hostDetail); + } + else { + hostDetail = new DetailVO(host.getId(), name, value); + + hostDetailsDao.persist(hostDetail); + } } private boolean checkCIDR(Host.Type type, HostPodVO pod, String serverPrivateIP, String serverPrivateNetmask) { diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index cca4add2dc..0b59e392db 100644 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -1733,6 +1733,12 @@ protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource _hostDao.update(host.getId(), host); } + if (startup instanceof StartupRoutingCommand) { + final StartupRoutingCommand ssCmd = (StartupRoutingCommand)startup; + + updateHostDetails(host, ssCmd); + } + try { resourceStateTransitTo(host, ResourceState.Event.InternalCreated, _nodeId); /* Agent goes to Connecting status */ @@ -1750,6 +1756,24 @@ protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource return host; } + private void updateHostDetails(HostVO host, StartupRoutingCommand startupRoutingCmd) { + final String name = "supportsResign"; + final String value = String.valueOf(startupRoutingCmd.getSupportsClonedVolumes()); + + DetailVO hostDetail = _hostDetailsDao.findDetail(host.getId(), name); + + if (hostDetail != null) { + hostDetail.setValue(value); + + _hostDetailsDao.update(hostDetail.getId(), hostDetail); + } + else { + hostDetail = new DetailVO(host.getId(), name, value); + + _hostDetailsDao.persist(hostDetail); + } + } + private boolean isFirstHostInCluster(final HostVO host) { boolean isFirstHost = true; if (host.getClusterId() != null) { diff --git a/server/src/com/cloud/storage/ResizeVolumePayload.java b/server/src/com/cloud/storage/ResizeVolumePayload.java index 7a927b2179..9e4c3ec528 100644 --- a/server/src/com/cloud/storage/ResizeVolumePayload.java +++ b/server/src/com/cloud/storage/ResizeVolumePayload.java @@ -21,16 +21,21 @@ public class ResizeVolumePayload { public final Long newSize; public final Long newMinIops; public final Long newMaxIops; + public final Integer newHypervisorSnapshotReserve; public final boolean shrinkOk; public final String instanceName; public final long[] hosts; + public final boolean isManaged; - public ResizeVolumePayload(Long newSize, Long newMinIops, Long newMaxIops, boolean shrinkOk, String instanceName, long[] hosts) { + public ResizeVolumePayload(Long newSize, Long newMinIops, Long newMaxIops, Integer newHypervisorSnapshotReserve, boolean shrinkOk, + String instanceName, long[] hosts, boolean isManaged) { this.newSize = newSize; this.newMinIops = newMinIops; this.newMaxIops = newMaxIops; + this.newHypervisorSnapshotReserve = newHypervisorSnapshotReserve; this.shrinkOk = shrinkOk; this.instanceName = instanceName; this.hosts = hosts; + this.isManaged = isManaged; } } diff --git a/server/src/com/cloud/storage/StorageManager.java b/server/src/com/cloud/storage/StorageManager.java index a399a083f7..0bf0011086 100644 --- a/server/src/com/cloud/storage/StorageManager.java +++ b/server/src/com/cloud/storage/StorageManager.java @@ -106,6 +106,30 @@ public interface StorageManager extends StorageService { boolean storagePoolHasEnoughSpace(List volume, StoragePool pool); + /** + * This comment is relevant to managed storage only. + * + * Long clusterId = only used for managed storage + * + * Some managed storage can be more efficient handling VM templates (via cloning) if it knows the capabilities of the compute cluster it is dealing with. + * If the compute cluster supports UUID resigning and the storage system can clone a volume from a volume, then this determines how much more space a + * new root volume (that makes use of a template) will take up on the storage system. + * + * For example, if a storage system can clone a volume from a volume and the compute cluster supports UUID resigning (relevant for hypervisors like + * XenServer and ESXi that put virtual disks in clustered file systems), then the storage system will need to determine if it already has a copy of + * the template or if it will need to create one first before cloning the template to a new volume to be used for the new root disk (assuming the root + * disk is being deployed from a template). If the template doesn't already exists on the storage system, then you need to take into consideration space + * required for that template (stored in one volume) and space required for a new volume created from that template volume (for your new root volume). + * + * If UUID resigning is not available in the compute cluster or the storage system doesn't support cloning a volume from a volume, then for each new + * root disk that uses a template, CloudStack will have the template be copied down to a newly created volume on the storage system (i.e. no need + * to take into consideration the possible need to first create a volume on the storage system for a template that will be used for the root disk + * via cloning). + * + * Cloning volumes on the back-end instead of copying down a new template for each new volume helps to alleviate load on the hypervisors. + */ + boolean storagePoolHasEnoughSpace(List volume, StoragePool pool, Long clusterId); + boolean registerHostListener(String providerUuid, HypervisorHostListener listener); void connectHostToSharedPool(long hostId, long poolId) throws StorageUnavailableException, StorageConflictException; diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 0509abc87c..331f09ea9d 100644 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -70,6 +70,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService.TemplateApiResult; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; @@ -1668,9 +1669,9 @@ public boolean storagePoolHasEnoughIops(List requestedVolumes, StoragePo return false; } - // Only IOPS guaranteed primary storage like SolidFire is using/setting IOPS. + // Only IOPS-guaranteed primary storage like SolidFire is using/setting IOPS. // This check returns true for storage that does not specify IOPS. - if (pool.getCapacityIops() == null ) { + if (pool.getCapacityIops() == null) { s_logger.info("Storage pool " + pool.getName() + " (" + pool.getId() + ") does not supply IOPS capacity, assuming enough capacity"); return true; @@ -1696,6 +1697,11 @@ public boolean storagePoolHasEnoughIops(List requestedVolumes, StoragePo @Override public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) { + return storagePoolHasEnoughSpace(volumes, pool, null); + } + + @Override + public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool, Long clusterId) { if (volumes == null || volumes.isEmpty()) { return false; } @@ -1704,10 +1710,11 @@ public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) return false; } - // allocated space includes template of specified volume + // allocated space includes templates StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); - long allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null); + long allocatedSizeWithTemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null); long totalAskingSize = 0; + for (Volume volume : volumes) { // refreshing the volume from the DB to get latest hv_ss_reserve (hypervisor snapshot reserve) field // I could have just assigned this to "volume", but decided to make a new variable for it so that it @@ -1718,18 +1725,37 @@ public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) // update the volume's hv_ss_reserve (hypervisor snapshot reserve) from a disk offering (used for managed storage) volService.updateHypervisorSnapshotReserveForVolume(getDiskOfferingVO(volumeVO), volumeVO.getId(), getHypervisorType(volumeVO)); - // hv_ss_reserve field might have been updated; refresh from DB to make use of it in getVolumeSizeIncludingHypervisorSnapshotReserve + // hv_ss_reserve field might have been updated; refresh from DB to make use of it in getDataObjectSizeIncludingHypervisorSnapshotReserve volumeVO = _volumeDao.findById(volume.getId()); } - if (volumeVO.getTemplateId() != null) { - VMTemplateVO tmpl = _templateDao.findByIdIncludingRemoved(volumeVO.getTemplateId()); - if (tmpl != null && tmpl.getFormat() != ImageFormat.ISO) { - allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, tmpl); + // this if statement should resolve to true at most once per execution of the for loop its contained within (for a root disk that is + // to leverage a template) + if (volume.getTemplateId() != null) { + VMTemplateVO tmpl = _templateDao.findByIdIncludingRemoved(volume.getTemplateId()); + + if (tmpl != null && !ImageFormat.ISO.equals(tmpl.getFormat())) { + allocatedSizeWithTemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, tmpl); } } + if (volumeVO.getState() != Volume.State.Ready) { - totalAskingSize = totalAskingSize + getVolumeSizeIncludingHypervisorSnapshotReserve(volumeVO, pool); + totalAskingSize += getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeVO, pool); + + if (ScopeType.ZONE.equals(poolVO.getScope()) && volumeVO.getTemplateId() != null) { + VMTemplateVO tmpl = _templateDao.findByIdIncludingRemoved(volumeVO.getTemplateId()); + + if (tmpl != null && !ImageFormat.ISO.equals(tmpl.getFormat())) { + // Storage plug-ins for zone-wide primary storage can be designed in such a way as to store a template on the + // primary storage once and make use of it in different clusters (via cloning). + // This next call leads to CloudStack asking how many more bytes it will need for the template (if the template is + // already stored on the primary storage, then the answer is 0). + + if (clusterId != null && _clusterDao.computeWhetherClusterSupportsResigning(clusterId)) { + totalAskingSize += getBytesRequiredForTemplate(tmpl, pool); + } + } + } } } @@ -1749,11 +1775,11 @@ public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) double storageAllocatedThreshold = CapacityManager.StorageAllocatedCapacityDisableThreshold.valueIn(pool.getDataCenterId()); if (s_logger.isDebugEnabled()) { s_logger.debug("Checking pool: " + pool.getId() + " for volume allocation " + volumes.toString() + ", maxSize : " + totalOverProvCapacity + - ", totalAllocatedSize : " + allocatedSizeWithtemplate + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " + + ", totalAllocatedSize : " + allocatedSizeWithTemplate + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " + storageAllocatedThreshold); } - double usedPercentage = (allocatedSizeWithtemplate + totalAskingSize) / (double)(totalOverProvCapacity); + double usedPercentage = (allocatedSizeWithTemplate + totalAskingSize) / (double)(totalOverProvCapacity); if (usedPercentage > storageAllocatedThreshold) { if (s_logger.isDebugEnabled()) { s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + @@ -1763,10 +1789,10 @@ public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) return false; } - if (totalOverProvCapacity < (allocatedSizeWithtemplate + totalAskingSize)) { + if (totalOverProvCapacity < (allocatedSizeWithTemplate + totalAskingSize)) { if (s_logger.isDebugEnabled()) { s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + - ", not enough storage, maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithtemplate + ", askingSize : " + + ", not enough storage, maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithTemplate + ", askingSize : " + totalAskingSize); } return false; @@ -1792,19 +1818,36 @@ private HypervisorType getHypervisorType(Volume volume) { return null; } - private long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { + private long getDataObjectSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName()); DataStoreDriver storeDriver = storeProvider.getDataStoreDriver(); if (storeDriver instanceof PrimaryDataStoreDriver) { PrimaryDataStoreDriver primaryStoreDriver = (PrimaryDataStoreDriver)storeDriver; - return primaryStoreDriver.getVolumeSizeIncludingHypervisorSnapshotReserve(volume, pool); + VolumeInfo volumeInfo = volFactory.getVolume(volume.getId()); + + return primaryStoreDriver.getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, pool); } return volume.getSize(); } + private long getBytesRequiredForTemplate(VMTemplateVO tmpl, StoragePool pool) { + DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName()); + DataStoreDriver storeDriver = storeProvider.getDataStoreDriver(); + + if (storeDriver instanceof PrimaryDataStoreDriver) { + PrimaryDataStoreDriver primaryStoreDriver = (PrimaryDataStoreDriver)storeDriver; + + TemplateInfo templateInfo = tmplFactory.getReadyTemplateOnImageStore(tmpl.getId(), pool.getDataCenterId()); + + return primaryStoreDriver.getBytesRequiredForTemplate(templateInfo, pool); + } + + return tmpl.getSize(); + } + @Override public void createCapacityEntry(long poolId) { StoragePoolVO storage = _storagePoolDao.findById(poolId); diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index 4c3de3eabc..395b00c13c 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -839,6 +839,7 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep Long newSize = null; Long newMinIops = null; Long newMaxIops = null; + Integer newHypervisorSnapshotReserve = null; boolean shrinkOk = cmd.getShrinkOk(); VolumeVO volume = _volsDao.findById(cmd.getEntityId()); @@ -881,6 +882,7 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep // if we are to use the existing disk offering if (newDiskOffering == null) { newSize = cmd.getSize(); + newHypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve(); // if the caller is looking to change the size of the volume if (newSize != null) { @@ -939,10 +941,6 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep throw new InvalidParameterValueException("There are no tags on the current disk offering. The new disk offering needs to have no tags, as well."); } - if (!areIntegersEqual(diskOffering.getHypervisorSnapshotReserve(), newDiskOffering.getHypervisorSnapshotReserve())) { - throw new InvalidParameterValueException("The hypervisor snapshot reverse on the new and old disk offerings must be equal."); - } - if (newDiskOffering.getDomainId() != null) { // not a public offering; check access _configMgr.checkDiskOfferingAccess(CallContext.current().getCallingAccount(), newDiskOffering); @@ -975,6 +973,9 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep newMinIops = newDiskOffering.getMinIops(); newMaxIops = newDiskOffering.getMaxIops(); } + + // if the hypervisor snapshot reserve value is null, it must remain null (currently only KVM uses null and null is all KVM uses for a value here) + newHypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve() != null ? newDiskOffering.getHypervisorSnapshotReserve() : null; } long currentSize = volume.getSize(); @@ -1013,6 +1014,7 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep volume.setSize(newSize); volume.setMinIops(newMinIops); volume.setMaxIops(newMaxIops); + volume.setHypervisorSnapshotReserve(newHypervisorSnapshotReserve); if (newDiskOffering != null) { volume.setDiskOfferingId(cmd.getNewDiskOfferingId()); @@ -1038,13 +1040,13 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep try { return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, - newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); + newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); } finally { _workJobDao.expunge(placeHolder.getId()); } } else { Outcome outcome = resizeVolumeThroughJobQueue(userVm.getId(), volume.getId(), currentSize, newSize, newMinIops, newMaxIops, - newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); + newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); try { outcome.get(); @@ -1079,19 +1081,7 @@ else if (jobResult instanceof Long) { } return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, - newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); - } - - private static boolean areIntegersEqual(Integer i1, Integer i2) { - if (i1 == null) { - i1 = 0; - } - - if (i2 == null) { - i2 = 0; - } - - return i1.equals(i2); + newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); } private void validateIops(Long minIops, Long maxIops) { @@ -1106,9 +1096,12 @@ private void validateIops(Long minIops, Long maxIops) { } } - private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long newSize, Long newMinIops, Long newMaxIops, Long newDiskOfferingId, boolean shrinkOk) { + private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long newSize, Long newMinIops, Long newMaxIops, + Integer newHypervisorSnapshotReserve, Long newDiskOfferingId, boolean shrinkOk) { VolumeVO volume = _volsDao.findById(volumeId); UserVmVO userVm = _userVmDao.findById(volume.getInstanceId()); + StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); + boolean isManaged = storagePool.isManaged(); /* * get a list of hosts to send the commands to, try the system the * associated vm is running on first, then the last known place it ran. @@ -1127,8 +1120,6 @@ private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long n final String errorMsg = "The VM must be stopped or the disk detached in order to resize with the XenServer Hypervisor."; - StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); - if (storagePool.isManaged() && storagePool.getHypervisor() == HypervisorType.Any && hosts != null && hosts.length > 0) { HostVO host = _hostDao.findById(hosts[0]); @@ -1143,13 +1134,20 @@ private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long n } } - ResizeVolumePayload payload = new ResizeVolumePayload(newSize, newMinIops, newMaxIops, shrinkOk, instanceName, hosts); + ResizeVolumePayload payload = new ResizeVolumePayload(newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, + shrinkOk, instanceName, hosts, isManaged); try { VolumeInfo vol = volFactory.getVolume(volume.getId()); vol.addPayload(payload); - StoragePoolVO storagePool = _storagePoolDao.findById(vol.getPoolId()); + // this call to resize has a different impact depending on whether the + // underlying primary storage is managed or not + // if managed, this is the chance for the plug-in to change IOPS value, if applicable + // if not managed, this is the chance for the plug-in to talk to the hypervisor layer + // to change the size of the disk + AsyncCallFuture future = volService.resize(vol); + VolumeApiResult result = future.get(); // managed storage is designed in such a way that the storage plug-in does not // talk to the hypervisor layer; as such, if the storage is managed and the @@ -1165,14 +1163,6 @@ private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long n _volsDao.update(volume.getId(), volume); } - // this call to resize has a different impact depending on whether the - // underlying primary storage is managed or not - // if managed, this is the chance for the plug-in to change IOPS value, if applicable - // if not managed, this is the chance for the plug-in to talk to the hypervisor layer - // to change the size of the disk - AsyncCallFuture future = volService.resize(vol); - VolumeApiResult result = future.get(); - if (result.isFailed()) { s_logger.warn("Failed to resize the volume " + volume); String details = ""; @@ -2758,9 +2748,9 @@ public Outcome detachVolumeFromVmThroughJobQueue(final Long vmId, final return new VmJobVolumeOutcome(workJob, volumeId); } - public Outcome resizeVolumeThroughJobQueue(final Long vmId, final long volumeId, - final long currentSize, final long newSize, final Long newMinIops, final Long newMaxIops, final Long newServiceOfferingId, final boolean shrinkOk) { - + public Outcome resizeVolumeThroughJobQueue(final Long vmId, final long volumeId, final long currentSize, final long newSize, + final Long newMinIops, final Long newMaxIops, final Integer newHypervisorSnapshotReserve, + final Long newServiceOfferingId, final boolean shrinkOk) { final CallContext context = CallContext.current(); final User callingUser = context.getCallingUser(); final Account callingAccount = context.getCallingAccount(); @@ -2781,7 +2771,7 @@ public Outcome resizeVolumeThroughJobQueue(final Long vmId, final long v // save work context info (there are some duplications) VmWorkResizeVolume workInfo = new VmWorkResizeVolume(callingUser.getId(), callingAccount.getId(), vm.getId(), - VolumeApiServiceImpl.VM_WORK_JOB_HANDLER, volumeId, currentSize, newSize, newMinIops, newMaxIops, newServiceOfferingId, shrinkOk); + VolumeApiServiceImpl.VM_WORK_JOB_HANDLER, volumeId, currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, newServiceOfferingId, shrinkOk); workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); @@ -2915,7 +2905,7 @@ private Pair orchestrateDetachVolumeFromVM(VmWorkDetachV @ReflectionUse private Pair orchestrateResizeVolume(VmWorkResizeVolume work) throws Exception { Volume vol = orchestrateResizeVolume(work.getVolumeId(), work.getCurrentSize(), work.getNewSize(), work.getNewMinIops(), work.getNewMaxIops(), - work.getNewServiceOfferingId(), work.isShrinkOk()); + work.getNewHypervisorSnapshotReserve(), work.getNewServiceOfferingId(), work.isShrinkOk()); return new Pair(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(new Long(vol.getId()))); } diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 757ab6110c..16762c5013 100644 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -35,6 +35,7 @@ import org.apache.cloudstack.api.command.user.snapshot.UpdateSnapshotPolicyCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; @@ -1013,9 +1014,14 @@ public SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationExc try { postCreateSnapshot(volume.getId(), snapshotId, payload.getSnapshotPolicyId()); - SnapshotDataStoreVO snapshotStoreRef = _snapshotStoreDao.findBySnapshot(snapshotId, DataStoreRole.Image); + + DataStoreRole dataStoreRole = getDataStoreRole(snapshot, _snapshotStoreDao, dataStoreMgr); + + SnapshotDataStoreVO snapshotStoreRef = _snapshotStoreDao.findBySnapshot(snapshotId, dataStoreRole); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(), snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, snapshotStoreRef.getPhysicalSize(), volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid()); + // Correct the resource count of snapshot in case of delta snapshots. _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.secondary_storage, new Long(volume.getSize() - snapshotStoreRef.getPhysicalSize())); } catch (Exception e) { @@ -1030,6 +1036,30 @@ public SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationExc return snapshot; } + private static DataStoreRole getDataStoreRole(Snapshot snapshot, SnapshotDataStoreDao snapshotStoreDao, DataStoreManager dataStoreMgr) { + SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Primary); + + if (snapshotStore == null) { + return DataStoreRole.Image; + } + + long storagePoolId = snapshotStore.getDataStoreId(); + DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + + Map mapCapabilities = dataStore.getDriver().getCapabilities(); + + if (mapCapabilities != null) { + String value = mapCapabilities.get(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString()); + Boolean supportsStorageSystemSnapshots = new Boolean(value); + + if (supportsStorageSystemSnapshots) { + return DataStoreRole.Primary; + } + } + + return DataStoreRole.Image; + } + @Override public boolean configure(String name, Map params) throws ConfigurationException { diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 4b27c8b326..ceee61604c 100644 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -38,7 +38,7 @@ import com.google.gson.GsonBuilder; import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd; -import org.apache.cloudstack.api.response.GetUploadParamsResponse; +import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand; import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; import org.apache.commons.collections.CollectionUtils; @@ -62,12 +62,14 @@ import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd; import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd; +import org.apache.cloudstack.api.response.GetUploadParamsResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; @@ -79,7 +81,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; -import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -689,7 +690,9 @@ public boolean resetTemplateDownloadStateOnPool(long templateStoragePoolRefId) { } try { + templateStoragePoolRef.setTemplateSize(0); templateStoragePoolRef.setDownloadState(VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED); + _tmpltPoolDao.update(templateStoragePoolRefId, templateStoragePoolRef); } finally { _tmpltPoolDao.releaseFromLockTable(templateStoragePoolRefId); @@ -873,41 +876,55 @@ public List getUnusedTemplatesInPool(StoragePoolVO pool @Override @DB public void evictTemplateFromStoragePool(VMTemplateStoragePoolVO templatePoolVO) { - //Need to hold the lock, otherwise, another thread may create a volume from the template at the same time. - //Assumption here is that, we will hold the same lock during create volume from template + // Need to hold the lock; otherwise, another thread may create a volume from the template at the same time. + // Assumption here is that we will hold the same lock during create volume from template. VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.acquireInLockTable(templatePoolVO.getId()); + if (templatePoolRef == null) { - s_logger.debug("can't aquire the lock for template pool ref:" + templatePoolVO.getId()); + s_logger.debug("Can't aquire the lock for template pool ref: " + templatePoolVO.getId()); + return; } - try { - StoragePool pool = (StoragePool)_dataStoreMgr.getPrimaryDataStore(templatePoolVO.getPoolId()); - VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templatePoolVO.getTemplateId()); + PrimaryDataStore pool = (PrimaryDataStore)_dataStoreMgr.getPrimaryDataStore(templatePoolVO.getPoolId()); + TemplateInfo template = _tmplFactory.getTemplate(templatePoolRef.getTemplateId(), pool); + try { if (s_logger.isDebugEnabled()) { s_logger.debug("Evicting " + templatePoolVO); } - DestroyCommand cmd = new DestroyCommand(pool, templatePoolVO); - try { + if (pool.isManaged()) { + // For managed store, just delete the template volume. + AsyncCallFuture future = _tmpltSvr.deleteTemplateOnPrimary(template, pool); + TemplateApiResult result = future.get(); + + if (result.isFailed()) { + s_logger.debug("Failed to delete template " + template.getId() + " from storage pool " + pool.getId()); + } else { + // Remove the templatePoolVO. + if (_tmpltPoolDao.remove(templatePoolVO.getId())) { + s_logger.debug("Successfully evicted template " + template.getName() + " from storage pool " + pool.getName()); + } + } + } else { + DestroyCommand cmd = new DestroyCommand(pool, templatePoolVO); Answer answer = _storageMgr.sendToPool(pool, cmd); if (answer != null && answer.getResult()) { - // Remove the templatePoolVO + // Remove the templatePoolVO. if (_tmpltPoolDao.remove(templatePoolVO.getId())) { - s_logger.debug("Successfully evicted template: " + template.getName() + " from storage pool: " + pool.getName()); + s_logger.debug("Successfully evicted template " + template.getName() + " from storage pool " + pool.getName()); } } else { - s_logger.info("Will retry evicte template: " + template.getName() + " from storage pool: " + pool.getName()); + s_logger.info("Will retry evict template " + template.getName() + " from storage pool " + pool.getName()); } - } catch (StorageUnavailableException e) { - s_logger.info("Storage is unavailable currently. Will retry evicte template: " + template.getName() + " from storage pool: " + pool.getName()); } + } catch (StorageUnavailableException | InterruptedException | ExecutionException e) { + s_logger.info("Storage is unavailable currently. Will retry evicte template " + template.getName() + " from storage pool " + pool.getName()); } finally { _tmpltPoolDao.releaseFromLockTable(templatePoolRef.getId()); } - } @Override @@ -1482,14 +1499,17 @@ public VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd command) t future = _tmpltSvr.createTemplateFromSnapshotAsync(snapInfo, tmplInfo, store); } else if (volumeId != null) { VolumeInfo volInfo = _volFactory.getVolume(volumeId); + future = _tmpltSvr.createTemplateFromVolumeAsync(volInfo, tmplInfo, store); } else { throw new CloudRuntimeException("Creating private Template need to specify snapshotId or volumeId"); } CommandResult result = null; + try { result = future.get(); + if (result.isFailed()) { privateTemplate = null; s_logger.debug("Failed to create template" + result.getResult()); diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js index 39dfccf2eb..29cd4c1cdc 100644 --- a/ui/scripts/storage.js +++ b/ui/scripts/storage.js @@ -1550,6 +1550,8 @@ preFilter: function(args) { if (args.context.volumes != null && args.context.volumes[0].type == 'ROOT') { args.$form.find('.form-item[rel=newdiskoffering]').hide(); + + selectedDiskOfferingObj = null; } else { args.$form.find('.form-item[rel=newsize]').hide(); } diff --git a/utils/src/main/java/com/cloud/utils/Utils.java b/utils/src/main/java/com/cloud/utils/Utils.java new file mode 100644 index 0000000000..53f0a8059c --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/Utils.java @@ -0,0 +1,38 @@ +// +// 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.utils; + +import java.util.Map; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; + +public class Utils { + public static Map getImmutableMap(Map map) { + Map filteredMap = Maps.filterValues(map, new Predicate() { + public boolean apply(final V input) { + return input != null; + } + }); + + return ImmutableMap.builder().putAll(filteredMap).build(); + } +} From acc781d0866b3d14fd098f5933621d29351d3f7a Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Fri, 13 May 2016 14:16:06 +0530 Subject: [PATCH 159/203] test: fix cleanup sequence for test_acl_listvolume test Changes the cleanup sequence as the cleanup code causes exceptions in several Travis runs such as: https://travis-ci.org/apache/cloudstack/jobs/129925224 Signed-off-by: Rohit Yadav --- test/integration/component/test_acl_listvolume.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/component/test_acl_listvolume.py b/test/integration/component/test_acl_listvolume.py index 65a1201571..12e514d943 100644 --- a/test/integration/component/test_acl_listvolume.py +++ b/test/integration/component/test_acl_listvolume.py @@ -357,9 +357,9 @@ def tearDownClass(cls): cls.apiclient = super(TestVolumeList, cls).getClsTestClient().getApiClient() cls.apiclient.connection.apiKey = cls.default_apikey cls.apiclient.connection.securityKey = cls.default_secretkey + cleanup_resources(cls.apiclient, cls.cleanup) cls.domain_1.delete(cls.apiclient,cleanup="true") cls.domain_2.delete(cls.apiclient,cleanup="true") - cleanup_resources(cls.apiclient, cls.cleanup) return def setUp(cls): From 39aa0e4f35259f1b4962f0469c82930a3fdac579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Aur=C3=A8le=20Brothier?= Date: Mon, 9 May 2016 11:39:04 +0200 Subject: [PATCH 160/203] DAO: Rewrite change for method findByIdIncludingRemoved(ID id) Also change the sibling method findById(final ID id) --- .../com/cloud/utils/db/GenericDaoBase.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/framework/db/src/com/cloud/utils/db/GenericDaoBase.java b/framework/db/src/com/cloud/utils/db/GenericDaoBase.java index 2de161b457..f1b8d0d4dc 100644 --- a/framework/db/src/com/cloud/utils/db/GenericDaoBase.java +++ b/framework/db/src/com/cloud/utils/db/GenericDaoBase.java @@ -942,12 +942,18 @@ protected List listIncludingRemovedBy(final SearchCriteria sc) { @DB() @SuppressWarnings("unchecked") public T findById(final ID id) { + T result = null; if (_cache != null) { final Element element = _cache.get(id); - return element == null ? lockRow(id, null) : (T)element.getObjectValue(); + if (element == null) { + result = lockRow(id, null); + } else { + result = (T)element.getObjectValue(); + } } else { - return lockRow(id, null); + result = lockRow(id, null); } + return result; } @Override @@ -968,13 +974,19 @@ public T findByUuidIncludingRemoved(final String uuid) { @Override @DB() - public T findByIdIncludingRemoved(ID id) { + public T findByIdIncludingRemoved(final ID id) { + T result = null; if (_cache != null) { final Element element = _cache.get(id); - return element == null ? findById(id, true, null) : (T)element.getObjectValue(); + if (element == null) { + result = findById(id, true, null); + } else { + result = (T)element.getObjectValue(); + } } else { - return findById(id, true, null); + result = findById(id, true, null); } + return result; } @Override From da36ffe1e7e43e74ed167e64bbe41d5b0913b4f5 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 12 May 2016 18:14:06 +0530 Subject: [PATCH 161/203] CLOUDSTACK-9377: Fix metrics pagesize issue Fixes listing of clusters and host to list all clusters/hosts by passing pagesize=-1. Signed-off-by: Rohit Yadav --- ui/scripts/metrics.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/scripts/metrics.js b/ui/scripts/metrics.js index 46d6b53bd0..3ce8470af3 100644 --- a/ui/scripts/metrics.js +++ b/ui/scripts/metrics.js @@ -153,7 +153,7 @@ $.ajax({ url: createURL('listClusters'), - data: {zoneid: zone.id}, + data: {zoneid: zone.id, pagesize: -1}, success: function(json) { if (json && json.listclustersresponse && json.listclustersresponse.cluster && json.listclustersresponse.count) { items[idx].clusters += parseInt(json.listclustersresponse.count); @@ -163,7 +163,7 @@ } $.ajax({ url: createURL('listHosts'), - data: {clusterid: cluster.id, type: 'routing'}, + data: {clusterid: cluster.id, type: 'routing', pagesize: -1}, success: function(json) { if (json && json.listhostsresponse && json.listhostsresponse.host && json.listhostsresponse.count) { items[idx].hosts += parseInt(json.listhostsresponse.count); @@ -415,7 +415,7 @@ $.ajax({ url: createURL('listHosts'), - data: {clusterid: cluster.id, type: 'routing'}, + data: {clusterid: cluster.id, type: 'routing', pagesize: -1}, success: function(json) { if (json && json.listhostsresponse && json.listhostsresponse.host && json.listhostsresponse.count) { items[idx].hosts += parseInt(json.listhostsresponse.count); From 9d215562eb9e395efd1b6433d59513c5267a4d4c Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Fri, 13 May 2016 13:52:49 -0600 Subject: [PATCH 162/203] Faster logic to see if a cluster supports resigning --- .../src/com/cloud/dc/dao/ClusterDao.java | 2 +- .../src/com/cloud/dc/dao/ClusterDaoImpl.java | 33 ++++-------- .../com/cloud/host/dao/HostDetailsDao.java | 2 - .../cloud/host/dao/HostDetailsDaoImpl.java | 26 --------- .../StorageSystemDataMotionStrategy.java | 8 +-- .../StorageSystemSnapshotStrategy.java | 4 +- .../storage/volume/VolumeServiceImpl.java | 2 +- .../cloud/resource/ResourceManagerImpl.java | 54 ++++++++++++++++--- .../com/cloud/storage/StorageManagerImpl.java | 2 +- 9 files changed, 65 insertions(+), 68 deletions(-) diff --git a/engine/schema/src/com/cloud/dc/dao/ClusterDao.java b/engine/schema/src/com/cloud/dc/dao/ClusterDao.java index 8e028226d8..06bc5a3afc 100644 --- a/engine/schema/src/com/cloud/dc/dao/ClusterDao.java +++ b/engine/schema/src/com/cloud/dc/dao/ClusterDao.java @@ -46,5 +46,5 @@ public interface ClusterDao extends GenericDao { List listAllCusters(long zoneId); - boolean computeWhetherClusterSupportsResigning(long clusterId); + boolean getSupportsResigning(long clusterId); } diff --git a/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java index aa0b21b49b..0c5bd6f4a7 100644 --- a/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java +++ b/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java @@ -28,11 +28,10 @@ import org.springframework.stereotype.Component; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.ClusterVO; import com.cloud.dc.HostPodVO; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.org.Grouping; import com.cloud.utils.db.GenericDaoBase; @@ -60,9 +59,7 @@ public class ClusterDaoImpl extends GenericDaoBase implements C private static final String GET_POD_CLUSTER_MAP_PREFIX = "SELECT pod_id, id FROM cloud.cluster WHERE cluster.id IN( "; private static final String GET_POD_CLUSTER_MAP_SUFFIX = " )"; @Inject - private HostDao hostDao; - @Inject - private HostDetailsDao hostDetailsDao; + private ClusterDetailsDao clusterDetailsDao; @Inject protected HostPodDao hostPodDao; @@ -269,33 +266,21 @@ public List listAllCusters(long zoneId) { } @Override - public boolean computeWhetherClusterSupportsResigning(long clusterId) { + public boolean getSupportsResigning(long clusterId) { ClusterVO cluster = findById(clusterId); if (cluster == null || cluster.getAllocationState() != Grouping.AllocationState.Enabled) { return false; } - List hosts = hostDao.findByClusterId(clusterId); - - if (hosts == null) { - return false; - } - - Map mapSupportsResign = hostDetailsDao.findDetails("supportsResign"); - - for (HostVO host : hosts) { - if (host == null) { - return false; - } + ClusterDetailsVO clusterDetailsVO = clusterDetailsDao.findDetail(clusterId, "supportsResign"); - String value = mapSupportsResign.get(host.getId()); + if (clusterDetailsVO != null) { + String value = clusterDetailsVO.getValue(); - if (Boolean.parseBoolean(value) == false) { - return false; - } + return Boolean.parseBoolean(value); } - return true; + return false; } } diff --git a/engine/schema/src/com/cloud/host/dao/HostDetailsDao.java b/engine/schema/src/com/cloud/host/dao/HostDetailsDao.java index 77e45dd2f4..7f1a6185e6 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDetailsDao.java +++ b/engine/schema/src/com/cloud/host/dao/HostDetailsDao.java @@ -24,8 +24,6 @@ public interface HostDetailsDao extends GenericDao { Map findDetails(long hostId); - Map findDetails(String name); - void persist(long hostId, Map details); DetailVO findDetail(long hostId, String name); diff --git a/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java b/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java index 525ee9afb5..b864a59210 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java +++ b/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java @@ -37,7 +37,6 @@ public class HostDetailsDaoImpl extends GenericDaoBase implements HostDetailsDao { protected final SearchBuilder HostSearch; protected final SearchBuilder DetailSearch; - protected final SearchBuilder NameSearch; public HostDetailsDaoImpl() { HostSearch = createSearchBuilder(); @@ -48,10 +47,6 @@ public HostDetailsDaoImpl() { DetailSearch.and("hostId", DetailSearch.entity().getHostId(), SearchCriteria.Op.EQ); DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ); DetailSearch.done(); - - NameSearch = createSearchBuilder(); - NameSearch.and("name", NameSearch.entity().getName(), SearchCriteria.Op.EQ); - NameSearch.done(); } @Override @@ -88,27 +83,6 @@ public Map findDetails(long hostId) { return details; } - @Override - public Map findDetails(String name) { - SearchCriteria sc = NameSearch.create(); - - sc.setParameters("name", name); - - List results = search(sc, null); - - Map details = new HashMap<>(results.size()); - - for (DetailVO result : results) { - if ("password".equals(result.getName())) { - details.put(result.getHostId(), DBEncryptionUtil.decrypt(result.getValue())); - } else { - details.put(result.getHostId(), result.getValue()); - } - } - - return details; - } - @Override public void deleteDetails(long hostId) { SearchCriteria sc = HostSearch.create(); diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java index adb1720540..7a59ad07c4 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java @@ -291,7 +291,7 @@ private void handleCreateTemplateFromSnapshot(SnapshotInfo snapshotInfo, Templat HostVO hostVO = getHost(snapshotInfo); boolean usingBackendSnapshot = usingBackendSnapshotFor(snapshotInfo); - boolean computeClusterSupportsResign = clusterDao.computeWhetherClusterSupportsResigning(hostVO.getClusterId()); + boolean computeClusterSupportsResign = clusterDao.getSupportsResigning(hostVO.getClusterId()); if (usingBackendSnapshot && !computeClusterSupportsResign) { String noSupportForResignErrMsg = "Unable to locate an applicable host with which to perform a resignature operation : Cluster ID = " + hostVO.getClusterId(); @@ -399,7 +399,7 @@ private void handleCreateVolumeFromTemplateBothOnStorageSystem(TemplateInfo temp throw new CloudRuntimeException("Unable to locate a host capable of resigning in the zone with the following ID: " + volumeInfo.getDataCenterId()); } - boolean computeClusterSupportsResign = clusterDao.computeWhetherClusterSupportsResigning(hostVO.getClusterId()); + boolean computeClusterSupportsResign = clusterDao.getSupportsResigning(hostVO.getClusterId()); if (!computeClusterSupportsResign) { String noSupportForResignErrMsg = "Unable to locate an applicable host with which to perform a resignature operation : Cluster ID = " + hostVO.getClusterId(); @@ -467,7 +467,7 @@ private void handleCreateVolumeFromSnapshotBothOnStorageSystem(SnapshotInfo snap HostVO hostVO = getHost(snapshotInfo); boolean usingBackendSnapshot = usingBackendSnapshotFor(snapshotInfo); - boolean computeClusterSupportsResign = clusterDao.computeWhetherClusterSupportsResigning(hostVO.getClusterId()); + boolean computeClusterSupportsResign = clusterDao.getSupportsResigning(hostVO.getClusterId()); if (usingBackendSnapshot && !computeClusterSupportsResign) { String noSupportForResignErrMsg = "Unable to locate an applicable host with which to perform a resignature operation : Cluster ID = " + hostVO.getClusterId(); @@ -711,7 +711,7 @@ private HostVO getHost(Long zoneId, boolean computeClusterMustSupportResign) { continue; } - if (clusterDao.computeWhetherClusterSupportsResigning(clusterId)) { + if (clusterDao.getSupportsResigning(clusterId)) { return host; } else { diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java index d74ee57dda..02691ff318 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java @@ -186,7 +186,7 @@ public SnapshotInfo takeSnapshot(SnapshotInfo snapshotInfo) { HostVO hostVO = getHost(volumeInfo.getId()); boolean canStorageSystemCreateVolumeFromSnapshot = canStorageSystemCreateVolumeFromSnapshot(volumeInfo.getPoolId()); - boolean computeClusterSupportsResign = clusterDao.computeWhetherClusterSupportsResigning(hostVO.getClusterId()); + boolean computeClusterSupportsResign = clusterDao.getSupportsResigning(hostVO.getClusterId()); // if canStorageSystemCreateVolumeFromSnapshot && computeClusterSupportsResign, then take a back-end snapshot or create a back-end clone; // else, just create a new back-end volume (eventually used to create a new SR on and to copy a VDI to) @@ -468,7 +468,7 @@ private Optional getHost(long zoneId, boolean computeClusterMustSupportR for (HostVO host : hosts) { if (host.getResourceState() == ResourceState.Enabled) { if (computeClusterMustSupportResign) { - if (clusterDao.computeWhetherClusterSupportsResigning(cluster.getId())) { + if (clusterDao.getSupportsResigning(cluster.getId())) { return Optional.of(host); } else { diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index 54e5105491..05ec7d0270 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -1093,7 +1093,7 @@ private HostVO getHost(Long zoneId, HypervisorType hypervisorType, boolean compu for (HostVO host : hosts) { if (host.getResourceState() == ResourceState.Enabled) { if (computeClusterMustSupportResign) { - if (clusterDao.computeWhetherClusterSupportsResigning(cluster.getId())) { + if (clusterDao.getSupportsResigning(cluster.getId())) { return host; } else { diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 0b59e392db..0689b814ef 100644 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -1736,7 +1736,7 @@ protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource if (startup instanceof StartupRoutingCommand) { final StartupRoutingCommand ssCmd = (StartupRoutingCommand)startup; - updateHostDetails(host, ssCmd); + updateSupportsClonedVolumes(host, ssCmd.getSupportsClonedVolumes()); } try { @@ -1756,21 +1756,61 @@ protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource return host; } - private void updateHostDetails(HostVO host, StartupRoutingCommand startupRoutingCmd) { + private void updateSupportsClonedVolumes(HostVO host, boolean supportsClonedVolumes) { final String name = "supportsResign"; - final String value = String.valueOf(startupRoutingCmd.getSupportsClonedVolumes()); DetailVO hostDetail = _hostDetailsDao.findDetail(host.getId(), name); if (hostDetail != null) { - hostDetail.setValue(value); + if (supportsClonedVolumes) { + hostDetail.setValue(Boolean.TRUE.toString()); - _hostDetailsDao.update(hostDetail.getId(), hostDetail); + _hostDetailsDao.update(hostDetail.getId(), hostDetail); + } + else { + _hostDetailsDao.remove(hostDetail.getId()); + } } else { - hostDetail = new DetailVO(host.getId(), name, value); + if (supportsClonedVolumes) { + hostDetail = new DetailVO(host.getId(), name, Boolean.TRUE.toString()); + + _hostDetailsDao.persist(hostDetail); + } + } + + boolean clusterSupportsResigning = true; - _hostDetailsDao.persist(hostDetail); + List hostVOs = _hostDao.findByClusterId(host.getClusterId()); + + for (HostVO hostVO : hostVOs) { + DetailVO hostDetailVO = _hostDetailsDao.findDetail(hostVO.getId(), name); + + if (hostDetailVO == null || Boolean.parseBoolean(hostDetailVO.getValue()) == false) { + clusterSupportsResigning = false; + + break; + } + } + + ClusterDetailsVO clusterDetailsVO = _clusterDetailsDao.findDetail(host.getClusterId(), name); + + if (clusterDetailsVO != null) { + if (clusterSupportsResigning) { + clusterDetailsVO.setValue(Boolean.TRUE.toString()); + + _clusterDetailsDao.update(clusterDetailsVO.getId(), clusterDetailsVO); + } + else { + _clusterDetailsDao.remove(clusterDetailsVO.getId()); + } + } + else { + if (clusterSupportsResigning) { + clusterDetailsVO = new ClusterDetailsVO(host.getClusterId(), name, Boolean.TRUE.toString()); + + _clusterDetailsDao.persist(clusterDetailsVO); + } } } diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 331f09ea9d..0c56d2d5ab 100644 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -1751,7 +1751,7 @@ public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool, // This next call leads to CloudStack asking how many more bytes it will need for the template (if the template is // already stored on the primary storage, then the answer is 0). - if (clusterId != null && _clusterDao.computeWhetherClusterSupportsResigning(clusterId)) { + if (clusterId != null && _clusterDao.getSupportsResigning(clusterId)) { totalAskingSize += getBytesRequiredForTemplate(tmpl, pool); } } From ed8d47eef2210847a93934d78eb32fc5cfb731fe Mon Sep 17 00:00:00 2001 From: Will Stevens Date: Mon, 16 May 2016 17:27:07 -0400 Subject: [PATCH 163/203] Revert "CLOUDSTACK-9348: Make NioConnectio loop less aggressive" This reverts commit 540d9572fd491db3ce182d26636fc74ada4e171c. This was reverted because it seemed to be related to an issue when doing a DeployDC, causing an `addHost` error. --- utils/src/main/java/com/cloud/utils/nio/Link.java | 5 +---- utils/src/main/java/com/cloud/utils/nio/NioConnection.java | 2 ++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/utils/src/main/java/com/cloud/utils/nio/Link.java b/utils/src/main/java/com/cloud/utils/nio/Link.java index 02ffaab4e0..da2c0d54e8 100644 --- a/utils/src/main/java/com/cloud/utils/nio/Link.java +++ b/utils/src/main/java/com/cloud/utils/nio/Link.java @@ -615,10 +615,7 @@ public static boolean doHandshake(final SocketChannel socketChannel, final SSLEn case NEED_TASK: Runnable task; while ((task = sslEngine.getDelegatedTask()) != null) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Running delegated task!"); - } - task.run(); + new Thread(task).run(); } break; case FINISHED: diff --git a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java index 6fdb4736ac..749e552c2c 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java @@ -171,6 +171,8 @@ public Boolean call() throws NioConnectionException { } catch (final IOException e) { s_logger.error("Agent will die due to this IOException!", e); throw new NioConnectionException(e.getMessage(), e); + } finally { + _selector.wakeup(); } } _isStartup = false; From 4e1f9cd82afd54a28f46215d0003adf743352a12 Mon Sep 17 00:00:00 2001 From: Will Stevens Date: Mon, 16 May 2016 17:29:42 -0400 Subject: [PATCH 164/203] Revert "Merge pull request #1538 from shapeblue/nio-test-timeoutfix" This reverts commit f88cb880974fa56866492c437af291e40bd1a4f6, reversing changes made to 688522ecd41d5e2bf09467aa236deb50f7826982. This was reverted because it seemed to be related to an issue when doing a DeployDC, causing an `addHost` error. --- utils/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/utils/pom.xml b/utils/pom.xml index 206eb1896a..9e2358680f 100755 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -208,7 +208,6 @@ com/cloud/utils/testcase/*TestCase* com/cloud/utils/db/*Test* - com/cloud/utils/testcase/NioTest.java From f175ad1ae09d96007aa3b37adcf79d8e4715a9e7 Mon Sep 17 00:00:00 2001 From: Will Stevens Date: Mon, 16 May 2016 17:30:20 -0400 Subject: [PATCH 165/203] Revert "Merge pull request #1534 from shapeblue/niotest-fix" This reverts commit 9f970f28b18534dffe33196ead60ea861f501fa9, reversing changes made to 6d0c92be7257afcf5f1a9f4453e3470e0083125d. This was reverted because it seemed to be related to an issue when doing a DeployDC, causing an `addHost` error. --- .../main/java/com/cloud/utils/nio/Link.java | 4 ++-- .../com/cloud/utils/nio/NioConnection.java | 2 -- .../com/cloud/utils/testcase/NioTest.java | 23 ++++++++----------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/utils/src/main/java/com/cloud/utils/nio/Link.java b/utils/src/main/java/com/cloud/utils/nio/Link.java index da2c0d54e8..f297d52c07 100644 --- a/utils/src/main/java/com/cloud/utils/nio/Link.java +++ b/utils/src/main/java/com/cloud/utils/nio/Link.java @@ -596,8 +596,8 @@ public static boolean doHandshake(final SocketChannel socketChannel, final SSLEn while (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { final long timeTaken = System.currentTimeMillis() - startTimeMills; - if (timeTaken > 15000L) { - s_logger.warn("SSL Handshake has taken more than 15s to connect to: " + socketChannel.getRemoteAddress() + + if (timeTaken > 60000L) { + s_logger.warn("SSL Handshake has taken more than 60s to connect to: " + socketChannel.getRemoteAddress() + ". Please investigate this connection."); return false; } diff --git a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java index 749e552c2c..6fdb4736ac 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java @@ -171,8 +171,6 @@ public Boolean call() throws NioConnectionException { } catch (final IOException e) { s_logger.error("Agent will die due to this IOException!", e); throw new NioConnectionException(e.getMessage(), e); - } finally { - _selector.wakeup(); } } _isStartup = false; diff --git a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java index 446b1e2fbf..20c31e21b1 100644 --- a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java +++ b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java @@ -61,9 +61,9 @@ public class NioTest { private static final Logger LOGGER = Logger.getLogger(NioTest.class); // Test should fail in due time instead of looping forever - private static final int TESTTIMEOUT = 60000; + private static final int TESTTIMEOUT = 300000; - final private int totalTestCount = 4; + final private int totalTestCount = 5; private int completedTestCount = 0; private NioServer server; @@ -71,7 +71,7 @@ public class NioTest { private List maliciousClients = new ArrayList<>(); private ExecutorService clientExecutor = Executors.newFixedThreadPool(totalTestCount, new NamedThreadFactory("NioClientHandler"));; - private ExecutorService maliciousExecutor = Executors.newFixedThreadPool(totalTestCount, new NamedThreadFactory("MaliciousNioClientHandler"));; + private ExecutorService maliciousExecutor = Executors.newFixedThreadPool(5*totalTestCount, new NamedThreadFactory("MaliciousNioClientHandler"));; private Random randomGenerator = new Random(); private byte[] testBytes; @@ -105,18 +105,12 @@ public void setUp() { Assert.fail(e.getMessage()); } - /** - * The malicious client(s) tries to block NioServer's main IO loop - * thread until SSL handshake timeout value (from Link class, 15s) after - * which the valid NioClient(s) get the opportunity to make connection(s) - */ - for (int i = 0; i < totalTestCount; i++) { - final NioClient maliciousClient = new NioMaliciousClient("NioMaliciousTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioMaliciousTestClient()); - maliciousClients.add(maliciousClient); - maliciousExecutor.submit(new ThreadedNioClient(maliciousClient)); - } - for (int i = 0; i < totalTestCount; i++) { + for (int j = 0; j < 4; j++) { + final NioClient maliciousClient = new NioMaliciousClient("NioMaliciousTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioMaliciousTestClient()); + maliciousClients.add(maliciousClient); + maliciousExecutor.submit(new ThreadedNioClient(maliciousClient)); + } final NioClient client = new NioClient("NioTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioTestClient()); clients.add(client); clientExecutor.submit(new ThreadedNioClient(client)); @@ -292,6 +286,7 @@ public void doTask(final Task task) { LOGGER.info("Server: Received OTHER task"); } } + } } } From b4ad38d687abc7173c7231748cb52135149415ca Mon Sep 17 00:00:00 2001 From: Will Stevens Date: Mon, 16 May 2016 17:30:44 -0400 Subject: [PATCH 166/203] Revert "Merge pull request #1493 from shapeblue/nio-fix" This reverts commit 7ce0e10fbcd949375e43535aae168421ecdaa562, reversing changes made to 29ba71f2db3a3b7dcdad3a7c1f83725cffd56261. This was reverted because it seemed to be related to an issue when doing a DeployDC, causing an `addHost` error. --- .../manager/ClusteredAgentManagerImpl.java | 9 +- utils/pom.xml | 1 + .../main/java/com/cloud/utils/nio/Link.java | 294 +++++++----------- .../java/com/cloud/utils/nio/NioClient.java | 31 +- .../com/cloud/utils/nio/NioConnection.java | 84 +++-- .../java/com/cloud/utils/nio/NioServer.java | 8 +- .../com/cloud/utils/testcase/NioTest.java | 249 ++++++--------- 7 files changed, 270 insertions(+), 406 deletions(-) diff --git a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java index 9239adc091..75f860ddfa 100644 --- a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java @@ -499,7 +499,7 @@ public SocketChannel connectToPeer(final String peerName, final SocketChannel pr SocketChannel ch1 = null; try { ch1 = SocketChannel.open(new InetSocketAddress(addr, Port.value())); - ch1.configureBlocking(false); + ch1.configureBlocking(true); // make sure we are working at blocking mode ch1.socket().setKeepAlive(true); ch1.socket().setSoTimeout(60 * 1000); try { @@ -507,11 +507,8 @@ public SocketChannel connectToPeer(final String peerName, final SocketChannel pr sslEngine = sslContext.createSSLEngine(ip, Port.value()); sslEngine.setUseClientMode(true); sslEngine.setEnabledProtocols(SSLUtils.getSupportedProtocols(sslEngine.getEnabledProtocols())); - sslEngine.beginHandshake(); - if (!Link.doHandshake(ch1, sslEngine, true)) { - ch1.close(); - throw new IOException("SSL handshake failed!"); - } + + Link.doHandshake(ch1, sslEngine, true); s_logger.info("SSL: Handshake done"); } catch (final Exception e) { ch1.close(); diff --git a/utils/pom.xml b/utils/pom.xml index 9e2358680f..206eb1896a 100755 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -208,6 +208,7 @@ com/cloud/utils/testcase/*TestCase* com/cloud/utils/db/*Test* + com/cloud/utils/testcase/NioTest.java diff --git a/utils/src/main/java/com/cloud/utils/nio/Link.java b/utils/src/main/java/com/cloud/utils/nio/Link.java index f297d52c07..6d6306a53b 100644 --- a/utils/src/main/java/com/cloud/utils/nio/Link.java +++ b/utils/src/main/java/com/cloud/utils/nio/Link.java @@ -19,33 +19,37 @@ package com.cloud.utils.nio; -import com.cloud.utils.PropertiesUtil; -import com.cloud.utils.db.DbProperties; -import org.apache.cloudstack.utils.security.SSLUtils; -import org.apache.log4j.Logger; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLEngineResult.HandshakeStatus; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; +import java.net.SocketTimeoutException; import java.nio.ByteBuffer; +import java.nio.channels.Channels; import java.nio.channels.ClosedChannelException; +import java.nio.channels.ReadableByteChannel; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.util.concurrent.ConcurrentLinkedQueue; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; + +import org.apache.cloudstack.utils.security.SSLUtils; +import org.apache.log4j.Logger; + +import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.db.DbProperties; + /** */ public class Link { @@ -449,185 +453,115 @@ public static SSLContext initSSLContext(boolean isClient) throws GeneralSecurity return sslContext; } - public static ByteBuffer enlargeBuffer(ByteBuffer buffer, final int sessionProposedCapacity) { - if (buffer == null || sessionProposedCapacity < 0) { - return buffer; - } - if (sessionProposedCapacity > buffer.capacity()) { - buffer = ByteBuffer.allocate(sessionProposedCapacity); - } else { - buffer = ByteBuffer.allocate(buffer.capacity() * 2); + public static void doHandshake(SocketChannel ch, SSLEngine sslEngine, boolean isClient) throws IOException { + if (s_logger.isTraceEnabled()) { + s_logger.trace("SSL: begin Handshake, isClient: " + isClient); } - return buffer; - } - public static ByteBuffer handleBufferUnderflow(final SSLEngine engine, ByteBuffer buffer) { - if (engine == null || buffer == null) { - return buffer; - } - if (buffer.position() < buffer.limit()) { - return buffer; + SSLEngineResult engResult; + SSLSession sslSession = sslEngine.getSession(); + HandshakeStatus hsStatus; + ByteBuffer in_pkgBuf = ByteBuffer.allocate(sslSession.getPacketBufferSize() + 40); + ByteBuffer in_appBuf = ByteBuffer.allocate(sslSession.getApplicationBufferSize() + 40); + ByteBuffer out_pkgBuf = ByteBuffer.allocate(sslSession.getPacketBufferSize() + 40); + ByteBuffer out_appBuf = ByteBuffer.allocate(sslSession.getApplicationBufferSize() + 40); + int count; + ch.socket().setSoTimeout(60 * 1000); + InputStream inStream = ch.socket().getInputStream(); + // Use readCh to make sure the timeout on reading is working + ReadableByteChannel readCh = Channels.newChannel(inStream); + + if (isClient) { + hsStatus = SSLEngineResult.HandshakeStatus.NEED_WRAP; + } else { + hsStatus = SSLEngineResult.HandshakeStatus.NEED_UNWRAP; } - ByteBuffer replaceBuffer = enlargeBuffer(buffer, engine.getSession().getPacketBufferSize()); - buffer.flip(); - replaceBuffer.put(buffer); - return replaceBuffer; - } - private static boolean doHandshakeUnwrap(final SocketChannel socketChannel, final SSLEngine sslEngine, - ByteBuffer peerAppData, ByteBuffer peerNetData, final int appBufferSize) throws IOException { - if (socketChannel == null || sslEngine == null || peerAppData == null || peerNetData == null || appBufferSize < 0) { - return false; - } - if (socketChannel.read(peerNetData) < 0) { - if (sslEngine.isInboundDone() && sslEngine.isOutboundDone()) { - return false; - } - try { - sslEngine.closeInbound(); - } catch (SSLException e) { - s_logger.warn("This SSL engine was forced to close inbound due to end of stream."); + while (hsStatus != SSLEngineResult.HandshakeStatus.FINISHED) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("SSL: Handshake status " + hsStatus); } - sslEngine.closeOutbound(); - // After closeOutbound the engine will be set to WRAP state, - // in order to try to send a close message to the client. - return true; - } - peerNetData.flip(); - SSLEngineResult result = null; - try { - result = sslEngine.unwrap(peerNetData, peerAppData); - peerNetData.compact(); - } catch (SSLException sslException) { - s_logger.error("SSL error occurred while processing unwrap data: " + sslException.getMessage()); - sslEngine.closeOutbound(); - return true; - } - switch (result.getStatus()) { - case OK: - break; - case BUFFER_OVERFLOW: - // Will occur when peerAppData's capacity is smaller than the data derived from peerNetData's unwrap. - peerAppData = enlargeBuffer(peerAppData, appBufferSize); - break; - case BUFFER_UNDERFLOW: - // Will occur either when no data was read from the peer or when the peerNetData buffer - // was too small to hold all peer's data. - peerNetData = handleBufferUnderflow(sslEngine, peerNetData); - break; - case CLOSED: - if (sslEngine.isOutboundDone()) { - return false; - } else { - sslEngine.closeOutbound(); - break; - } - default: - throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); - } - return true; - } - - private static boolean doHandshakeWrap(final SocketChannel socketChannel, final SSLEngine sslEngine, - ByteBuffer myAppData, ByteBuffer myNetData, ByteBuffer peerNetData, - final int netBufferSize) throws IOException { - if (socketChannel == null || sslEngine == null || myNetData == null || peerNetData == null - || myAppData == null || netBufferSize < 0) { - return false; - } - myNetData.clear(); - SSLEngineResult result = null; - try { - result = sslEngine.wrap(myAppData, myNetData); - } catch (SSLException sslException) { - s_logger.error("SSL error occurred while processing wrap data: " + sslException.getMessage()); - sslEngine.closeOutbound(); - return true; - } - switch (result.getStatus()) { - case OK : - myNetData.flip(); - while (myNetData.hasRemaining()) { - socketChannel.write(myNetData); + engResult = null; + if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP) { + out_pkgBuf.clear(); + out_appBuf.clear(); + out_appBuf.put("Hello".getBytes()); + engResult = sslEngine.wrap(out_appBuf, out_pkgBuf); + out_pkgBuf.flip(); + int remain = out_pkgBuf.limit(); + while (remain != 0) { + remain -= ch.write(out_pkgBuf); + if (remain < 0) { + throw new IOException("Too much bytes sent?"); + } } - break; - case BUFFER_OVERFLOW: - // Will occur if there is not enough space in myNetData buffer to write all the data - // that would be generated by the method wrap. Since myNetData is set to session's packet - // size we should not get to this point because SSLEngine is supposed to produce messages - // smaller or equal to that, but a general handling would be the following: - myNetData = enlargeBuffer(myNetData, netBufferSize); - break; - case BUFFER_UNDERFLOW: - throw new SSLException("Buffer underflow occurred after a wrap. We should not reach here."); - case CLOSED: - try { - myNetData.flip(); - while (myNetData.hasRemaining()) { - socketChannel.write(myNetData); + } else if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) { + in_appBuf.clear(); + // One packet may contained multiply operation + if (in_pkgBuf.position() == 0 || !in_pkgBuf.hasRemaining()) { + in_pkgBuf.clear(); + count = 0; + try { + count = readCh.read(in_pkgBuf); + } catch (SocketTimeoutException ex) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Handshake reading time out! Cut the connection"); + } + count = -1; + } + if (count == -1) { + throw new IOException("Connection closed with -1 on reading size."); } - // At this point the handshake status will probably be NEED_UNWRAP - // so we make sure that peerNetData is clear to read. - peerNetData.clear(); - } catch (Exception e) { - s_logger.error("Failed to send server's CLOSE message due to socket channel's failure."); + in_pkgBuf.flip(); } - break; - default: - throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); - } - return true; - } - - public static boolean doHandshake(final SocketChannel socketChannel, final SSLEngine sslEngine, final boolean isClient) throws IOException { - if (socketChannel == null || sslEngine == null) { - return false; - } - final int appBufferSize = sslEngine.getSession().getApplicationBufferSize(); - final int netBufferSize = sslEngine.getSession().getPacketBufferSize(); - ByteBuffer myAppData = ByteBuffer.allocate(appBufferSize); - ByteBuffer peerAppData = ByteBuffer.allocate(appBufferSize); - ByteBuffer myNetData = ByteBuffer.allocate(netBufferSize); - ByteBuffer peerNetData = ByteBuffer.allocate(netBufferSize); - - final long startTimeMills = System.currentTimeMillis(); - - HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); - while (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED - && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { - final long timeTaken = System.currentTimeMillis() - startTimeMills; - if (timeTaken > 60000L) { - s_logger.warn("SSL Handshake has taken more than 60s to connect to: " + socketChannel.getRemoteAddress() + - ". Please investigate this connection."); - return false; - } - switch (handshakeStatus) { - case NEED_UNWRAP: - if (!doHandshakeUnwrap(socketChannel, sslEngine, peerAppData, peerNetData, appBufferSize)) { - return false; + engResult = sslEngine.unwrap(in_pkgBuf, in_appBuf); + ByteBuffer tmp_pkgBuf = ByteBuffer.allocate(sslSession.getPacketBufferSize() + 40); + int loop_count = 0; + while (engResult.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) { + // The client is too slow? Cut it and let it reconnect + if (loop_count > 10) { + throw new IOException("Too many times in SSL BUFFER_UNDERFLOW, disconnect guest."); } - break; - case NEED_WRAP: - if (!doHandshakeWrap(socketChannel, sslEngine, myAppData, myNetData, peerNetData, netBufferSize)) { - return false; + // We need more packets to complete this operation + if (s_logger.isTraceEnabled()) { + s_logger.trace("SSL: Buffer underflowed, getting more packets"); } - break; - case NEED_TASK: - Runnable task; - while ((task = sslEngine.getDelegatedTask()) != null) { - new Thread(task).run(); + tmp_pkgBuf.clear(); + count = ch.read(tmp_pkgBuf); + if (count == -1) { + throw new IOException("Connection closed with -1 on reading size."); } - break; - case FINISHED: - break; - case NOT_HANDSHAKING: - break; - default: - throw new IllegalStateException("Invalid SSL status: " + handshakeStatus); + tmp_pkgBuf.flip(); + + in_pkgBuf.mark(); + in_pkgBuf.position(in_pkgBuf.limit()); + in_pkgBuf.limit(in_pkgBuf.limit() + tmp_pkgBuf.limit()); + in_pkgBuf.put(tmp_pkgBuf); + in_pkgBuf.reset(); + + in_appBuf.clear(); + engResult = sslEngine.unwrap(in_pkgBuf, in_appBuf); + loop_count++; + } + } else if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK) { + Runnable run; + while ((run = sslEngine.getDelegatedTask()) != null) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("SSL: Running delegated task!"); + } + run.run(); + } + } else if (hsStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { + throw new IOException("NOT a handshaking!"); + } + if (engResult != null && engResult.getStatus() != SSLEngineResult.Status.OK) { + throw new IOException("Fail to handshake! " + engResult.getStatus()); } - handshakeStatus = sslEngine.getHandshakeStatus(); + if (engResult != null) + hsStatus = engResult.getHandshakeStatus(); + else + hsStatus = sslEngine.getHandshakeStatus(); } - return true; } } diff --git a/utils/src/main/java/com/cloud/utils/nio/NioClient.java b/utils/src/main/java/com/cloud/utils/nio/NioClient.java index dc4f670de1..d989f306c5 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioClient.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioClient.java @@ -36,6 +36,7 @@ public class NioClient extends NioConnection { private static final Logger s_logger = Logger.getLogger(NioClient.class); protected String _host; + protected String _bindAddress; protected SocketChannel _clientConnection; public NioClient(final String name, final String host, final int port, final int workers, final HandlerFactory factory) { @@ -43,6 +44,10 @@ public NioClient(final String name, final String host, final int port, final int _host = host; } + public void setBindAddress(final String ipAddress) { + _bindAddress = ipAddress; + } + @Override protected void init() throws IOException { _selector = Selector.open(); @@ -50,25 +55,33 @@ protected void init() throws IOException { try { _clientConnection = SocketChannel.open(); - + _clientConnection.configureBlocking(true); s_logger.info("Connecting to " + _host + ":" + _port); + + if (_bindAddress != null) { + s_logger.info("Binding outbound interface at " + _bindAddress); + + final InetSocketAddress bindAddr = new InetSocketAddress(_bindAddress, 0); + _clientConnection.socket().bind(bindAddr); + } + final InetSocketAddress peerAddr = new InetSocketAddress(_host, _port); _clientConnection.connect(peerAddr); - _clientConnection.configureBlocking(false); + + SSLEngine sslEngine = null; + // Begin SSL handshake in BLOCKING mode + _clientConnection.configureBlocking(true); final SSLContext sslContext = Link.initSSLContext(true); - SSLEngine sslEngine = sslContext.createSSLEngine(_host, _port); + sslEngine = sslContext.createSSLEngine(_host, _port); sslEngine.setUseClientMode(true); sslEngine.setEnabledProtocols(SSLUtils.getSupportedProtocols(sslEngine.getEnabledProtocols())); - sslEngine.beginHandshake(); - if (!Link.doHandshake(_clientConnection, sslEngine, true)) { - s_logger.error("SSL Handshake failed while connecting to host: " + _host + " port: " + _port); - _selector.close(); - throw new IOException("SSL Handshake failed while connecting to host: " + _host + " port: " + _port); - } + + Link.doHandshake(_clientConnection, sslEngine, true); s_logger.info("SSL: Handshake done"); s_logger.info("Connected to " + _host + ":" + _port); + _clientConnection.configureBlocking(false); final Link link = new Link(peerAddr, this); link.setSSLEngine(sslEngine); final SelectionKey key = _clientConnection.register(_selector, SelectionKey.OP_READ); diff --git a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java index 6fdb4736ac..249f512d9c 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java @@ -19,13 +19,8 @@ package com.cloud.utils.nio; -import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.exception.NioConnectionException; -import org.apache.cloudstack.utils.security.SSLUtils; -import org.apache.log4j.Logger; +import static com.cloud.utils.AutoCloseableUtil.closeAutoCloseable; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; import java.io.IOException; import java.net.ConnectException; import java.net.InetSocketAddress; @@ -49,7 +44,14 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import static com.cloud.utils.AutoCloseableUtil.closeAutoCloseable; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; + +import org.apache.cloudstack.utils.security.SSLUtils; +import org.apache.log4j.Logger; + +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.exception.NioConnectionException; /** * NioConnection abstracts the NIO socket operations. The Java implementation @@ -69,7 +71,6 @@ public abstract class NioConnection implements Callable { protected HandlerFactory _factory; protected String _name; protected ExecutorService _executor; - protected ExecutorService _sslHandshakeExecutor; public NioConnection(final String name, final int port, final int workers, final HandlerFactory factory) { _name = name; @@ -78,7 +79,6 @@ public NioConnection(final String name, final int port, final int workers, final _port = port; _factory = factory; _executor = new ThreadPoolExecutor(workers, 5 * workers, 1, TimeUnit.DAYS, new LinkedBlockingQueue(), new NamedThreadFactory(name + "-Handler")); - _sslHandshakeExecutor = Executors.newCachedThreadPool(new NamedThreadFactory(name + "-SSLHandshakeHandler")); } public void start() throws NioConnectionException { @@ -185,9 +185,8 @@ public Boolean call() throws NioConnectionException { protected void accept(final SelectionKey key) throws IOException { final ServerSocketChannel serverSocketChannel = (ServerSocketChannel)key.channel(); - final SocketChannel socketChannel = serverSocketChannel.accept(); - socketChannel.configureBlocking(false); + final SocketChannel socketChannel = serverSocketChannel.accept(); final Socket socket = socketChannel.socket(); socket.setKeepAlive(true); @@ -195,52 +194,43 @@ protected void accept(final SelectionKey key) throws IOException { s_logger.trace("Connection accepted for " + socket); } - final SSLEngine sslEngine; + // Begin SSL handshake in BLOCKING mode + socketChannel.configureBlocking(true); + + SSLEngine sslEngine = null; try { final SSLContext sslContext = Link.initSSLContext(false); sslEngine = sslContext.createSSLEngine(); sslEngine.setUseClientMode(false); sslEngine.setNeedClientAuth(false); sslEngine.setEnabledProtocols(SSLUtils.getSupportedProtocols(sslEngine.getEnabledProtocols())); - final NioConnection nioConnection = this; - _sslHandshakeExecutor.submit(new Runnable() { - @Override - public void run() { - _selector.wakeup(); - try { - sslEngine.beginHandshake(); - if (!Link.doHandshake(socketChannel, sslEngine, false)) { - throw new IOException("SSL handshake timed out with " + socketChannel.getRemoteAddress()); - } - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Handshake done"); - } - final InetSocketAddress saddr = (InetSocketAddress)socket.getRemoteSocketAddress(); - final Link link = new Link(saddr, nioConnection); - link.setSSLEngine(sslEngine); - link.setKey(socketChannel.register(key.selector(), SelectionKey.OP_READ, link)); - final Task task = _factory.create(Task.Type.CONNECT, link, null); - registerLink(saddr, link); - _executor.submit(task); - } catch (IOException e) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("Connection closed due to failure: " + e.getMessage()); - } - closeAutoCloseable(socket, "accepting socket"); - closeAutoCloseable(socketChannel, "accepting socketChannel"); - } finally { - _selector.wakeup(); - } - } - }); + + Link.doHandshake(socketChannel, sslEngine, false); + } catch (final Exception e) { if (s_logger.isTraceEnabled()) { - s_logger.trace("Connection closed due to failure: " + e.getMessage()); + s_logger.trace("Socket " + socket + " closed on read. Probably -1 returned: " + e.getMessage()); } - closeAutoCloseable(socket, "accepting socket"); closeAutoCloseable(socketChannel, "accepting socketChannel"); - } finally { - _selector.wakeup(); + closeAutoCloseable(socket, "opened socket"); + return; + } + + if (s_logger.isTraceEnabled()) { + s_logger.trace("SSL: Handshake done"); + } + socketChannel.configureBlocking(false); + final InetSocketAddress saddr = (InetSocketAddress)socket.getRemoteSocketAddress(); + final Link link = new Link(saddr, this); + link.setSSLEngine(sslEngine); + link.setKey(socketChannel.register(key.selector(), SelectionKey.OP_READ, link)); + final Task task = _factory.create(Task.Type.CONNECT, link, null); + registerLink(saddr, link); + + try { + _executor.submit(task); + } catch (final Exception e) { + s_logger.warn("Exception occurred when submitting the task", e); } } diff --git a/utils/src/main/java/com/cloud/utils/nio/NioServer.java b/utils/src/main/java/com/cloud/utils/nio/NioServer.java index 13d5476cba..539c2bb13d 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioServer.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioServer.java @@ -43,10 +43,6 @@ public NioServer(final String name, final int port, final int workers, final Han _links = new WeakHashMap(1024); } - public int getPort() { - return _serverSocket.socket().getLocalPort(); - } - @Override protected void init() throws IOException { _selector = SelectorProvider.provider().openSelector(); @@ -57,9 +53,9 @@ protected void init() throws IOException { _localAddr = new InetSocketAddress(_port); _serverSocket.socket().bind(_localAddr); - _serverSocket.register(_selector, SelectionKey.OP_ACCEPT); + _serverSocket.register(_selector, SelectionKey.OP_ACCEPT, null); - s_logger.info("NioConnection started and listening on " + _serverSocket.socket().getLocalSocketAddress()); + s_logger.info("NioConnection started and listening on " + _localAddr.toString()); } @Override diff --git a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java index 20c31e21b1..d8510cfcac 100644 --- a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java +++ b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java @@ -19,7 +19,14 @@ package com.cloud.utils.testcase; -import com.cloud.utils.concurrency.NamedThreadFactory; +import java.nio.channels.ClosedChannelException; +import java.util.Random; + +import junit.framework.TestCase; + +import org.apache.log4j.Logger; +import org.junit.Assert; + import com.cloud.utils.exception.NioConnectionException; import com.cloud.utils.nio.HandlerFactory; import com.cloud.utils.nio.Link; @@ -27,200 +34,131 @@ import com.cloud.utils.nio.NioServer; import com.cloud.utils.nio.Task; import com.cloud.utils.nio.Task.Type; -import org.apache.log4j.Logger; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.Selector; -import java.nio.channels.SocketChannel; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; /** - * NioTest demonstrates that NioServer can function without getting its main IO - * loop blocked when an aggressive or malicious client connects to the server but - * fail to participate in SSL handshake. In this test, we run bunch of clients - * that send a known payload to the server, to which multiple malicious clients - * also try to connect and hang. - * A malicious client could cause denial-of-service if the server's main IO loop - * along with SSL handshake was blocking. A passing tests shows that NioServer - * can still function in case of connection load and that the main IO loop along - * with SSL handshake is non-blocking with some internal timeout mechanism. + * + * + * + * */ -public class NioTest { - - private static final Logger LOGGER = Logger.getLogger(NioTest.class); - - // Test should fail in due time instead of looping forever - private static final int TESTTIMEOUT = 300000; +public class NioTest extends TestCase { - final private int totalTestCount = 5; - private int completedTestCount = 0; + private static final Logger s_logger = Logger.getLogger(NioTest.class); - private NioServer server; - private List clients = new ArrayList<>(); - private List maliciousClients = new ArrayList<>(); + private NioServer _server; + private NioClient _client; - private ExecutorService clientExecutor = Executors.newFixedThreadPool(totalTestCount, new NamedThreadFactory("NioClientHandler"));; - private ExecutorService maliciousExecutor = Executors.newFixedThreadPool(5*totalTestCount, new NamedThreadFactory("MaliciousNioClientHandler"));; + private Link _clientLink; - private Random randomGenerator = new Random(); - private byte[] testBytes; + private int _testCount; + private int _completedCount; private boolean isTestsDone() { boolean result; synchronized (this) { - result = totalTestCount == completedTestCount; + result = _testCount == _completedCount; } return result; } + private void getOneMoreTest() { + synchronized (this) { + _testCount++; + } + } + private void oneMoreTestDone() { synchronized (this) { - completedTestCount++; + _completedCount++; } } - @Before + @Override public void setUp() { - LOGGER.info("Setting up Benchmark Test"); + s_logger.info("Test"); - completedTestCount = 0; - testBytes = new byte[1000000]; - randomGenerator.nextBytes(testBytes); + _testCount = 0; + _completedCount = 0; - server = new NioServer("NioTestServer", 0, 1, new NioTestServer()); + _server = new NioServer("NioTestServer", 7777, 5, new NioTestServer()); try { - server.start(); + _server.start(); } catch (final NioConnectionException e) { - Assert.fail(e.getMessage()); + fail(e.getMessage()); } - for (int i = 0; i < totalTestCount; i++) { - for (int j = 0; j < 4; j++) { - final NioClient maliciousClient = new NioMaliciousClient("NioMaliciousTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioMaliciousTestClient()); - maliciousClients.add(maliciousClient); - maliciousExecutor.submit(new ThreadedNioClient(maliciousClient)); - } - final NioClient client = new NioClient("NioTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioTestClient()); - clients.add(client); - clientExecutor.submit(new ThreadedNioClient(client)); + _client = new NioClient("NioTestServer", "127.0.0.1", 7777, 5, new NioTestClient()); + try { + _client.start(); + } catch (final NioConnectionException e) { + fail(e.getMessage()); } - } - - @After - public void tearDown() { - stopClient(); - stopServer(); - } - protected void stopClient() { - for (NioClient client : clients) { - client.stop(); - } - for (NioClient maliciousClient : maliciousClients) { - maliciousClient.stop(); + while (_clientLink == null) { + try { + s_logger.debug("Link is not up! Waiting ..."); + Thread.sleep(1000); + } catch (final InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } - LOGGER.info("Clients stopped."); - } - - protected void stopServer() { - server.stop(); - LOGGER.info("Server stopped."); } - @Test(timeout=TESTTIMEOUT) - public void testConnection() { + @Override + public void tearDown() { while (!isTestsDone()) { try { - LOGGER.debug(completedTestCount + "/" + totalTestCount + " tests done. Waiting for completion"); + s_logger.debug(_completedCount + "/" + _testCount + " tests done. Waiting for completion"); Thread.sleep(1000); } catch (final InterruptedException e) { - Assert.fail(e.getMessage()); + // TODO Auto-generated catch block + e.printStackTrace(); } } - LOGGER.debug(completedTestCount + "/" + totalTestCount + " tests done."); + stopClient(); + stopServer(); } - protected void doServerProcess(final byte[] data) { - oneMoreTestDone(); - Assert.assertArrayEquals(testBytes, data); - LOGGER.info("Verify data received by server done."); + protected void stopClient() { + _client.stop(); + s_logger.info("Client stopped."); } - public byte[] getTestBytes() { - return testBytes; + protected void stopServer() { + _server.stop(); + s_logger.info("Server stopped."); } - public class ThreadedNioClient implements Runnable { - final private NioClient client; - ThreadedNioClient(final NioClient client) { - this.client = client; - } - - @Override - public void run() { - try { - client.start(); - } catch (NioConnectionException e) { - Assert.fail(e.getMessage()); - } - } + protected void setClientLink(final Link link) { + _clientLink = link; } - public class NioMaliciousClient extends NioClient { + Random randomGenerator = new Random(); - public NioMaliciousClient(String name, String host, int port, int workers, HandlerFactory factory) { - super(name, host, port, workers, factory); - } + byte[] _testBytes; - @Override - protected void init() throws IOException { - _selector = Selector.open(); - try { - _clientConnection = SocketChannel.open(); - LOGGER.info("Connecting to " + _host + ":" + _port); - final InetSocketAddress peerAddr = new InetSocketAddress(_host, _port); - _clientConnection.connect(peerAddr); - // This is done on purpose, the malicious client would connect - // to the server and then do nothing, hence using a large sleep value - Thread.sleep(Long.MAX_VALUE); - } catch (final IOException e) { - _selector.close(); - throw e; - } catch (InterruptedException e) { - LOGGER.debug(e.getMessage()); - } + public void testConnection() { + _testBytes = new byte[1000000]; + randomGenerator.nextBytes(_testBytes); + try { + getOneMoreTest(); + _clientLink.send(_testBytes); + s_logger.info("Client: Data sent"); + getOneMoreTest(); + _clientLink.send(_testBytes); + s_logger.info("Client: Data sent"); + } catch (final ClosedChannelException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } } - public class NioMaliciousTestClient implements HandlerFactory { - - @Override - public Task create(final Type type, final Link link, final byte[] data) { - return new NioMaliciousTestClientHandler(type, link, data); - } - - public class NioMaliciousTestClientHandler extends Task { - - public NioMaliciousTestClientHandler(final Type type, final Link link, final byte[] data) { - super(type, link, data); - } - - @Override - public void doTask(final Task task) { - LOGGER.info("Malicious Client: Received task " + task.getType().toString()); - } - } + protected void doServerProcess(final byte[] data) { + oneMoreTestDone(); + Assert.assertArrayEquals(_testBytes, data); + s_logger.info("Verify done."); } public class NioTestClient implements HandlerFactory { @@ -239,23 +177,18 @@ public NioTestClientHandler(final Type type, final Link link, final byte[] data) @Override public void doTask(final Task task) { if (task.getType() == Task.Type.CONNECT) { - LOGGER.info("Client: Received CONNECT task"); - try { - LOGGER.info("Sending data to server"); - task.getLink().send(getTestBytes()); - } catch (ClosedChannelException e) { - LOGGER.error(e.getMessage()); - e.printStackTrace(); - } + s_logger.info("Client: Received CONNECT task"); + setClientLink(task.getLink()); } else if (task.getType() == Task.Type.DATA) { - LOGGER.info("Client: Received DATA task"); + s_logger.info("Client: Received DATA task"); } else if (task.getType() == Task.Type.DISCONNECT) { - LOGGER.info("Client: Received DISCONNECT task"); + s_logger.info("Client: Received DISCONNECT task"); stopClient(); } else if (task.getType() == Task.Type.OTHER) { - LOGGER.info("Client: Received OTHER task"); + s_logger.info("Client: Received OTHER task"); } } + } } @@ -275,15 +208,15 @@ public NioTestServerHandler(final Type type, final Link link, final byte[] data) @Override public void doTask(final Task task) { if (task.getType() == Task.Type.CONNECT) { - LOGGER.info("Server: Received CONNECT task"); + s_logger.info("Server: Received CONNECT task"); } else if (task.getType() == Task.Type.DATA) { - LOGGER.info("Server: Received DATA task"); + s_logger.info("Server: Received DATA task"); doServerProcess(task.getData()); } else if (task.getType() == Task.Type.DISCONNECT) { - LOGGER.info("Server: Received DISCONNECT task"); + s_logger.info("Server: Received DISCONNECT task"); stopServer(); } else if (task.getType() == Task.Type.OTHER) { - LOGGER.info("Server: Received OTHER task"); + s_logger.info("Server: Received OTHER task"); } } From d64f224a7b83c28b6b4698458c651f26b8cf9f0c Mon Sep 17 00:00:00 2001 From: SudharmaJain Date: Tue, 20 Oct 2015 11:01:34 +0530 Subject: [PATCH 167/203] CLOUDSTACK-8970 Centos 6.{1,2,3,4,5} guest OS mapping for vmware is not available --- setup/db/db/schema-481to490.sql | 51 +++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/setup/db/db/schema-481to490.sql b/setup/db/db/schema-481to490.sql index 15b0d59ebd..bd1dd82d1a 100644 --- a/setup/db/db/schema-481to490.sql +++ b/setup/db/db/schema-481to490.sql @@ -494,3 +494,54 @@ CREATE TABLE IF NOT EXISTS `cloud`.`oobm` ( KEY `i_oobm__mgmt_server_id` (`mgmt_server_id`), CONSTRAINT `fk_oobm__host_id` FOREIGN KEY (`host_id`) REFERENCES `host` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centosGuest', 171, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centosGuest', 171, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centosGuest', 171, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centosGuest', 171, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centosGuest', 171, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centos64Guest', 172, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centos64Guest', 172, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centos64Guest', 172, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centos64Guest', 172, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centos64Guest', 172, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centosGuest', 177, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centosGuest', 177, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centosGuest', 177, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centosGuest', 177, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centosGuest', 177, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centos64Guest', 178, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centos64Guest', 178, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centos64Guest', 178, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centos64Guest', 178, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centos64Guest', 178, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centosGuest', 179, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centosGuest', 179, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centosGuest', 179, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centosGuest', 179, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centosGuest', 179, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centos64Guest', 180, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centos64Guest', 180, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centos64Guest', 180, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centos64Guest', 180, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centos64Guest', 180, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centosGuest', 181, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centosGuest', 181, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centosGuest', 181, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centosGuest', 181, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centosGuest', 181, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centos64Guest', 182, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centos64Guest', 182, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centos64Guest', 182, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centos64Guest', 182, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centos64Guest', 182, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centosGuest', 227, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centosGuest', 227, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centosGuest', 227, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centosGuest', 227, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centosGuest', 227, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centos64Guest', 228, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centos64Guest', 228, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centos64Guest', 228, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centos64Guest', 228, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centos64Guest', 228, now(), 0); From 59edbb53378b700c21a6dd722cd92a7286450644 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 17 May 2016 14:45:50 +0200 Subject: [PATCH 168/203] CLOUDSTACK-9380: fix NPE in listDomains API for a mistake --- server/src/com/cloud/api/query/dao/DomainJoinDaoImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/com/cloud/api/query/dao/DomainJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/DomainJoinDaoImpl.java index be3f5b4126..6aecb8159d 100644 --- a/server/src/com/cloud/api/query/dao/DomainJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/DomainJoinDaoImpl.java @@ -110,7 +110,7 @@ public void setResourceLimits(DomainJoinVO domain, boolean fullView, ResourceLim long volumeLimit = ApiDBUtils.findCorrectResourceLimitForDomain(domain.getVolumeLimit(), fullView, ResourceType.volume, domain.getId()); String volumeLimitDisplay = (fullView || volumeLimit == -1) ? "Unlimited" : String.valueOf(volumeLimit); - long volumeTotal = (domain.getVolumeTotal() == 0) ? 0 : domain.getVolumeTotal(); + long volumeTotal = (domain.getVolumeTotal() == null) ? 0 : domain.getVolumeTotal(); String volumeAvail = (fullView || volumeLimit == -1) ? "Unlimited" : String.valueOf(volumeLimit - volumeTotal); response.setVolumeLimit(volumeLimitDisplay); response.setVolumeTotal(volumeTotal); From 1770f3cb86f84128c40571330af55a7255fa49cc Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Wed, 18 May 2016 13:46:18 +0530 Subject: [PATCH 169/203] dynamic-roles: remove unnecessary order by ID On some MySQL server envs, this may cause a SQL statement error, though I was unable to reproduce it. Since it's not needed, an order by 'sort_order' is enough, we can safely remove it. Signed-off-by: Rohit Yadav --- .../org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java index 960b652a3b..8f6fa83f01 100644 --- a/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java @@ -156,7 +156,6 @@ public List findAllByRoleIdSorted(final Long roleId) { sc.setParameters("roleId", roleId); } final Filter searchBySorted = new Filter(RolePermissionVO.class, "sortOrder", true, null, null); - searchBySorted.addOrderBy(RolePermissionVO.class, "id", true); final List rolePermissionList = listBy(sc, searchBySorted); if (rolePermissionList == null) { return Collections.emptyList(); From 3bb70daeccbb96d77e04e15983ccee161ccbba4e Mon Sep 17 00:00:00 2001 From: Romain Dartigues Date: Wed, 18 May 2016 23:34:19 +0200 Subject: [PATCH 170/203] add DHCP lease folders for Ubuntu Add "/var/lib/dhcp/*" to the search path for Ubuntu; tested under Ubuntu Precise and Trusty, not yet with newer releases. --- setup/bindir/cloud-set-guest-sshkey.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/bindir/cloud-set-guest-sshkey.in b/setup/bindir/cloud-set-guest-sshkey.in index 03d57f5366..80e40646ad 100755 --- a/setup/bindir/cloud-set-guest-sshkey.in +++ b/setup/bindir/cloud-set-guest-sshkey.in @@ -27,7 +27,7 @@ user=root # Add your DHCP lease folders here -DHCP_FOLDERS="/var/lib/dhclient/* /var/lib/dhcp3/*" +DHCP_FOLDERS="/var/lib/dhclient/* /var/lib/dhcp3/* /var/lib/dhcp/*" keys_received=0 file_count=0 From 07dcac7373054f7af057756f752afe66fb459589 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 19 May 2016 09:56:46 +0530 Subject: [PATCH 171/203] packaging: backup commands.properties as it does not exist in new rpms In case of rpms, the commands.properties file is bundled at /usr/share/cloudstack-management/webapps/client/WEB-INF/classes/commands.properties In case of a rpm upgrade, new rpms won't ship with commands.properties file. For existing installations this copies the commands.properties file to /etc/cloudstack/management Signed-off-by: Rohit Yadav --- packaging/centos63/cloud.spec | 7 +++++++ packaging/centos7/cloud.spec | 7 +++++++ packaging/fedora20/cloud.spec | 7 +++++++ packaging/fedora21/cloud.spec | 7 +++++++ 4 files changed, 28 insertions(+) diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index 25970ea5a3..7ead8061d5 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -396,6 +396,13 @@ if [ -d "%{_sysconfdir}/cloud" ] ; then mv %{_sysconfdir}/cloud %{_sysconfdir}/cloud.rpmsave fi +# in case of upgrade to 4.9+ copy commands.properties if not exists in /etc/cloudstack/management/ +if [ "$1" == "2" ] ; then + if [ -f "%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties" ] && [ ! -f "%{_sysconfdir}/%{name}/management/commands.properties" ] ; then + cp -p %{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties %{_sysconfdir}/%{name}/management/commands.properties + fi +fi + %post management if [ "$1" == "1" ] ; then /sbin/chkconfig --add cloudstack-management > /dev/null 2>&1 || true diff --git a/packaging/centos7/cloud.spec b/packaging/centos7/cloud.spec index 68cc048a48..917db09697 100644 --- a/packaging/centos7/cloud.spec +++ b/packaging/centos7/cloud.spec @@ -352,6 +352,13 @@ id cloud > /dev/null 2>&1 || /usr/sbin/useradd -M -c "CloudStack unprivileged us rm -rf %{_localstatedir}/cache/cloudstack +# in case of upgrade to 4.9+ copy commands.properties if not exists in /etc/cloudstack/management/ +if [ "$1" == "2" ] ; then + if [ -f "%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties" ] && [ ! -f "%{_sysconfdir}/%{name}/management/commands.properties" ] ; then + cp -p %{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties %{_sysconfdir}/%{name}/management/commands.properties + fi +fi + %post management if [ "$1" == "1" ] ; then /usr/bin/systemctl on cloudstack-management > /dev/null 2>&1 || true diff --git a/packaging/fedora20/cloud.spec b/packaging/fedora20/cloud.spec index b1d11b13a4..084472b43e 100644 --- a/packaging/fedora20/cloud.spec +++ b/packaging/fedora20/cloud.spec @@ -395,6 +395,13 @@ if [ -d "%{_sysconfdir}/cloud" ] ; then mv %{_sysconfdir}/cloud %{_sysconfdir}/cloud.rpmsave fi +# in case of upgrade to 4.9+ copy commands.properties if not exists in /etc/cloudstack/management/ +if [ "$1" == "2" ] ; then + if [ -f "%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties" ] && [ ! -f "%{_sysconfdir}/%{name}/management/commands.properties" ] ; then + cp -p %{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties %{_sysconfdir}/%{name}/management/commands.properties + fi +fi + %post management if [ "$1" == "1" ] ; then /sbin/chkconfig --add cloudstack-management > /dev/null 2>&1 || true diff --git a/packaging/fedora21/cloud.spec b/packaging/fedora21/cloud.spec index 561452e3e9..dbf761feaa 100644 --- a/packaging/fedora21/cloud.spec +++ b/packaging/fedora21/cloud.spec @@ -395,6 +395,13 @@ if [ -d "%{_sysconfdir}/cloud" ] ; then mv %{_sysconfdir}/cloud %{_sysconfdir}/cloud.rpmsave fi +# in case of upgrade to 4.9+ copy commands.properties if not exists in /etc/cloudstack/management/ +if [ "$1" == "2" ] ; then + if [ -f "%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties" ] && [ ! -f "%{_sysconfdir}/%{name}/management/commands.properties" ] ; then + cp -p %{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties %{_sysconfdir}/%{name}/management/commands.properties + fi +fi + %post management if [ "$1" == "1" ] ; then /sbin/chkconfig --add cloudstack-management > /dev/null 2>&1 || true From 20638caaa4fede993dd6ce4fd071bc6f473b884b Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Sat, 14 May 2016 11:46:32 +0530 Subject: [PATCH 172/203] packaging: don't bundle systemvm.zip in rpms Removes bundling of systemvm.zip in cloudstack-common rpms. This is not done in debian packaging either there we remove for rpms as well, as this file is not used by any subsystem but systemvm.iso is used. Signed-off-by: Rohit Yadav --- packaging/centos63/cloud.spec | 2 -- packaging/centos7/cloud.spec | 2 -- packaging/fedora20/cloud.spec | 2 -- packaging/fedora21/cloud.spec | 2 -- 4 files changed, 8 deletions(-) diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index 7ead8061d5..c267e8fdfe 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -234,7 +234,6 @@ mkdir -p ${RPM_BUILD_ROOT}%{python_sitearch}/ mkdir -p ${RPM_BUILD_ROOT}%/usr/bin cp -r scripts/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts install -D systemvm/dist/systemvm.iso ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.iso -install -D systemvm/dist/systemvm.zip ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.zip install python/lib/cloud_utils.py ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py cp -r python/lib/cloudutils ${RPM_BUILD_ROOT}%{python_sitearch}/ python -m py_compile ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py @@ -612,7 +611,6 @@ fi %attr(0755,root,root) %{_datadir}/%{name}-common/scripts %attr(0755,root,root) /usr/bin/cloudstack-sccs %attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.iso -%attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.zip %attr(0644,root,root) %{python_sitearch}/cloud_utils.py %attr(0644,root,root) %{python_sitearch}/cloud_utils.pyc %attr(0644,root,root) %{python_sitearch}/cloudutils/* diff --git a/packaging/centos7/cloud.spec b/packaging/centos7/cloud.spec index 917db09697..b99d950d83 100644 --- a/packaging/centos7/cloud.spec +++ b/packaging/centos7/cloud.spec @@ -202,7 +202,6 @@ mkdir -p ${RPM_BUILD_ROOT}%{python_sitearch}/ mkdir -p ${RPM_BUILD_ROOT}%/usr/bin cp -r scripts/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts install -D systemvm/dist/systemvm.iso ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.iso -install -D systemvm/dist/systemvm.zip ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.zip install python/lib/cloud_utils.py ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py cp -r python/lib/cloudutils ${RPM_BUILD_ROOT}%{python_sitearch}/ python -m py_compile ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py @@ -508,7 +507,6 @@ fi %attr(0755,root,root) %{_datadir}/%{name}-common/scripts %attr(0755,root,root) /usr/bin/cloudstack-sccs %attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.iso -%attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.zip %attr(0644,root,root) %{python_sitearch}/cloud_utils.py %attr(0644,root,root) %{python_sitearch}/cloud_utils.pyc %attr(0644,root,root) %{python_sitearch}/cloudutils/* diff --git a/packaging/fedora20/cloud.spec b/packaging/fedora20/cloud.spec index 084472b43e..0a80991154 100644 --- a/packaging/fedora20/cloud.spec +++ b/packaging/fedora20/cloud.spec @@ -234,7 +234,6 @@ mkdir -p ${RPM_BUILD_ROOT}%{python_sitearch}/ mkdir -p ${RPM_BUILD_ROOT}%/usr/bin cp -r scripts/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts install -D systemvm/dist/systemvm.iso ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.iso -install -D systemvm/dist/systemvm.zip ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.zip install python/lib/cloud_utils.py ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py cp -r python/lib/cloudutils ${RPM_BUILD_ROOT}%{python_sitearch}/ python -m py_compile ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py @@ -610,7 +609,6 @@ fi %attr(0755,root,root) %{_datadir}/%{name}-common/scripts %attr(0755,root,root) /usr/bin/cloudstack-sccs %attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.iso -%attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.zip %attr(0644,root,root) %{python_sitearch}/cloud_utils.py %attr(0644,root,root) %{python_sitearch}/cloud_utils.pyc %attr(0644,root,root) %{python_sitearch}/cloudutils/* diff --git a/packaging/fedora21/cloud.spec b/packaging/fedora21/cloud.spec index dbf761feaa..a749d13254 100644 --- a/packaging/fedora21/cloud.spec +++ b/packaging/fedora21/cloud.spec @@ -234,7 +234,6 @@ mkdir -p ${RPM_BUILD_ROOT}%{python_sitearch}/ mkdir -p ${RPM_BUILD_ROOT}%/usr/bin cp -r scripts/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts install -D systemvm/dist/systemvm.iso ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.iso -install -D systemvm/dist/systemvm.zip ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.zip install python/lib/cloud_utils.py ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py cp -r python/lib/cloudutils ${RPM_BUILD_ROOT}%{python_sitearch}/ python -m py_compile ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py @@ -610,7 +609,6 @@ fi %attr(0755,root,root) %{_datadir}/%{name}-common/scripts %attr(0755,root,root) /usr/bin/cloudstack-sccs %attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.iso -%attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.zip %attr(0644,root,root) %{python_sitearch}/cloud_utils.py %attr(0644,root,root) %{python_sitearch}/cloud_utils.pyc %attr(0644,root,root) %{python_sitearch}/cloudutils/* From 05e1db7373cd4a17d3101b13d95b1e47c3c0eace Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 19 May 2016 11:36:30 +0530 Subject: [PATCH 173/203] migrate-dynamicroles: use mysql.connector due to #1054 Due to PR #1054 this patch fixes the dynamic-roles migration script to use the mysql-connector-python dependency. Signed-off-by: Rohit Yadav --- scripts/util/migrate-dynamicroles.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/util/migrate-dynamicroles.py b/scripts/util/migrate-dynamicroles.py index e97e94cb25..d2356fb345 100755 --- a/scripts/util/migrate-dynamicroles.py +++ b/scripts/util/migrate-dynamicroles.py @@ -25,9 +25,9 @@ from optparse import OptionParser try: - import MySQLdb + import mysql.connector except ImportError: - print("MySQLdb cannot be imported, please install python-mysqldb(apt) or mysql-python(yum)") + print("mysql.connector cannot be imported, please install mysql-connector-python") sys.exit(1) dryrun = False @@ -82,7 +82,7 @@ def main(): if options.dryrun: dryrun = True - conn = MySQLdb.connect( + conn = mysql.connector.connect( host=options.host, user=options.user, passwd=options.password, From 9c7518698d2f4a9fcc6a83fd22dd5b2fc4260232 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Fri, 15 Apr 2016 00:24:53 +0530 Subject: [PATCH 174/203] CLOUDSTACK-9348: NioConnection improvements - Unit test to demonstrate denial of service attack The NioConnection uses blocking handlers for various events such as connect, accept, read, write. In case a client connects NioServer (used by agent mgr to service agents on port 8250) but fails to participate in SSL handshake or just sits idle, this would block the main IO/selector loop in NioConnection. Such a client could be either malicious or aggresive. This unit test demonstrates such a malicious client that can perform a denial-of-service attack on NioServer that blocks it to serve any other client. - Use non-blocking SSL handshake - Uses non-blocking socket config in NioClient and NioServer/NioConnection - Scalable connectivity from agents and peer clustered-management server - Removes blocking ssl handshake code with a non-blocking code - Protects from denial-of-service issues that can degrade mgmt server responsiveness due to an aggressive/malicious client - Uses separate executor services for handling ssl handshakes Signed-off-by: Rohit Yadav --- .../manager/ClusteredAgentManagerImpl.java | 9 +- .../main/java/com/cloud/utils/nio/Link.java | 297 +++++++++++------- .../java/com/cloud/utils/nio/NioClient.java | 31 +- .../com/cloud/utils/nio/NioConnection.java | 86 ++--- .../java/com/cloud/utils/nio/NioServer.java | 6 +- .../com/cloud/utils/testcase/NioTest.java | 249 +++++++++------ 6 files changed, 408 insertions(+), 270 deletions(-) diff --git a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java index 75f860ddfa..9239adc091 100644 --- a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java @@ -499,7 +499,7 @@ public SocketChannel connectToPeer(final String peerName, final SocketChannel pr SocketChannel ch1 = null; try { ch1 = SocketChannel.open(new InetSocketAddress(addr, Port.value())); - ch1.configureBlocking(true); // make sure we are working at blocking mode + ch1.configureBlocking(false); ch1.socket().setKeepAlive(true); ch1.socket().setSoTimeout(60 * 1000); try { @@ -507,8 +507,11 @@ public SocketChannel connectToPeer(final String peerName, final SocketChannel pr sslEngine = sslContext.createSSLEngine(ip, Port.value()); sslEngine.setUseClientMode(true); sslEngine.setEnabledProtocols(SSLUtils.getSupportedProtocols(sslEngine.getEnabledProtocols())); - - Link.doHandshake(ch1, sslEngine, true); + sslEngine.beginHandshake(); + if (!Link.doHandshake(ch1, sslEngine, true)) { + ch1.close(); + throw new IOException("SSL handshake failed!"); + } s_logger.info("SSL: Handshake done"); } catch (final Exception e) { ch1.close(); diff --git a/utils/src/main/java/com/cloud/utils/nio/Link.java b/utils/src/main/java/com/cloud/utils/nio/Link.java index 6d6306a53b..02ffaab4e0 100644 --- a/utils/src/main/java/com/cloud/utils/nio/Link.java +++ b/utils/src/main/java/com/cloud/utils/nio/Link.java @@ -19,37 +19,33 @@ package com.cloud.utils.nio; +import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.db.DbProperties; +import org.apache.cloudstack.utils.security.SSLUtils; +import org.apache.log4j.Logger; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; -import java.net.SocketTimeoutException; import java.nio.ByteBuffer; -import java.nio.channels.Channels; import java.nio.channels.ClosedChannelException; -import java.nio.channels.ReadableByteChannel; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.util.concurrent.ConcurrentLinkedQueue; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLEngineResult.HandshakeStatus; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; - -import org.apache.cloudstack.utils.security.SSLUtils; -import org.apache.log4j.Logger; - -import com.cloud.utils.PropertiesUtil; -import com.cloud.utils.db.DbProperties; - /** */ public class Link { @@ -453,115 +449,188 @@ public static SSLContext initSSLContext(boolean isClient) throws GeneralSecurity return sslContext; } - public static void doHandshake(SocketChannel ch, SSLEngine sslEngine, boolean isClient) throws IOException { - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: begin Handshake, isClient: " + isClient); + public static ByteBuffer enlargeBuffer(ByteBuffer buffer, final int sessionProposedCapacity) { + if (buffer == null || sessionProposedCapacity < 0) { + return buffer; } - - SSLEngineResult engResult; - SSLSession sslSession = sslEngine.getSession(); - HandshakeStatus hsStatus; - ByteBuffer in_pkgBuf = ByteBuffer.allocate(sslSession.getPacketBufferSize() + 40); - ByteBuffer in_appBuf = ByteBuffer.allocate(sslSession.getApplicationBufferSize() + 40); - ByteBuffer out_pkgBuf = ByteBuffer.allocate(sslSession.getPacketBufferSize() + 40); - ByteBuffer out_appBuf = ByteBuffer.allocate(sslSession.getApplicationBufferSize() + 40); - int count; - ch.socket().setSoTimeout(60 * 1000); - InputStream inStream = ch.socket().getInputStream(); - // Use readCh to make sure the timeout on reading is working - ReadableByteChannel readCh = Channels.newChannel(inStream); - - if (isClient) { - hsStatus = SSLEngineResult.HandshakeStatus.NEED_WRAP; + if (sessionProposedCapacity > buffer.capacity()) { + buffer = ByteBuffer.allocate(sessionProposedCapacity); } else { - hsStatus = SSLEngineResult.HandshakeStatus.NEED_UNWRAP; + buffer = ByteBuffer.allocate(buffer.capacity() * 2); } + return buffer; + } - while (hsStatus != SSLEngineResult.HandshakeStatus.FINISHED) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Handshake status " + hsStatus); + public static ByteBuffer handleBufferUnderflow(final SSLEngine engine, ByteBuffer buffer) { + if (engine == null || buffer == null) { + return buffer; + } + if (buffer.position() < buffer.limit()) { + return buffer; + } + ByteBuffer replaceBuffer = enlargeBuffer(buffer, engine.getSession().getPacketBufferSize()); + buffer.flip(); + replaceBuffer.put(buffer); + return replaceBuffer; + } + + private static boolean doHandshakeUnwrap(final SocketChannel socketChannel, final SSLEngine sslEngine, + ByteBuffer peerAppData, ByteBuffer peerNetData, final int appBufferSize) throws IOException { + if (socketChannel == null || sslEngine == null || peerAppData == null || peerNetData == null || appBufferSize < 0) { + return false; + } + if (socketChannel.read(peerNetData) < 0) { + if (sslEngine.isInboundDone() && sslEngine.isOutboundDone()) { + return false; } - engResult = null; - if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP) { - out_pkgBuf.clear(); - out_appBuf.clear(); - out_appBuf.put("Hello".getBytes()); - engResult = sslEngine.wrap(out_appBuf, out_pkgBuf); - out_pkgBuf.flip(); - int remain = out_pkgBuf.limit(); - while (remain != 0) { - remain -= ch.write(out_pkgBuf); - if (remain < 0) { - throw new IOException("Too much bytes sent?"); - } - } - } else if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) { - in_appBuf.clear(); - // One packet may contained multiply operation - if (in_pkgBuf.position() == 0 || !in_pkgBuf.hasRemaining()) { - in_pkgBuf.clear(); - count = 0; - try { - count = readCh.read(in_pkgBuf); - } catch (SocketTimeoutException ex) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("Handshake reading time out! Cut the connection"); - } - count = -1; - } - if (count == -1) { - throw new IOException("Connection closed with -1 on reading size."); - } - in_pkgBuf.flip(); + try { + sslEngine.closeInbound(); + } catch (SSLException e) { + s_logger.warn("This SSL engine was forced to close inbound due to end of stream."); + } + sslEngine.closeOutbound(); + // After closeOutbound the engine will be set to WRAP state, + // in order to try to send a close message to the client. + return true; + } + peerNetData.flip(); + SSLEngineResult result = null; + try { + result = sslEngine.unwrap(peerNetData, peerAppData); + peerNetData.compact(); + } catch (SSLException sslException) { + s_logger.error("SSL error occurred while processing unwrap data: " + sslException.getMessage()); + sslEngine.closeOutbound(); + return true; + } + switch (result.getStatus()) { + case OK: + break; + case BUFFER_OVERFLOW: + // Will occur when peerAppData's capacity is smaller than the data derived from peerNetData's unwrap. + peerAppData = enlargeBuffer(peerAppData, appBufferSize); + break; + case BUFFER_UNDERFLOW: + // Will occur either when no data was read from the peer or when the peerNetData buffer + // was too small to hold all peer's data. + peerNetData = handleBufferUnderflow(sslEngine, peerNetData); + break; + case CLOSED: + if (sslEngine.isOutboundDone()) { + return false; + } else { + sslEngine.closeOutbound(); + break; } - engResult = sslEngine.unwrap(in_pkgBuf, in_appBuf); - ByteBuffer tmp_pkgBuf = ByteBuffer.allocate(sslSession.getPacketBufferSize() + 40); - int loop_count = 0; - while (engResult.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) { - // The client is too slow? Cut it and let it reconnect - if (loop_count > 10) { - throw new IOException("Too many times in SSL BUFFER_UNDERFLOW, disconnect guest."); - } - // We need more packets to complete this operation - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Buffer underflowed, getting more packets"); - } - tmp_pkgBuf.clear(); - count = ch.read(tmp_pkgBuf); - if (count == -1) { - throw new IOException("Connection closed with -1 on reading size."); - } - tmp_pkgBuf.flip(); - - in_pkgBuf.mark(); - in_pkgBuf.position(in_pkgBuf.limit()); - in_pkgBuf.limit(in_pkgBuf.limit() + tmp_pkgBuf.limit()); - in_pkgBuf.put(tmp_pkgBuf); - in_pkgBuf.reset(); + default: + throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + } + return true; + } - in_appBuf.clear(); - engResult = sslEngine.unwrap(in_pkgBuf, in_appBuf); - loop_count++; + private static boolean doHandshakeWrap(final SocketChannel socketChannel, final SSLEngine sslEngine, + ByteBuffer myAppData, ByteBuffer myNetData, ByteBuffer peerNetData, + final int netBufferSize) throws IOException { + if (socketChannel == null || sslEngine == null || myNetData == null || peerNetData == null + || myAppData == null || netBufferSize < 0) { + return false; + } + myNetData.clear(); + SSLEngineResult result = null; + try { + result = sslEngine.wrap(myAppData, myNetData); + } catch (SSLException sslException) { + s_logger.error("SSL error occurred while processing wrap data: " + sslException.getMessage()); + sslEngine.closeOutbound(); + return true; + } + switch (result.getStatus()) { + case OK : + myNetData.flip(); + while (myNetData.hasRemaining()) { + socketChannel.write(myNetData); } - } else if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK) { - Runnable run; - while ((run = sslEngine.getDelegatedTask()) != null) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Running delegated task!"); + break; + case BUFFER_OVERFLOW: + // Will occur if there is not enough space in myNetData buffer to write all the data + // that would be generated by the method wrap. Since myNetData is set to session's packet + // size we should not get to this point because SSLEngine is supposed to produce messages + // smaller or equal to that, but a general handling would be the following: + myNetData = enlargeBuffer(myNetData, netBufferSize); + break; + case BUFFER_UNDERFLOW: + throw new SSLException("Buffer underflow occurred after a wrap. We should not reach here."); + case CLOSED: + try { + myNetData.flip(); + while (myNetData.hasRemaining()) { + socketChannel.write(myNetData); } - run.run(); + // At this point the handshake status will probably be NEED_UNWRAP + // so we make sure that peerNetData is clear to read. + peerNetData.clear(); + } catch (Exception e) { + s_logger.error("Failed to send server's CLOSE message due to socket channel's failure."); } - } else if (hsStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { - throw new IOException("NOT a handshaking!"); + break; + default: + throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + } + return true; + } + + public static boolean doHandshake(final SocketChannel socketChannel, final SSLEngine sslEngine, final boolean isClient) throws IOException { + if (socketChannel == null || sslEngine == null) { + return false; + } + final int appBufferSize = sslEngine.getSession().getApplicationBufferSize(); + final int netBufferSize = sslEngine.getSession().getPacketBufferSize(); + ByteBuffer myAppData = ByteBuffer.allocate(appBufferSize); + ByteBuffer peerAppData = ByteBuffer.allocate(appBufferSize); + ByteBuffer myNetData = ByteBuffer.allocate(netBufferSize); + ByteBuffer peerNetData = ByteBuffer.allocate(netBufferSize); + + final long startTimeMills = System.currentTimeMillis(); + + HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); + while (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED + && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { + final long timeTaken = System.currentTimeMillis() - startTimeMills; + if (timeTaken > 15000L) { + s_logger.warn("SSL Handshake has taken more than 15s to connect to: " + socketChannel.getRemoteAddress() + + ". Please investigate this connection."); + return false; } - if (engResult != null && engResult.getStatus() != SSLEngineResult.Status.OK) { - throw new IOException("Fail to handshake! " + engResult.getStatus()); + switch (handshakeStatus) { + case NEED_UNWRAP: + if (!doHandshakeUnwrap(socketChannel, sslEngine, peerAppData, peerNetData, appBufferSize)) { + return false; + } + break; + case NEED_WRAP: + if (!doHandshakeWrap(socketChannel, sslEngine, myAppData, myNetData, peerNetData, netBufferSize)) { + return false; + } + break; + case NEED_TASK: + Runnable task; + while ((task = sslEngine.getDelegatedTask()) != null) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("SSL: Running delegated task!"); + } + task.run(); + } + break; + case FINISHED: + break; + case NOT_HANDSHAKING: + break; + default: + throw new IllegalStateException("Invalid SSL status: " + handshakeStatus); } - if (engResult != null) - hsStatus = engResult.getHandshakeStatus(); - else - hsStatus = sslEngine.getHandshakeStatus(); + handshakeStatus = sslEngine.getHandshakeStatus(); } + return true; } } diff --git a/utils/src/main/java/com/cloud/utils/nio/NioClient.java b/utils/src/main/java/com/cloud/utils/nio/NioClient.java index d989f306c5..dc4f670de1 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioClient.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioClient.java @@ -36,7 +36,6 @@ public class NioClient extends NioConnection { private static final Logger s_logger = Logger.getLogger(NioClient.class); protected String _host; - protected String _bindAddress; protected SocketChannel _clientConnection; public NioClient(final String name, final String host, final int port, final int workers, final HandlerFactory factory) { @@ -44,10 +43,6 @@ public NioClient(final String name, final String host, final int port, final int _host = host; } - public void setBindAddress(final String ipAddress) { - _bindAddress = ipAddress; - } - @Override protected void init() throws IOException { _selector = Selector.open(); @@ -55,33 +50,25 @@ protected void init() throws IOException { try { _clientConnection = SocketChannel.open(); - _clientConnection.configureBlocking(true); - s_logger.info("Connecting to " + _host + ":" + _port); - - if (_bindAddress != null) { - s_logger.info("Binding outbound interface at " + _bindAddress); - - final InetSocketAddress bindAddr = new InetSocketAddress(_bindAddress, 0); - _clientConnection.socket().bind(bindAddr); - } + s_logger.info("Connecting to " + _host + ":" + _port); final InetSocketAddress peerAddr = new InetSocketAddress(_host, _port); _clientConnection.connect(peerAddr); - - SSLEngine sslEngine = null; - // Begin SSL handshake in BLOCKING mode - _clientConnection.configureBlocking(true); + _clientConnection.configureBlocking(false); final SSLContext sslContext = Link.initSSLContext(true); - sslEngine = sslContext.createSSLEngine(_host, _port); + SSLEngine sslEngine = sslContext.createSSLEngine(_host, _port); sslEngine.setUseClientMode(true); sslEngine.setEnabledProtocols(SSLUtils.getSupportedProtocols(sslEngine.getEnabledProtocols())); - - Link.doHandshake(_clientConnection, sslEngine, true); + sslEngine.beginHandshake(); + if (!Link.doHandshake(_clientConnection, sslEngine, true)) { + s_logger.error("SSL Handshake failed while connecting to host: " + _host + " port: " + _port); + _selector.close(); + throw new IOException("SSL Handshake failed while connecting to host: " + _host + " port: " + _port); + } s_logger.info("SSL: Handshake done"); s_logger.info("Connected to " + _host + ":" + _port); - _clientConnection.configureBlocking(false); final Link link = new Link(peerAddr, this); link.setSSLEngine(sslEngine); final SelectionKey key = _clientConnection.register(_selector, SelectionKey.OP_READ); diff --git a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java index 249f512d9c..9d755d6bce 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java @@ -19,8 +19,13 @@ package com.cloud.utils.nio; -import static com.cloud.utils.AutoCloseableUtil.closeAutoCloseable; +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.exception.NioConnectionException; +import org.apache.cloudstack.utils.security.SSLUtils; +import org.apache.log4j.Logger; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; import java.io.IOException; import java.net.ConnectException; import java.net.InetSocketAddress; @@ -44,14 +49,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; - -import org.apache.cloudstack.utils.security.SSLUtils; -import org.apache.log4j.Logger; - -import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.exception.NioConnectionException; +import static com.cloud.utils.AutoCloseableUtil.closeAutoCloseable; /** * NioConnection abstracts the NIO socket operations. The Java implementation @@ -71,6 +69,7 @@ public abstract class NioConnection implements Callable { protected HandlerFactory _factory; protected String _name; protected ExecutorService _executor; + protected ExecutorService _sslHandshakeExecutor; public NioConnection(final String name, final int port, final int workers, final HandlerFactory factory) { _name = name; @@ -79,6 +78,7 @@ public NioConnection(final String name, final int port, final int workers, final _port = port; _factory = factory; _executor = new ThreadPoolExecutor(workers, 5 * workers, 1, TimeUnit.DAYS, new LinkedBlockingQueue(), new NamedThreadFactory(name + "-Handler")); + _sslHandshakeExecutor = Executors.newCachedThreadPool(new NamedThreadFactory(name + "-SSLHandshakeHandler")); } public void start() throws NioConnectionException { @@ -125,7 +125,7 @@ public boolean isStartup() { public Boolean call() throws NioConnectionException { while (_isRunning) { try { - _selector.select(); + _selector.select(1000); // Someone is ready for I/O, get the ready keys final Set readyKeys = _selector.selectedKeys(); @@ -185,8 +185,9 @@ public Boolean call() throws NioConnectionException { protected void accept(final SelectionKey key) throws IOException { final ServerSocketChannel serverSocketChannel = (ServerSocketChannel)key.channel(); - final SocketChannel socketChannel = serverSocketChannel.accept(); + socketChannel.configureBlocking(false); + final Socket socket = socketChannel.socket(); socket.setKeepAlive(true); @@ -194,43 +195,52 @@ protected void accept(final SelectionKey key) throws IOException { s_logger.trace("Connection accepted for " + socket); } - // Begin SSL handshake in BLOCKING mode - socketChannel.configureBlocking(true); - - SSLEngine sslEngine = null; + final SSLEngine sslEngine; try { final SSLContext sslContext = Link.initSSLContext(false); sslEngine = sslContext.createSSLEngine(); sslEngine.setUseClientMode(false); sslEngine.setNeedClientAuth(false); sslEngine.setEnabledProtocols(SSLUtils.getSupportedProtocols(sslEngine.getEnabledProtocols())); - - Link.doHandshake(socketChannel, sslEngine, false); - + final NioConnection nioConnection = this; + _sslHandshakeExecutor.submit(new Runnable() { + @Override + public void run() { + _selector.wakeup(); + try { + sslEngine.beginHandshake(); + if (!Link.doHandshake(socketChannel, sslEngine, false)) { + throw new IOException("SSL handshake timed out with " + socketChannel.getRemoteAddress()); + } + if (s_logger.isTraceEnabled()) { + s_logger.trace("SSL: Handshake done"); + } + final InetSocketAddress saddr = (InetSocketAddress)socket.getRemoteSocketAddress(); + final Link link = new Link(saddr, nioConnection); + link.setSSLEngine(sslEngine); + link.setKey(socketChannel.register(key.selector(), SelectionKey.OP_READ, link)); + final Task task = _factory.create(Task.Type.CONNECT, link, null); + registerLink(saddr, link); + _executor.submit(task); + } catch (IOException e) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Connection closed due to failure: " + e.getMessage()); + } + closeAutoCloseable(socket, "accepting socket"); + closeAutoCloseable(socketChannel, "accepting socketChannel"); + } finally { + _selector.wakeup(); + } + } + }); } catch (final Exception e) { if (s_logger.isTraceEnabled()) { - s_logger.trace("Socket " + socket + " closed on read. Probably -1 returned: " + e.getMessage()); + s_logger.trace("Connection closed due to failure: " + e.getMessage()); } + closeAutoCloseable(socket, "accepting socket"); closeAutoCloseable(socketChannel, "accepting socketChannel"); - closeAutoCloseable(socket, "opened socket"); - return; - } - - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Handshake done"); - } - socketChannel.configureBlocking(false); - final InetSocketAddress saddr = (InetSocketAddress)socket.getRemoteSocketAddress(); - final Link link = new Link(saddr, this); - link.setSSLEngine(sslEngine); - link.setKey(socketChannel.register(key.selector(), SelectionKey.OP_READ, link)); - final Task task = _factory.create(Task.Type.CONNECT, link, null); - registerLink(saddr, link); - - try { - _executor.submit(task); - } catch (final Exception e) { - s_logger.warn("Exception occurred when submitting the task", e); + } finally { + _selector.wakeup(); } } diff --git a/utils/src/main/java/com/cloud/utils/nio/NioServer.java b/utils/src/main/java/com/cloud/utils/nio/NioServer.java index 539c2bb13d..b655f1838b 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioServer.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioServer.java @@ -43,6 +43,10 @@ public NioServer(final String name, final int port, final int workers, final Han _links = new WeakHashMap(1024); } + public int getPort() { + return _serverSocket.socket().getLocalPort(); + } + @Override protected void init() throws IOException { _selector = SelectorProvider.provider().openSelector(); @@ -55,7 +59,7 @@ protected void init() throws IOException { _serverSocket.register(_selector, SelectionKey.OP_ACCEPT, null); - s_logger.info("NioConnection started and listening on " + _localAddr.toString()); + s_logger.info("NioConnection started and listening on " + _serverSocket.socket().getLocalSocketAddress()); } @Override diff --git a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java index d8510cfcac..894aa1adc8 100644 --- a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java +++ b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java @@ -19,14 +19,7 @@ package com.cloud.utils.testcase; -import java.nio.channels.ClosedChannelException; -import java.util.Random; - -import junit.framework.TestCase; - -import org.apache.log4j.Logger; -import org.junit.Assert; - +import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.exception.NioConnectionException; import com.cloud.utils.nio.HandlerFactory; import com.cloud.utils.nio.Link; @@ -34,131 +27,199 @@ import com.cloud.utils.nio.NioServer; import com.cloud.utils.nio.Task; import com.cloud.utils.nio.Task.Type; +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** - * - * - * - * + * NioTest demonstrates that NioServer can function without getting its main IO + * loop blocked when an aggressive or malicious client connects to the server but + * fail to participate in SSL handshake. In this test, we run bunch of clients + * that send a known payload to the server, to which multiple malicious clients + * also try to connect and hang. + * A malicious client could cause denial-of-service if the server's main IO loop + * along with SSL handshake was blocking. A passing tests shows that NioServer + * can still function in case of connection load and that the main IO loop along + * with SSL handshake is non-blocking with some internal timeout mechanism. */ -public class NioTest extends TestCase { +public class NioTest { + + private static final Logger LOGGER = Logger.getLogger(NioTest.class); - private static final Logger s_logger = Logger.getLogger(NioTest.class); + // Test should fail in due time instead of looping forever + private static final int TESTTIMEOUT = 60000; - private NioServer _server; - private NioClient _client; + final private int totalTestCount = 2; + private int completedTestCount = 0; - private Link _clientLink; + private NioServer server; + private List clients = new ArrayList<>(); + private List maliciousClients = new ArrayList<>(); - private int _testCount; - private int _completedCount; + private ExecutorService clientExecutor = Executors.newFixedThreadPool(totalTestCount, new NamedThreadFactory("NioClientHandler"));; + private ExecutorService maliciousExecutor = Executors.newFixedThreadPool(totalTestCount, new NamedThreadFactory("MaliciousNioClientHandler"));; + + private Random randomGenerator = new Random(); + private byte[] testBytes; private boolean isTestsDone() { boolean result; synchronized (this) { - result = _testCount == _completedCount; + result = totalTestCount == completedTestCount; } return result; } - private void getOneMoreTest() { - synchronized (this) { - _testCount++; - } - } - private void oneMoreTestDone() { synchronized (this) { - _completedCount++; + completedTestCount++; } } - @Override + @Before public void setUp() { - s_logger.info("Test"); + LOGGER.info("Setting up Benchmark Test"); - _testCount = 0; - _completedCount = 0; + completedTestCount = 0; + testBytes = new byte[1000000]; + randomGenerator.nextBytes(testBytes); - _server = new NioServer("NioTestServer", 7777, 5, new NioTestServer()); + server = new NioServer("NioTestServer", 0, 1, new NioTestServer()); try { - _server.start(); + server.start(); } catch (final NioConnectionException e) { - fail(e.getMessage()); + Assert.fail(e.getMessage()); } - _client = new NioClient("NioTestServer", "127.0.0.1", 7777, 5, new NioTestClient()); - try { - _client.start(); - } catch (final NioConnectionException e) { - fail(e.getMessage()); - } + for (int i = 0; i < totalTestCount; i++) { + final NioClient maliciousClient = new NioMaliciousClient("NioMaliciousTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioMaliciousTestClient()); + maliciousClients.add(maliciousClient); + maliciousExecutor.submit(new ThreadedNioClient(maliciousClient)); - while (_clientLink == null) { - try { - s_logger.debug("Link is not up! Waiting ..."); - Thread.sleep(1000); - } catch (final InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + final NioClient client = new NioClient("NioTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioTestClient()); + clients.add(client); + clientExecutor.submit(new ThreadedNioClient(client)); } } - @Override + @After public void tearDown() { + stopClient(); + stopServer(); + } + + protected void stopClient() { + for (NioClient client : clients) { + client.stop(); + } + for (NioClient maliciousClient : maliciousClients) { + maliciousClient.stop(); + } + LOGGER.info("Clients stopped."); + } + + protected void stopServer() { + server.stop(); + LOGGER.info("Server stopped."); + } + + @Test(timeout=TESTTIMEOUT) + public void testConnection() { while (!isTestsDone()) { try { - s_logger.debug(_completedCount + "/" + _testCount + " tests done. Waiting for completion"); + LOGGER.debug(completedTestCount + "/" + totalTestCount + " tests done. Waiting for completion"); Thread.sleep(1000); } catch (final InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Assert.fail(e.getMessage()); } } - stopClient(); - stopServer(); + LOGGER.debug(completedTestCount + "/" + totalTestCount + " tests done."); } - protected void stopClient() { - _client.stop(); - s_logger.info("Client stopped."); + protected void doServerProcess(final byte[] data) { + oneMoreTestDone(); + Assert.assertArrayEquals(testBytes, data); + LOGGER.info("Verify data received by server done."); } - protected void stopServer() { - _server.stop(); - s_logger.info("Server stopped."); + public byte[] getTestBytes() { + return testBytes; } - protected void setClientLink(final Link link) { - _clientLink = link; + public class ThreadedNioClient implements Runnable { + final private NioClient client; + ThreadedNioClient(final NioClient client) { + this.client = client; + } + + @Override + public void run() { + try { + client.start(); + } catch (NioConnectionException e) { + Assert.fail(e.getMessage()); + } + } } - Random randomGenerator = new Random(); + public class NioMaliciousClient extends NioClient { - byte[] _testBytes; + public NioMaliciousClient(String name, String host, int port, int workers, HandlerFactory factory) { + super(name, host, port, workers, factory); + } - public void testConnection() { - _testBytes = new byte[1000000]; - randomGenerator.nextBytes(_testBytes); - try { - getOneMoreTest(); - _clientLink.send(_testBytes); - s_logger.info("Client: Data sent"); - getOneMoreTest(); - _clientLink.send(_testBytes); - s_logger.info("Client: Data sent"); - } catch (final ClosedChannelException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + @Override + protected void init() throws IOException { + _selector = Selector.open(); + try { + _clientConnection = SocketChannel.open(); + LOGGER.info("Connecting to " + _host + ":" + _port); + final InetSocketAddress peerAddr = new InetSocketAddress(_host, _port); + _clientConnection.connect(peerAddr); + // This is done on purpose, the malicious client would connect + // to the server and then do nothing, hence using a large sleep value + Thread.sleep(Long.MAX_VALUE); + } catch (final IOException e) { + _selector.close(); + throw e; + } catch (InterruptedException e) { + LOGGER.debug(e.getMessage()); + } } } - protected void doServerProcess(final byte[] data) { - oneMoreTestDone(); - Assert.assertArrayEquals(_testBytes, data); - s_logger.info("Verify done."); + public class NioMaliciousTestClient implements HandlerFactory { + + @Override + public Task create(final Type type, final Link link, final byte[] data) { + return new NioMaliciousTestClientHandler(type, link, data); + } + + public class NioMaliciousTestClientHandler extends Task { + + public NioMaliciousTestClientHandler(final Type type, final Link link, final byte[] data) { + super(type, link, data); + } + + @Override + public void doTask(final Task task) { + LOGGER.info("Malicious Client: Received task " + task.getType().toString()); + } + } } public class NioTestClient implements HandlerFactory { @@ -177,18 +238,23 @@ public NioTestClientHandler(final Type type, final Link link, final byte[] data) @Override public void doTask(final Task task) { if (task.getType() == Task.Type.CONNECT) { - s_logger.info("Client: Received CONNECT task"); - setClientLink(task.getLink()); + LOGGER.info("Client: Received CONNECT task"); + try { + LOGGER.info("Sending data to server"); + task.getLink().send(getTestBytes()); + } catch (ClosedChannelException e) { + LOGGER.error(e.getMessage()); + e.printStackTrace(); + } } else if (task.getType() == Task.Type.DATA) { - s_logger.info("Client: Received DATA task"); + LOGGER.info("Client: Received DATA task"); } else if (task.getType() == Task.Type.DISCONNECT) { - s_logger.info("Client: Received DISCONNECT task"); + LOGGER.info("Client: Received DISCONNECT task"); stopClient(); } else if (task.getType() == Task.Type.OTHER) { - s_logger.info("Client: Received OTHER task"); + LOGGER.info("Client: Received OTHER task"); } } - } } @@ -208,18 +274,17 @@ public NioTestServerHandler(final Type type, final Link link, final byte[] data) @Override public void doTask(final Task task) { if (task.getType() == Task.Type.CONNECT) { - s_logger.info("Server: Received CONNECT task"); + LOGGER.info("Server: Received CONNECT task"); } else if (task.getType() == Task.Type.DATA) { - s_logger.info("Server: Received DATA task"); + LOGGER.info("Server: Received DATA task"); doServerProcess(task.getData()); } else if (task.getType() == Task.Type.DISCONNECT) { - s_logger.info("Server: Received DISCONNECT task"); + LOGGER.info("Server: Received DISCONNECT task"); stopServer(); } else if (task.getType() == Task.Type.OTHER) { - s_logger.info("Server: Received OTHER task"); + LOGGER.info("Server: Received OTHER task"); } } - } } } From 18a6aa89bead3c0b321b759570f3de804d6e8105 Mon Sep 17 00:00:00 2001 From: Sudhansu Date: Fri, 22 Apr 2016 15:36:51 +0530 Subject: [PATCH 175/203] CLOUDSTACK-9366: Capacity of one zone-wide primary storage ignored introduced new capacityType parameter in updateCapacityState method and necessary changes to add capacity_type clause in sql also fixed incorrect sql builder logic (unused code path for which it is never surfaced ) Added marvin test to check host and storagepool capacity when host is disabled Added conditions to ensure the capacity_type is added only when capacity_type length is greater than 0. Added checks in marvin test to ensure the capacity exists for a host before disabling it. Added checks to avoid index out of range exception --- .../com/cloud/capacity/dao/CapacityDao.java | 3 +- .../cloud/capacity/dao/CapacityDaoImpl.java | 40 +++- .../cloud/resource/ResourceManagerImpl.java | 3 +- .../maint/test_capacity_host_delete.py | 210 ++++++++++++++++++ 4 files changed, 245 insertions(+), 11 deletions(-) create mode 100644 test/integration/component/maint/test_capacity_host_delete.py diff --git a/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java b/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java index 50d6052bc4..fcccd56dd6 100644 --- a/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java +++ b/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java @@ -50,8 +50,7 @@ List findCapacityBy(Integer capacityType, Long zoneId, List listCapacitiesGroupedByLevelAndType(Integer capacityType, Long zoneId, Long podId, Long clusterId, int level, Long limit); - void updateCapacityState(Long dcId, Long podId, Long clusterId, - Long hostId, String capacityState); + void updateCapacityState(Long dcId, Long podId, Long clusterId, Long hostId, String capacityState, short[] capacityType); List listClustersCrossingThreshold(short capacityType, Long zoneId, String configName, long computeRequested); diff --git a/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java b/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java index bc992b0bb5..1b1b856af7 100644 --- a/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -962,35 +962,59 @@ public Pair, Map> orderPodsByAggregateCapacity(long zon } @Override - public void updateCapacityState(Long dcId, Long podId, Long clusterId, Long hostId, String capacityState) { + public void updateCapacityState(Long dcId, Long podId, Long clusterId, Long hostId, String capacityState, short[] capacityType) { TransactionLegacy txn = TransactionLegacy.currentTxn(); StringBuilder sql = new StringBuilder(UPDATE_CAPACITY_STATE); List resourceIdList = new ArrayList(); + StringBuilder where = new StringBuilder(); if (dcId != null) { - sql.append(" data_center_id = ?"); + where.append(" data_center_id = ? "); resourceIdList.add(dcId); } if (podId != null) { - sql.append(" pod_id = ?"); + where.append((where.length() > 0) ? " and pod_id = ? " : " pod_id = ? "); resourceIdList.add(podId); } if (clusterId != null) { - sql.append(" cluster_id = ?"); + where.append((where.length() > 0) ? " and cluster_id = ? " : " cluster_id = ? "); resourceIdList.add(clusterId); } if (hostId != null) { - sql.append(" host_id = ?"); + where.append((where.length() > 0) ? " and host_id = ? " : " host_id = ? "); resourceIdList.add(hostId); } + if (capacityType != null && capacityType.length > 0) { + where.append((where.length() > 0) ? " and capacity_type in " : " capacity_type in "); + + StringBuilder builder = new StringBuilder(); + for( int i = 0 ; i < capacityType.length; i++ ) { + if(i==0){ + builder.append(" (? "); + }else{ + builder.append(" ,? "); + } + } + builder.append(" ) "); + + where.append(builder); + } + sql.append(where); + PreparedStatement pstmt = null; try { pstmt = txn.prepareAutoCloseStatement(sql.toString()); - pstmt.setString(1, capacityState); - for (int i = 0; i < resourceIdList.size(); i++) { - pstmt.setLong(2 + i, resourceIdList.get(i)); + int i = 1; + pstmt.setString(i, capacityState); + i = i + 1; + for (int j=0 ; j < resourceIdList.size(); j++, i++) { + pstmt.setLong(i, resourceIdList.get(j)); } + for(int j=0; j < capacityType.length; i++, j++ ) { + pstmt.setShort(i, capacityType[j]); + } + pstmt.executeUpdate(); } catch (Exception e) { s_logger.warn("Error updating CapacityVO", e); diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index cca4add2dc..d6333b96fe 100644 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -1177,7 +1177,8 @@ public boolean resourceStateTransitTo(final Host host, final ResourceState.Event // TO DO - Make it more granular and have better conversion into capacity type if(host.getType() == Type.Routing){ final CapacityState capacityState = nextState == ResourceState.Enabled ? CapacityState.Enabled : CapacityState.Disabled; - _capacityDao.updateCapacityState(null, null, null, host.getId(), capacityState.toString()); + final short[] capacityTypes = {Capacity.CAPACITY_TYPE_CPU, Capacity.CAPACITY_TYPE_MEMORY}; + _capacityDao.updateCapacityState(null, null, null, host.getId(), capacityState.toString(), capacityTypes); } return _hostDao.updateResourceState(currentState, event, nextState, host); } diff --git a/test/integration/component/maint/test_capacity_host_delete.py b/test/integration/component/maint/test_capacity_host_delete.py new file mode 100644 index 0000000000..aba5152e35 --- /dev/null +++ b/test/integration/component/maint/test_capacity_host_delete.py @@ -0,0 +1,210 @@ +# 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 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. + +# Test from the Marvin - Testing in Python wiki + +# All tests inherit from cloudstackTestCase +from marvin.cloudstackTestCase import cloudstackTestCase, unittest + +# Import Integration Libraries + +# base - contains all resources as entities and defines create, delete, +# list operations on them +from marvin.lib.base import Host, Cluster, Zone, Pod + +# utils - utility classes for common cleanup, external library wrappers etc +from marvin.lib.utils import cleanup_resources + +# common - commonly used methods for all tests are listed here +from marvin.lib.common import get_zone, get_domain, list_hosts, get_pod + +from nose.plugins.attrib import attr + +import time +import logging +# These tests need to be run separately and not in parallel with other tests. +# Because it disables the host +# host_id column of op_host_capacity refers to host_id or a storage pool id +# +# This test is to make sure that Disable host only disables the capacities of type +# CPU and MEMORY +# +# TEST: +# Base Condition: There exists a host and storage pool with same id +# +# Steps: +# 1. Find a host and storage pool having same id +# 2. Disable the host +# 3. verify that the CPU(1) and MEMORY(0) capacity in op_host_capacity for above host +# is disabled +# 4. verify that the STORAGE(3) capacity in op_host_capacity for storage pool with id +# same as above host is not disabled +# + +def update_host(apiclient, state, host_id): + """ + Function to Enable/Disable Host + """ + host_status = Host.update( + apiclient, + id=host_id, + allocationstate=state + ) + return host_status.resourcestate + + +def check_db(self, host_state): + """ + Function to check capacity_state in op_host_capacity table + """ + capacity_state = None + if self.host_db_id and self.host_db_id[0]: + capacity_state = self.dbclient.execute( + "select capacity_state from op_host_capacity where host_id='%s' and capacity_type in (0,1) order by capacity_type asc;" % + self.host_db_id[0][0]) + + if capacity_state and len(capacity_state)==2: + if capacity_state[0]: + self.assertEqual( + capacity_state[0][0], + host_state + + "d", + "Invalid db query response for capacity_state %s" % + capacity_state[0][0]) + + if capacity_state[1]: + self.assertEqual( + capacity_state[1][0], + host_state + + "d", + "Invalid db query response for capacity_state %s" % + capacity_state[1][0]) + else: + self.logger.debug("Could not find capacities of type 1 and 0. Does not have necessary data to run this test") + + capacity_state = None + if self.host_db_id and self.host_db_id[0]: + capacity_state = self.dbclient.execute( + "select capacity_state from op_host_capacity where host_id='%s' and capacity_type = 3 order by capacity_type asc;" % + self.host_db_id[0][0]) + + if capacity_state and capacity_state[0]: + self.assertNotEqual( + capacity_state[0][0], + host_state + + "d", + "Invalid db query response for capacity_state %s" % + capacity_state[0][0]) + else: + self.logger.debug("Could not find capacities of type 3. Does not have necessary data to run this test") + + +class TestHosts(cloudstackTestCase): + + """ + Testing Hosts + """ + @classmethod + def setUpClass(cls): + cls.testClient = super(TestHosts, cls).getClsTestClient() + cls.testdata = cls.testClient.getParsedTestDataConfig() + cls.apiclient = cls.testClient.getApiClient() + cls.dbclient = cls.testClient.getDbConnection() + cls._cleanup = [] + + # get zone, domain etc + cls.zone = Zone(get_zone(cls.apiclient, cls.testClient.getZoneForTests()).__dict__) + cls.domain = get_domain(cls.apiclient) + cls.pod = get_pod(cls.apiclient, cls.zone.id) + + cls.logger = logging.getLogger('TestHosts') + cls.stream_handler = logging.StreamHandler() + cls.logger.setLevel(logging.DEBUG) + cls.logger.addHandler(cls.stream_handler) + + cls.storage_pool_db_id = None + # list hosts + hosts = list_hosts(cls.apiclient, type="Routing") + i = 0 + while (i < len(hosts)): + host_id = hosts[i].id + cls.logger.debug("Trying host id : %s" % host_id) + host_db_id = cls.dbclient.execute( + "select id from host where uuid='%s';" % + host_id) + + if host_db_id and host_db_id[0]: + cls.logger.debug("found host db id : %s" % host_db_id) + storage_pool_db_id = cls.dbclient.execute( + "select id from storage_pool where id='%s' and removed is null;" % + host_db_id[0][0]) + + if storage_pool_db_id and storage_pool_db_id[0]: + cls.logger.debug("Found storage_pool_db_id : %s" % storage_pool_db_id[0][0]) + capacity_state = cls.dbclient.execute( + "select count(capacity_state) from op_host_capacity where host_id='%s' and capacity_type in (0,1,3) and capacity_state = 'Enabled'" % + host_db_id[0][0]) + + if capacity_state and capacity_state[0]: + cls.logger.debug("Check capacity count : %s" % capacity_state[0][0]) + + if capacity_state[0][0] == 3: + cls.logger.debug("found host id : %s, can be used for this test" % host_id) + cls.my_host_id = host_id + cls.host_db_id = host_db_id + cls.storage_pool_db_id = storage_pool_db_id + break + if not cls.storage_pool_db_id: + i = i + 1 + + + if cls.storage_pool_db_id is None: + raise unittest.SkipTest("There is no host and storage pool available in the setup to run this test") + + + + @classmethod + def tearDownClass(cls): + cleanup_resources(cls.apiclient, cls._cleanup) + return + + def setUp(self): + self.logger.debug("Capacity check for Disable host") + self.cleanup = [] + return + + def tearDown(self): + # Clean up + cleanup_resources(self.apiclient, self.cleanup) + return + + @attr(tags=["advanced", "basic"], required_hardware="false") + def test_01_op_host_capacity_disable_host(self): + + host_state = "Disable" + host_resourcestate = update_host( + self.apiclient, + host_state, + self.my_host_id) + self.assertEqual( + host_resourcestate, + host_state + "d", + "Host state not correct" + ) + check_db(self, host_state) + + return From 2d2819974eb44928599053445bc5b2876c9102e5 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Fri, 22 Apr 2016 12:47:05 -0700 Subject: [PATCH 176/203] CLOUDSTACK-9368: Fix for Support configurable NFS version for Secondary Storage mounts --- api/src/com/cloud/agent/api/to/NfsTO.java | 9 ++ .../agent/api/BackupSnapshotCommand.java | 8 -- ...atePrivateTemplateFromSnapshotCommand.java | 8 -- ...reatePrivateTemplateFromVolumeCommand.java | 8 -- .../api/CreateVolumeFromSnapshotCommand.java | 9 -- .../agent/api/GetStorageStatsCommand.java | 16 +--- .../agent/api/SecStorageSetupCommand.java | 11 +-- .../com/cloud/agent/api/SnapshotCommand.java | 3 +- .../agent/api/storage/CopyVolumeCommand.java | 11 +-- .../api/storage/ListTemplateCommand.java | 16 +--- .../PrimaryStorageDownloadCommand.java | 8 -- .../cloud/agent/api/storage/SsCommand.java | 4 +- .../agent/api/storage/StorageCommand.java | 8 +- .../api/storage/StorageNfsVersionCommand.java | 44 +++++++++ .../TemplateOrVolumePostUploadCommand.java | 6 +- .../storage/image/TemplateServiceImpl.java | 3 +- .../MockLocalNfsSecondaryStorageResource.java | 2 +- .../image/BaseImageStoreDriverImpl.java | 1 + .../image/NfsImageStoreDriverImpl.java | 48 ++++++++++ .../cloud/resource/AgentStorageResource.java | 2 +- .../driver/SimulatorImageStoreDriverImpl.java | 5 +- .../vmware/manager/VmwareManagerImpl.java | 7 +- .../manager/VmwareStorageManagerImpl.java | 24 ++--- .../vmware/manager/VmwareStorageMount.java | 2 +- .../vmware/resource/VmwareResource.java | 68 ++++++++++++- .../PremiumSecondaryStorageResource.java | 3 +- ...VmwareSecondaryStorageResourceHandler.java | 4 +- .../resource/VmwareStorageProcessor.java | 25 +++-- .../VmwareStorageSubsystemCommandHandler.java | 21 +++- .../vmware/resource/VmwareResourceTest.java | 95 ++++++++++++++++++- .../CloudStackImageStoreDriverImpl.java | 5 +- .../src/com/cloud/server/StatsCollector.java | 3 +- .../cloud/storage/ImageStoreDetailsUtil.java | 6 +- .../storage/ImageStoreDetailsUtilTest.java | 14 +-- .../SecondaryStorageManagerImpl.java | 5 +- .../LocalNfsSecondaryStorageResource.java | 4 +- .../LocalSecondaryStorageResource.java | 2 +- .../resource/NfsSecondaryStorageResource.java | 37 ++++++-- .../resource/SecondaryStorageResource.java | 2 +- .../storage/template/DownloadManagerImpl.java | 5 +- 40 files changed, 398 insertions(+), 164 deletions(-) create mode 100755 core/src/com/cloud/agent/api/storage/StorageNfsVersionCommand.java create mode 100755 engine/storage/src/org/apache/cloudstack/storage/image/NfsImageStoreDriverImpl.java diff --git a/api/src/com/cloud/agent/api/to/NfsTO.java b/api/src/com/cloud/agent/api/to/NfsTO.java index 51d1aadef2..1cf7218ea1 100644 --- a/api/src/com/cloud/agent/api/to/NfsTO.java +++ b/api/src/com/cloud/agent/api/to/NfsTO.java @@ -24,6 +24,7 @@ public class NfsTO implements DataStoreTO { private DataStoreRole _role; private String uuid; private static final String pathSeparator = "/"; + private Integer nfsVersion; public NfsTO() { @@ -71,4 +72,12 @@ public void setUuid(String uuid) { public String getPathSeparator() { return pathSeparator; } + + public Integer getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(Integer nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/com/cloud/agent/api/BackupSnapshotCommand.java b/core/src/com/cloud/agent/api/BackupSnapshotCommand.java index d93c32f990..2c8c0cca20 100644 --- a/core/src/com/cloud/agent/api/BackupSnapshotCommand.java +++ b/core/src/com/cloud/agent/api/BackupSnapshotCommand.java @@ -39,7 +39,6 @@ public class BackupSnapshotCommand extends SnapshotCommand { private S3TO s3; StorageFilerTO pool; private Long secHostId; - private String nfsVersion; protected BackupSnapshotCommand() { @@ -109,11 +108,4 @@ public Long getSecHostId() { return secHostId; } - public String getNfsVersion() { - return nfsVersion; - } - - public void setNfsVersion(String nfsVersion) { - this.nfsVersion = nfsVersion; - } } diff --git a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java index 5a09994ab7..30b59ff4ef 100644 --- a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java +++ b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java @@ -28,7 +28,6 @@ public class CreatePrivateTemplateFromSnapshotCommand extends SnapshotCommand { private String origTemplateInstallPath; private Long newTemplateId; private String templateName; - private String nfsVersion; protected CreatePrivateTemplateFromSnapshotCommand() { @@ -74,11 +73,4 @@ public String getTemplateName() { return templateName; } - public String getNfsVersion() { - return nfsVersion; - } - - public void setNfsVersion(String nfsVersion) { - this.nfsVersion = nfsVersion; - } } diff --git a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java index b6cc6ac447..38a2f94fa4 100644 --- a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java +++ b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java @@ -32,7 +32,6 @@ public class CreatePrivateTemplateFromVolumeCommand extends SnapshotCommand { StorageFilerTO _primaryPool; // For XenServer private String _secondaryStorageUrl; - private String nfsVersion; public CreatePrivateTemplateFromVolumeCommand() { } @@ -101,11 +100,4 @@ public void setTemplateId(long templateId) { _templateId = templateId; } - public String getNfsVersion() { - return nfsVersion; - } - - public void setNfsVersion(String nfsVersion) { - this.nfsVersion = nfsVersion; - } } diff --git a/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java b/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java index 933be03606..4526ce7db6 100644 --- a/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java +++ b/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java @@ -26,8 +26,6 @@ */ public class CreateVolumeFromSnapshotCommand extends SnapshotCommand { - private String nfsVersion; - protected CreateVolumeFromSnapshotCommand() { } @@ -53,11 +51,4 @@ public CreateVolumeFromSnapshotCommand(StoragePool pool, String secondaryStorage setWait(wait); } - public String getNfsVersion() { - return nfsVersion; - } - - public void setNfsVersion(String nfsVersion) { - this.nfsVersion = nfsVersion; - } } diff --git a/core/src/com/cloud/agent/api/GetStorageStatsCommand.java b/core/src/com/cloud/agent/api/GetStorageStatsCommand.java index 84b5426451..94a574c51b 100644 --- a/core/src/com/cloud/agent/api/GetStorageStatsCommand.java +++ b/core/src/com/cloud/agent/api/GetStorageStatsCommand.java @@ -20,17 +20,17 @@ package com.cloud.agent.api; import com.cloud.agent.api.LogLevel.Log4jLevel; +import com.cloud.agent.api.storage.StorageNfsVersionCommand; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.storage.Storage.StoragePoolType; @LogLevel(Log4jLevel.Trace) -public class GetStorageStatsCommand extends Command { +public class GetStorageStatsCommand extends StorageNfsVersionCommand { private String id; private String localPath; private StoragePoolType pooltype; private String secUrl; private DataStoreTO store; - private String nfsVersion; public String getSecUrl() { return secUrl; @@ -55,9 +55,9 @@ public GetStorageStatsCommand(DataStoreTO store) { this.store = store; } - public GetStorageStatsCommand(DataStoreTO store, String nfsVersion) { + public GetStorageStatsCommand(DataStoreTO store, Integer nfsVersion) { + super(nfsVersion); this.store = store; - this.nfsVersion = nfsVersion; } public GetStorageStatsCommand(String secUrl) { @@ -87,14 +87,6 @@ public DataStoreTO getStore() { return this.store; } - public String getNfsVersion() { - return nfsVersion; - } - - public void setNfsVersion(String nfsVersion) { - this.nfsVersion = nfsVersion; - } - @Override public boolean executeInSequence() { return false; diff --git a/core/src/com/cloud/agent/api/SecStorageSetupCommand.java b/core/src/com/cloud/agent/api/SecStorageSetupCommand.java index 316e4698dc..061346cd3b 100644 --- a/core/src/com/cloud/agent/api/SecStorageSetupCommand.java +++ b/core/src/com/cloud/agent/api/SecStorageSetupCommand.java @@ -21,14 +21,14 @@ import org.apache.cloudstack.framework.security.keystore.KeystoreManager; +import com.cloud.agent.api.storage.StorageNfsVersionCommand; import com.cloud.agent.api.to.DataStoreTO; -public class SecStorageSetupCommand extends Command { +public class SecStorageSetupCommand extends StorageNfsVersionCommand { private DataStoreTO store; private String secUrl; private KeystoreManager.Certificates certs; private String postUploadKey; - private String nfsVersion; public SecStorageSetupCommand() { @@ -76,11 +76,4 @@ public void setPostUploadKey(String postUploadKey) { this.postUploadKey = postUploadKey; } - public String getNfsVersion() { - return nfsVersion; - } - - public void setNfsVersion(String nfsVersion) { - this.nfsVersion = nfsVersion; - } } diff --git a/core/src/com/cloud/agent/api/SnapshotCommand.java b/core/src/com/cloud/agent/api/SnapshotCommand.java index cf4eeb5da5..0e527e2f84 100644 --- a/core/src/com/cloud/agent/api/SnapshotCommand.java +++ b/core/src/com/cloud/agent/api/SnapshotCommand.java @@ -19,6 +19,7 @@ package com.cloud.agent.api; +import com.cloud.agent.api.storage.StorageNfsVersionCommand; import com.cloud.agent.api.to.StorageFilerTO; import com.cloud.storage.StoragePool; @@ -26,7 +27,7 @@ * This currently assumes that both primary and secondary storage are mounted on * the XenServer. */ -public class SnapshotCommand extends Command { +public class SnapshotCommand extends StorageNfsVersionCommand { protected String primaryStoragePoolNameLabel; StorageFilerTO primaryPool; private String snapshotUuid; diff --git a/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java b/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java index 7ab822c03b..a75e9ba3be 100644 --- a/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java +++ b/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java @@ -19,11 +19,10 @@ package com.cloud.agent.api.storage; -import com.cloud.agent.api.Command; import com.cloud.agent.api.to.StorageFilerTO; import com.cloud.storage.StoragePool; -public class CopyVolumeCommand extends Command { +public class CopyVolumeCommand extends StorageNfsVersionCommand { long volumeId; String volumePath; @@ -32,7 +31,6 @@ public class CopyVolumeCommand extends Command { boolean toSecondaryStorage; String vmName; boolean executeInSequence = false; - String nfsVersion; public CopyVolumeCommand() { } @@ -77,11 +75,4 @@ public String getVmName() { return vmName; } - public String getNfsVersion() { - return nfsVersion; - } - - public void setNfsVersion(String nfsVersion) { - this.nfsVersion = nfsVersion; - } } diff --git a/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java b/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java index bacc83aea5..6f60933f55 100644 --- a/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java +++ b/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java @@ -23,21 +23,17 @@ public class ListTemplateCommand extends StorageCommand { private DataStoreTO store; - private String nfsVersion; - - //private String secUrl; public ListTemplateCommand() { } public ListTemplateCommand(DataStoreTO store) { this.store = store; -// this.secUrl = url; } - public ListTemplateCommand(DataStoreTO store, String nfsVersion) { + public ListTemplateCommand(DataStoreTO store, Integer nfsVersion) { + super(nfsVersion); this.store = store; - this.nfsVersion = nfsVersion; } @Override @@ -49,12 +45,4 @@ public DataStoreTO getDataStore() { return store; } - public String getNfsVersion() { - return nfsVersion; - } - - // public String getSecUrl() { - // return secUrl; - // } - } diff --git a/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java b/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java index 9dae513b98..725bd0cdde 100644 --- a/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java +++ b/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java @@ -35,7 +35,6 @@ public class PrimaryStorageDownloadCommand extends AbstractDownloadCommand { String secondaryStorageUrl; String primaryStorageUrl; - String nfsVersion; protected PrimaryStorageDownloadCommand() { } @@ -89,11 +88,4 @@ public boolean executeInSequence() { return true; } - public String getNfsVersion() { - return nfsVersion; - } - - public void setNfsVersion(String nfsVersion) { - this.nfsVersion = nfsVersion; - } } diff --git a/core/src/com/cloud/agent/api/storage/SsCommand.java b/core/src/com/cloud/agent/api/storage/SsCommand.java index 187ae03be4..575b2450a2 100644 --- a/core/src/com/cloud/agent/api/storage/SsCommand.java +++ b/core/src/com/cloud/agent/api/storage/SsCommand.java @@ -19,9 +19,7 @@ package com.cloud.agent.api.storage; -import com.cloud.agent.api.Command; - -public abstract class SsCommand extends Command { +public abstract class SsCommand extends StorageNfsVersionCommand { private String secUrl; public SsCommand() { diff --git a/core/src/com/cloud/agent/api/storage/StorageCommand.java b/core/src/com/cloud/agent/api/storage/StorageCommand.java index a6719c40c1..429755cba4 100644 --- a/core/src/com/cloud/agent/api/storage/StorageCommand.java +++ b/core/src/com/cloud/agent/api/storage/StorageCommand.java @@ -19,11 +19,13 @@ package com.cloud.agent.api.storage; -import com.cloud.agent.api.Command; - -public abstract class StorageCommand extends Command { +public abstract class StorageCommand extends StorageNfsVersionCommand { protected StorageCommand() { super(); } + protected StorageCommand(Integer nfsVersion){ + super(nfsVersion); + } + } diff --git a/core/src/com/cloud/agent/api/storage/StorageNfsVersionCommand.java b/core/src/com/cloud/agent/api/storage/StorageNfsVersionCommand.java new file mode 100755 index 0000000000..b99713dea1 --- /dev/null +++ b/core/src/com/cloud/agent/api/storage/StorageNfsVersionCommand.java @@ -0,0 +1,44 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +package com.cloud.agent.api.storage; + +import com.cloud.agent.api.Command; + +public abstract class StorageNfsVersionCommand extends Command { + + protected StorageNfsVersionCommand(){ + super(); + } + + protected StorageNfsVersionCommand(Integer nfsVersion){ + super(); + this.nfsVersion = nfsVersion; + } + + private Integer nfsVersion; + + public Integer getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(Integer nfsVersion) { + this.nfsVersion = nfsVersion; + } + +} diff --git a/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java b/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java index bfcd9ae9b4..29fdd19116 100644 --- a/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java +++ b/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java @@ -53,7 +53,7 @@ public class TemplateOrVolumePostUploadCommand { private long accountId; - private String nfsVersion; + private Integer nfsVersion; public TemplateOrVolumePostUploadCommand(long entityId, String entityUUID, String absolutePath, String checksum, String type, String name, String imageFormat, String dataTo, String dataToRole) { @@ -199,11 +199,11 @@ public long getAccountId() { return accountId; } - public String getNfsVersion() { + public Integer getNfsVersion() { return nfsVersion; } - public void setNfsVersion(String nfsVersion) { + public void setNfsVersion(Integer nfsVersion) { this.nfsVersion = nfsVersion; } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index 0d96660d58..8dcc439f0a 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -638,7 +638,8 @@ protected Void createTemplateAsyncCallBack(AsyncCallbackDispatcher listTemplate(DataStore ssStore) { - ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO(), imageStoreDetailsUtil.getNfsVersion(ssStore.getId())); + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(ssStore.getId()); + ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO(), nfsVersion); EndPoint ep = _epSelector.select(ssStore); Answer answer = null; if (ep == null) { diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java index 5c41dcab0e..f732805016 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java @@ -51,7 +51,7 @@ public MockLocalNfsSecondaryStorageResource() { } @Override - public String getRootDir(String secUrl, String nfsVersion) { + public String getRootDir(String secUrl, Integer nfsVersion) { return "/mnt"; } diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java index 0068c2d4f7..288fae4e1a 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java @@ -79,6 +79,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { VMTemplateZoneDao _vmTemplateZoneDao; @Inject AlertManager _alertMgr; + protected String _proxy = null; protected Proxy getHttpProxy() { diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/NfsImageStoreDriverImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/NfsImageStoreDriverImpl.java new file mode 100755 index 0000000000..28d9d4646e --- /dev/null +++ b/engine/storage/src/org/apache/cloudstack/storage/image/NfsImageStoreDriverImpl.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.image; + +import java.util.Map; + +import javax.inject.Inject; + +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; + +public abstract class NfsImageStoreDriverImpl extends BaseImageStoreDriverImpl { + + @Inject + ImageStoreDetailsDao _imageStoreDetailsDao; + + private static final String NFS_VERSION_DETAILS_KEY = "nfs.version"; + + /** + * Retrieve NFS version to be used for imgStoreId store, if provided in image_store_details table + * @param imgStoreId store id + * @return "nfs.version" associated value for imgStoreId in image_store_details table if exists, null if not + */ + protected Integer getNfsVersion(long imgStoreId){ + Map imgStoreDetails = _imageStoreDetailsDao.getDetails(imgStoreId); + if (imgStoreDetails != null && imgStoreDetails.containsKey(NFS_VERSION_DETAILS_KEY)){ + String nfsVersionParam = imgStoreDetails.get(NFS_VERSION_DETAILS_KEY); + return (nfsVersionParam != null ? Integer.valueOf(nfsVersionParam) : null); + } + return null; + } + +} diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java index 9b1f091db7..c77550e5da 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java @@ -109,7 +109,7 @@ public boolean configure(String name, Map params) throws Configu } @Override - public String getRootDir(String url, String nfsVersion) { + public String getRootDir(String url, Integer nfsVersion) { // TODO Auto-generated method stub return null; } diff --git a/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java b/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java index 4497448af0..14d75f846e 100644 --- a/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java +++ b/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java @@ -35,7 +35,7 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; -import org.apache.cloudstack.storage.image.BaseImageStoreDriverImpl; +import org.apache.cloudstack.storage.image.NfsImageStoreDriverImpl; import org.apache.cloudstack.storage.image.store.ImageStoreImpl; import com.cloud.agent.api.storage.DownloadAnswer; @@ -47,7 +47,7 @@ import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; -public class SimulatorImageStoreDriverImpl extends BaseImageStoreDriverImpl { +public class SimulatorImageStoreDriverImpl extends NfsImageStoreDriverImpl { private static final Logger s_logger = Logger.getLogger(SimulatorImageStoreDriverImpl.class); @Inject @@ -67,6 +67,7 @@ public DataStoreTO getStoreTO(DataStore store) { NfsTO nfsTO = new NfsTO(); nfsTO.setRole(store.getRole()); nfsTO.setUrl(nfsStore.getUri()); + nfsTO.setNfsVersion(getNfsVersion(nfsStore.getId())); return nfsTO; } 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 63124e1ca9..da83283afd 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -553,7 +553,8 @@ public boolean needRecycle(String workerTag) { @Override public void prepareSecondaryStorageStore(String storageUrl, Long storeId) { - String mountPoint = getMountPoint(storageUrl, imageStoreDetailsUtil.getNfsVersion(storeId)); + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(storeId); + String mountPoint = getMountPoint(storageUrl, nfsVersion); GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm"); try { @@ -661,7 +662,7 @@ public void run() { } @Override - public String getMountPoint(String storageUrl, String nfsVersion) { + public String getMountPoint(String storageUrl, Integer nfsVersion) { String mountPoint = null; synchronized (_storageMounts) { mountPoint = _storageMounts.get(storageUrl); @@ -752,7 +753,7 @@ private void shutdownCleanup() { } } - protected String mount(String path, String parent, String nfsVersion) { + protected String mount(String path, String parent, Integer nfsVersion) { String mountPoint = setupMountPoint(parent); if (mountPoint == null) { s_logger.warn("Unable to create a mount point"); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index c7c53bacba..c5c1c438eb 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -93,7 +93,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { - private String _nfsVersion; + private Integer _nfsVersion; @Override public boolean execute(VmwareHostService hostService, CreateEntityDownloadURLCommand cmd) { @@ -141,7 +141,7 @@ public VmwareStorageManagerImpl(VmwareStorageMount mountService) { _mountService = mountService; } - public VmwareStorageManagerImpl(VmwareStorageMount mountService, String nfsVersion) { + public VmwareStorageManagerImpl(VmwareStorageMount mountService, Integer nfsVersion) { assert (mountService != null); _mountService = mountService; _nfsVersion = nfsVersion; @@ -555,7 +555,7 @@ public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCom // templateName: name in secondary storage // templateUuid: will be used at hypervisor layer private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl, - String templatePathAtSecondaryStorage, String templateName, String templateUuid, String nfsVersion) throws Exception { + String templatePathAtSecondaryStorage, String templateName, String templateUuid, Integer nfsVersion) throws Exception { s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: " + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage + ", templateName: " + templateName); @@ -611,7 +611,7 @@ private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, } private Ternary createTemplateFromVolume(VirtualMachineMO vmMo, long accountId, long templateId, String templateUniqueName, String secStorageUrl, - String volumePath, String workerVmName, String nfsVersion) throws Exception { + String volumePath, String workerVmName, Integer nfsVersion) throws Exception { String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId); @@ -676,7 +676,7 @@ private Ternary createTemplateFromVolume(VirtualMachineMO vm } private Ternary createTemplateFromSnapshot(long accountId, long templateId, String templateUniqueName, String secStorageUrl, long volumeId, - String backedUpSnapshotUuid, String nfsVersion) throws Exception { + String backedUpSnapshotUuid, Integer nfsVersion) throws Exception { String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId); @@ -860,14 +860,14 @@ private void writeMetaOvaForTemplate(String installFullPath, String ovfFilename, } private String createVolumeFromSnapshot(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, long accountId, long volumeId, - String secStorageUrl, String snapshotBackupUuid, String nfsVersion) throws Exception { + String secStorageUrl, String snapshotBackupUuid, Integer nfsVersion) throws Exception { restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), snapshotBackupUuid, nfsVersion); return null; } private void restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, String secStorageUrl, String secStorageDir, - String backupName, String nfsVersion) throws Exception { + String backupName, Integer nfsVersion) throws Exception { String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String srcOVAFileName = secondaryMountPoint + "/" + secStorageDir + "/" + backupName + "." + ImageFormat.OVA.getFileExtension(); @@ -927,7 +927,7 @@ private void restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, Datasto } private String backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, long accountId, long volumeId, String volumePath, String snapshotUuid, String secStorageUrl, - String prevSnapshotUuid, String prevBackupUuid, String workerVmName, String nfsVersion) throws Exception { + String prevSnapshotUuid, String prevBackupUuid, String workerVmName, Integer nfsVersion) throws Exception { String backupUuid = UUID.randomUUID().toString(); exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), backupUuid, workerVmName, nfsVersion); @@ -935,7 +935,7 @@ private String backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, long acco } private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath, String secStorageUrl, String secStorageDir, String exportName, - String workerVmName, String nfsVersion) throws Exception { + String workerVmName, Integer nfsVersion) throws Exception { String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String exportPath = secondaryMountPoint + "/" + secStorageDir + "/" + exportName; @@ -980,7 +980,7 @@ private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volume } private Pair copyVolumeToSecStorage(VmwareHostService hostService, VmwareHypervisorHost hyperHost, CopyVolumeCommand cmd, String vmName, - long volumeId, String poolId, String volumePath, String secStorageUrl, String workerVmName, String nfsVersion) throws Exception { + long volumeId, String poolId, String volumePath, String secStorageUrl, String workerVmName, Integer nfsVersion) throws Exception { String volumeFolder = String.valueOf(volumeId) + "/"; VirtualMachineMO workerVm = null; @@ -1038,7 +1038,7 @@ private String getVolumePathInDatastore(DatastoreMO dsMo, String volumeFileName) return datastoreVolumePath; } - private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, long volumeId, DatastoreMO dsMo, String secStorageUrl, String exportName, String nfsVersion) + private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, long volumeId, DatastoreMO dsMo, String secStorageUrl, String exportName, Integer nfsVersion) throws Exception { String volumeFolder = String.valueOf(volumeId) + "/"; @@ -1458,7 +1458,7 @@ public RevertToVMSnapshotAnswer execute(VmwareHostService hostService, RevertToV } } - private String deleteVolumeDirOnSecondaryStorage(long volumeId, String secStorageUrl, String nfsVersion) throws Exception { + private String deleteVolumeDirOnSecondaryStorage(long volumeId, String secStorageUrl, Integer nfsVersion) throws Exception { String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String volumeMountRoot = secondaryMountPoint + "/" + getVolumeRelativeDirInSecStroage(volumeId); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java index 54b52f6dff..fd139e418b 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java @@ -17,5 +17,5 @@ package com.cloud.hypervisor.vmware.manager; public interface VmwareStorageMount { - String getMountPoint(String storageUrl, String nfsVersion); + String getMountPoint(String storageUrl, Integer nfsVersion); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index a640f3aa7c..238ba3ed86 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -97,7 +97,9 @@ import com.vmware.vim25.VirtualMachineVideoCard; import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec; +import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; +import org.apache.cloudstack.storage.resource.NfsSecondaryStorageResource; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.commons.lang.math.NumberUtils; @@ -306,6 +308,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa protected String _password; protected String _guid; protected String _vCenterAddress; + protected Integer storageNfsVersion; protected String _privateNetworkVSwitchName; protected VmwareTrafficLabel _guestTrafficInfo = new VmwareTrafficLabel(TrafficType.Guest); @@ -475,6 +478,7 @@ public Answer executeRequest(Command cmd) { } else if (clz == UnregisterVMCommand.class) { return execute((UnregisterVMCommand) cmd); } else if (cmd instanceof StorageSubSystemCommand) { + checkStorageProcessorAndHandlerNfsVersionAttribute((StorageSubSystemCommand)cmd); return storageHandler.handleStorageCommands((StorageSubSystemCommand) cmd); } else if (clz == ScaleVmCommand.class) { return execute((ScaleVmCommand)cmd); @@ -523,6 +527,64 @@ public Answer executeRequest(Command cmd) { return answer; } + /** + * Check if storage NFS version is already set or needs to be reconfigured.
+ * If _storageNfsVersion is not null -> nothing to do, version already set.
+ * If _storageNfsVersion is null -> examine StorageSubSystemCommand to get NFS version and set it + * to the storage processor and storage handler. + * @param cmd command to execute + */ + protected void checkStorageProcessorAndHandlerNfsVersionAttribute(StorageSubSystemCommand cmd) { + if (storageNfsVersion != null) return; + if (cmd instanceof CopyCommand){ + examineStorageSubSystemCommandNfsVersion((CopyCommand) cmd); + } + } + + /** + * Examine StorageSubSystem command to get storage NFS version, if provided + * @param cmd command to execute + */ + protected void examineStorageSubSystemCommandNfsVersion(CopyCommand cmd){ + DataStoreTO srcDataStore = cmd.getSrcTO().getDataStore(); + boolean nfsVersionFound = false; + + if (srcDataStore instanceof NfsTO){ + nfsVersionFound = getStorageNfsVersionFromNfsTO((NfsTO) srcDataStore); + } + + if (nfsVersionFound){ + setCurrentNfsVersionInProcessorAndHandler(); + } + } + + /** + * Get storage NFS version from NfsTO + * @param nfsTO nfsTO + * @return true if NFS version was found and not null, false in other case + */ + protected boolean getStorageNfsVersionFromNfsTO(NfsTO nfsTO){ + if (nfsTO != null && nfsTO.getNfsVersion() != null){ + storageNfsVersion = nfsTO.getNfsVersion(); + return true; + } + return false; + } + + /** + * Sets _storageNfsVersion into storage processor and storage handler by calling reconfigureNfsVersion on the storage handler, + * which will set NFS version into it and the storage processor. + */ + protected void setCurrentNfsVersionInProcessorAndHandler() { + VmwareStorageSubsystemCommandHandler handler = (VmwareStorageSubsystemCommandHandler) storageHandler; + boolean success = handler.reconfigureNfsVersion(storageNfsVersion); + if (success){ + s_logger.info("NFS version " + storageNfsVersion + " successfully set in VmwareStorageProcessor and VmwareStorageSubsystemCommandHandler"); + } else { + s_logger.error("Error while setting NFS version " + storageNfsVersion); + } + } + /** * Registers the vm to the inventory given the vmx file. */ @@ -5311,8 +5373,10 @@ else if (value != null && value.equalsIgnoreCase("ide")) value = (String)params.get("scripts.timeout"); int timeout = NumbersUtil.parseInt(value, 1440) * 1000; - _storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, _fullCloneFlag, (VmwareStorageMount)mgr, timeout, this, _shutdownWaitMs, null, (String)params.get("nfsVersion")); - storageHandler = new VmwareStorageSubsystemCommandHandler(_storageProcessor, (String)params.get("nfsVersion")); + + storageNfsVersion = NfsSecondaryStorageResource.retrieveNfsVersionFromParams(params); + _storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, _fullCloneFlag, (VmwareStorageMount)mgr, timeout, this, _shutdownWaitMs, null, storageNfsVersion); + storageHandler = new VmwareStorageSubsystemCommandHandler(_storageProcessor, storageNfsVersion); _vrResource = new VirtualRoutingResource(this); if (!_vrResource.configure(name, params)) { diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java index 1ec4958509..fd89cc7bb0 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java @@ -102,7 +102,8 @@ public boolean configure(String name, Map params) throws Configu VmwareSecondaryStorageContextFactory.initFactoryEnvironment(); } - registerHandler(Hypervisor.HypervisorType.VMware, new VmwareSecondaryStorageResourceHandler(this, (String)params.get("nfsVersion"))); + Integer nfsVersion = NfsSecondaryStorageResource.retrieveNfsVersionFromParams(params); + registerHandler(Hypervisor.HypervisorType.VMware, new VmwareSecondaryStorageResourceHandler(this, nfsVersion)); return true; } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java index 3c4e6340d3..9a8c37a098 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java @@ -66,7 +66,7 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe * private Map _activeHosts = new HashMap(); */ - public VmwareSecondaryStorageResourceHandler(PremiumSecondaryStorageResource resource, String nfsVersion) { + public VmwareSecondaryStorageResourceHandler(PremiumSecondaryStorageResource resource, Integer nfsVersion) { _resource = resource; _storageMgr = new VmwareStorageManagerImpl(this, nfsVersion); _gson = GsonHelper.getGsonLogger(); @@ -304,7 +304,7 @@ public String getWorkerName(VmwareContext context, Command cmd, int workerSequen } @Override - public String getMountPoint(String storageUrl, String nfsVersion) { + public String getMountPoint(String storageUrl, Integer nfsVersion) { return _resource.getRootDir(storageUrl, nfsVersion); } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index b2766e666d..eb18e0b9a8 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -125,10 +125,10 @@ public class VmwareStorageProcessor implements StorageProcessor { protected Integer _shutdownWaitMs; private final Gson _gson; private final StorageLayer _storage = new JavaStorageLayer(); - private String _nfsVersion; + private Integer _nfsVersion; public VmwareStorageProcessor(VmwareHostService hostService, boolean fullCloneFlag, VmwareStorageMount mountService, Integer timeout, VmwareResource resource, - Integer shutdownWaitMs, PremiumSecondaryStorageResource storageResource, String nfsVersion) { + Integer shutdownWaitMs, PremiumSecondaryStorageResource storageResource, Integer nfsVersion) { this.hostService = hostService; _fullCloneFlag = fullCloneFlag; this.mountService = mountService; @@ -169,7 +169,7 @@ private String getOVFFilePath(String srcOVAFileName) { } private VirtualMachineMO copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl, - String templatePathAtSecondaryStorage, String templateName, String templateUuid, boolean createSnapshot, String nfsVersion) throws Exception { + String templatePathAtSecondaryStorage, String templateName, String templateUuid, boolean createSnapshot, Integer nfsVersion) throws Exception { s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: " + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage + ", templateName: " + templateName); @@ -532,7 +532,7 @@ public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd) { } } - private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, String srcVolumePath, DatastoreMO dsMo, String secStorageUrl, long wait, String nfsVersion) throws Exception { + private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, String srcVolumePath, DatastoreMO dsMo, String secStorageUrl, long wait, Integer nfsVersion) throws Exception { String volumeFolder = null; String volumeName = null; @@ -552,7 +552,7 @@ private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyper return new Pair(volumeFolder, newVolume); } - private String deleteVolumeDirOnSecondaryStorage(String volumeDir, String secStorageUrl, String nfsVersion) throws Exception { + private String deleteVolumeDirOnSecondaryStorage(String volumeDir, String secStorageUrl, Integer nfsVersion) throws Exception { String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String volumeMountRoot = secondaryMountPoint + File.separator + volumeDir; @@ -734,7 +734,7 @@ private void postCreatePrivateTemplate(String installFullPath, long templateId, } private Ternary createTemplateFromVolume(VirtualMachineMO vmMo, String installPath, long templateId, String templateUniqueName, - String secStorageUrl, String volumePath, String workerVmName, String nfsVersion) throws Exception { + String secStorageUrl, String volumePath, String workerVmName, Integer nfsVersion) throws Exception { String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String installFullPath = secondaryMountPoint + "/" + installPath; @@ -899,7 +899,7 @@ private void writeMetaOvaForTemplate(String installFullPath, String ovfFilename, } private Ternary createTemplateFromSnapshot(String installPath, String templateUniqueName, String secStorageUrl, String snapshotPath, - Long templateId, long wait, String nfsVersion) throws Exception { + Long templateId, long wait, Integer nfsVersion) throws Exception { //Snapshot path is decoded in this form: /snapshots/account/volumeId/uuid/uuid String backupSSUuid; String snapshotFolder; @@ -1066,7 +1066,7 @@ public Answer createTemplateFromSnapshot(CopyCommand cmd) { // return Pair private Pair exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath, String secStorageUrl, String secStorageDir, - String exportName, String workerVmName, String nfsVersion) throws Exception { + String exportName, String workerVmName, Integer nfsVersion) throws Exception { String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String exportPath = secondaryMountPoint + "/" + secStorageDir + "/" + exportName; @@ -1110,7 +1110,7 @@ private Pair exportVolumeToSecondaryStroage(VirtualMachineMO v // Ternary private Ternary backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, String installPath, String volumePath, String snapshotUuid, - String secStorageUrl, String prevSnapshotUuid, String prevBackupUuid, String workerVmName, String nfsVersion) throws Exception { + String secStorageUrl, String prevSnapshotUuid, String prevBackupUuid, String workerVmName, Integer nfsVersion) throws Exception { String backupUuid = UUID.randomUUID().toString(); Pair snapshotInfo = exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, installPath, backupUuid, workerVmName, nfsVersion); @@ -2212,7 +2212,7 @@ private List getManagedIqnsFromVirtualDisks(List virtualDis } private Long restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, String secStorageUrl, String secStorageDir, - String backupName, long wait, String nfsVersion) throws Exception { + String backupName, long wait, Integer nfsVersion) throws Exception { String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, null); String srcOVAFileName = null; @@ -2389,4 +2389,9 @@ private String getControllerFromConfigurationSetting() throws Exception { private String getLegacyVmDataDiskController() throws Exception { return DiskControllerType.lsilogic.toString(); } + + public void setNfsVersion(Integer nfsVersion){ + this._nfsVersion = nfsVersion; + s_logger.debug("VmwareProcessor instance now using NFS version: " + nfsVersion); + } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java index 40fa47b03b..7252f51bf3 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java @@ -43,7 +43,7 @@ public class VmwareStorageSubsystemCommandHandler extends StorageSubsystemComman private static final Logger s_logger = Logger.getLogger(VmwareStorageSubsystemCommandHandler.class); private VmwareStorageManager storageManager; private PremiumSecondaryStorageResource storageResource; - private String _nfsVersion; + private Integer _nfsVersion; public PremiumSecondaryStorageResource getStorageResource() { return storageResource; @@ -61,11 +61,28 @@ public void setStorageManager(VmwareStorageManager storageManager) { this.storageManager = storageManager; } - public VmwareStorageSubsystemCommandHandler(StorageProcessor processor, String nfsVersion) { + public VmwareStorageSubsystemCommandHandler(StorageProcessor processor, Integer nfsVersion) { super(processor); this._nfsVersion = nfsVersion; } + /** + * Reconfigure NFS version for storage operations + * @param nfsVersion NFS version to set + * @return true if NFS version could be configured, false in other case + */ + public boolean reconfigureNfsVersion(Integer nfsVersion){ + try { + VmwareStorageProcessor processor = (VmwareStorageProcessor) this.processor; + processor.setNfsVersion(nfsVersion); + this._nfsVersion = nfsVersion; + return true; + } catch (Exception e){ + s_logger.error("Error while reconfiguring NFS version " + nfsVersion); + return false; + } + } + @Override protected Answer execute(CopyCommand cmd) { DataTO srcData = cmd.getSrcTO(); diff --git a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java index f554da9b39..22388a8a69 100644 --- a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java +++ b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java @@ -20,17 +20,27 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.mock; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.never; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import org.apache.cloudstack.storage.command.CopyCommand; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import com.vmware.vim25.VirtualDevice; import com.vmware.vim25.VirtualMachineConfigSpec; @@ -38,14 +48,26 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.ScaleVmAnswer; import com.cloud.agent.api.ScaleVmCommand; +import com.cloud.agent.api.to.DataTO; +import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; import com.cloud.hypervisor.vmware.util.VmwareContext; +import com.cloud.storage.resource.VmwareStorageProcessor; +import com.cloud.storage.resource.VmwareStorageSubsystemCommandHandler; +@RunWith(PowerMockRunner.class) +@PrepareForTest(CopyCommand.class) public class VmwareResourceTest { + @Mock + VmwareStorageProcessor storageProcessor; + @Mock + VmwareStorageSubsystemCommandHandler storageHandler; + @Spy + @InjectMocks VmwareResource _resource = new VmwareResource() { @Override @@ -57,6 +79,7 @@ public ScaleVmAnswer execute(ScaleVmCommand cmd) { public VmwareHypervisorHost getHyperHost(VmwareContext context, Command cmd) { return hyperHost; } + }; @Mock @@ -75,12 +98,25 @@ public VmwareHypervisorHost getHyperHost(VmwareContext context, Command cmd) { VirtualMachineMO vmMo3dgpu; @Mock VirtualMachineTO vmSpec3dgpu; + @Mock + DataTO srcDataTO; + @Mock + NfsTO srcDataNfsTO; + + CopyCommand storageCmd; + + private static final Integer NFS_VERSION = Integer.valueOf(3); + private static final Integer NFS_VERSION_NOT_PRESENT = null; @Before public void setup() { MockitoAnnotations.initMocks(this); + storageCmd = PowerMockito.mock(CopyCommand.class); doReturn(context).when(_resource).getServiceContext(null); when(cmd.getVirtualMachine()).thenReturn(vmSpec); + when(storageCmd.getSrcTO()).thenReturn(srcDataTO); + when(srcDataTO.getDataStore()).thenReturn(srcDataNfsTO); + when(srcDataNfsTO.getNfsVersion()).thenReturn(NFS_VERSION); } //Test successful scaling up the vm @@ -117,4 +153,61 @@ public void testStartVm3dgpuEnabled() throws Exception{ verify(vmMo3dgpu).configureVm(any(VirtualMachineConfigSpec.class)); } -} + // --------------------------------------------------------------------------------------------------- + + @Test + public void testgetNfsVersionFromNfsTONull(){ + assertFalse(_resource.getStorageNfsVersionFromNfsTO(null)); + } + + @Test + public void testgetNfsVersionFromNfsTONfsVersionNull(){ + when(srcDataNfsTO.getNfsVersion()).thenReturn(NFS_VERSION_NOT_PRESENT); + assertFalse(_resource.getStorageNfsVersionFromNfsTO(srcDataNfsTO)); + } + + @Test + public void testgetNfsVersionFromNfsTONfsVersion(){ + assertTrue(_resource.getStorageNfsVersionFromNfsTO(srcDataNfsTO)); + } + + // --------------------------------------------------------------------------------------------------- + + @Test + public void testSetCurrentNfsVersionInProcessorAndHandler(){ + _resource.setCurrentNfsVersionInProcessorAndHandler(); + verify(storageHandler).reconfigureNfsVersion(any(Integer.class)); + } + + // --------------------------------------------------------------------------------------------------- + + @Test + public void testExamineStorageSubSystemCommandNfsVersionNotPresent(){ + when(srcDataNfsTO.getNfsVersion()).thenReturn(NFS_VERSION_NOT_PRESENT); + _resource.examineStorageSubSystemCommandNfsVersion(storageCmd); + verify(_resource, never()).setCurrentNfsVersionInProcessorAndHandler(); + } + + @Test + public void testExamineStorageSubSystemCommandNfsVersion(){ + _resource.examineStorageSubSystemCommandNfsVersion(storageCmd); + verify(_resource).setCurrentNfsVersionInProcessorAndHandler(); + } + + // --------------------------------------------------------------------------------------------------- + + @Test + public void checkStorageProcessorAndHandlerNfsVersionAttributeVersionNotSet(){ + _resource.checkStorageProcessorAndHandlerNfsVersionAttribute(storageCmd); + verify(_resource).examineStorageSubSystemCommandNfsVersion(storageCmd); + assertEquals(NFS_VERSION, _resource.storageNfsVersion); + } + + @Test + public void checkStorageProcessorAndHandlerNfsVersionAttributeVersionSet(){ + _resource.storageNfsVersion = NFS_VERSION; + _resource.checkStorageProcessorAndHandlerNfsVersionAttribute(storageCmd); + verify(_resource, never()).examineStorageSubSystemCommandNfsVersion(storageCmd); + } + +} \ No newline at end of file diff --git a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java index 05222c81f1..b8b5226261 100644 --- a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java +++ b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java @@ -32,7 +32,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.storage.image.BaseImageStoreDriverImpl; +import org.apache.cloudstack.storage.image.NfsImageStoreDriverImpl; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; import org.apache.cloudstack.storage.image.store.ImageStoreImpl; @@ -44,7 +44,7 @@ import com.cloud.storage.Storage.ImageFormat; import com.cloud.utils.exception.CloudRuntimeException; -public class CloudStackImageStoreDriverImpl extends BaseImageStoreDriverImpl { +public class CloudStackImageStoreDriverImpl extends NfsImageStoreDriverImpl { private static final Logger s_logger = Logger.getLogger(CloudStackImageStoreDriverImpl.class); @Inject @@ -60,6 +60,7 @@ public DataStoreTO getStoreTO(DataStore store) { NfsTO nfsTO = new NfsTO(); nfsTO.setRole(store.getRole()); nfsTO.setUrl(nfsStore.getUri()); + nfsTO.setNfsVersion(getNfsVersion(nfsStore.getId())); return nfsTO; } diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index 4204b7689c..e4687e4daf 100644 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -770,7 +770,8 @@ protected void runInContext() { continue; } - GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO(), imageStoreDetailsUtil.getNfsVersion(store.getId())); + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(store.getId()); + GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO(), nfsVersion); EndPoint ssAhost = _epSelector.select(store); if (ssAhost == null) { s_logger.debug("There is no secondary storage VM for secondary storage host " + store.getName()); diff --git a/server/src/com/cloud/storage/ImageStoreDetailsUtil.java b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java index 63bd5c54d6..7107650779 100755 --- a/server/src/com/cloud/storage/ImageStoreDetailsUtil.java +++ b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java @@ -38,7 +38,7 @@ public class ImageStoreDetailsUtil { * @return {@code null} if {@code nfs.version} is not found for storeId
* {@code X} if {@code nfs.version} is found found for storeId */ - public String getNfsVersion(long storeId) { + public Integer getNfsVersion(long storeId) throws NumberFormatException { String nfsVersion = null; if (imageStoreDetailsDao.getDetails(storeId) != null){ Map storeDetails = imageStoreDetailsDao.getDetails(storeId); @@ -46,7 +46,7 @@ public String getNfsVersion(long storeId) { nfsVersion = storeDetails.get("nfs.version"); } } - return nfsVersion; + return (nfsVersion != null ? Integer.valueOf(nfsVersion) : null); } /** @@ -56,7 +56,7 @@ public String getNfsVersion(long storeId) { * @return {@code null} if {@code nfs.version} is not found for storeUuid
* {@code X} if {@code nfs.version} is found found for storeUuid */ - public String getNfsVersionByUuid(String storeUuid){ + public Integer getNfsVersionByUuid(String storeUuid){ ImageStoreVO imageStore = imageStoreDao.findByUuid(storeUuid); if (imageStore != null){ return getNfsVersion(imageStore.getId()); diff --git a/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java b/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java index 026a7d346d..4b3ce40bbd 100755 --- a/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java +++ b/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java @@ -34,7 +34,7 @@ public class ImageStoreDetailsUtilTest { private final static long STORE_ID = 1l; private final static String STORE_UUID = "aaaa-aaaa-aaaa-aaaa"; - private final static String NFS_VERSION = "3"; + private final static Integer NFS_VERSION = 3; ImageStoreDetailsUtil imageStoreDetailsUtil = new ImageStoreDetailsUtil(); @@ -44,7 +44,7 @@ public class ImageStoreDetailsUtilTest { @Before public void setup() throws Exception { Map imgStoreDetails = new HashMap(); - imgStoreDetails.put("nfs.version", NFS_VERSION); + imgStoreDetails.put("nfs.version", String.valueOf(NFS_VERSION)); when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails); ImageStoreVO imgStoreVO = mock(ImageStoreVO.class); @@ -57,7 +57,7 @@ public void setup() throws Exception { @Test public void testGetNfsVersion(){ - String nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); assertEquals(NFS_VERSION, nfsVersion); } @@ -67,7 +67,7 @@ public void testGetNfsVersionNotFound(){ imgStoreDetails.put("other.prop", "propValue"); when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails); - String nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); assertNull(nfsVersion); } @@ -76,20 +76,20 @@ public void testGetNfsVersionNoDetails(){ Map imgStoreDetails = new HashMap(); when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails); - String nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); assertNull(nfsVersion); } @Test public void testGetNfsVersionByUuid(){ - String nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(STORE_UUID); + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(STORE_UUID); assertEquals(NFS_VERSION, nfsVersion); } @Test public void testGetNfsVersionByUuidNoImgStore(){ when(imgStoreDao.findByUuid(STORE_UUID)).thenReturn(null); - String nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(STORE_UUID); + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(STORE_UUID); assertNull(nfsVersion); } } \ No newline at end of file diff --git a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java index eeec23dacf..176c7e9914 100644 --- a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java @@ -313,7 +313,8 @@ public boolean generateSetupCommand(Long ssHostId) { setupCmd = new SecStorageSetupCommand(ssStore.getTO(), secUrl, certs); } - setupCmd.setNfsVersion(imageStoreDetailsUtil.getNfsVersion(ssStore.getId())); + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(ssStore.getId()); + setupCmd.setNfsVersion(nfsVersion); //template/volume file upload key String postUploadKey = _configDao.getValue(Config.SSVMPSK.key()); @@ -1135,7 +1136,7 @@ public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, Depl if (dc.getDns2() != null) { buf.append(" dns2=").append(dc.getDns2()); } - String nfsVersion = imageStoreDetailsUtil != null ? imageStoreDetailsUtil.getNfsVersion(secStore.getId()) : null; + Integer nfsVersion = imageStoreDetailsUtil != null ? imageStoreDetailsUtil.getNfsVersion(secStore.getId()) : null; buf.append(" nfsVersion=").append(nfsVersion); String bootArgs = buf.toString(); diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java index 6f189ef5f3..c02fe8a610 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java @@ -53,7 +53,7 @@ public Answer executeRequest(Command cmd) { } @Override - synchronized public String getRootDir(String secUrl, String nfsVersion) { + synchronized public String getRootDir(String secUrl, Integer nfsVersion) { try { URI uri = new URI(secUrl); String dir = mountUri(uri, nfsVersion); @@ -66,7 +66,7 @@ synchronized public String getRootDir(String secUrl, String nfsVersion) { } @Override - protected void mount(String localRootPath, String remoteDevice, URI uri, String nfsVersion) { + protected void mount(String localRootPath, String remoteDevice, URI uri, Integer nfsVersion) { ensureLocalRootPathExists(localRootPath, uri); if (mountExists(localRootPath, uri)) { diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java index d953338c91..c6f6ba81ea 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java @@ -72,7 +72,7 @@ public void disconnected() { } @Override - public String getRootDir(String url, String nfsVersion) { + public String getRootDir(String url, Integer nfsVersion) { return getRootDir(); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index e7a9076f14..420842f229 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -205,7 +205,7 @@ public void setTimeout(int timeout) { private String _storageIp; private String _storageNetmask; private String _storageGateway; - private String _nfsVersion; + private Integer _nfsVersion; private final List nfsIps = new ArrayList(); protected String _parent = "/mnt/SecStorage"; final private String _tmpltpp = "template.properties"; @@ -229,6 +229,26 @@ public void setInSystemVM(boolean inSystemVM) { _inSystemVM = inSystemVM; } + /** + * Retrieve converted "nfsVersion" value from params + * @param params + * @return nfsVersion value if exists, null in other case + */ + public static Integer retrieveNfsVersionFromParams(Map params){ + Integer nfsVersion = null; + if (params.get("nfsVersion") != null){ + String nfsVersionParam = (String)params.get("nfsVersion"); + try { + nfsVersion = Integer.valueOf(nfsVersionParam); + } + catch (NumberFormatException e){ + s_logger.error("Couldn't cast " + nfsVersionParam + " to integer"); + return null; + } + } + return nfsVersion; + } + @Override public Answer executeRequest(Command cmd) { if (cmd instanceof DownloadProgressCommand) { @@ -559,7 +579,7 @@ protected Answer copySnapshotToTemplateFromNfsToNfs(CopyCommand cmd, SnapshotObj return new CopyCmdAnswer(""); } - protected File getFile(String path, String nfsPath, String nfsVersion) { + protected File getFile(String path, String nfsPath, Integer nfsVersion) { String filePath = getRootDir(nfsPath, nfsVersion) + File.separator + path; File f = new File(filePath); if (!f.exists()) { @@ -688,7 +708,7 @@ protected Long determineS3VolumeIdFromKey(String key) { return Long.parseLong(StringUtils.substringAfterLast(StringUtils.substringBeforeLast(key, S3Utils.SEPARATOR), S3Utils.SEPARATOR)); } - private String determineStorageTemplatePath(final String storagePath, String dataPath, String nfsVersion) { + private String determineStorageTemplatePath(final String storagePath, String dataPath, Integer nfsVersion) { return join(asList(getRootDir(storagePath, nfsVersion), dataPath), File.separator); } @@ -2046,7 +2066,7 @@ protected Answer deleteVolume(final DeleteCommand cmd) { } @Override - synchronized public String getRootDir(String secUrl, String nfsVersion) { + synchronized public String getRootDir(String secUrl, Integer nfsVersion) { if (!_inSystemVM) { return _parent; } @@ -2209,7 +2229,7 @@ public boolean configure(String name, Map params) throws Configu startAdditionalServices(); _params.put("install.numthreads", "50"); _params.put("secondary.storage.vm", "true"); - _nfsVersion = (String)params.get("nfsVersion"); + _nfsVersion = retrieveNfsVersionFromParams(params); } try { @@ -2385,10 +2405,11 @@ private String configureIpFirewall(List ipList, boolean isAppend) { * crresponding to the remote device. Will throw for unsupported * scheme. * @param imgStoreId + * @param nfsVersion NFS version to use in mount command * @return name of folder in _parent that device was mounted. * @throws UnknownHostException */ - protected String mountUri(URI uri, String nfsVersion) throws UnknownHostException { + protected String mountUri(URI uri, Integer nfsVersion) throws UnknownHostException { String uriHostIp = getUriHostIp(uri); String nfsPath = uriHostIp + ":" + uri.getPath(); @@ -2432,7 +2453,7 @@ protected void umount(String localRootPath, URI uri) { s_logger.debug("Successfully umounted " + localRootPath); } - protected void mount(String localRootPath, String remoteDevice, URI uri, String nfsVersion) { + protected void mount(String localRootPath, String remoteDevice, URI uri, Integer nfsVersion) { s_logger.debug("mount " + uri.toString() + " on " + localRootPath + ((nfsVersion != null) ? " nfsVersion="+nfsVersion : "")); ensureLocalRootPathExists(localRootPath, uri); @@ -2448,7 +2469,7 @@ protected void mount(String localRootPath, String remoteDevice, URI uri, String checkForVolumesDir(localRootPath); } - protected void attemptMount(String localRootPath, String remoteDevice, URI uri, String nfsVersion) { + protected void attemptMount(String localRootPath, String remoteDevice, URI uri, Integer nfsVersion) { String result; s_logger.debug("Make cmdline call to mount " + remoteDevice + " at " + localRootPath + " based on uri " + uri + ((nfsVersion != null) ? " nfsVersion=" + nfsVersion : "")); diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java index 3c24b6c6de..d7e0c7e93d 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java @@ -23,6 +23,6 @@ */ public interface SecondaryStorageResource extends ServerResource { - String getRootDir(String cmd, String nfsVersion); + String getRootDir(String cmd, Integer nfsVersion); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java index affe8a716a..40a1e1cdde 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java @@ -44,6 +44,7 @@ import org.apache.cloudstack.storage.command.DownloadCommand.ResourceType; import org.apache.cloudstack.storage.command.DownloadProgressCommand; import org.apache.cloudstack.storage.command.DownloadProgressCommand.RequestType; +import org.apache.cloudstack.storage.resource.NfsSecondaryStorageResource; import org.apache.cloudstack.storage.resource.SecondaryStorageResource; import org.apache.log4j.Logger; @@ -89,7 +90,7 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager StorageLayer _storage; public Map _processors; - private String _nfsVersion; + private Integer _nfsVersion; public class Completion implements DownloadCompleteCallback { private final String jobId; @@ -984,7 +985,7 @@ public boolean configure(String name, Map params) throws Configu String inSystemVM = (String)params.get("secondary.storage.vm"); if (inSystemVM != null && "true".equalsIgnoreCase(inSystemVM)) { s_logger.info("DownloadManager: starting additional services since we are inside system vm"); - _nfsVersion = (String)params.get("nfsVersion"); + _nfsVersion = NfsSecondaryStorageResource.retrieveNfsVersionFromParams(params); startAdditionalServices(); blockOutgoingOnPrivate(); } From 0acd3c12a2c40d4ccf89e4d531cf8de7c9d69d2a Mon Sep 17 00:00:00 2001 From: "Sverrir A. Berg" Date: Tue, 3 May 2016 15:17:59 +0000 Subject: [PATCH 177/203] Convert patchviasocket to python (removes perl dependency for KVM agent) As requested here: https://github.com/apache/cloudstack/pull/1495 No scripts are using perl so that install requirement can be removed. The new scripts are using standard python packages only. Includes extensive unit test. --- .../resource/LibvirtComputingResource.java | 4 +- scripts/installer/windows/client.wxs | 2 +- scripts/vm/hypervisor/kvm/patchviasocket.pl | 58 ------- scripts/vm/hypervisor/kvm/patchviasocket.py | 80 ++++++++++ .../vm/hypervisor/kvm/test_patchviasocket.py | 142 ++++++++++++++++++ 5 files changed, 225 insertions(+), 61 deletions(-) delete mode 100755 scripts/vm/hypervisor/kvm/patchviasocket.pl create mode 100755 scripts/vm/hypervisor/kvm/patchviasocket.py create mode 100755 scripts/vm/hypervisor/kvm/test_patchviasocket.py 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 17b3fd586a..eea16ae953 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -633,9 +633,9 @@ public boolean configure(final String name, final Map params) th throw new ConfigurationException("Unable to find versions.sh"); } - _patchViaSocketPath = Script.findScript(kvmScriptsDir + "/patch/", "patchviasocket.pl"); + _patchViaSocketPath = Script.findScript(kvmScriptsDir + "/patch/", "patchviasocket.py"); if (_patchViaSocketPath == null) { - throw new ConfigurationException("Unable to find patchviasocket.pl"); + throw new ConfigurationException("Unable to find patchviasocket.py"); } _heartBeatPath = Script.findScript(kvmScriptsDir, "kvmheartbeat.sh"); diff --git a/scripts/installer/windows/client.wxs b/scripts/installer/windows/client.wxs index 414d813475..f5aec48bde 100644 --- a/scripts/installer/windows/client.wxs +++ b/scripts/installer/windows/client.wxs @@ -1055,7 +1055,7 @@ - + diff --git a/scripts/vm/hypervisor/kvm/patchviasocket.pl b/scripts/vm/hypervisor/kvm/patchviasocket.pl deleted file mode 100755 index 7bcd245bc3..0000000000 --- a/scripts/vm/hypervisor/kvm/patchviasocket.pl +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/perl -w -# 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. - -############################################################# -# This script connects to the system vm socket and writes the -# authorized_keys and cmdline data to it. The system VM then -# reads it from /dev/vport0p1 in cloud_early_config -############################################################# - -use strict; -use Getopt::Std; -use IO::Socket; -$|=1; - -my $opts = {}; -getopt('pn',$opts); -my $name = $opts->{n}; -my $cmdline = $opts->{p}; -my $sockfile = "/var/lib/libvirt/qemu/$name.agent"; -my $pubkeyfile = "/root/.ssh/id_rsa.pub.cloud"; - -if (! -S $sockfile) { - print "ERROR: $sockfile socket not found\n"; - exit 1; -} - -if (! -f $pubkeyfile) { - print "ERROR: ssh public key not found on host at $pubkeyfile\n"; - exit 1; -} - -open(FILE,$pubkeyfile) or die "ERROR: unable to open $pubkeyfile - $^E"; -my $key = ; -close FILE; - -$cmdline =~ s/%/ /g; -my $msg = "pubkey:" . $key . "\ncmdline:" . $cmdline; - -my $socket = IO::Socket::UNIX->new(Peer=>$sockfile,Type=>SOCK_STREAM) - or die "ERROR: unable to connect to $sockfile - $^E\n"; -print $socket "$msg\n"; -close $socket; - diff --git a/scripts/vm/hypervisor/kvm/patchviasocket.py b/scripts/vm/hypervisor/kvm/patchviasocket.py new file mode 100755 index 0000000000..d9616c9e8b --- /dev/null +++ b/scripts/vm/hypervisor/kvm/patchviasocket.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# 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. + +# +# This script connects to the system vm socket and writes the +# authorized_keys and cmdline data to it. The system VM then +# reads it from /dev/vport0p1 in cloud_early_config +# + +import argparse +import os +import socket + +SOCK_FILE = "/var/lib/libvirt/qemu/{name}.agent" +PUB_KEY_FILE = "/root/.ssh/id_rsa.pub.cloud" +MESSAGE = "pubkey:{key}\ncmdline:{cmdline}\n" + + +def read_pub_key(key_file): + try: + if os.path.isfile(key_file): + with open(key_file, "r") as f: + return f.read() + except IOError: + return None + + +def send_to_socket(sock_file, key_file, cmdline): + pub_key = read_pub_key(key_file) + + if not pub_key: + print("ERROR: ssh public key not found on host at {0}".format(key_file)) + return 1 + + # Keep old substitution from perl code: + cmdline = cmdline.replace("%", " ") + + msg = MESSAGE.format(key=pub_key, cmdline=cmdline) + + if not os.path.exists(sock_file): + print("ERROR: {0} socket not found".format(sock_file)) + return 1 + + try: + s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + s.connect(sock_file) + s.sendall(msg) + s.close() + except IOError as e: + print("ERROR: unable to connect to {0} - {1}".format(sock_file, e.strerror)) + return 1 + + return 0 # Success + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Send configuration to system VM socket") + parser.add_argument("-n", "--name", required=True, help="Name of VM") + parser.add_argument("-p", "--cmdline", required=True, help="Command line") + + arguments = parser.parse_args() + + socket_file = SOCK_FILE.format(name=arguments.name) + + exit(send_to_socket(socket_file, PUB_KEY_FILE, arguments.cmdline)) diff --git a/scripts/vm/hypervisor/kvm/test_patchviasocket.py b/scripts/vm/hypervisor/kvm/test_patchviasocket.py new file mode 100755 index 0000000000..074b159a7a --- /dev/null +++ b/scripts/vm/hypervisor/kvm/test_patchviasocket.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# 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. + +import patchviasocket + +import getpass +import os +import socket +import tempfile +import time +import threading +import unittest + +KEY_DATA = "I luv\nCloudStack\n" +CMD_DATA = "/run/this-for-me --please=TRUE! very%quickly" +NON_EXISTING_FILE = "must-not-exist" + + +def write_key_file(): + tmpfile = tempfile.mktemp(".sck") + with open(tmpfile, "w") as f: + f.write(KEY_DATA) + return tmpfile + + +class SocketThread(threading.Thread): + def __init__(self): + super(SocketThread, self).__init__() + self._data = "" + self._file = tempfile.mktemp(".sck") + self._ready = False + + def data(self): + return self._data + + def file(self): + return self._file + + def wait_until_ready(self): + while not self._ready: + time.sleep(0.050) + + def run(self): + TIMEOUT = 0.314 # Very short time for tests that don't write to socket. + MAX_SIZE = 10 * 1024 + + s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + s.bind(self._file) + s.listen(1) + s.settimeout(TIMEOUT) + try: + self._ready = True + client, address = s.accept() + self._data = client.recv(MAX_SIZE) + client.close() + except socket.timeout: + pass + s.close() + os.remove(self._file) + + +class TestPatchViaSocket(unittest.TestCase): + def setUp(self): + self._key_file = write_key_file() + + self._unreadable = write_key_file() + os.chmod(self._unreadable, 0) + + self.assertFalse(os.path.exists(NON_EXISTING_FILE)) + self.assertNotEqual("root", getpass.getuser(), "must be non-root user (to test access denied errors)") + + def tearDown(self): + os.remove(self._key_file) + os.remove(self._unreadable) + + def test_read_file(self): + pub_key = patchviasocket.read_pub_key(self._key_file) + self.assertEqual(KEY_DATA, pub_key) + + def test_read_file_error(self): + self.assertIsNone(patchviasocket.read_pub_key(NON_EXISTING_FILE)) + self.assertIsNone(patchviasocket.read_pub_key(self._unreadable)) + self.assertIsNone(patchviasocket.read_pub_key("/tmp")) # folder is not a file + + def test_write_to_socket(self): + reader = SocketThread() + reader.start() + reader.wait_until_ready() + self.assertEquals(0, patchviasocket.send_to_socket(reader.file(), self._key_file, CMD_DATA)) + reader.join() + data = reader.data() + self.assertIn(KEY_DATA, data) + self.assertIn(CMD_DATA.replace("%", " "), data) + self.assertNotIn("LUV", data) + self.assertNotIn("very%quickly", data) # Testing substitution + + def test_host_key_error(self): + reader = SocketThread() + reader.start() + reader.wait_until_ready() + self.assertEquals(1, patchviasocket.send_to_socket(reader.file(), NON_EXISTING_FILE, CMD_DATA)) + reader.join() # timeout + + def test_nonexistant_socket_error(self): + reader = SocketThread() + reader.start() + reader.wait_until_ready() + self.assertEquals(1, patchviasocket.send_to_socket(NON_EXISTING_FILE, self._key_file, CMD_DATA)) + reader.join() # timeout + + def test_invalid_socket_error(self): + reader = SocketThread() + reader.start() + reader.wait_until_ready() + self.assertEquals(1, patchviasocket.send_to_socket(self._key_file, self._key_file, CMD_DATA)) + reader.join() # timeout + + def test_access_denied_socket_error(self): + reader = SocketThread() + reader.start() + reader.wait_until_ready() + self.assertEquals(1, patchviasocket.send_to_socket(self._unreadable, self._key_file, CMD_DATA)) + reader.join() # timeout + + +if __name__ == '__main__': + unittest.main() From 751d3552dc3e3514c51fb9038ab91a625470212f Mon Sep 17 00:00:00 2001 From: Sverrir Berg Date: Tue, 17 May 2016 15:06:35 +0000 Subject: [PATCH 178/203] patchviasocket improve error handling more detailed error if host file not found or cannot be opened using mkstemp and mkdtemp for improved security improve resource cleanup in error conditions in unit test --- scripts/vm/hypervisor/kvm/patchviasocket.py | 20 ++++---- .../vm/hypervisor/kvm/test_patchviasocket.py | 46 ++++++++++--------- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/scripts/vm/hypervisor/kvm/patchviasocket.py b/scripts/vm/hypervisor/kvm/patchviasocket.py index d9616c9e8b..c971d5dcc5 100755 --- a/scripts/vm/hypervisor/kvm/patchviasocket.py +++ b/scripts/vm/hypervisor/kvm/patchviasocket.py @@ -31,22 +31,18 @@ MESSAGE = "pubkey:{key}\ncmdline:{cmdline}\n" -def read_pub_key(key_file): - try: - if os.path.isfile(key_file): - with open(key_file, "r") as f: - return f.read() - except IOError: - return None - - def send_to_socket(sock_file, key_file, cmdline): - pub_key = read_pub_key(key_file) - - if not pub_key: + if not os.path.exists(key_file): print("ERROR: ssh public key not found on host at {0}".format(key_file)) return 1 + try: + with open(key_file, "r") as f: + pub_key = f.read() + except IOError as e: + print("ERROR: unable to open {0} - {1}".format(key_file, e.strerror)) + return 1 + # Keep old substitution from perl code: cmdline = cmdline.replace("%", " ") diff --git a/scripts/vm/hypervisor/kvm/test_patchviasocket.py b/scripts/vm/hypervisor/kvm/test_patchviasocket.py index 074b159a7a..6b411d3224 100755 --- a/scripts/vm/hypervisor/kvm/test_patchviasocket.py +++ b/scripts/vm/hypervisor/kvm/test_patchviasocket.py @@ -32,7 +32,7 @@ def write_key_file(): - tmpfile = tempfile.mktemp(".sck") + _, tmpfile = tempfile.mkstemp(".sck") with open(tmpfile, "w") as f: f.write(KEY_DATA) return tmpfile @@ -42,7 +42,8 @@ class SocketThread(threading.Thread): def __init__(self): super(SocketThread, self).__init__() self._data = "" - self._file = tempfile.mktemp(".sck") + self._folder = tempfile.mkdtemp(".sck") + self._file = os.path.join(self._folder, "socket") self._ready = False def data(self): @@ -60,18 +61,21 @@ def run(self): MAX_SIZE = 10 * 1024 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - s.bind(self._file) - s.listen(1) - s.settimeout(TIMEOUT) try: - self._ready = True - client, address = s.accept() - self._data = client.recv(MAX_SIZE) - client.close() - except socket.timeout: - pass - s.close() - os.remove(self._file) + s.bind(self._file) + s.listen(1) + s.settimeout(TIMEOUT) + try: + self._ready = True + client, address = s.accept() + self._data = client.recv(MAX_SIZE) + client.close() + except socket.timeout: + pass + finally: + s.close() + os.remove(self._file) + os.rmdir(self._folder) class TestPatchViaSocket(unittest.TestCase): @@ -88,15 +92,6 @@ def tearDown(self): os.remove(self._key_file) os.remove(self._unreadable) - def test_read_file(self): - pub_key = patchviasocket.read_pub_key(self._key_file) - self.assertEqual(KEY_DATA, pub_key) - - def test_read_file_error(self): - self.assertIsNone(patchviasocket.read_pub_key(NON_EXISTING_FILE)) - self.assertIsNone(patchviasocket.read_pub_key(self._unreadable)) - self.assertIsNone(patchviasocket.read_pub_key("/tmp")) # folder is not a file - def test_write_to_socket(self): reader = SocketThread() reader.start() @@ -116,6 +111,13 @@ def test_host_key_error(self): self.assertEquals(1, patchviasocket.send_to_socket(reader.file(), NON_EXISTING_FILE, CMD_DATA)) reader.join() # timeout + def test_host_key_access_denied(self): + reader = SocketThread() + reader.start() + reader.wait_until_ready() + self.assertEquals(1, patchviasocket.send_to_socket(reader.file(), self._unreadable, CMD_DATA)) + reader.join() # timeout + def test_nonexistant_socket_error(self): reader = SocketThread() reader.start() From a538e78bdb5af7dc2009dfc34f9c00d5f0d7ada7 Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Fri, 20 May 2016 20:56:57 -0600 Subject: [PATCH 179/203] =?UTF-8?q?Removing=20=E2=80=9C=5F=E2=80=9D=20from?= =?UTF-8?q?=20the=20front=20of=20member=20variables=20in=20=E2=80=9CComman?= =?UTF-8?q?d=E2=80=9D=20classes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agent/api/ModifyStoragePoolAnswer.java | 22 ++++++++-------- .../agent/api/ModifyStoragePoolCommand.java | 26 +++++++++---------- .../cloud/agent/api/ModifyTargetsCommand.java | 12 ++++----- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/core/src/com/cloud/agent/api/ModifyStoragePoolAnswer.java b/core/src/com/cloud/agent/api/ModifyStoragePoolAnswer.java index 0e42d9a6d1..6e6dadc67f 100644 --- a/core/src/com/cloud/agent/api/ModifyStoragePoolAnswer.java +++ b/core/src/com/cloud/agent/api/ModifyStoragePoolAnswer.java @@ -24,41 +24,41 @@ import com.cloud.storage.template.TemplateProp; public class ModifyStoragePoolAnswer extends Answer { - private StoragePoolInfo _poolInfo; - private Map _templateInfo; - private String _localDatastoreName; + private StoragePoolInfo poolInfo; + private Map templateInfo; + private String localDatastoreName; public ModifyStoragePoolAnswer(ModifyStoragePoolCommand cmd, long capacityBytes, long availableBytes, Map tInfo) { super(cmd); result = true; - _poolInfo = new StoragePoolInfo(null, cmd.getPool().getHost(), cmd.getPool().getPath(), cmd.getLocalPath(), cmd.getPool().getType(), capacityBytes, availableBytes); + poolInfo = new StoragePoolInfo(null, cmd.getPool().getHost(), cmd.getPool().getPath(), cmd.getLocalPath(), cmd.getPool().getType(), capacityBytes, availableBytes); - _templateInfo = tInfo; + templateInfo = tInfo; } public void setPoolInfo(StoragePoolInfo poolInfo) { - _poolInfo = poolInfo; + this.poolInfo = poolInfo; } public StoragePoolInfo getPoolInfo() { - return _poolInfo; + return poolInfo; } public void setTemplateInfo(Map templateInfo) { - _templateInfo = templateInfo; + this.templateInfo = templateInfo; } public Map getTemplateInfo() { - return _templateInfo; + return templateInfo; } public void setLocalDatastoreName(String localDatastoreName) { - _localDatastoreName = localDatastoreName; + this.localDatastoreName = localDatastoreName; } public String getLocalDatastoreName() { - return _localDatastoreName; + return localDatastoreName; } } diff --git a/core/src/com/cloud/agent/api/ModifyStoragePoolCommand.java b/core/src/com/cloud/agent/api/ModifyStoragePoolCommand.java index 9ec4a278f2..c2ab0ab7f3 100644 --- a/core/src/com/cloud/agent/api/ModifyStoragePoolCommand.java +++ b/core/src/com/cloud/agent/api/ModifyStoragePoolCommand.java @@ -28,15 +28,15 @@ public class ModifyStoragePoolCommand extends Command { public static final String LOCAL_PATH_PREFIX = "/mnt/"; - private boolean _add; - private StorageFilerTO _pool; - private String _localPath; - private String _storagePath; + private boolean add; + private StorageFilerTO pool; + private String localPath; + private String storagePath; public ModifyStoragePoolCommand(boolean add, StoragePool pool, String localPath) { - _add = add; - _pool = new StorageFilerTO(pool); - _localPath = localPath; + this.add = add; + this.pool = new StorageFilerTO(pool); + this.localPath = localPath; } public ModifyStoragePoolCommand(boolean add, StoragePool pool) { @@ -44,27 +44,27 @@ public ModifyStoragePoolCommand(boolean add, StoragePool pool) { } public boolean getAdd() { - return _add; + return add; } public void setPool(StoragePool pool) { - _pool = new StorageFilerTO(pool); + this.pool = new StorageFilerTO(pool); } public StorageFilerTO getPool() { - return _pool; + return pool; } public String getLocalPath() { - return _localPath; + return localPath; } public void setStoragePath(String storagePath) { - _storagePath = storagePath; + this.storagePath = storagePath; } public String getStoragePath() { - return _storagePath; + return storagePath; } @Override diff --git a/core/src/com/cloud/agent/api/ModifyTargetsCommand.java b/core/src/com/cloud/agent/api/ModifyTargetsCommand.java index 721516be2c..424d797495 100644 --- a/core/src/com/cloud/agent/api/ModifyTargetsCommand.java +++ b/core/src/com/cloud/agent/api/ModifyTargetsCommand.java @@ -31,23 +31,23 @@ public class ModifyTargetsCommand extends Command { public static final String MUTUAL_CHAP_NAME = "mutualChapName"; public static final String MUTUAL_CHAP_SECRET = "mutualChapSecret"; - private boolean _add; - private List> _targets; + private boolean add; + private List> targets; public void setAdd(boolean add) { - _add = add; + this.add = add; } public boolean getAdd() { - return _add; + return add; } public void setTargets(List> targets) { - _targets = targets; + this.targets = targets; } public List> getTargets() { - return _targets; + return targets; } @Override From 15da0c2b33bd52eff60d96fdd42f49d61481b5aa Mon Sep 17 00:00:00 2001 From: Sverrir Berg Date: Fri, 20 May 2016 15:43:55 +0000 Subject: [PATCH 180/203] Revert "Add perl-modules as install dependency for cloudstack-agent" perl-modules are no longer required. See: https://github.com/apache/cloudstack/pull/1533 This reverts commit 64b72a5c5a410f41bd869cc9d40807d888e05055. --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 728f6ff530..6452c03c5d 100644 --- a/debian/control +++ b/debian/control @@ -22,7 +22,7 @@ Description: CloudStack server library Package: cloudstack-agent Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, openjdk-8-jre-headless | openjdk-7-jre-headless, cloudstack-common (= ${source:Version}), lsb-base (>= 4.0), libcommons-daemon-java, openssh-client, qemu-kvm (>= 1.0), libvirt-bin (>= 0.9.8), uuid-runtime, iproute, ebtables, vlan, jsvc, ipset, python-libvirt, ethtool, iptables, perl-modules +Depends: ${misc:Depends}, ${python:Depends}, openjdk-8-jre-headless | openjdk-7-jre-headless, cloudstack-common (= ${source:Version}), lsb-base (>= 4.0), libcommons-daemon-java, openssh-client, qemu-kvm (>= 1.0), libvirt-bin (>= 0.9.8), uuid-runtime, iproute, ebtables, vlan, jsvc, ipset, python-libvirt, ethtool, iptables Conflicts: cloud-agent, cloud-agent-libs, cloud-agent-deps, cloud-agent-scripts Description: CloudStack agent The CloudStack agent is in charge of managing shared computing resources in From c12d83601d5203ffee461901f92f21f3337769c3 Mon Sep 17 00:00:00 2001 From: Kishan Kavala Date: Mon, 23 May 2016 15:23:23 +0530 Subject: [PATCH 181/203] Bug-ID: CLOUDSTACK-8870: Skip external device usage collection if no external devices exist --- engine/schema/src/com/cloud/host/dao/HostDao.java | 2 ++ .../schema/src/com/cloud/host/dao/HostDaoImpl.java | 7 +++++++ .../network/ExternalDeviceUsageManagerImpl.java | 11 ++++++++++- .../ExternalLoadBalancerDeviceManagerImplTest.java | 13 +++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/engine/schema/src/com/cloud/host/dao/HostDao.java b/engine/schema/src/com/cloud/host/dao/HostDao.java index 3cfdc94af8..88a354725a 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDao.java +++ b/engine/schema/src/com/cloud/host/dao/HostDao.java @@ -97,4 +97,6 @@ public interface HostDao extends GenericDao, StateDao listAllHostsByType(Host.Type type); HostVO findByPublicIp(String publicIp); + + List listByType(Type type); } diff --git a/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java b/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java index 54133b90d0..46f8a4da2b 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java +++ b/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java @@ -1137,4 +1137,11 @@ public List listAllHostsByType(Host.Type type) { return listBy(sc); } + + @Override + public List listByType(Host.Type type) { + SearchCriteria sc = TypeSearch.create(); + sc.setParameters("type", type); + return listBy(sc); + } } diff --git a/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java b/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java index 59b398f5b5..200b279bf9 100644 --- a/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java +++ b/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java @@ -340,6 +340,15 @@ public ExternalDeviceNetworkUsageTask() { @Override protected void runInContext() { + + // Check if there are any external devices + // Skip external device usage collection if none exist + + if(_hostDao.listByType(Host.Type.ExternalFirewall).isEmpty() && _hostDao.listByType(Host.Type.ExternalLoadBalancer).isEmpty()){ + s_logger.debug("External devices are not used. Skipping external device usage collection"); + return; + } + GlobalLock scanLock = GlobalLock.getInternLock("ExternalDeviceNetworkUsageManagerImpl"); try { if (scanLock.lock(20)) { @@ -356,7 +365,7 @@ protected void runInContext() { } } - private void runExternalDeviceNetworkUsageTask() { + protected void runExternalDeviceNetworkUsageTask() { s_logger.debug("External devices stats collector is running..."); for (DataCenterVO zone : _dcDao.listAll()) { diff --git a/server/test/com/cloud/network/ExternalLoadBalancerDeviceManagerImplTest.java b/server/test/com/cloud/network/ExternalLoadBalancerDeviceManagerImplTest.java index 046bdb6475..dbc31ba6ef 100644 --- a/server/test/com/cloud/network/ExternalLoadBalancerDeviceManagerImplTest.java +++ b/server/test/com/cloud/network/ExternalLoadBalancerDeviceManagerImplTest.java @@ -20,11 +20,13 @@ import java.lang.reflect.Field; import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import javax.inject.Inject; +import com.cloud.host.Host; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.junit.Assert; @@ -207,4 +209,15 @@ private void setupLBHealthChecksMocks() throws URISyntaxException { HostVO hostVo = Mockito.mock(HostVO.class); Mockito.when(_hostDao.findById(Mockito.anyLong())).thenReturn(hostVo); } + + + @Test + public void testUsageTask() { + ExternalDeviceUsageManagerImpl.ExternalDeviceNetworkUsageTask usageTask = Mockito + .mock(ExternalDeviceUsageManagerImpl.ExternalDeviceNetworkUsageTask.class); + Mockito.when(_hostDao.listByType(Host.Type.ExternalFirewall)).thenReturn(new ArrayList()); + Mockito.when(_hostDao.listByType(Host.Type.ExternalLoadBalancer)).thenReturn(new ArrayList()); + usageTask.runInContext(); + Mockito.verify(usageTask, Mockito.times(0)).runExternalDeviceNetworkUsageTask(); + } } From 02c5d44f0b431ea1902ec1aed7167e932930d3b3 Mon Sep 17 00:00:00 2001 From: Nick Livens Date: Mon, 23 May 2016 15:50:28 +0200 Subject: [PATCH 182/203] Dynamic loading of DB driver + support for other DB providers --- build/replace.properties | 1 + client/tomcatconf/db.properties.in | 3 ++ .../snapshot/test/resources/db.properties | 5 +++ .../com/cloud/utils/db/TransactionLegacy.java | 44 ++++++++++++++----- framework/db/test/db.properties | 5 +++ framework/jobs/test/resources/db.properties | 5 +++ packaging/centos63/replace.properties | 1 + packaging/centos7/replace.properties | 1 + packaging/centos7/tomcat7/db.properties | 5 +++ packaging/debian/replace.properties | 1 + packaging/fedora20/replace.properties | 1 + packaging/fedora21/replace.properties | 1 + .../globodns/test/resources/db.properties | 5 +++ .../test/resources/db.properties | 5 +++ server/test/resources/db.properties | 5 +++ .../iam/plugin/test/resources/db.properties | 5 +++ .../iam/server/test/resources/db.properties | 5 +++ tools/devcloud-kvm/pom.xml | 2 +- tools/devcloud/pom.xml | 2 +- tools/devcloud4/pom.xml | 2 +- usage/conf/db.properties.in | 1 + usage/test/resources/db.properties | 5 +++ utils/conf/db.properties | 5 +++ 23 files changed, 100 insertions(+), 15 deletions(-) diff --git a/build/replace.properties b/build/replace.properties index 3983b1031c..9e0b65c690 100644 --- a/build/replace.properties +++ b/build/replace.properties @@ -21,6 +21,7 @@ DBROOTPW= MSLOG=vmops.log APISERVERLOG=api.log DBHOST=localhost +DBDRIVER=jdbc:mysql AGENTLOGDIR=logs AGENTLOG=logs/agent.log MSMNTDIR=/mnt diff --git a/client/tomcatconf/db.properties.in b/client/tomcatconf/db.properties.in index 74b926306e..1c2b55f3b8 100644 --- a/client/tomcatconf/db.properties.in +++ b/client/tomcatconf/db.properties.in @@ -25,6 +25,7 @@ region.id=1 db.cloud.username=@DBUSER@ db.cloud.password=@DBPW@ db.cloud.host=@DBHOST@ +db.cloud.driver=@DBDRIVER@ db.cloud.port=3306 db.cloud.name=cloud @@ -56,6 +57,7 @@ db.cloud.encrypt.secret= db.usage.username=@DBUSER@ db.usage.password=@DBPW@ db.usage.host=@DBHOST@ +db.usage.driver=@DBDRIVER@ db.usage.port=3306 db.usage.name=cloud_usage @@ -69,6 +71,7 @@ db.usage.url.params= db.simulator.username=@DBUSER@ db.simulator.password=@DBPW@ db.simulator.host=@DBHOST@ +db.simulator.driver=@DBDRIVER@ db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/engine/storage/snapshot/test/resources/db.properties b/engine/storage/snapshot/test/resources/db.properties index a458b2306f..e8e94121fe 100644 --- a/engine/storage/snapshot/test/resources/db.properties +++ b/engine/storage/snapshot/test/resources/db.properties @@ -26,6 +26,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -46,6 +47,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -59,6 +62,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/framework/db/src/com/cloud/utils/db/TransactionLegacy.java b/framework/db/src/com/cloud/utils/db/TransactionLegacy.java index af834ca115..523162e222 100644 --- a/framework/db/src/com/cloud/utils/db/TransactionLegacy.java +++ b/framework/db/src/com/cloud/utils/db/TransactionLegacy.java @@ -20,6 +20,8 @@ import java.io.File; import java.io.IOException; import java.sql.Connection; +import java.sql.Driver; +import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -1024,6 +1026,7 @@ public static void initDataSource(Properties dbProps) { final String cloudUsername = dbProps.getProperty("db.cloud.username"); final String cloudPassword = dbProps.getProperty("db.cloud.password"); final String cloudHost = dbProps.getProperty("db.cloud.host"); + final String cloudDriver = dbProps.getProperty("db.cloud.driver"); final int cloudPort = Integer.parseInt(dbProps.getProperty("db.cloud.port")); final String cloudDbName = dbProps.getProperty("db.cloud.name"); final boolean cloudAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.cloud.autoReconnect")); @@ -1072,10 +1075,12 @@ public static void initDataSource(Properties dbProps) { new GenericObjectPool(null, cloudMaxActive, GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION, cloudMaxWait, cloudMaxIdle, cloudTestOnBorrow, false, cloudTimeBtwEvictionRunsMillis, 1, cloudMinEvcitableIdleTimeMillis, cloudTestWhileIdle); - final ConnectionFactory cloudConnectionFactory = - new DriverManagerConnectionFactory("jdbc:mysql://" + cloudHost + (s_dbHAEnabled ? "," + cloudSlaves : "") + ":" + cloudPort + "/" + cloudDbName + - "?autoReconnect=" + cloudAutoReconnect + (url != null ? "&" + url : "") + (useSSL ? "&useSSL=true" : "") + - (s_dbHAEnabled ? "&" + cloudDbHAParams : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : ""), cloudUsername, cloudPassword); + final String cloudConnectionUri = cloudDriver + "://" + cloudHost + (s_dbHAEnabled ? "," + cloudSlaves : "") + ":" + cloudPort + "/" + cloudDbName + + "?autoReconnect=" + cloudAutoReconnect + (url != null ? "&" + url : "") + (useSSL ? "&useSSL=true" : "") + + (s_dbHAEnabled ? "&" + cloudDbHAParams : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : ""); + loadDbDriver(cloudConnectionUri); + + final ConnectionFactory cloudConnectionFactory = new DriverManagerConnectionFactory(cloudConnectionUri, cloudUsername, cloudPassword); final KeyedObjectPoolFactory poolableObjFactory = (cloudPoolPreparedStatements ? new StackKeyedObjectPoolFactory() : null); @@ -1092,6 +1097,7 @@ public static void initDataSource(Properties dbProps) { final String usageUsername = dbProps.getProperty("db.usage.username"); final String usagePassword = dbProps.getProperty("db.usage.password"); final String usageHost = dbProps.getProperty("db.usage.host"); + final String usageDriver = dbProps.getProperty("db.usage.driver"); final int usagePort = Integer.parseInt(dbProps.getProperty("db.usage.port")); final String usageDbName = dbProps.getProperty("db.usage.name"); final boolean usageAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.usage.autoReconnect")); @@ -1100,11 +1106,12 @@ public static void initDataSource(Properties dbProps) { final GenericObjectPool usageConnectionPool = new GenericObjectPool(null, usageMaxActive, GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION, usageMaxWait, usageMaxIdle); - final ConnectionFactory usageConnectionFactory = - new DriverManagerConnectionFactory("jdbc:mysql://" + usageHost + (s_dbHAEnabled ? "," + dbProps.getProperty("db.cloud.slaves") : "") + ":" + usagePort + - "/" + usageDbName + "?autoReconnect=" + usageAutoReconnect + (usageUrl != null ? "&" + usageUrl : "") + - (s_dbHAEnabled ? "&" + getDBHAParams("usage", dbProps) : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : ""), usageUsername, - usagePassword); + final String usageConnectionUri = usageDriver + "://" + usageHost + (s_dbHAEnabled ? "," + dbProps.getProperty("db.cloud.slaves") : "") + ":" + usagePort + + "/" + usageDbName + "?autoReconnect=" + usageAutoReconnect + (usageUrl != null ? "&" + usageUrl : "") + + (s_dbHAEnabled ? "&" + getDBHAParams("usage", dbProps) : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : ""); + loadDbDriver(usageConnectionUri); + + final ConnectionFactory usageConnectionFactory = new DriverManagerConnectionFactory(usageConnectionUri, usageUsername, usagePassword); final PoolableConnectionFactory usagePoolableConnectionFactory = new PoolableConnectionFactory(usageConnectionFactory, usageConnectionPool, new StackKeyedObjectPoolFactory(), null, false, false); @@ -1120,6 +1127,7 @@ public static void initDataSource(Properties dbProps) { final String simulatorUsername = dbProps.getProperty("db.simulator.username"); final String simulatorPassword = dbProps.getProperty("db.simulator.password"); final String simulatorHost = dbProps.getProperty("db.simulator.host"); + final String simulatorDriver = dbProps.getProperty("db.simulator.driver"); final int simulatorPort = Integer.parseInt(dbProps.getProperty("db.simulator.port")); final String simulatorDbName = dbProps.getProperty("db.simulator.name"); final boolean simulatorAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.simulator.autoReconnect")); @@ -1127,9 +1135,11 @@ public static void initDataSource(Properties dbProps) { final GenericObjectPool simulatorConnectionPool = new GenericObjectPool(null, simulatorMaxActive, GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION, simulatorMaxWait, simulatorMaxIdle); - final ConnectionFactory simulatorConnectionFactory = - new DriverManagerConnectionFactory("jdbc:mysql://" + simulatorHost + ":" + simulatorPort + "/" + simulatorDbName + "?autoReconnect=" + - simulatorAutoReconnect, simulatorUsername, simulatorPassword); + final String simulatorConnectionUri = simulatorDriver + "://" + simulatorHost + ":" + simulatorPort + "/" + simulatorDbName + "?autoReconnect=" + + simulatorAutoReconnect; + loadDbDriver(simulatorConnectionUri); + + final ConnectionFactory simulatorConnectionFactory = new DriverManagerConnectionFactory(simulatorConnectionUri, simulatorUsername, simulatorPassword); final PoolableConnectionFactory simulatorPoolableConnectionFactory = new PoolableConnectionFactory(simulatorConnectionFactory, simulatorConnectionPool, new StackKeyedObjectPoolFactory(), null, false, false); @@ -1147,6 +1157,16 @@ public static void initDataSource(Properties dbProps) { } } + private static void loadDbDriver(String dbConnectionUri) { + try { + Driver driver = DriverManager.getDriver(dbConnectionUri); + s_logger.debug("Successfully loaded DB driver " + driver.getClass().getName() + " for connection " + dbConnectionUri); + } catch (SQLException e) { + s_logger.error("Failed to load DB driver for connection " + dbConnectionUri, e); + throw new CloudRuntimeException("Failed to load DB driver for connection " + dbConnectionUri, e); + } + } + private static String getDBHAParams(String dbName, Properties dbProps) { StringBuilder sb = new StringBuilder(); sb.append("failOverReadOnly=" + dbProps.getProperty("db." + dbName + ".failOverReadOnly")); diff --git a/framework/db/test/db.properties b/framework/db/test/db.properties index 49fd68aa93..c7aeaad264 100644 --- a/framework/db/test/db.properties +++ b/framework/db/test/db.properties @@ -29,6 +29,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -49,6 +50,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -62,6 +65,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/framework/jobs/test/resources/db.properties b/framework/jobs/test/resources/db.properties index 9d250ba8b0..235de85869 100644 --- a/framework/jobs/test/resources/db.properties +++ b/framework/jobs/test/resources/db.properties @@ -22,6 +22,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -42,6 +43,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -55,6 +58,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/packaging/centos63/replace.properties b/packaging/centos63/replace.properties index 6a3101f9b5..bdf6e223b5 100644 --- a/packaging/centos63/replace.properties +++ b/packaging/centos63/replace.properties @@ -21,6 +21,7 @@ DBROOTPW= MSLOG=vmops.log APISERVERLOG=api.log DBHOST=localhost +DBDRIVER=jdbc:mysql COMPONENTS-SPEC=components-premium.xml REMOTEHOST=localhost AGENTCLASSPATH= diff --git a/packaging/centos7/replace.properties b/packaging/centos7/replace.properties index aec359e2e6..0b0f2cc12d 100644 --- a/packaging/centos7/replace.properties +++ b/packaging/centos7/replace.properties @@ -21,6 +21,7 @@ DBROOTPW= MSLOG=vmops.log APISERVERLOG=api.log DBHOST=localhost +DBDRIVER=jdbc:mysql COMPONENTS-SPEC=components-premium.xml REMOTEHOST=localhost AGENTCLASSPATH= diff --git a/packaging/centos7/tomcat7/db.properties b/packaging/centos7/tomcat7/db.properties index 36ade8ce86..6161f3a6e2 100644 --- a/packaging/centos7/tomcat7/db.properties +++ b/packaging/centos7/tomcat7/db.properties @@ -25,6 +25,7 @@ region.id=1 db.cloud.username=cloud db.cloud.password=ENC(vlzQjmqOV4s5q7n+S1OMbA==) db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -56,6 +57,8 @@ db.cloud.encrypt.secret=ENC(zaGuSF5a4KyWayn2t0yyjDa0HjdToVtZ) db.usage.password=ENC(cQEcN5aVucSYK+WUkPjDcw==) db.usage.username=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -69,6 +72,8 @@ db.usage.url.params= db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/packaging/debian/replace.properties b/packaging/debian/replace.properties index 6d55a98820..e1d28bb954 100644 --- a/packaging/debian/replace.properties +++ b/packaging/debian/replace.properties @@ -21,6 +21,7 @@ DBROOTPW= MSLOG=vmops.log APISERVERLOG=api.log DBHOST=localhost +DBDRIVER=jdbc:mysql COMPONENTS-SPEC=components-premium.xml REMOTEHOST=localhost AGENTCLASSPATH= diff --git a/packaging/fedora20/replace.properties b/packaging/fedora20/replace.properties index 6a3101f9b5..bdf6e223b5 100644 --- a/packaging/fedora20/replace.properties +++ b/packaging/fedora20/replace.properties @@ -21,6 +21,7 @@ DBROOTPW= MSLOG=vmops.log APISERVERLOG=api.log DBHOST=localhost +DBDRIVER=jdbc:mysql COMPONENTS-SPEC=components-premium.xml REMOTEHOST=localhost AGENTCLASSPATH= diff --git a/packaging/fedora21/replace.properties b/packaging/fedora21/replace.properties index 6a3101f9b5..bdf6e223b5 100644 --- a/packaging/fedora21/replace.properties +++ b/packaging/fedora21/replace.properties @@ -21,6 +21,7 @@ DBROOTPW= MSLOG=vmops.log APISERVERLOG=api.log DBHOST=localhost +DBDRIVER=jdbc:mysql COMPONENTS-SPEC=components-premium.xml REMOTEHOST=localhost AGENTCLASSPATH= diff --git a/plugins/network-elements/globodns/test/resources/db.properties b/plugins/network-elements/globodns/test/resources/db.properties index 6ebe10af5f..6e38a4a6f3 100644 --- a/plugins/network-elements/globodns/test/resources/db.properties +++ b/plugins/network-elements/globodns/test/resources/db.properties @@ -27,6 +27,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -47,6 +48,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -60,6 +63,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/plugins/network-elements/juniper-contrail/test/resources/db.properties b/plugins/network-elements/juniper-contrail/test/resources/db.properties index 9d250ba8b0..235de85869 100644 --- a/plugins/network-elements/juniper-contrail/test/resources/db.properties +++ b/plugins/network-elements/juniper-contrail/test/resources/db.properties @@ -22,6 +22,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -42,6 +43,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -55,6 +58,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/server/test/resources/db.properties b/server/test/resources/db.properties index 45baf4cf97..e9355a3db3 100644 --- a/server/test/resources/db.properties +++ b/server/test/resources/db.properties @@ -26,6 +26,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -46,6 +47,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -59,6 +62,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/services/iam/plugin/test/resources/db.properties b/services/iam/plugin/test/resources/db.properties index faa577c982..a672d63f79 100644 --- a/services/iam/plugin/test/resources/db.properties +++ b/services/iam/plugin/test/resources/db.properties @@ -27,6 +27,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -47,6 +48,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -60,6 +63,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/services/iam/server/test/resources/db.properties b/services/iam/server/test/resources/db.properties index faa577c982..a672d63f79 100644 --- a/services/iam/server/test/resources/db.properties +++ b/services/iam/server/test/resources/db.properties @@ -27,6 +27,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -47,6 +48,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -60,6 +63,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/tools/devcloud-kvm/pom.xml b/tools/devcloud-kvm/pom.xml index a71968e95d..b0e12341c3 100644 --- a/tools/devcloud-kvm/pom.xml +++ b/tools/devcloud-kvm/pom.xml @@ -83,7 +83,7 @@ org.gjt.mm.mysql.Driver - jdbc:mysql://${db.cloud.host}:${db.cloud.port}/cloud + ${db.cloud.driver}://${db.cloud.host}:${db.cloud.port}/cloud ${db.cloud.username} ${db.cloud.password} diff --git a/tools/devcloud/pom.xml b/tools/devcloud/pom.xml index e8bcaebe60..8644ff45a5 100644 --- a/tools/devcloud/pom.xml +++ b/tools/devcloud/pom.xml @@ -83,7 +83,7 @@ org.gjt.mm.mysql.Driver - jdbc:mysql://${db.cloud.host}:${db.cloud.port}/cloud + ${db.cloud.driver}://${db.cloud.host}:${db.cloud.port}/cloud ${db.cloud.username} ${db.cloud.password} diff --git a/tools/devcloud4/pom.xml b/tools/devcloud4/pom.xml index 47493931ba..e3cee0c2b8 100644 --- a/tools/devcloud4/pom.xml +++ b/tools/devcloud4/pom.xml @@ -83,7 +83,7 @@ org.gjt.mm.mysql.Driver - jdbc:mysql://${db.cloud.host}:${db.cloud.port}/cloud + ${db.cloud.driver}://${db.cloud.host}:${db.cloud.port}/cloud ${db.cloud.username} ${db.cloud.password} diff --git a/usage/conf/db.properties.in b/usage/conf/db.properties.in index 0dd49ede8b..35a40def7b 100644 --- a/usage/conf/db.properties.in +++ b/usage/conf/db.properties.in @@ -19,6 +19,7 @@ db.usage.username=@DBUSER@ db.usage.password=@DBPW@ db.usage.host=@DBHOST@ +db.usage.driver=@DBDRIVER@ db.usage.port=3306 db.usage.name=cloud_usage diff --git a/usage/test/resources/db.properties b/usage/test/resources/db.properties index a458b2306f..e8e94121fe 100644 --- a/usage/test/resources/db.properties +++ b/usage/test/resources/db.properties @@ -26,6 +26,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -46,6 +47,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -59,6 +62,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/utils/conf/db.properties b/utils/conf/db.properties index 49fd68aa93..c7aeaad264 100644 --- a/utils/conf/db.properties +++ b/utils/conf/db.properties @@ -29,6 +29,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -49,6 +50,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -62,6 +65,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 From 58772934344d2b0316ddb479a977b15b6e97c015 Mon Sep 17 00:00:00 2001 From: Loic Lambiel Date: Fri, 15 May 2015 15:15:26 +0200 Subject: [PATCH 183/203] CLOUDSTACK-9203 security group update on running instance cherry-picked from a exoscale internal fix: Implement security group move on updateVM API call Prevent security group update while instance is running Conflicts: api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java server/src/com/cloud/vm/UserVmManager.java server/src/com/cloud/vm/UserVmManagerImpl.java --- .../api/command/user/vm/UpdateVMCmd.java | 16 ++++++- server/src/com/cloud/vm/UserVmManager.java | 2 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 46 +++++++++++++++++-- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java index 458122d6d7..9a8bdc2aa3 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java @@ -29,6 +29,7 @@ import org.apache.cloudstack.api.ResponseObject.ResponseView; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.GuestOSResponse; +import org.apache.cloudstack.api.response.SecurityGroupResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.context.CallContext; @@ -39,6 +40,7 @@ import com.cloud.vm.VirtualMachine; import java.util.Collection; +import java.util.List; import java.util.Map; @APICommand(name = "updateVirtualMachine", description="Updates properties of a virtual machine. The VM has to be stopped and restarted for the " + @@ -96,6 +98,14 @@ public class UpdateVMCmd extends BaseCustomIdCmd { @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, description = "Details in key/value pairs.") protected Map details; + @ACL + @Parameter(name = ApiConstants.SECURITY_GROUP_IDS, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = SecurityGroupResponse.class, + description = "list of security group ids to be applied on the virtual machine.") + private List securityGroupIdList; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -145,7 +155,11 @@ public Map getDetails() { return (Map) (paramsCollection.toArray())[0]; } -///////////////////////////////////////////////////// + public List getSecurityGroupIdList() { + return securityGroupIdList; + } + + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/server/src/com/cloud/vm/UserVmManager.java b/server/src/com/cloud/vm/UserVmManager.java index fe0e98c8cd..411fd9b669 100644 --- a/server/src/com/cloud/vm/UserVmManager.java +++ b/server/src/com/cloud/vm/UserVmManager.java @@ -103,7 +103,7 @@ boolean upgradeVirtualMachine(Long id, Long serviceOfferingId, Map securityGroupIdList) throws ResourceUnavailableException, InsufficientCapacityException; //the validateCustomParameters, save and remove CustomOfferingDetils functions can be removed from the interface once we can //find a common place for all the scaling and upgrading code of both user and systemvms. diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 83ee2489c6..a253fdd6f8 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2289,6 +2289,7 @@ public UserVm updateVirtualMachine(UpdateVMCmd cmd) throws ResourceUnavailableEx String hostName = cmd.getHostName(); Map details = cmd.getDetails(); Account caller = CallContext.current().getCallingAccount(); + List securityGroupIdList = cmd.getSecurityGroupIdList(); // Input validation and permission checks UserVmVO vmInstance = _vmDao.findById(id); @@ -2339,7 +2340,7 @@ public UserVm updateVirtualMachine(UpdateVMCmd cmd) throws ResourceUnavailableEx } return updateVirtualMachine(id, displayName, group, ha, isDisplayVm, osTypeId, userData, isDynamicallyScalable, - cmd.getHttpMethod(), cmd.getCustomId(), hostName, cmd.getInstanceName()); + cmd.getHttpMethod(), cmd.getCustomId(), hostName, cmd.getInstanceName(), securityGroupIdList); } private void saveUsageEvent(UserVmVO vm) { @@ -2389,10 +2390,11 @@ private void generateNetworkUsageForVm(VirtualMachine vm, boolean isDisplay, Str @Override public UserVm updateVirtualMachine(long id, String displayName, String group, Boolean ha, Boolean isDisplayVmEnabled, Long osTypeId, String userData, - Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName) throws ResourceUnavailableException, InsufficientCapacityException { + Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName, List securityGroupIdList) + throws ResourceUnavailableException, InsufficientCapacityException { UserVmVO vm = _vmDao.findById(id); if (vm == null) { - throw new CloudRuntimeException("Unable to find virual machine with id " + id); + throw new CloudRuntimeException("Unable to find virtual machine with id " + id); } if(instanceName != null){ @@ -2451,6 +2453,44 @@ public UserVm updateVirtualMachine(long id, String displayName, String group, Bo isDynamicallyScalable = vm.isDynamicallyScalable(); } + boolean isVMware = (vm.getHypervisorType() == HypervisorType.VMware); + + if (securityGroupIdList != null && isVMware) { + throw new InvalidParameterValueException("Security group feature is not supported for vmWare hypervisor"); + } else { + // Get default guest network in Basic zone + Network defaultNetwork = null; + try { + DataCenterVO zone = _dcDao.findById(vm.getDataCenterId()); + + if (zone.getNetworkType() == NetworkType.Basic) { + // Get default guest network in Basic zone + defaultNetwork = _networkModel.getExclusiveGuestNetwork(zone.getId()); + } else if (zone.isSecurityGroupEnabled()) { + NicVO defaultNic = _nicDao.findDefaultNicForVM(vm.getId()); + if (defaultNic != null) { + defaultNetwork = _networkDao.findById(defaultNic.getNetworkId()); + } + } + } catch (InvalidParameterValueException e) { + if(s_logger.isDebugEnabled()) { + s_logger.debug(e.getMessage(),e); + } + defaultNetwork = _networkModel.getDefaultNetworkForVm(id); + } + + if (securityGroupIdList != null && _networkModel.isSecurityGroupSupportedInNetwork(defaultNetwork) && _networkModel.canAddDefaultSecurityGroup()) { + if (vm.getState() == State.Stopped) { + // Remove instance from security groups + _securityGroupMgr.removeInstanceFromGroups(id); + // Add instance in provided groups + _securityGroupMgr.addInstanceToGroups(id, securityGroupIdList); + } else { + throw new InvalidParameterValueException("Virtual machine must be stopped prior to update security groups "); + } + } + } + if (hostName != null) { // Check is hostName is RFC compliant checkNameForRFCCompliance(hostName); From 78cd64a6c21462c8d6e728890b0d2e82e4498c2c Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Wed, 30 Dec 2015 13:13:38 +0100 Subject: [PATCH 184/203] CLOUDSTACK-9203 refactorred DeployVM code to be used by UpdateVM as well Conflicts: api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java --- .../api/command/user/vm/DeployVMCmd.java | 212 ++++-------------- .../command/user/vm/SecurityGroupAction.java | 25 +++ .../api/command/user/vm/UpdateVMCmd.java | 26 ++- .../src/com/cloud/vm/UserVmManagerImpl.java | 172 +++++++++++++- 4 files changed, 252 insertions(+), 183 deletions(-) create mode 100644 api/src/org/apache/cloudstack/api/command/user/vm/SecurityGroupAction.java diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index d71638f16d..da0ce2a2ff 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -16,25 +16,14 @@ // under the License. package org.apache.cloudstack.api.command.user.vm; -import com.cloud.dc.DataCenter; -import com.cloud.dc.DataCenter.NetworkType; -import com.cloud.event.EventTypes; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InsufficientServerCapacityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.network.Network; -import com.cloud.network.Network.IpAddresses; -import com.cloud.offering.DiskOffering; -import com.cloud.offering.ServiceOffering; -import com.cloud.template.VirtualMachineTemplate; -import com.cloud.user.Account; -import com.cloud.uservm.UserVm; -import com.cloud.utils.net.NetUtils; -import com.cloud.vm.VirtualMachine; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.ACL; @@ -59,17 +48,23 @@ import org.apache.cloudstack.context.CallContext; import org.apache.log4j.Logger; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.Network; +import com.cloud.network.Network.IpAddresses; +import com.cloud.uservm.UserVm; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.VirtualMachine; @APICommand(name = "deployVirtualMachine", description = "Creates and automatically starts a virtual machine based on a service offering, disk offering, and template.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = true) -public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd { +public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityGroupAction { public static final Logger s_logger = Logger.getLogger(DeployVMCmd.class.getName()); private static final String s_name = "deployvirtualmachineresponse"; @@ -257,26 +252,12 @@ public boolean isDisplay() { return displayVm; } - public List getSecurityGroupIdList() { - if (securityGroupNameList != null && securityGroupIdList != null) { - throw new InvalidParameterValueException("securitygroupids parameter is mutually exclusive with securitygroupnames parameter"); - } + public List getSecurityGroupNameList() { + return securityGroupNameList; + } - //transform group names to ids here - if (securityGroupNameList != null) { - List securityGroupIds = new ArrayList(); - for (String groupName : securityGroupNameList) { - Long groupId = _responseGenerator.getSecurityGroupId(groupName, getEntityOwnerId()); - if (groupId == null) { - throw new InvalidParameterValueException("Unable to find group by name " + groupName); - } else { - securityGroupIds.add(groupId); - } - } - return securityGroupIds; - } else { - return securityGroupIdList; - } + public List getSecurityGroupIdList() { + return securityGroupIdList; } public Long getServiceOfferingId() { @@ -328,7 +309,7 @@ public boolean getStartVm() { return startVm == null ? true : startVm; } - private Map getIpToNetworkMap() { + public Map getIpToNetworkMap() { if ((networkIds != null || ipAddress != null || getIp6Address() != null) && ipToNetworkList != null) { throw new InvalidParameterValueException("NetworkIds and ipAddress can't be specified along with ipToNetworkMap parameter"); } @@ -363,6 +344,10 @@ private Map getIpToNetworkMap() { return ipToNetworkMap; } + public String getIpAddress() { + return ipAddress; + } + public String getIp6Address() { if (ip6Address == null) { return null; @@ -392,6 +377,11 @@ public List getAffinityGroupIdList() { } } + public String getKeyboard() { + // TODO Auto-generated method stub + return keyboard; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -478,137 +468,11 @@ public void execute() { } } - // this is an opportunity to verify that parameters that came in via the Details Map are OK - // for example, minIops and maxIops should either both be specified or neither be specified and, - // if specified, minIops should be <= maxIops - private void verifyDetails() { - Map map = getDetails(); - - if (map != null) { - String minIops = (String)map.get("minIops"); - String maxIops = (String)map.get("maxIops"); - - verifyMinAndMaxIops(minIops, maxIops); - - minIops = (String)map.get("minIopsDo"); - maxIops = (String)map.get("maxIopsDo"); - - verifyMinAndMaxIops(minIops, maxIops); - } - } - - private void verifyMinAndMaxIops(String minIops, String maxIops) { - if ((minIops != null && maxIops == null) || (minIops == null && maxIops != null)) { - throw new InvalidParameterValueException("Either 'Min IOPS' and 'Max IOPS' must both be specified or neither be specified."); - } - - long lMinIops; - - try { - if (minIops != null) { - lMinIops = Long.parseLong(minIops); - } - else { - lMinIops = 0; - } - } - catch (NumberFormatException ex) { - throw new InvalidParameterValueException("'Min IOPS' must be a whole number."); - } - - long lMaxIops; - - try { - if (maxIops != null) { - lMaxIops = Long.parseLong(maxIops); - } - else { - lMaxIops = 0; - } - } - catch (NumberFormatException ex) { - throw new InvalidParameterValueException("'Max IOPS' must be a whole number."); - } - - if (lMinIops > lMaxIops) { - throw new InvalidParameterValueException("'Min IOPS' must be less than or equal to 'Max IOPS'."); - } - } @Override public void create() throws ResourceAllocationException { try { - //Verify that all objects exist before passing them to the service - Account owner = _accountService.getActiveAccountById(getEntityOwnerId()); - - verifyDetails(); - - DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId); - if (zone == null) { - throw new InvalidParameterValueException("Unable to find zone by id=" + zoneId); - } - - ServiceOffering serviceOffering = _entityMgr.findById(ServiceOffering.class, serviceOfferingId); - if (serviceOffering == null) { - throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId); - } - - if(!serviceOffering.isDynamic()) { - for(String detail: getDetails().keySet()) { - if(detail.equalsIgnoreCase("cpuNumber") || detail.equalsIgnoreCase("cpuSpeed") || detail.equalsIgnoreCase("memory")) { - throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering"); - } - } - } - - VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId); - // Make sure a valid template ID was specified - if (template == null) { - throw new InvalidParameterValueException("Unable to find the template " + templateId); - } - - DiskOffering diskOffering = null; - if (diskOfferingId != null) { - diskOffering = _entityMgr.findById(DiskOffering.class, diskOfferingId); - if (diskOffering == null) { - throw new InvalidParameterValueException("Unable to find disk offering " + diskOfferingId); - } - } - - if (!zone.isLocalStorageEnabled()) { - if (serviceOffering.getUseLocalStorage()) { - throw new InvalidParameterValueException("Zone is not configured to use local storage but service offering " + serviceOffering.getName() + " uses it"); - } - if (diskOffering != null && diskOffering.getUseLocalStorage()) { - throw new InvalidParameterValueException("Zone is not configured to use local storage but disk offering " + diskOffering.getName() + " uses it"); - } - } - - UserVm vm = null; - IpAddresses addrs = new IpAddresses(ipAddress, getIp6Address()); - if (zone.getNetworkType() == NetworkType.Basic) { - if (getNetworkIds() != null) { - throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); - } else { - vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(), owner, name, displayName, diskOfferingId, - size, group, getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, getAffinityGroupIdList(), - getDetails(), getCustomId()); - } - } else { - if (zone.isSecurityGroupEnabled()) { - vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(), owner, name, - displayName, diskOfferingId, size, group, getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, - getAffinityGroupIdList(), getDetails(), getCustomId()); - - } else { - if (getSecurityGroupIdList() != null && !getSecurityGroupIdList().isEmpty()) { - throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone"); - } - vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName, diskOfferingId, size, group, - getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, getAffinityGroupIdList(), getDetails(), - getCustomId()); - } - } + UserVm vm = _userVmService.createVirtualMachine(this); if (vm != null) { setEntityId(vm.getId()); diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/SecurityGroupAction.java b/api/src/org/apache/cloudstack/api/command/user/vm/SecurityGroupAction.java new file mode 100644 index 0000000000..87a829e467 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/vm/SecurityGroupAction.java @@ -0,0 +1,25 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.vm; + +import java.util.List; + +public interface SecurityGroupAction { + List getSecurityGroupIdList(); + List getSecurityGroupNameList(); + long getEntityOwnerId(); +} diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java index 9a8bdc2aa3..4508f7e471 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java @@ -16,7 +16,9 @@ // under the License. package org.apache.cloudstack.api.command.user.vm; -import org.apache.log4j.Logger; +import java.util.Collection; +import java.util.List; +import java.util.Map; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; @@ -32,6 +34,7 @@ import org.apache.cloudstack.api.response.SecurityGroupResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; @@ -39,15 +42,11 @@ import com.cloud.uservm.UserVm; import com.cloud.vm.VirtualMachine; -import java.util.Collection; -import java.util.List; -import java.util.Map; - @APICommand(name = "updateVirtualMachine", description="Updates properties of a virtual machine. The VM has to be stopped and restarted for the " + "new properties to take effect. UpdateVirtualMachine does not first check whether the VM is stopped. " + "Therefore, stop the VM manually before issuing this call.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = true) -public class UpdateVMCmd extends BaseCustomIdCmd { +public class UpdateVMCmd extends BaseCustomIdCmd implements SecurityGroupAction { public static final Logger s_logger = Logger.getLogger(UpdateVMCmd.class.getName()); private static final String s_name = "updatevirtualmachineresponse"; @@ -106,6 +105,17 @@ public class UpdateVMCmd extends BaseCustomIdCmd { description = "list of security group ids to be applied on the virtual machine.") private List securityGroupIdList; + @ACL + @Parameter(name = ApiConstants.SECURITY_GROUP_NAMES, + type = CommandType.LIST, + collectionType = CommandType.STRING, + entityType = SecurityGroupResponse.class, + description = "comma separated list of security groups names that going to be applied to the virtual machine. " + + "Should be passed only when vm is created from a zone with Basic Network support. " + + "Mutually exclusive with securitygroupids parameter" + ) + private List securityGroupNameList; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -159,6 +169,10 @@ public List getSecurityGroupIdList() { return securityGroupIdList; } + public List getSecurityGroupNameList() { + return securityGroupNameList; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index a253fdd6f8..9eddf6dabd 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -55,6 +55,7 @@ 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.ScaleVMCmd; +import org.apache.cloudstack.api.command.user.vm.SecurityGroupAction; 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; @@ -194,6 +195,7 @@ import com.cloud.network.security.dao.SecurityGroupVMMapDao; import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.offering.DiskOffering; import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offering.ServiceOffering; @@ -2289,7 +2291,7 @@ public UserVm updateVirtualMachine(UpdateVMCmd cmd) throws ResourceUnavailableEx String hostName = cmd.getHostName(); Map details = cmd.getDetails(); Account caller = CallContext.current().getCallingAccount(); - List securityGroupIdList = cmd.getSecurityGroupIdList(); + List securityGroupIdList = getSecurityGroupIdList(cmd); // Input validation and permission checks UserVmVO vmInstance = _vmDao.findById(id); @@ -4320,8 +4322,172 @@ public HypervisorType getHypervisorTypeOfUserVM(long vmId) { @Override public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { - // TODO Auto-generated method stub - return null; + //Verify that all objects exist before passing them to the service + Account owner = _accountService.getActiveAccountById(cmd.getEntityOwnerId()); + + verifyDetails(cmd.getDetails()); + + Long zoneId = cmd.getZoneId(); + + DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId); + if (zone == null) { + throw new InvalidParameterValueException("Unable to find zone by id=" + zoneId); + } + + Long serviceOfferingId = cmd.getServiceOfferingId(); + + ServiceOffering serviceOffering = _entityMgr.findById(ServiceOffering.class, serviceOfferingId); + if (serviceOffering == null) { + throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId); + } + + Long templateId = cmd.getTemplateId(); + + if(!serviceOffering.isDynamic()) { + for(String detail: cmd.getDetails().keySet()) { + if(detail.equalsIgnoreCase("cpuNumber") || detail.equalsIgnoreCase("cpuSpeed") || detail.equalsIgnoreCase("memory")) { + throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering"); + } + } + } + + VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId); + // Make sure a valid template ID was specified + if (template == null) { + throw new InvalidParameterValueException("Unable to use template " + templateId); + } + + Long diskOfferingId = cmd.getDiskOfferingId(); + DiskOffering diskOffering = null; + if (diskOfferingId != null) { + diskOffering = _entityMgr.findById(DiskOffering.class, diskOfferingId); + if (diskOffering == null) { + throw new InvalidParameterValueException("Unable to find disk offering " + diskOfferingId); + } + } + + if (!zone.isLocalStorageEnabled()) { + if (serviceOffering.getUseLocalStorage()) { + throw new InvalidParameterValueException("Zone is not configured to use local storage but service offering " + serviceOffering.getName() + " uses it"); + } + if (diskOffering != null && diskOffering.getUseLocalStorage()) { + throw new InvalidParameterValueException("Zone is not configured to use local storage but disk offering " + diskOffering.getName() + " uses it"); + } + } + + String ipAddress = cmd.getIpAddress(); + String ip6Address = cmd.getIp6Address(); + String name = cmd.getName(); + String displayName = cmd.getDisplayName(); + UserVm vm = null; + IpAddresses addrs = new IpAddresses(ipAddress, ip6Address); + Long size = cmd.getSize(); + String group = cmd.getGroup(); + String userData = cmd.getUserData(); + String sshKeyPairName = cmd.getSSHKeyPairName(); + Boolean displayVm = cmd.getDisplayVm(); + String keyboard = cmd.getKeyboard(); + if (zone.getNetworkType() == NetworkType.Basic) { + if (cmd.getNetworkIds() != null) { + throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); + } else { + vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd), owner, name, displayName, diskOfferingId, + size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData , sshKeyPairName , cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(), + cmd.getDetails(), cmd.getCustomId()); + } + } else { + if (zone.isSecurityGroupEnabled()) { + vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, cmd.getNetworkIds(), getSecurityGroupIdList(cmd), owner, name, + displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, + cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId()); + + } else { + if (cmd.getSecurityGroupIdList() != null && !cmd.getSecurityGroupIdList().isEmpty()) { + throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone"); + } + vm = createAdvancedVirtualMachine(zone, serviceOffering, template, cmd.getNetworkIds(), owner, name, displayName, diskOfferingId, size, group, + cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(), + cmd.getCustomId()); + } + } + return vm; + } + + private List getSecurityGroupIdList(SecurityGroupAction cmd) { + if (cmd.getSecurityGroupNameList() != null && cmd.getSecurityGroupIdList() != null) { + throw new InvalidParameterValueException("securitygroupids parameter is mutually exclusive with securitygroupnames parameter"); + } + + //transform group names to ids here + if (cmd.getSecurityGroupNameList() != null) { + List securityGroupIds = new ArrayList(); + for (String groupName : cmd.getSecurityGroupNameList()) { + SecurityGroup sg = _securityGroupMgr.getSecurityGroup(groupName, cmd.getEntityOwnerId()); + if (sg == null) { + throw new InvalidParameterValueException("Unable to find group by name " + groupName); + } else { + securityGroupIds.add(sg.getId()); + } + } + return securityGroupIds; + } else { + return cmd.getSecurityGroupIdList(); + } + } + + // this is an opportunity to verify that parameters that came in via the Details Map are OK + // for example, minIops and maxIops should either both be specified or neither be specified and, + // if specified, minIops should be <= maxIops + private void verifyDetails(Map details) { + if (details != null) { + String minIops = (String)details.get("minIops"); + String maxIops = (String)details.get("maxIops"); + + verifyMinAndMaxIops(minIops, maxIops); + + minIops = (String)details.get("minIopsDo"); + maxIops = (String)details.get("maxIopsDo"); + + verifyMinAndMaxIops(minIops, maxIops); + } + } + + private void verifyMinAndMaxIops(String minIops, String maxIops) { + if ((minIops != null && maxIops == null) || (minIops == null && maxIops != null)) { + throw new InvalidParameterValueException("Either 'Min IOPS' and 'Max IOPS' must both be specified or neither be specified."); + } + + long lMinIops; + + try { + if (minIops != null) { + lMinIops = Long.parseLong(minIops); + } + else { + lMinIops = 0; + } + } + catch (NumberFormatException ex) { + throw new InvalidParameterValueException("'Min IOPS' must be a whole number."); + } + + long lMaxIops; + + try { + if (maxIops != null) { + lMaxIops = Long.parseLong(maxIops); + } + else { + lMaxIops = 0; + } + } + catch (NumberFormatException ex) { + throw new InvalidParameterValueException("'Max IOPS' must be a whole number."); + } + + if (lMinIops > lMaxIops) { + throw new InvalidParameterValueException("'Min IOPS' must be less than or equal to 'Max IOPS'."); + } } @Override From b0c27e48d787271cbdaf4ef1e5f787049545b234 Mon Sep 17 00:00:00 2001 From: Nick Livens Date: Mon, 2 May 2016 10:15:52 +0200 Subject: [PATCH 185/203] CLOUDSTACK-9242 : Remodel Nuage VSP plugin --- plugins/network-elements/nuage-vsp/pom.xml | 12 +- .../cloudstack/vsp/spring-vsp-context.xml | 2 +- .../cloud/agent/api/VspResourceAnswer.java | 60 --- .../cloud/agent/api/VspResourceCommand.java | 119 ----- .../api/element/ApplyAclRuleVspCommand.java | 184 +------- .../api/element/ApplyStaticNatVspCommand.java | 101 +---- .../api/element/ImplementVspCommand.java | 238 +--------- .../api/element/ShutDownVpcVspCommand.java | 29 +- .../api/guru/DeallocateVmVspCommand.java | 187 +------- .../api/guru/ImplementNetworkVspCommand.java | 304 +------------ .../guru/ReserveVmInterfaceVspCommand.java | 369 ++-------------- .../api/guru/TrashNetworkVspCommand.java | 101 +---- .../GetApiDefaultsAnswer.java} | 33 +- ...ommand.java => GetApiDefaultsCommand.java} | 4 +- .../api/manager/GetClientDefaultsAnswer.java | 81 ---- .../agent/api/sync/SyncDomainCommand.java | 31 +- .../api/commands/AddNuageVspDeviceCmd.java | 24 +- .../api/commands/DeleteNuageVspDeviceCmd.java | 12 +- .../IssueNuageVspResourceRequestCmd.java | 213 --------- .../api/commands/ListNuageVspDevicesCmd.java | 12 +- .../api/commands/UpdateNuageVspDeviceCmd.java | 12 +- .../network/element/NuageVspElement.java | 240 +++------- .../guru/NuageVspGuestNetworkGuru.java | 301 ++++--------- .../network/manager/NuageVspManager.java | 2 + .../network/manager/NuageVspManagerImpl.java | 130 ++++-- .../network/resource/NuageVspResource.java | 152 ++----- .../com/cloud/network/sync/NuageVspSync.java | 26 -- .../cloud/network/sync/NuageVspSyncImpl.java | 65 --- .../com/cloud/util/NuageVspEntityBuilder.java | 368 ++++++++++++++++ .../src/com/cloud/util/NuageVspUtil.java | 9 +- .../vsp/acs/NuageVspPluginClientLoader.java | 91 ++-- .../vsp/acs/client/NuageVspApiClient.java | 32 -- .../vsp/acs/client/NuageVspElementClient.java | 42 -- .../vsp/acs/client/NuageVspGuruClient.java | 43 -- .../vsp/acs/client/NuageVspManagerClient.java | 42 -- .../vsp/acs/client/NuageVspSyncClient.java | 29 -- .../nuage-vsp/test/com/cloud/NuageTest.java | 157 +++++++ .../com/cloud/agent/api/CommandsTest.java | 63 +-- .../network/element/NuageVspElementTest.java | 193 ++++---- .../guru/NuageVspGuestNetworkGuruTest.java | 216 ++++----- .../network/manager/NuageVspManagerTest.java | 73 ++-- .../resource/NuageVspResourceTest.java | 122 +++--- .../cloud/network/sync/NuageVspSyncTest.java | 72 --- .../cloud/util/NuageVspEntityBuilderTest.java | 412 ++++++++++++++++++ plugins/pom.xml | 12 +- ui/scripts/system.js | 4 +- 46 files changed, 1751 insertions(+), 3273 deletions(-) delete mode 100644 plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceAnswer.java delete mode 100644 plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceCommand.java rename plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/{sync/SyncVspCommand.java => manager/GetApiDefaultsAnswer.java} (56%) rename plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/{GetClientDefaultsCommand.java => GetApiDefaultsCommand.java} (92%) delete mode 100644 plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsAnswer.java delete mode 100644 plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/IssueNuageVspResourceRequestCmd.java delete mode 100644 plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java delete mode 100644 plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSyncImpl.java create mode 100644 plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java delete mode 100644 plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspApiClient.java delete mode 100644 plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspElementClient.java delete mode 100644 plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspGuruClient.java delete mode 100644 plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspManagerClient.java delete mode 100644 plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspSyncClient.java create mode 100644 plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java delete mode 100644 plugins/network-elements/nuage-vsp/test/com/cloud/network/sync/NuageVspSyncTest.java create mode 100644 plugins/network-elements/nuage-vsp/test/com/cloud/util/NuageVspEntityBuilderTest.java diff --git a/plugins/network-elements/nuage-vsp/pom.xml b/plugins/network-elements/nuage-vsp/pom.xml index 402f9a3829..7369ba5fa7 100644 --- a/plugins/network-elements/nuage-vsp/pom.xml +++ b/plugins/network-elements/nuage-vsp/pom.xml @@ -28,11 +28,17 @@ 4.9.0-SNAPSHOT ../../pom.xml
+ + + nuage-vsp + http://cs.mv.nuagenetworks.net/releases/ + + - org.apache.commons - commons-lang3 - ${cs.commons-lang3.version} + net.nuage.vsp + nuage-vsp-acs-client + 3.2.8.0 diff --git a/plugins/network-elements/nuage-vsp/resources/META-INF/cloudstack/vsp/spring-vsp-context.xml b/plugins/network-elements/nuage-vsp/resources/META-INF/cloudstack/vsp/spring-vsp-context.xml index c579789e5e..c447c441c9 100644 --- a/plugins/network-elements/nuage-vsp/resources/META-INF/cloudstack/vsp/spring-vsp-context.xml +++ b/plugins/network-elements/nuage-vsp/resources/META-INF/cloudstack/vsp/spring-vsp-context.xml @@ -37,5 +37,5 @@ - + diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceAnswer.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceAnswer.java deleted file mode 100644 index 979dcd315f..0000000000 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceAnswer.java +++ /dev/null @@ -1,60 +0,0 @@ -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -package com.cloud.agent.api; - -public class VspResourceAnswer extends Answer { - - private String _resourceInfo; - - public VspResourceAnswer(Command cmd, String resourceInfo, String details) { - super(cmd, true, details); - this._resourceInfo = resourceInfo; - } - - public VspResourceAnswer(VspResourceCommand cmd, boolean success, String details) { - super(cmd, success, details); - } - - public VspResourceAnswer(VspResourceCommand cmd, Exception e) { - super(cmd, e); - } - - public String getResourceInfo() { - return this._resourceInfo; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - VspResourceAnswer that = (VspResourceAnswer) o; - - if (_resourceInfo != null ? !_resourceInfo.equals(that._resourceInfo) : that._resourceInfo != null) - return false; - - return true; - } - - @Override - public int hashCode() { - return _resourceInfo != null ? _resourceInfo.hashCode() : 0; - } -} diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceCommand.java deleted file mode 100644 index 6e03dabc1b..0000000000 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceCommand.java +++ /dev/null @@ -1,119 +0,0 @@ -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -package com.cloud.agent.api; - -public class VspResourceCommand extends Command { - - private final String _method; - private final String _resource; - private final String _resourceId; - private final String _childResource; - private final Object _entityDetails; - private final String _resourceFilter; - private final String _proxyUserUuid; - private final String _proxyUserDomainuuid; - - public VspResourceCommand(String method, String resource, String resourceId, String childResource, Object entityDetails, String resourceFilter, String proxyUserUuid, - String proxyUserDomainuuid) { - super(); - this._method = method; - this._resource = resource; - this._resourceId = resourceId; - this._childResource = childResource; - this._entityDetails = entityDetails; - this._resourceFilter = resourceFilter; - this._proxyUserUuid = proxyUserUuid; - this._proxyUserDomainuuid = proxyUserDomainuuid; - } - - public String getRequestType() { - return _method; - } - - public String getResource() { - return _resource; - } - - public String getResourceId() { - return _resourceId; - } - - public String getChildResource() { - return _childResource; - } - - public Object getEntityDetails() { - return _entityDetails; - } - - public String getResourceFilter() { - return _resourceFilter; - } - - public String getProxyUserUuid() { - return _proxyUserUuid; - } - - public String getProxyUserDomainuuid() { - return _proxyUserDomainuuid; - } - - @Override - public boolean executeInSequence() { - return false; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - VspResourceCommand that = (VspResourceCommand) o; - - if (_childResource != null ? !_childResource.equals(that._childResource) : that._childResource != null) - return false; - if (_entityDetails != null ? !_entityDetails.equals(that._entityDetails) : that._entityDetails != null) - return false; - if (_method != null ? !_method.equals(that._method) : that._method != null) return false; - if (_proxyUserDomainuuid != null ? !_proxyUserDomainuuid.equals(that._proxyUserDomainuuid) : that._proxyUserDomainuuid != null) - return false; - if (_proxyUserUuid != null ? !_proxyUserUuid.equals(that._proxyUserUuid) : that._proxyUserUuid != null) - return false; - if (_resource != null ? !_resource.equals(that._resource) : that._resource != null) return false; - if (_resourceFilter != null ? !_resourceFilter.equals(that._resourceFilter) : that._resourceFilter != null) - return false; - if (_resourceId != null ? !_resourceId.equals(that._resourceId) : that._resourceId != null) return false; - - return true; - } - - @Override - public int hashCode() { - int result = _method != null ? _method.hashCode() : 0; - result = 31 * result + (_resource != null ? _resource.hashCode() : 0); - result = 31 * result + (_resourceId != null ? _resourceId.hashCode() : 0); - result = 31 * result + (_childResource != null ? _childResource.hashCode() : 0); - result = 31 * result + (_entityDetails != null ? _entityDetails.hashCode() : 0); - result = 31 * result + (_resourceFilter != null ? _resourceFilter.hashCode() : 0); - result = 31 * result + (_proxyUserUuid != null ? _proxyUserUuid.hashCode() : 0); - result = 31 * result + (_proxyUserDomainuuid != null ? _proxyUserDomainuuid.hashCode() : 0); - return result; - } -} diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyAclRuleVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyAclRuleVspCommand.java index 7b1d40bc09..50cace6ffc 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyAclRuleVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyAclRuleVspCommand.java @@ -19,173 +19,43 @@ package com.cloud.agent.api.element; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspNetwork; import java.util.List; -import java.util.Map; public class ApplyAclRuleVspCommand extends Command { - private final boolean _networkAcl; - private final String _networkUuid; - private final String _networkDomainUuid; - private final String _vpcOrSubnetUuid; - private final String _networkName; - private final boolean _isL2Network; - private final List> _aclRules; - private final long _networkId; - private final boolean _egressDefaultPolicy; - private final Boolean _acsIngressAcl; + private final VspAclRule.ACLType _aclType; + private final VspNetwork _network; + private final List _aclRules; private final boolean _networkReset; - private final String _domainTemplateName; - private ApplyAclRuleVspCommand(boolean networkAcl, String networkUuid, String networkDomainUuid, String vpcOrSubnetUuid, String networkName, boolean isL2Network, - List> aclRules, long networkId, boolean egressDefaultPolicy, Boolean acsIngressAcl, boolean networkReset, String domainTemplateName) { + public ApplyAclRuleVspCommand(VspAclRule.ACLType aclType, VspNetwork network, List aclRules, boolean networkReset) { super(); - this._networkAcl = networkAcl; - this._networkUuid = networkUuid; - this._networkDomainUuid = networkDomainUuid; - this._vpcOrSubnetUuid = vpcOrSubnetUuid; - this._networkName = networkName; - this._isL2Network = isL2Network; + this._aclType = aclType; + this._network = network; this._aclRules = aclRules; - this._networkId = networkId; - this._egressDefaultPolicy = egressDefaultPolicy; - this._acsIngressAcl = acsIngressAcl; this._networkReset = networkReset; - this._domainTemplateName = domainTemplateName; } - public boolean isNetworkAcl() { - return _networkAcl; + public VspAclRule.ACLType getAclType() { + return _aclType; } - public String getNetworkUuid() { - return _networkUuid; + public VspNetwork getNetwork() { + return _network; } - public String getNetworkDomainUuid() { - return _networkDomainUuid; - } - - public String getVpcOrSubnetUuid() { - return _vpcOrSubnetUuid; - } - - public String getNetworkName() { - return _networkName; - } - - public boolean isL2Network() { - return _isL2Network; - } - - public List> getAclRules() { + public List getAclRules() { return _aclRules; } - public long getNetworkId() { - return _networkId; - } - - public boolean isEgressDefaultPolicy() { - return _egressDefaultPolicy; - } - - public Boolean getAcsIngressAcl() { - return _acsIngressAcl; - } - public boolean isNetworkReset() { return _networkReset; } - public String getDomainTemplateName() { - return _domainTemplateName; - } - - public static class Builder implements CmdBuilder { - private boolean _networkAcl; - private String _networkUuid; - private String _networkDomainUuid; - private String _vpcOrSubnetUuid; - private String _networkName; - private boolean _isL2Network; - private List> _aclRules; - private long _networkId; - private boolean _egressDefaultPolicy; - private Boolean _acsIngressAcl; - private boolean _networkReset; - private String _domainTemplateName; - - public Builder networkAcl(boolean networkAcl) { - this._networkAcl = networkAcl; - return this; - } - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder networkDomainUuid(String networkDomainUuid) { - this._networkDomainUuid = networkDomainUuid; - return this; - } - - public Builder vpcOrSubnetUuid(String vpcOrSubnetUuid) { - this._vpcOrSubnetUuid = vpcOrSubnetUuid; - return this; - } - - public Builder networkName(String networkName) { - this._networkName = networkName; - return this; - } - - public Builder isL2Network(boolean isL2Network) { - this._isL2Network = isL2Network; - return this; - } - - public Builder aclRules(List> aclRules) { - this._aclRules = aclRules; - return this; - } - - public Builder networkId(long networkId) { - this._networkId = networkId; - return this; - } - - public Builder egressDefaultPolicy(boolean egressDefaultPolicy) { - this._egressDefaultPolicy = egressDefaultPolicy; - return this; - } - - public Builder acsIngressAcl(Boolean acsIngressAcl) { - this._acsIngressAcl = acsIngressAcl; - return this; - } - - public Builder networkReset(boolean networkReset) { - this._networkReset = networkReset; - return this; - } - - public Builder domainTemplateName(String domainTemplateName) { - this._domainTemplateName = domainTemplateName; - return this; - } - - @Override - public ApplyAclRuleVspCommand build() { - return new ApplyAclRuleVspCommand(_networkAcl, _networkUuid, _networkDomainUuid, _vpcOrSubnetUuid, _networkName, _isL2Network, _aclRules, - _networkId, _egressDefaultPolicy, _acsIngressAcl, _networkReset, _domainTemplateName); - } - } - @Override public boolean executeInSequence() { return false; @@ -199,22 +69,10 @@ public boolean equals(Object o) { ApplyAclRuleVspCommand that = (ApplyAclRuleVspCommand) o; - if (_egressDefaultPolicy != that._egressDefaultPolicy) return false; - if (_isL2Network != that._isL2Network) return false; - if (_networkAcl != that._networkAcl) return false; - if (_networkId != that._networkId) return false; if (_networkReset != that._networkReset) return false; if (_aclRules != null ? !_aclRules.equals(that._aclRules) : that._aclRules != null) return false; - if (_acsIngressAcl != null ? !_acsIngressAcl.equals(that._acsIngressAcl) : that._acsIngressAcl != null) - return false; - if (_domainTemplateName != null ? !_domainTemplateName.equals(that._domainTemplateName) : that._domainTemplateName != null) - return false; - if (_networkDomainUuid != null ? !_networkDomainUuid.equals(that._networkDomainUuid) : that._networkDomainUuid != null) - return false; - if (_networkName != null ? !_networkName.equals(that._networkName) : that._networkName != null) return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; - if (_vpcOrSubnetUuid != null ? !_vpcOrSubnetUuid.equals(that._vpcOrSubnetUuid) : that._vpcOrSubnetUuid != null) - return false; + if (_aclType != that._aclType) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; return true; } @@ -222,18 +80,10 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_networkAcl ? 1 : 0); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_networkDomainUuid != null ? _networkDomainUuid.hashCode() : 0); - result = 31 * result + (_vpcOrSubnetUuid != null ? _vpcOrSubnetUuid.hashCode() : 0); - result = 31 * result + (_networkName != null ? _networkName.hashCode() : 0); - result = 31 * result + (_isL2Network ? 1 : 0); + result = 31 * result + (_aclType != null ? _aclType.hashCode() : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); result = 31 * result + (_aclRules != null ? _aclRules.hashCode() : 0); - result = 31 * result + (int) (_networkId ^ (_networkId >>> 32)); - result = 31 * result + (_egressDefaultPolicy ? 1 : 0); - result = 31 * result + (_acsIngressAcl != null ? _acsIngressAcl.hashCode() : 0); result = 31 * result + (_networkReset ? 1 : 0); - result = 31 * result + (_domainTemplateName != null ? _domainTemplateName.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyStaticNatVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyStaticNatVspCommand.java index cc4e9300c9..500f091919 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyStaticNatVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyStaticNatVspCommand.java @@ -19,100 +19,31 @@ package com.cloud.agent.api.element; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; import java.util.List; -import java.util.Map; public class ApplyStaticNatVspCommand extends Command { - private final String _networkDomainUuid; - private final String _networkUuid; - private final String _vpcOrSubnetUuid; - private final boolean _isL3Network; - private final boolean _isVpc; - private final List> _staticNatDetails; + private final VspNetwork _network; + private final List _staticNatDetails; - private ApplyStaticNatVspCommand(String networkDomainUuid, String networkUuid, String vpcOrSubnetUuid, boolean isL3Network, boolean isVpc, - List> staticNatDetails) { + public ApplyStaticNatVspCommand(VspNetwork network, List staticNatDetails) { super(); - this._networkDomainUuid = networkDomainUuid; - this._networkUuid = networkUuid; - this._vpcOrSubnetUuid = vpcOrSubnetUuid; - this._isL3Network = isL3Network; - this._isVpc = isVpc; + this._network = network; this._staticNatDetails = staticNatDetails; } - public String getNetworkDomainUuid() { - return _networkDomainUuid; + public VspNetwork getNetwork() { + return _network; } - public String getNetworkUuid() { - return _networkUuid; - } - - public String getVpcOrSubnetUuid() { - return _vpcOrSubnetUuid; - } - - public boolean isL3Network() { - return _isL3Network; - } - - public boolean isVpc() { - return _isVpc; - } - - public List> getStaticNatDetails() { + public List getStaticNatDetails() { return _staticNatDetails; } - public static class Builder implements CmdBuilder { - private String _networkDomainUuid; - private String _networkUuid; - private String _vpcOrSubnetUuid; - private boolean _isL3Network; - private boolean _isVpc; - private List> _staticNatDetails; - - public Builder networkDomainUuid(String networkDomainUuid) { - this._networkDomainUuid = networkDomainUuid; - return this; - } - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder vpcOrSubnetUuid(String vpcOrSubnetUuid) { - this._vpcOrSubnetUuid = vpcOrSubnetUuid; - return this; - } - - public Builder isL3Network(boolean isL3Network) { - this._isL3Network = isL3Network; - return this; - } - - public Builder isVpc(boolean isVpc) { - this._isVpc = isVpc; - return this; - } - - public Builder staticNatDetails(List> staticNatDetails) { - this._staticNatDetails = staticNatDetails; - return this; - } - - @Override - public ApplyStaticNatVspCommand build() { - return new ApplyStaticNatVspCommand(_networkDomainUuid, _networkUuid, _vpcOrSubnetUuid, _isL3Network, _isVpc, _staticNatDetails); - } - } - @Override public boolean executeInSequence() { return false; @@ -126,15 +57,9 @@ public boolean equals(Object o) { ApplyStaticNatVspCommand that = (ApplyStaticNatVspCommand) o; - if (_isL3Network != that._isL3Network) return false; - if (_isVpc != that._isVpc) return false; - if (_networkDomainUuid != null ? !_networkDomainUuid.equals(that._networkDomainUuid) : that._networkDomainUuid != null) - return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; if (_staticNatDetails != null ? !_staticNatDetails.equals(that._staticNatDetails) : that._staticNatDetails != null) return false; - if (_vpcOrSubnetUuid != null ? !_vpcOrSubnetUuid.equals(that._vpcOrSubnetUuid) : that._vpcOrSubnetUuid != null) - return false; return true; } @@ -142,11 +67,7 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_networkDomainUuid != null ? _networkDomainUuid.hashCode() : 0); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_vpcOrSubnetUuid != null ? _vpcOrSubnetUuid.hashCode() : 0); - result = 31 * result + (_isL3Network ? 1 : 0); - result = 31 * result + (_isVpc ? 1 : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); result = 31 * result + (_staticNatDetails != null ? _staticNatDetails.hashCode() : 0); return result; } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ImplementVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ImplementVspCommand.java index c1de6b9de8..2145f60172 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ImplementVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ImplementVspCommand.java @@ -19,220 +19,48 @@ package com.cloud.agent.api.element; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspNetwork; import java.util.List; -import java.util.Map; public class ImplementVspCommand extends Command { - private final long _networkId; - private final String _networkDomainUuid; - private final String _networkUuid; - private final String _networkName; - private final String _vpcOrSubnetUuid; - private final boolean _isL2Network; - private final boolean _isL3Network; - private final boolean _isVpc; - private final boolean _isShared; - private final String _domainTemplateName; - private final boolean _isFirewallServiceSupported; + private final VspNetwork _network; private final List _dnsServers; - private final List> _ingressFirewallRules; - private final List> _egressFirewallRules; - private final List _acsFipUuid; - private final boolean _egressDefaultPolicy; + private final List _ingressFirewallRules; + private final List _egressFirewallRules; + private final List _floatingIpUuids; - private ImplementVspCommand(long networkId, String networkDomainUuid, String networkUuid, String networkName, String vpcOrSubnetUuid, boolean isL2Network, boolean isL3Network, - boolean isVpc, boolean isShared, String domainTemplateName, boolean isFirewallServiceSupported, List dnsServers, List> ingressFirewallRules, - List> egressFirewallRules, List acsFipUuid, boolean egressDefaultPolicy) { + public ImplementVspCommand(VspNetwork network, List dnsServers, List ingressFirewallRules, + List egressFirewallRules, List floatingIpUuids) { super(); - this._networkId = networkId; - this._networkDomainUuid = networkDomainUuid; - this._networkUuid = networkUuid; - this._networkName = networkName; - this._vpcOrSubnetUuid = vpcOrSubnetUuid; - this._isL2Network = isL2Network; - this._isL3Network = isL3Network; - this._isVpc = isVpc; - this._isShared = isShared; - this._domainTemplateName = domainTemplateName; - this._isFirewallServiceSupported = isFirewallServiceSupported; + this._network = network; this._dnsServers = dnsServers; this._ingressFirewallRules = ingressFirewallRules; this._egressFirewallRules = egressFirewallRules; - this._acsFipUuid = acsFipUuid; - this._egressDefaultPolicy = egressDefaultPolicy; + this._floatingIpUuids = floatingIpUuids; } - public long getNetworkId() { - return _networkId; - } - - public String getNetworkDomainUuid() { - return _networkDomainUuid; - } - - public String getNetworkUuid() { - return _networkUuid; - } - - public String getNetworkName() { - return _networkName; - } - - public String getVpcOrSubnetUuid() { - return _vpcOrSubnetUuid; - } - - public boolean isL2Network() { - return _isL2Network; - } - - public boolean isL3Network() { - return _isL3Network; - } - - public boolean isVpc() { - return _isVpc; - } - - public boolean isShared() { - return _isShared; - } - - public String getDomainTemplateName() { - return _domainTemplateName; - } - - public boolean isFirewallServiceSupported() { - return _isFirewallServiceSupported; + public VspNetwork getNetwork() { + return _network; } public List getDnsServers() { return _dnsServers; } - public List> getIngressFirewallRules() { + public List getIngressFirewallRules() { return _ingressFirewallRules; } - public List> getEgressFirewallRules() { + public List getEgressFirewallRules() { return _egressFirewallRules; } - public List getAcsFipUuid() { - return _acsFipUuid; - } - - public boolean isEgressDefaultPolicy() { - return _egressDefaultPolicy; - } - - public static class Builder implements CmdBuilder { - private long _networkId; - private String _networkDomainUuid; - private String _networkUuid; - private String _networkName; - private String _vpcOrSubnetUuid; - private boolean _isL2Network; - private boolean _isL3Network; - private boolean _isVpc; - private boolean _isShared; - private String _domainTemplateName; - private boolean _isFirewallServiceSupported; - private List _dnsServers; - private List> _ingressFirewallRules; - private List> _egressFirewallRules; - private List _acsFipUuid; - private boolean _egressDefaultPolicy; - - public Builder networkId(long networkId) { - this._networkId = networkId; - return this; - } - - public Builder networkDomainUuid(String networkDomainUuid) { - this._networkDomainUuid = networkDomainUuid; - return this; - } - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder networkName(String networkName) { - this._networkName = networkName; - return this; - } - - public Builder vpcOrSubnetUuid(String vpcOrSubnetUuid) { - this._vpcOrSubnetUuid = vpcOrSubnetUuid; - return this; - } - - public Builder isL2Network(boolean isL2Network) { - this._isL2Network = isL2Network; - return this; - } - - public Builder isL3Network(boolean isL3Network) { - this._isL3Network = isL3Network; - return this; - } - - public Builder isVpc(boolean isVpc) { - this._isVpc = isVpc; - return this; - } - - public Builder isShared(boolean isShared) { - this._isShared = isShared; - return this; - } - - public Builder domainTemplateName(String domainTemplateName) { - this._domainTemplateName = domainTemplateName; - return this; - } - - public Builder isFirewallServiceSupported(boolean isFirewallServiceSupported) { - this._isFirewallServiceSupported = isFirewallServiceSupported; - return this; - } - - public Builder dnsServers(List dnsServers) { - this._dnsServers = dnsServers; - return this; - } - - public Builder ingressFirewallRules(List> ingressFirewallRules) { - this._ingressFirewallRules = ingressFirewallRules; - return this; - } - - public Builder egressFirewallRules(List> egressFirewallRules) { - this._egressFirewallRules = egressFirewallRules; - return this; - } - - public Builder acsFipUuid(List acsFipUuid) { - this._acsFipUuid = acsFipUuid; - return this; - } - - public Builder egressDefaultPolicy(boolean egressDefaultPolicy) { - this._egressDefaultPolicy = egressDefaultPolicy; - return this; - } - - @Override - public ImplementVspCommand build() { - return new ImplementVspCommand(_networkId, _networkDomainUuid, _networkUuid, _networkName, _vpcOrSubnetUuid, _isL2Network, _isL3Network, _isVpc, _isShared, - _domainTemplateName, _isFirewallServiceSupported, _dnsServers, _ingressFirewallRules, _egressFirewallRules, _acsFipUuid, _egressDefaultPolicy); - } + public List getFloatingIpUuids() { + return _floatingIpUuids; } @Override @@ -248,27 +76,14 @@ public boolean equals(Object o) { ImplementVspCommand that = (ImplementVspCommand) o; - if (_egressDefaultPolicy != that._egressDefaultPolicy) return false; - if (_isFirewallServiceSupported != that._isFirewallServiceSupported) return false; - if (_isL2Network != that._isL2Network) return false; - if (_isL3Network != that._isL3Network) return false; - if (_isShared != that._isShared) return false; - if (_isVpc != that._isVpc) return false; - if (_networkId != that._networkId) return false; - if (_acsFipUuid != null ? !_acsFipUuid.equals(that._acsFipUuid) : that._acsFipUuid != null) return false; if (_dnsServers != null ? !_dnsServers.equals(that._dnsServers) : that._dnsServers != null) return false; - if (_domainTemplateName != null ? !_domainTemplateName.equals(that._domainTemplateName) : that._domainTemplateName != null) - return false; if (_egressFirewallRules != null ? !_egressFirewallRules.equals(that._egressFirewallRules) : that._egressFirewallRules != null) return false; - if (_ingressFirewallRules != null ? !_ingressFirewallRules.equals(that._ingressFirewallRules) : that._ingressFirewallRules != null) + if (_floatingIpUuids != null ? !_floatingIpUuids.equals(that._floatingIpUuids) : that._floatingIpUuids != null) return false; - if (_networkDomainUuid != null ? !_networkDomainUuid.equals(that._networkDomainUuid) : that._networkDomainUuid != null) - return false; - if (_networkName != null ? !_networkName.equals(that._networkName) : that._networkName != null) return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; - if (_vpcOrSubnetUuid != null ? !_vpcOrSubnetUuid.equals(that._vpcOrSubnetUuid) : that._vpcOrSubnetUuid != null) + if (_ingressFirewallRules != null ? !_ingressFirewallRules.equals(that._ingressFirewallRules) : that._ingressFirewallRules != null) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; return true; } @@ -276,22 +91,11 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (int) (_networkId ^ (_networkId >>> 32)); - result = 31 * result + (_networkDomainUuid != null ? _networkDomainUuid.hashCode() : 0); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_networkName != null ? _networkName.hashCode() : 0); - result = 31 * result + (_vpcOrSubnetUuid != null ? _vpcOrSubnetUuid.hashCode() : 0); - result = 31 * result + (_isL2Network ? 1 : 0); - result = 31 * result + (_isL3Network ? 1 : 0); - result = 31 * result + (_isVpc ? 1 : 0); - result = 31 * result + (_isShared ? 1 : 0); - result = 31 * result + (_domainTemplateName != null ? _domainTemplateName.hashCode() : 0); - result = 31 * result + (_isFirewallServiceSupported ? 1 : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); result = 31 * result + (_dnsServers != null ? _dnsServers.hashCode() : 0); result = 31 * result + (_ingressFirewallRules != null ? _ingressFirewallRules.hashCode() : 0); result = 31 * result + (_egressFirewallRules != null ? _egressFirewallRules.hashCode() : 0); - result = 31 * result + (_acsFipUuid != null ? _acsFipUuid.hashCode() : 0); - result = 31 * result + (_egressDefaultPolicy ? 1 : 0); + result = 31 * result + (_floatingIpUuids != null ? _floatingIpUuids.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java index 4c41e5140a..d91734bcf0 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java @@ -19,7 +19,6 @@ package com.cloud.agent.api.element; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; public class ShutDownVpcVspCommand extends Command { @@ -28,7 +27,7 @@ public class ShutDownVpcVspCommand extends Command { private final String _vpcUuid; private final String _domainTemplateName; - private ShutDownVpcVspCommand(String domainUuid, String vpcUuid, String domainTemplateName) { + public ShutDownVpcVspCommand(String domainUuid, String vpcUuid, String domainTemplateName) { super(); this._domainUuid = domainUuid; this._vpcUuid = vpcUuid; @@ -47,32 +46,6 @@ public String getDomainTemplateName() { return _domainTemplateName; } - public static class Builder implements CmdBuilder { - private String _domainUuid; - private String _vpcUuid; - private String _domainTemplateName; - - public Builder domainUuid(String domainUuid) { - this._domainUuid = domainUuid; - return this; - } - - public Builder vpcUuid(String vpcUuid) { - this._vpcUuid = vpcUuid; - return this; - } - - public Builder domainTemplateName(String domainTemplateName) { - this._domainTemplateName = domainTemplateName; - return this; - } - - @Override - public ShutDownVpcVspCommand build() { - return new ShutDownVpcVspCommand(_domainUuid, _vpcUuid, _domainTemplateName); - } - } - @Override public boolean executeInSequence() { return false; diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/DeallocateVmVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/DeallocateVmVspCommand.java index 421fa4c689..10dffccacc 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/DeallocateVmVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/DeallocateVmVspCommand.java @@ -19,156 +19,34 @@ package com.cloud.agent.api.guru; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspVm; public class DeallocateVmVspCommand extends Command { - private final String _networkUuid; - private final String _nicFromDdUuid; - private final String _nicMacAddress; - private final String _nicIp4Address; - private final boolean _isL3Network; - private final boolean _isSharedNetwork; - private final String _vpcUuid; - private final String _networksDomainUuid; - private final String _vmInstanceName; - private final String _vmUuid; - private final boolean _isExpungingState; + private final VspNetwork _network; + private final VspVm _vm; + private final VspNic _nic; - private DeallocateVmVspCommand(String networkUuid, String nicFromDdUuid, String nicMacAddress, String nicIp4Address, boolean isL3Network, boolean isSharedNetwork, String vpcUuid, - String networksDomainUuid, String vmInstanceName, String vmUuid, boolean isExpungingState) { + public DeallocateVmVspCommand(VspNetwork network, VspVm vm, VspNic nic) { super(); - this._networkUuid = networkUuid; - this._nicFromDdUuid = nicFromDdUuid; - this._nicMacAddress = nicMacAddress; - this._nicIp4Address = nicIp4Address; - this._isL3Network = isL3Network; - this._isSharedNetwork = isSharedNetwork; - this._vpcUuid = vpcUuid; - this._networksDomainUuid = networksDomainUuid; - this._vmInstanceName = vmInstanceName; - this._vmUuid = vmUuid; - this._isExpungingState = isExpungingState; + this._network = network; + this._vm = vm; + this._nic = nic; } - public String getNetworkUuid() { - return _networkUuid; + public VspNetwork getNetwork() { + return this._network; } - public String getNicFromDdUuid() { - return _nicFromDdUuid; + public VspVm getVm() { + return this._vm; } - public String getNicMacAddress() { - return _nicMacAddress; - } - - public String getNicIp4Address() { - return _nicIp4Address; - } - - public boolean isL3Network() { - return _isL3Network; - } - - public boolean isSharedNetwork() { - return _isSharedNetwork; - } - - public String getVpcUuid() { - return _vpcUuid; - } - - public String getNetworksDomainUuid() { - return _networksDomainUuid; - } - - public String getVmInstanceName() { - return _vmInstanceName; - } - - public String getVmUuid() { - return _vmUuid; - } - - public boolean isExpungingState() { - return _isExpungingState; - } - - public static class Builder implements CmdBuilder { - private String _networkUuid; - private String _nicFromDdUuid; - private String _nicMacAddress; - private String _nicIp4Address; - private boolean _isL3Network; - private boolean _isSharedNetwork; - private String _vpcUuid; - private String _networksDomainUuid; - private String _vmInstanceName; - private String _vmUuid; - private boolean _isExpungingState; - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder nicFromDbUuid(String nicFromDbUuid) { - this._nicFromDdUuid = nicFromDbUuid; - return this; - } - - public Builder nicMacAddress(String nicMacAddress) { - this._nicMacAddress = nicMacAddress; - return this; - } - - public Builder nicIp4Address(String nicIp4Address) { - this._nicIp4Address = nicIp4Address; - return this; - } - - public Builder isL3Network(boolean isL3Network) { - this._isL3Network = isL3Network; - return this; - } - - public Builder isSharedNetwork(boolean isSharedNetwork) { - this._isSharedNetwork = isSharedNetwork; - return this; - } - - public Builder vpcUuid(String vpcUuid) { - this._vpcUuid = vpcUuid; - return this; - } - - public Builder networksDomainUuid(String networksDomainUuid) { - this._networksDomainUuid = networksDomainUuid; - return this; - } - - public Builder vmInstanceName(String vmInstanceName) { - this._vmInstanceName = vmInstanceName; - return this; - } - - public Builder vmUuid(String vmUuid) { - this._vmUuid = vmUuid; - return this; - } - - public Builder isExpungingState(boolean isExpungingState) { - this._isExpungingState = isExpungingState; - return this; - } - - @Override - public DeallocateVmVspCommand build() { - return new DeallocateVmVspCommand(_networkUuid,_nicFromDdUuid, _nicMacAddress, _nicIp4Address, _isL3Network, _isSharedNetwork, _vpcUuid, - _networksDomainUuid, _vmInstanceName, _vmUuid, _isExpungingState); - } + public VspNic getNic() { + return this._nic; } @Override @@ -184,22 +62,9 @@ public boolean equals(Object o) { DeallocateVmVspCommand that = (DeallocateVmVspCommand) o; - if (_isExpungingState != that._isExpungingState) return false; - if (_isL3Network != that._isL3Network) return false; - if (_isSharedNetwork != that._isSharedNetwork) return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; - if (_networksDomainUuid != null ? !_networksDomainUuid.equals(that._networksDomainUuid) : that._networksDomainUuid != null) - return false; - if (_nicFromDdUuid != null ? !_nicFromDdUuid.equals(that._nicFromDdUuid) : that._nicFromDdUuid != null) - return false; - if (_nicIp4Address != null ? !_nicIp4Address.equals(that._nicIp4Address) : that._nicIp4Address != null) - return false; - if (_nicMacAddress != null ? !_nicMacAddress.equals(that._nicMacAddress) : that._nicMacAddress != null) - return false; - if (_vmInstanceName != null ? !_vmInstanceName.equals(that._vmInstanceName) : that._vmInstanceName != null) - return false; - if (_vmUuid != null ? !_vmUuid.equals(that._vmUuid) : that._vmUuid != null) return false; - if (_vpcUuid != null ? !_vpcUuid.equals(that._vpcUuid) : that._vpcUuid != null) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; + if (_nic != null ? !_nic.equals(that._nic) : that._nic != null) return false; + if (_vm != null ? !_vm.equals(that._vm) : that._vm != null) return false; return true; } @@ -207,17 +72,9 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_nicFromDdUuid != null ? _nicFromDdUuid.hashCode() : 0); - result = 31 * result + (_nicMacAddress != null ? _nicMacAddress.hashCode() : 0); - result = 31 * result + (_nicIp4Address != null ? _nicIp4Address.hashCode() : 0); - result = 31 * result + (_isL3Network ? 1 : 0); - result = 31 * result + (_isSharedNetwork ? 1 : 0); - result = 31 * result + (_vpcUuid != null ? _vpcUuid.hashCode() : 0); - result = 31 * result + (_networksDomainUuid != null ? _networksDomainUuid.hashCode() : 0); - result = 31 * result + (_vmInstanceName != null ? _vmInstanceName.hashCode() : 0); - result = 31 * result + (_vmUuid != null ? _vmUuid.hashCode() : 0); - result = 31 * result + (_isExpungingState ? 1 : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); + result = 31 * result + (_vm != null ? _vm.hashCode() : 0); + result = 31 * result + (_nic != null ? _nic.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ImplementNetworkVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ImplementNetworkVspCommand.java index 575e57d362..bb3575690d 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ImplementNetworkVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ImplementNetworkVspCommand.java @@ -19,272 +19,30 @@ package com.cloud.agent.api.guru; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspNetwork; -import java.util.Collection; import java.util.List; public class ImplementNetworkVspCommand extends Command { - private final String _networkDomainName; - private final String _networkDomainPath; - private final String _networkDomainUuid; - private final String _networkAccountName; - private final String _networkAccountUuid; - private final String _networkName; - private final String _networkCidr; - private final String _networkGateway; - private final Long _networkAclId; + private final VspNetwork _network; private final List _dnsServers; - private final List _gatewaySystemIds; - private final String _networkUuid; - private final boolean _isL3Network; - private final boolean _isVpc; - private final boolean _isSharedNetwork; - private final String _vpcName; - private final String _vpcUuid; - private final boolean _defaultEgressPolicy; - private final List _ipAddressRange; - private final String _domainTemplateName; - private ImplementNetworkVspCommand(String networkDomainName, String networkDomainPath, String networkDomainUuid, String networkAccountName, String networkAccountUuid, - String networkName, String networkCidr, String networkGateway, Long networkAclId, List dnsServers, List gatewaySystemIds, String networkUuid, - boolean isL3Network, boolean isVpc, boolean isSharedNetwork, String vpcName, String vpcUuid, boolean defaultEgressPolicy, List ipAddressRange, - String domainTemplateName) { + public ImplementNetworkVspCommand(VspNetwork network, List dnsServers) { super(); - this._networkDomainName = networkDomainName; - this._networkDomainPath = networkDomainPath; - this._networkDomainUuid = networkDomainUuid; - this._networkAccountName = networkAccountName; - this._networkAccountUuid = networkAccountUuid; - this._networkName = networkName; - this._networkCidr = networkCidr; - this._networkGateway = networkGateway; - this._networkAclId = networkAclId; + this._network = network; this._dnsServers = dnsServers; - this._gatewaySystemIds = gatewaySystemIds; - this._networkUuid = networkUuid; - this._isL3Network = isL3Network; - this._isVpc = isVpc; - this._isSharedNetwork = isSharedNetwork; - this._vpcName = vpcName; - this._vpcUuid = vpcUuid; - this._defaultEgressPolicy = defaultEgressPolicy; - this._ipAddressRange = ipAddressRange; - this._domainTemplateName = domainTemplateName; } - public String getNetworkDomainName() { - return _networkDomainName; - } - - public String getNetworkDomainPath() { - return _networkDomainPath; - } - - public String getNetworkDomainUuid() { - return _networkDomainUuid; - } - - public String getNetworkAccountName() { - return _networkAccountName; - } - - public String getNetworkAccountUuid() { - return _networkAccountUuid; - } - - public String getNetworkName() { - return _networkName; - } - - public String getNetworkCidr() { - return _networkCidr; - } - - public String getNetworkGateway() { - return _networkGateway; - } - - public Long getNetworkAclId() { - return _networkAclId; + public VspNetwork getNetwork() { + return _network; } public List getDnsServers() { return _dnsServers; } - public List getGatewaySystemIds() { - return _gatewaySystemIds; - } - - public String getNetworkUuid() { - return _networkUuid; - } - - public boolean isL3Network() { - return _isL3Network; - } - - public boolean isVpc() { - return _isVpc; - } - - public boolean isSharedNetwork() { - return _isSharedNetwork; - } - - public String getVpcName() { - return _vpcName; - } - - public String getVpcUuid() { - return _vpcUuid; - } - - public boolean isDefaultEgressPolicy() { - return _defaultEgressPolicy; - } - - public Collection getIpAddressRange() { - return _ipAddressRange; - } - - public String getDomainTemplateName() { - return _domainTemplateName; - } - - public static class Builder implements CmdBuilder { - private String _networkDomainName; - private String _networkDomainPath; - private String _networkDomainUuid; - private String _networkAccountName; - private String _networkAccountUuid; - private String _networkName; - private String _networkCidr; - private String _networkGateway; - private Long _networkAclId; - private List _dnsServers; - private List _gatewaySystemIds; - private String _networkUuid; - private boolean _isL3Network; - private boolean _isVpc; - private boolean _isSharedNetwork; - private String _vpcName; - private String _vpcUuid; - private boolean _defaultEgressPolicy; - private List _ipAddressRange; - private String _domainTemplateName; - - public Builder networkDomainName(String networkDomainName) { - this._networkDomainName = networkDomainName; - return this; - } - - public Builder networkDomainPath(String networkDomainPath) { - this._networkDomainPath = networkDomainPath; - return this; - } - - public Builder networkDomainUuid(String networkDomainUuid) { - this._networkDomainUuid = networkDomainUuid; - return this; - } - - public Builder networkAccountName(String networkAccountName) { - this._networkAccountName = networkAccountName; - return this; - } - - public Builder networkAccountUuid(String networkAccountUuid) { - this._networkAccountUuid = networkAccountUuid; - return this; - } - - public Builder networkName(String networkName) { - this._networkName = networkName; - return this; - } - - public Builder networkCidr(String networkCidr) { - this._networkCidr = networkCidr; - return this; - } - - public Builder networkGateway(String networkGateway) { - this._networkGateway = networkGateway; - return this; - } - - public Builder networkAclId(Long networkAclId) { - this._networkAclId = networkAclId; - return this; - } - - public Builder dnsServers(List dnsServers) { - this._dnsServers = dnsServers; - return this; - } - - public Builder gatewaySystemIds(List gatewaySystemIds) { - this._gatewaySystemIds = gatewaySystemIds; - return this; - } - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder isL3Network(boolean isL3Network) { - this._isL3Network = isL3Network; - return this; - } - - public Builder isVpc(boolean isVpc) { - this._isVpc = isVpc; - return this; - } - - public Builder isSharedNetwork(boolean isSharedNetwork) { - this._isSharedNetwork = isSharedNetwork; - return this; - } - - public Builder vpcName(String vpcName) { - this._vpcName = vpcName; - return this; - } - - public Builder vpcUuid(String vpcUuid) { - this._vpcUuid = vpcUuid; - return this; - } - - public Builder defaultEgressPolicy(boolean defaultEgressPolicy) { - this._defaultEgressPolicy = defaultEgressPolicy; - return this; - } - - public Builder ipAddressRange(List ipAddressRange) { - this._ipAddressRange = ipAddressRange; - return this; - } - - public Builder domainTemplateName(String domainTemplateName) { - this._domainTemplateName = domainTemplateName; - return this; - } - - @Override - public ImplementNetworkVspCommand build() { - return new ImplementNetworkVspCommand(_networkDomainName, _networkDomainPath, _networkDomainUuid, _networkAccountName, _networkAccountUuid, _networkName, - _networkCidr, _networkGateway, _networkAclId, _dnsServers, _gatewaySystemIds, _networkUuid, _isL3Network, _isVpc, _isSharedNetwork, _vpcName, _vpcUuid, - _defaultEgressPolicy, _ipAddressRange, _domainTemplateName); - } - } - @Override public boolean executeInSequence() { return false; @@ -298,36 +56,8 @@ public boolean equals(Object o) { ImplementNetworkVspCommand that = (ImplementNetworkVspCommand) o; - if (_defaultEgressPolicy != that._defaultEgressPolicy) return false; - if (_isL3Network != that._isL3Network) return false; - if (_isSharedNetwork != that._isSharedNetwork) return false; - if (_isVpc != that._isVpc) return false; if (_dnsServers != null ? !_dnsServers.equals(that._dnsServers) : that._dnsServers != null) return false; - if (_domainTemplateName != null ? !_domainTemplateName.equals(that._domainTemplateName) : that._domainTemplateName != null) - return false; - if (_gatewaySystemIds != null ? !_gatewaySystemIds.equals(that._gatewaySystemIds) : that._gatewaySystemIds != null) - return false; - if (_ipAddressRange != null ? !_ipAddressRange.equals(that._ipAddressRange) : that._ipAddressRange != null) - return false; - if (_networkAccountName != null ? !_networkAccountName.equals(that._networkAccountName) : that._networkAccountName != null) - return false; - if (_networkAccountUuid != null ? !_networkAccountUuid.equals(that._networkAccountUuid) : that._networkAccountUuid != null) - return false; - if (_networkAclId != null ? !_networkAclId.equals(that._networkAclId) : that._networkAclId != null) - return false; - if (_networkCidr != null ? !_networkCidr.equals(that._networkCidr) : that._networkCidr != null) return false; - if (_networkDomainName != null ? !_networkDomainName.equals(that._networkDomainName) : that._networkDomainName != null) - return false; - if (_networkDomainPath != null ? !_networkDomainPath.equals(that._networkDomainPath) : that._networkDomainPath != null) - return false; - if (_networkDomainUuid != null ? !_networkDomainUuid.equals(that._networkDomainUuid) : that._networkDomainUuid != null) - return false; - if (_networkGateway != null ? !_networkGateway.equals(that._networkGateway) : that._networkGateway != null) - return false; - if (_networkName != null ? !_networkName.equals(that._networkName) : that._networkName != null) return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; - if (_vpcName != null ? !_vpcName.equals(that._vpcName) : that._vpcName != null) return false; - if (_vpcUuid != null ? !_vpcUuid.equals(that._vpcUuid) : that._vpcUuid != null) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; return true; } @@ -335,26 +65,8 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_networkDomainName != null ? _networkDomainName.hashCode() : 0); - result = 31 * result + (_networkDomainPath != null ? _networkDomainPath.hashCode() : 0); - result = 31 * result + (_networkDomainUuid != null ? _networkDomainUuid.hashCode() : 0); - result = 31 * result + (_networkAccountName != null ? _networkAccountName.hashCode() : 0); - result = 31 * result + (_networkAccountUuid != null ? _networkAccountUuid.hashCode() : 0); - result = 31 * result + (_networkName != null ? _networkName.hashCode() : 0); - result = 31 * result + (_networkCidr != null ? _networkCidr.hashCode() : 0); - result = 31 * result + (_networkGateway != null ? _networkGateway.hashCode() : 0); - result = 31 * result + (_networkAclId != null ? _networkAclId.hashCode() : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); result = 31 * result + (_dnsServers != null ? _dnsServers.hashCode() : 0); - result = 31 * result + (_gatewaySystemIds != null ? _gatewaySystemIds.hashCode() : 0); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_isL3Network ? 1 : 0); - result = 31 * result + (_isVpc ? 1 : 0); - result = 31 * result + (_isSharedNetwork ? 1 : 0); - result = 31 * result + (_vpcName != null ? _vpcName.hashCode() : 0); - result = 31 * result + (_vpcUuid != null ? _vpcUuid.hashCode() : 0); - result = 31 * result + (_defaultEgressPolicy ? 1 : 0); - result = 31 * result + (_ipAddressRange != null ? _ipAddressRange.hashCode() : 0); - result = 31 * result + (_domainTemplateName != null ? _domainTemplateName.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ReserveVmInterfaceVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ReserveVmInterfaceVspCommand.java index abcd0f2c69..299b9a6ec7 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ReserveVmInterfaceVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ReserveVmInterfaceVspCommand.java @@ -19,303 +19,41 @@ package com.cloud.agent.api.guru; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; +import net.nuage.vsp.acs.client.api.model.VspVm; public class ReserveVmInterfaceVspCommand extends Command { - private final String _nicUuid; - private final String _nicMacAddress; - private final String _networkUuid; - private final boolean _isL3Network; - private final boolean _isSharedNetwork; - private final String _vpcUuid; - private final String _networkDomainUuid; - private final String _networksAccountUuid; - private final boolean _isDomainRouter; - private final String _domainRouterIp; - private final String _vmInstanceName; - private final String _vmUuid; - private final String _vmUserName; - private final String _vmUserDomainName; - private final boolean _useStaticIp; - private final String _staticIp; - private final String _staticNatIpUuid; - private final String _staticNatIpAddress; - private final boolean _isStaticNatIpAllocated; - private final boolean _isOneToOneNat; - private final String _staticNatVlanUuid; - private final String _staticNatVlanGateway; - private final String _staticNatVlanNetmask; + private final VspNetwork _network; + private final VspVm _vm; + private final VspNic _nic; + private final VspStaticNat _staticNat; - private ReserveVmInterfaceVspCommand(String nicUuid, String nicMacAddress, String networkUuid, boolean isL3Network, boolean isSharedNetwork, String vpcUuid, String networkDomainUuid, - String networksAccountUuid, boolean isDomainRouter, String domainRouterIp, String vmInstanceName, String vmUuid, String vmUserName, String vmUserDomainName, - boolean useStaticIp, String staticIp, String staticNatIpUuid, String staticNatIpAddress, boolean isStaticNatIpAllocated, boolean isOneToOneNat, String staticNatVlanUuid, - String staticNatVlanGateway, String staticNatVlanNetmask) { + public ReserveVmInterfaceVspCommand(VspNetwork network, VspVm vm, VspNic nic, VspStaticNat staticNat) { super(); - this._nicUuid = nicUuid; - this._nicMacAddress = nicMacAddress; - this._networkUuid = networkUuid; - this._isL3Network = isL3Network; - this._isSharedNetwork = isSharedNetwork; - this._vpcUuid = vpcUuid; - this._networkDomainUuid = networkDomainUuid; - this._networksAccountUuid = networksAccountUuid; - this._isDomainRouter = isDomainRouter; - this._domainRouterIp = domainRouterIp; - this._vmInstanceName = vmInstanceName; - this._vmUuid = vmUuid; - this._vmUserName = vmUserName; - this._vmUserDomainName = vmUserDomainName; - this._useStaticIp = useStaticIp; - this._staticIp = staticIp; - this._staticNatIpUuid = staticNatIpUuid; - this._staticNatIpAddress = staticNatIpAddress; - this._isStaticNatIpAllocated = isStaticNatIpAllocated; - this._isOneToOneNat = isOneToOneNat; - this._staticNatVlanUuid = staticNatVlanUuid; - this._staticNatVlanGateway = staticNatVlanGateway; - this._staticNatVlanNetmask = staticNatVlanNetmask; + this._network = network; + this._vm = vm; + this._nic = nic; + this._staticNat = staticNat; } - public String getNicUuid() { - return _nicUuid; + public VspNetwork getNetwork() { + return _network; } - public String getNicMacAddress() { - return _nicMacAddress; + public VspVm getVm() { + return _vm; } - public String getNetworkUuid() { - return _networkUuid; + public VspNic getNic() { + return _nic; } - public boolean isL3Network() { - return _isL3Network; - } - - public boolean isSharedNetwork() { - return _isSharedNetwork; - } - - public String getVpcUuid() { - return _vpcUuid; - } - - public String getNetworkDomainUuid() { - return _networkDomainUuid; - } - - public String getNetworksAccountUuid() { - return _networksAccountUuid; - } - - public boolean isDomainRouter() { - return _isDomainRouter; - } - - public String getDomainRouterIp() { - return _domainRouterIp; - } - - public String getVmInstanceName() { - return _vmInstanceName; - } - - public String getVmUuid() { - return _vmUuid; - } - - public String getVmUserName() { - return _vmUserName; - } - - public String getVmUserDomainName() { - return _vmUserDomainName; - } - - public boolean useStaticIp() { - return _useStaticIp; - } - - public String getStaticIp() { - return _staticIp; - } - - public String getStaticNatIpUuid() { - return _staticNatIpUuid; - } - - public String getStaticNatIpAddress() { - return _staticNatIpAddress; - } - - public boolean isStaticNatIpAllocated() { - return _isStaticNatIpAllocated; - } - - public boolean isOneToOneNat() { - return _isOneToOneNat; - } - - public String getStaticNatVlanUuid() { - return _staticNatVlanUuid; - } - - public String getStaticNatVlanGateway() { - return _staticNatVlanGateway; - } - - public String getStaticNatVlanNetmask() { - return _staticNatVlanNetmask; - } - - public static class Builder implements CmdBuilder { - private String _nicUuid; - private String _nicMacAddress; - private String _networkUuid; - private boolean _isL3Network; - private boolean _isSharedNetwork; - private String _vpcUuid; - private String _networkDomainUuid; - private String _networksAccountUuid; - private boolean _isDomainRouter; - private String _domainRouterIp; - private String _vmInstanceName; - private String _vmUuid; - private String _vmUserName; - private String _vmUserDomainName; - private boolean _useStaticIp; - private String _staticIp; - private String _staticNatIpUuid; - private String _staticNatIpAddress; - private boolean _isStaticNatIpAllocated; - private boolean _isOneToOneNat; - private String _staticNatVlanUuid; - private String _staticNatVlanGateway; - private String _staticNatVlanNetmask; - - public Builder nicUuid(String nicUuid) { - this._nicUuid = nicUuid; - return this; - } - - public Builder nicMacAddress(String nicMacAddress) { - this._nicMacAddress = nicMacAddress; - return this; - } - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder isL3Network(boolean isL3Network) { - this._isL3Network = isL3Network; - return this; - } - - public Builder isSharedNetwork(boolean isSharedNetwork) { - this._isSharedNetwork = isSharedNetwork; - return this; - } - - public Builder vpcUuid(String vpcUuid) { - this._vpcUuid = vpcUuid; - return this; - } - - public Builder networkDomainUuid(String networkDomainUuid) { - this._networkDomainUuid = networkDomainUuid; - return this; - } - - public Builder networksAccountUuid(String networksAccountUuid) { - this._networksAccountUuid = networksAccountUuid; - return this; - } - - public Builder isDomainRouter(boolean isDomainRouter) { - this._isDomainRouter = isDomainRouter; - return this; - } - - public Builder domainRouterIp(String domainRouterIp) { - this._domainRouterIp = domainRouterIp; - return this; - } - - public Builder vmInstanceName(String vmInstanceName) { - this._vmInstanceName = vmInstanceName; - return this; - } - - public Builder vmUuid(String vmUuid) { - this._vmUuid = vmUuid; - return this; - } - - public Builder vmUserName(String vmUserName) { - this._vmUserName = vmUserName; - return this; - } - - public Builder vmUserDomainName(String vmUserDomainName) { - this._vmUserDomainName = vmUserDomainName; - return this; - } - - public Builder useStaticIp(boolean useStaticIp) { - this._useStaticIp = useStaticIp; - return this; - } - - public Builder staticIp(String staticIp) { - this._staticIp = staticIp; - return this; - } - - public Builder staticNatIpUuid(String staticNatIpUuid) { - this._staticNatIpUuid = staticNatIpUuid; - return this; - } - - public Builder staticNatIpAddress(String staticNatIpAddress) { - this._staticNatIpAddress = staticNatIpAddress; - return this; - } - - public Builder isStaticNatIpAllocated(boolean isStaticNatIpAllocated) { - this._isStaticNatIpAllocated = isStaticNatIpAllocated; - return this; - } - - public Builder isOneToOneNat(boolean isOneToOneNat) { - this._isOneToOneNat = isOneToOneNat; - return this; - } - - public Builder staticNatVlanUuid(String staticNatVlanUuid) { - this._staticNatVlanUuid = staticNatVlanUuid; - return this; - } - - public Builder staticNatVlanGateway(String staticNatVlanGateway) { - this._staticNatVlanGateway = staticNatVlanGateway; - return this; - } - - public Builder staticNatVlanNetmask(String staticNatVlanNetmask) { - this._staticNatVlanNetmask = staticNatVlanNetmask; - return this; - } - - @Override - public ReserveVmInterfaceVspCommand build() { - return new ReserveVmInterfaceVspCommand(_nicUuid, _nicMacAddress, _networkUuid, _isL3Network, _isSharedNetwork, _vpcUuid, _networkDomainUuid, _networksAccountUuid, - _isDomainRouter, _domainRouterIp, _vmInstanceName, _vmUuid, _vmUserName, _vmUserDomainName, _useStaticIp, _staticIp, _staticNatIpUuid, _staticNatIpAddress, - _isStaticNatIpAllocated, _isOneToOneNat, _staticNatVlanUuid, _staticNatVlanGateway, _staticNatVlanNetmask); - } + public VspStaticNat getStaticNat() { + return _staticNat; } @Override @@ -331,40 +69,10 @@ public boolean equals(Object o) { ReserveVmInterfaceVspCommand that = (ReserveVmInterfaceVspCommand) o; - if (_isDomainRouter != that._isDomainRouter) return false; - if (_isL3Network != that._isL3Network) return false; - if (_isOneToOneNat != that._isOneToOneNat) return false; - if (_isSharedNetwork != that._isSharedNetwork) return false; - if (_isStaticNatIpAllocated != that._isStaticNatIpAllocated) return false; - if (_useStaticIp != that._useStaticIp) return false; - if (_domainRouterIp != null ? !_domainRouterIp.equals(that._domainRouterIp) : that._domainRouterIp != null) - return false; - if (_networkDomainUuid != null ? !_networkDomainUuid.equals(that._networkDomainUuid) : that._networkDomainUuid != null) - return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; - if (_networksAccountUuid != null ? !_networksAccountUuid.equals(that._networksAccountUuid) : that._networksAccountUuid != null) - return false; - if (_nicMacAddress != null ? !_nicMacAddress.equals(that._nicMacAddress) : that._nicMacAddress != null) - return false; - if (_nicUuid != null ? !_nicUuid.equals(that._nicUuid) : that._nicUuid != null) return false; - if (_staticIp != null ? !_staticIp.equals(that._staticIp) : that._staticIp != null) return false; - if (_staticNatIpAddress != null ? !_staticNatIpAddress.equals(that._staticNatIpAddress) : that._staticNatIpAddress != null) - return false; - if (_staticNatIpUuid != null ? !_staticNatIpUuid.equals(that._staticNatIpUuid) : that._staticNatIpUuid != null) - return false; - if (_staticNatVlanGateway != null ? !_staticNatVlanGateway.equals(that._staticNatVlanGateway) : that._staticNatVlanGateway != null) - return false; - if (_staticNatVlanNetmask != null ? !_staticNatVlanNetmask.equals(that._staticNatVlanNetmask) : that._staticNatVlanNetmask != null) - return false; - if (_staticNatVlanUuid != null ? !_staticNatVlanUuid.equals(that._staticNatVlanUuid) : that._staticNatVlanUuid != null) - return false; - if (_vmInstanceName != null ? !_vmInstanceName.equals(that._vmInstanceName) : that._vmInstanceName != null) - return false; - if (_vmUserDomainName != null ? !_vmUserDomainName.equals(that._vmUserDomainName) : that._vmUserDomainName != null) - return false; - if (_vmUserName != null ? !_vmUserName.equals(that._vmUserName) : that._vmUserName != null) return false; - if (_vmUuid != null ? !_vmUuid.equals(that._vmUuid) : that._vmUuid != null) return false; - if (_vpcUuid != null ? !_vpcUuid.equals(that._vpcUuid) : that._vpcUuid != null) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; + if (_nic != null ? !_nic.equals(that._nic) : that._nic != null) return false; + if (_staticNat != null ? !_staticNat.equals(that._staticNat) : that._staticNat != null) return false; + if (_vm != null ? !_vm.equals(that._vm) : that._vm != null) return false; return true; } @@ -372,29 +80,10 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_nicUuid != null ? _nicUuid.hashCode() : 0); - result = 31 * result + (_nicMacAddress != null ? _nicMacAddress.hashCode() : 0); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_isL3Network ? 1 : 0); - result = 31 * result + (_isSharedNetwork ? 1 : 0); - result = 31 * result + (_vpcUuid != null ? _vpcUuid.hashCode() : 0); - result = 31 * result + (_networkDomainUuid != null ? _networkDomainUuid.hashCode() : 0); - result = 31 * result + (_networksAccountUuid != null ? _networksAccountUuid.hashCode() : 0); - result = 31 * result + (_isDomainRouter ? 1 : 0); - result = 31 * result + (_domainRouterIp != null ? _domainRouterIp.hashCode() : 0); - result = 31 * result + (_vmInstanceName != null ? _vmInstanceName.hashCode() : 0); - result = 31 * result + (_vmUuid != null ? _vmUuid.hashCode() : 0); - result = 31 * result + (_vmUserName != null ? _vmUserName.hashCode() : 0); - result = 31 * result + (_vmUserDomainName != null ? _vmUserDomainName.hashCode() : 0); - result = 31 * result + (_useStaticIp ? 1 : 0); - result = 31 * result + (_staticIp != null ? _staticIp.hashCode() : 0); - result = 31 * result + (_staticNatIpUuid != null ? _staticNatIpUuid.hashCode() : 0); - result = 31 * result + (_staticNatIpAddress != null ? _staticNatIpAddress.hashCode() : 0); - result = 31 * result + (_isStaticNatIpAllocated ? 1 : 0); - result = 31 * result + (_isOneToOneNat ? 1 : 0); - result = 31 * result + (_staticNatVlanUuid != null ? _staticNatVlanUuid.hashCode() : 0); - result = 31 * result + (_staticNatVlanGateway != null ? _staticNatVlanGateway.hashCode() : 0); - result = 31 * result + (_staticNatVlanNetmask != null ? _staticNatVlanNetmask.hashCode() : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); + result = 31 * result + (_vm != null ? _vm.hashCode() : 0); + result = 31 * result + (_nic != null ? _nic.hashCode() : 0); + result = 31 * result + (_staticNat != null ? _staticNat.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/TrashNetworkVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/TrashNetworkVspCommand.java index 4a01fdcc3d..b3f8f8e012 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/TrashNetworkVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/TrashNetworkVspCommand.java @@ -19,94 +19,20 @@ package com.cloud.agent.api.guru; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspNetwork; public class TrashNetworkVspCommand extends Command { - private final String _domainUuid; - private final String _networkUuid; - private final boolean _isL3Network; - private final boolean _isSharedNetwork; - private final String _vpcUuid; - private final String _domainTemplateName; + private final VspNetwork _network; - private TrashNetworkVspCommand(String domainUuid, String networkUuid, boolean isL3Network, boolean isSharedNetwork, String vpcUuid, String domainTemplateName) { + public TrashNetworkVspCommand(VspNetwork network) { super(); - this._domainUuid = domainUuid; - this._networkUuid = networkUuid; - this._isL3Network = isL3Network; - this._isSharedNetwork = isSharedNetwork; - this._vpcUuid = vpcUuid; - this._domainTemplateName = domainTemplateName; + this._network = network; } - public String getDomainUuid() { - return _domainUuid; - } - - public String getNetworkUuid() { - return _networkUuid; - } - - public boolean isL3Network() { - return _isL3Network; - } - - public boolean isSharedNetwork() { - return _isSharedNetwork; - } - - public String getVpcUuid() { - return _vpcUuid; - } - - public String getDomainTemplateName() { - return _domainTemplateName; - } - - public static class Builder implements CmdBuilder { - private String _domainUuid; - private String _networkUuid; - private boolean _isL3Network; - private boolean _isSharedNetwork; - private String _vpcUuid; - private String _domainTemplateName; - - public Builder domainUuid(String domainUuid) { - this._domainUuid = domainUuid; - return this; - } - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder isL3Network(boolean isL3Network) { - this._isL3Network = isL3Network; - return this; - } - - public Builder isSharedNetwork(boolean isSharedNetwork) { - this._isSharedNetwork = isSharedNetwork; - return this; - } - - public Builder vpcUuid(String vpcUuid) { - this._vpcUuid = vpcUuid; - return this; - } - - public Builder domainTemplateName(String domainTemplateName) { - this._domainTemplateName = domainTemplateName; - return this; - } - - @Override - public TrashNetworkVspCommand build() { - return new TrashNetworkVspCommand(_domainUuid, _networkUuid, _isL3Network, _isSharedNetwork, _vpcUuid, _domainTemplateName); - } + public VspNetwork getNetwork() { + return _network; } @Override @@ -122,13 +48,7 @@ public boolean equals(Object o) { TrashNetworkVspCommand that = (TrashNetworkVspCommand) o; - if (_isL3Network != that._isL3Network) return false; - if (_isSharedNetwork != that._isSharedNetwork) return false; - if (_domainTemplateName != null ? !_domainTemplateName.equals(that._domainTemplateName) : that._domainTemplateName != null) - return false; - if (_domainUuid != null ? !_domainUuid.equals(that._domainUuid) : that._domainUuid != null) return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; - if (_vpcUuid != null ? !_vpcUuid.equals(that._vpcUuid) : that._vpcUuid != null) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; return true; } @@ -136,12 +56,7 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_domainUuid != null ? _domainUuid.hashCode() : 0); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_isL3Network ? 1 : 0); - result = 31 * result + (_isSharedNetwork ? 1 : 0); - result = 31 * result + (_vpcUuid != null ? _vpcUuid.hashCode() : 0); - result = 31 * result + (_domainTemplateName != null ? _domainTemplateName.hashCode() : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsAnswer.java similarity index 56% rename from plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncVspCommand.java rename to plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsAnswer.java index cfcfb870cd..c02eef1699 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsAnswer.java @@ -17,38 +17,37 @@ // under the License. // -package com.cloud.agent.api.sync; +package com.cloud.agent.api.manager; -import com.cloud.agent.api.Command; +import com.cloud.agent.api.Answer; +import net.nuage.vsp.acs.client.api.model.VspApiDefaults; -public class SyncVspCommand extends Command { +public class GetApiDefaultsAnswer extends Answer { - private final String _nuageVspEntity; + private VspApiDefaults _apiDefaults; - public SyncVspCommand(String nuageVspEntity) { - super(); - this._nuageVspEntity = nuageVspEntity; + public GetApiDefaultsAnswer(GetApiDefaultsCommand cmd, VspApiDefaults defaults) { + super(cmd); + this._apiDefaults = defaults; } - @Override - public boolean executeInSequence() { - return false; + public GetApiDefaultsAnswer(GetApiDefaultsCommand cmd, Exception e) { + super(cmd, e); } - public String getNuageVspEntity() { - return _nuageVspEntity; + public VspApiDefaults getApiDefaults() { + return _apiDefaults; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof SyncVspCommand)) return false; + if (!(o instanceof GetApiDefaultsAnswer)) return false; if (!super.equals(o)) return false; - SyncVspCommand that = (SyncVspCommand) o; + GetApiDefaultsAnswer that = (GetApiDefaultsAnswer) o; - if (_nuageVspEntity != null ? !_nuageVspEntity.equals(that._nuageVspEntity) : that._nuageVspEntity != null) - return false; + if (_apiDefaults != null ? !_apiDefaults.equals(that._apiDefaults) : that._apiDefaults != null) return false; return true; } @@ -56,7 +55,7 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_nuageVspEntity != null ? _nuageVspEntity.hashCode() : 0); + result = 31 * result + (_apiDefaults != null ? _apiDefaults.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsCommand.java similarity index 92% rename from plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsCommand.java rename to plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsCommand.java index 2ffbe04ea4..3fca16a242 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsCommand.java @@ -25,9 +25,9 @@ * The super class implementations for equals and hashCode are acceptable because this class does not track any state * in addition to the super class. */ -public class GetClientDefaultsCommand extends Command { +public class GetApiDefaultsCommand extends Command { - public GetClientDefaultsCommand() { + public GetApiDefaultsCommand() { super(); } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsAnswer.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsAnswer.java deleted file mode 100644 index f748e1cbb4..0000000000 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsAnswer.java +++ /dev/null @@ -1,81 +0,0 @@ -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -package com.cloud.agent.api.manager; - -import com.cloud.agent.api.Answer; - -import java.util.Map; - -public class GetClientDefaultsAnswer extends Answer { - - private String _currentApiVersion; - private Integer _apiRetryCount; - private Long _apiRetryInterval; - - public GetClientDefaultsAnswer(GetClientDefaultsCommand cmd, Map defaults) { - super(cmd); - this._currentApiVersion = (String) defaults.get("CURRENT_API_VERSION"); - this._apiRetryCount = (Integer) defaults.get("DEFAULT_API_RETRY_COUNT"); - this._apiRetryInterval = (Long) defaults.get("DEFAULT_API_RETRY_INTERVAL"); - } - - public GetClientDefaultsAnswer(GetClientDefaultsCommand cmd, Exception e) { - super(cmd, e); - } - - public String getCurrentApiVersion() { - return _currentApiVersion; - } - - public Integer getApiRetryCount() { - return _apiRetryCount; - } - - public Long getApiRetryInterval() { - return _apiRetryInterval; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof GetClientDefaultsAnswer)) return false; - if (!super.equals(o)) return false; - - GetClientDefaultsAnswer that = (GetClientDefaultsAnswer) o; - - if (_apiRetryCount != null ? !_apiRetryCount.equals(that._apiRetryCount) : that._apiRetryCount != null) - return false; - if (_apiRetryInterval != null ? !_apiRetryInterval.equals(that._apiRetryInterval) : that._apiRetryInterval != null) - return false; - if (_currentApiVersion != null ? !_currentApiVersion.equals(that._currentApiVersion) : that._currentApiVersion != null) - return false; - - return true; - } - - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (_currentApiVersion != null ? _currentApiVersion.hashCode() : 0); - result = 31 * result + (_apiRetryCount != null ? _apiRetryCount.hashCode() : 0); - result = 31 * result + (_apiRetryInterval != null ? _apiRetryInterval.hashCode() : 0); - return result; - } -} diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncDomainCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncDomainCommand.java index 7ae474f2d1..90a30a4b3a 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncDomainCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncDomainCommand.java @@ -20,34 +20,23 @@ package com.cloud.agent.api.sync; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspDomain; public class SyncDomainCommand extends Command { - private final String _domainUuid; - private final String _domainName; - private final String _domainPath; + private final VspDomain _domain; private final boolean _toAdd; private final boolean _toRemove; - public SyncDomainCommand(String domainUuid, String domainName, String domainPath, boolean toAdd, boolean toRemove) { + public SyncDomainCommand(VspDomain domain, boolean toAdd, boolean toRemove) { super(); - this._domainUuid = domainUuid; - this._domainName = domainName; - this._domainPath = domainPath; + this._domain = domain; this._toAdd = toAdd; this._toRemove = toRemove; } - public String getDomainUuid() { - return _domainUuid; - } - - public String getDomainName() { - return _domainName; - } - - public String getDomainPath() { - return _domainPath; + public VspDomain getDomain() { + return _domain; } public boolean isToAdd() { @@ -73,9 +62,7 @@ public boolean equals(Object o) { if (_toAdd != that._toAdd) return false; if (_toRemove != that._toRemove) return false; - if (_domainName != null ? !_domainName.equals(that._domainName) : that._domainName != null) return false; - if (_domainPath != null ? !_domainPath.equals(that._domainPath) : that._domainPath != null) return false; - if (_domainUuid != null ? !_domainUuid.equals(that._domainUuid) : that._domainUuid != null) return false; + if (_domain != null ? !_domain.equals(that._domain) : that._domain != null) return false; return true; } @@ -83,9 +70,7 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_domainUuid != null ? _domainUuid.hashCode() : 0); - result = 31 * result + (_domainName != null ? _domainName.hashCode() : 0); - result = 31 * result + (_domainPath != null ? _domainPath.hashCode() : 0); + result = 31 * result + (_domain != null ? _domain.hashCode() : 0); result = 31 * result + (_toAdd ? 1 : 0); result = 31 * result + (_toRemove ? 1 : 0); return result; diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/AddNuageVspDeviceCmd.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/AddNuageVspDeviceCmd.java index 7590901a5f..62a15ea5a7 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/AddNuageVspDeviceCmd.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/AddNuageVspDeviceCmd.java @@ -29,6 +29,7 @@ import com.cloud.network.NuageVspDeviceVO; import com.cloud.network.manager.NuageVspManager; import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -41,9 +42,12 @@ import javax.inject.Inject; -@APICommand(name = "addNuageVspDevice", responseObject = NuageVspDeviceResponse.class, description = "Adds a Nuage VSP device", since = "4.5") +@APICommand(name = AddNuageVspDeviceCmd.APINAME, description = "Adds a Nuage VSP device", responseObject = NuageVspDeviceResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.5", + authorized = {RoleType.Admin}) public class AddNuageVspDeviceCmd extends BaseAsyncCmd { - private static final String s_name = "addnuagevspdeviceresponse"; + public static final String APINAME = "addNuageVspDevice"; @Inject NuageVspManager _nuageVspManager; @@ -68,14 +72,14 @@ public class AddNuageVspDeviceCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, required = true, description = "the password of CMS user in Nuage VSD") private String password; - @Parameter(name = VspConstants.NUAGE_VSP_API_VERSION, type = CommandType.STRING, required = true, description = "the version of the API to use to communicate to Nuage VSD") + @Parameter(name = VspConstants.NUAGE_VSP_API_VERSION, type = CommandType.STRING, description = "the version of the API to use to communicate to Nuage VSD") private String apiVersion; - @Parameter(name = VspConstants.NUAGE_VSP_API_RETRY_COUNT, type = CommandType.INTEGER, required = true, description = "the number of retries on failure to communicate to Nuage VSD") - private int apiRetryCount; + @Parameter(name = VspConstants.NUAGE_VSP_API_RETRY_COUNT, type = CommandType.INTEGER, description = "the number of retries on failure to communicate to Nuage VSD") + private Integer apiRetryCount; - @Parameter(name = VspConstants.NUAGE_VSP_API_RETRY_INTERVAL, type = CommandType.LONG, required = true, description = "the time to wait after failure before retrying to communicate to Nuage VSD") - private long apiRetryInterval; + @Parameter(name = VspConstants.NUAGE_VSP_API_RETRY_INTERVAL, type = CommandType.LONG, description = "the time to wait after failure before retrying to communicate to Nuage VSD") + private Long apiRetryInterval; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -117,7 +121,7 @@ public void setApiVersion(String apiVersion) { this.apiVersion = apiVersion; } - public int getApiRetryCount() { + public Integer getApiRetryCount() { return apiRetryCount; } @@ -125,7 +129,7 @@ public void setApiRetryCount(int apiRetryCount) { this.apiRetryCount = apiRetryCount; } - public long getApiRetryInterval() { + public Long getApiRetryInterval() { return apiRetryInterval; } @@ -158,7 +162,7 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE @Override public String getCommandName() { - return s_name; + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; } @Override diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/DeleteNuageVspDeviceCmd.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/DeleteNuageVspDeviceCmd.java index 971f9c93f4..05a17d6734 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/DeleteNuageVspDeviceCmd.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/DeleteNuageVspDeviceCmd.java @@ -28,9 +28,11 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.manager.NuageVspManager; import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.SuccessResponse; @@ -38,9 +40,13 @@ import javax.inject.Inject; -@APICommand(name = "deleteNuageVspDevice", responseObject = SuccessResponse.class, description = "delete a nuage vsp device", since = "4.5") +@APICommand(name = DeleteNuageVspDeviceCmd.APINAME, description = "delete a nuage vsp device", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.5", + authorized = {RoleType.Admin}) public class DeleteNuageVspDeviceCmd extends BaseAsyncCmd { - private static final String s_name = "deletenuagevspdeviceresponse"; + public static final String APINAME = "deleteNuageVspDevice"; + @Inject NuageVspManager _nuageVspManager; @@ -83,7 +89,7 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE @Override public String getCommandName() { - return s_name; + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; } @Override diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/IssueNuageVspResourceRequestCmd.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/IssueNuageVspResourceRequestCmd.java deleted file mode 100644 index 559b30d40a..0000000000 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/IssueNuageVspResourceRequestCmd.java +++ /dev/null @@ -1,213 +0,0 @@ -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -package com.cloud.api.commands; - -import com.cloud.agent.AgentManager; -import com.cloud.agent.api.VspResourceAnswer; -import com.cloud.agent.api.VspResourceCommand; -import com.cloud.api.response.NuageVspResourceResponse; -import com.cloud.domain.dao.DomainDao; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.network.NuageVspDeviceVO; -import com.cloud.network.dao.NuageVspDao; -import com.cloud.offering.NetworkOffering; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.response.NetworkOfferingResponse; -import org.apache.cloudstack.api.response.PhysicalNetworkResponse; -import org.apache.cloudstack.api.response.ZoneResponse; -import org.apache.cloudstack.context.CallContext; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; - -import javax.inject.Inject; -import java.util.List; - -@APICommand(name = "issueNuageVspResourceRequest", responseObject = NuageVspResourceResponse.class, description = "Issues a Nuage VSP REST API resource request", since = "4.5") -public class IssueNuageVspResourceRequestCmd extends BaseCmd { - private static final Logger s_logger = Logger.getLogger(IssueNuageVspResourceRequestCmd.class.getName()); - private static final String s_name = "nuagevspresourceresponse"; - - @Inject - protected AccountManager _accountMgr; - @Inject - protected DomainDao _domainDao; - @Inject - protected NuageVspDao _nuageConfigDao; - @Inject - HostDao _hostDao; - @Inject - AgentManager _agentMgr; - - ///////////////////////////////////////////////////// - //////////////// API parameters ///////////////////// - ///////////////////////////////////////////////////// - - @Parameter(name = ApiConstants.NETWORK_OFFERING_ID, type = CommandType.UUID, entityType = NetworkOfferingResponse.class, required = true, description = "the network offering id") - private Long networkOfferingId; - - @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, required = true, description = "the Zone ID for the network") - private Long zoneId; - - @Parameter(name = ApiConstants.PHYSICAL_NETWORK_ID, type = CommandType.UUID, entityType = PhysicalNetworkResponse.class, description = "the ID of the physical network in to which Nuage VSP Controller is added") - private Long physicalNetworkId; - - @Parameter(name = VspConstants.NUAGE_VSP_API_METHOD, type = CommandType.STRING, required = true, description = "the Nuage VSP REST API method type") - private String method; - - @Parameter(name = VspConstants.NUAGE_VSP_API_RESOURCE, type = CommandType.STRING, required = true, description = "the resource in Nuage VSP") - private String resource; - - @Parameter(name = VspConstants.NUAGE_VSP_API_RESOURCE_ID, type = CommandType.STRING, description = "the ID of the resource in Nuage VSP") - private String resourceId; - - @Parameter(name = VspConstants.NUAGE_VSP_API_CHILD_RESOURCE, type = CommandType.STRING, description = "the child resource in Nuage VSP") - private String childResource; - - @Parameter(name = VspConstants.NUAGE_VSP_API_RESOURCE_FILTER, type = CommandType.STRING, description = "the resource filter in Nuage VSP") - private String resourceFilter; - - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// - - public Long getNetworkOfferingId() { - return networkOfferingId; - } - - public Long getZoneId() { - Long physicalNetworkId = getPhysicalNetworkId(); - - if (physicalNetworkId == null && zoneId == null) { - throw new InvalidParameterValueException("Zone id is required"); - } - - return zoneId; - } - - public Long getPhysicalNetworkId() { - if (physicalNetworkId != null) { - return physicalNetworkId; - } - - NetworkOffering offering = _entityMgr.findById(NetworkOffering.class, networkOfferingId); - if (offering == null) { - throw new InvalidParameterValueException("Unable to find network offering by id " + networkOfferingId); - } - - if (zoneId == null) { - throw new InvalidParameterValueException("ZoneId is required as physicalNetworkId is null"); - } - return _networkService.findPhysicalNetworkId(zoneId, offering.getTags(), offering.getTrafficType()); - } - - public String getMethod() { - return method; - } - - public void setMethod(String method) { - this.method = method; - } - - public String getResource() { - return resource; - } - - public void setResource(String resource) { - this.resource = resource; - } - - public String getResourceId() { - return resourceId; - } - - public void setResourceId(String resourceId) { - this.resourceId = resourceId; - } - - public String getChildResource() { - return childResource; - } - - public void setChildResource(String childResource) { - this.childResource = childResource; - } - - public String getResourceFilter() { - return resourceFilter; - } - - public void setResourceFilter(String resourceFilter) { - this.resourceFilter = resourceFilter; - } - - @Override - public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { - long accountId = CallContext.current().getCallingAccount().getAccountId(); - Account account = _accountMgr.getAccount(accountId); - - List nuageVspDevices = _nuageConfigDao.listByPhysicalNetwork(getPhysicalNetworkId()); - if (nuageVspDevices != null && (!nuageVspDevices.isEmpty())) { - NuageVspDeviceVO config = nuageVspDevices.iterator().next(); - HostVO nuageVspHost = _hostDao.findById(config.getHostId()); - VspResourceCommand cmd = new VspResourceCommand(method, resource, resourceId, childResource, null, resourceFilter, null, null); - VspResourceAnswer answer = (VspResourceAnswer)_agentMgr.easySend(nuageVspHost.getId(), cmd); - if (answer == null || !answer.getResult()) { - s_logger.error("VspResourceCommand failed"); - if ((null != answer) && (null != answer.getDetails())) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, answer.getDetails()); - } - } else { - NuageVspResourceResponse response = new NuageVspResourceResponse(); - response.setResourceInfo(StringUtils.isBlank(answer.getResourceInfo()) ? "" : answer.getResourceInfo()); - response.setObjectName("nuagevspresource"); - response.setResponseName(getCommandName()); - this.setResponseObject(response); - } - } else { - String errorMessage = "No Nuage VSP Controller configured on physical network " + getPhysicalNetworkId(); - s_logger.error(errorMessage); - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMessage); - } - } - - @Override - public String getCommandName() { - return s_name; - } - - @Override - public long getEntityOwnerId() { - return CallContext.current().getCallingAccount().getId(); - } - -} \ No newline at end of file diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/ListNuageVspDevicesCmd.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/ListNuageVspDevicesCmd.java index 2d08e12e3d..d9f80e7856 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/ListNuageVspDevicesCmd.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/ListNuageVspDevicesCmd.java @@ -28,9 +28,11 @@ import com.cloud.network.NuageVspDeviceVO; import com.cloud.network.manager.NuageVspManager; import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; @@ -41,9 +43,13 @@ import java.util.ArrayList; import java.util.List; -@APICommand(name = "listNuageVspDevices", responseObject = NuageVspDeviceResponse.class, description = "Lists Nuage VSP devices", since = "4.5") +@APICommand(name = ListNuageVspDevicesCmd.APINAME, description = "Lists Nuage VSP devices", responseObject = NuageVspDeviceResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.5", + authorized = {RoleType.Admin}) public class ListNuageVspDevicesCmd extends BaseListCmd { - private static final String s_name = "listnuagevspdeviceresponse"; + public static final String APINAME = "listNuageVspDevices"; + @Inject NuageVspManager _nuageVspManager; @@ -99,7 +105,7 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE @Override public String getCommandName() { - return s_name; + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/UpdateNuageVspDeviceCmd.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/UpdateNuageVspDeviceCmd.java index d235b2b595..4197bd65a7 100755 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/UpdateNuageVspDeviceCmd.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/UpdateNuageVspDeviceCmd.java @@ -29,6 +29,7 @@ import com.cloud.network.NuageVspDeviceVO; import com.cloud.network.manager.NuageVspManager; import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -38,14 +39,15 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.PhysicalNetworkResponse; import org.apache.cloudstack.context.CallContext; -import org.apache.log4j.Logger; import javax.inject.Inject; -@APICommand(name = "updateNuageVspDevice", responseObject = NuageVspDeviceResponse.class, description = "Update a Nuage VSP device", since = "4.6") +@APICommand(name = UpdateNuageVspDeviceCmd.APINAME, description = "Update a Nuage VSP device", responseObject = NuageVspDeviceResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.6", + authorized = {RoleType.Admin}) public class UpdateNuageVspDeviceCmd extends BaseAsyncCmd { - private static final Logger s_logger = Logger.getLogger(UpdateNuageVspDeviceCmd.class); - private static final String s_name = "updatenuagevspdeviceresponse"; + public static final String APINAME = "updateNuageVspDevice"; @Inject NuageVspManager _nuageVspManager; @@ -160,7 +162,7 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE @Override public String getCommandName() { - return s_name; + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; } @Override diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java index d0d5ad21a6..531c8284ec 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java @@ -74,14 +74,12 @@ import com.cloud.network.vpc.dao.VpcDao; import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; import com.cloud.offering.NetworkOffering; -import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceStateAdapter; import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; -import com.cloud.util.NuageVspUtil; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.NicProfile; @@ -91,11 +89,18 @@ import com.cloud.vm.dao.NicDao; import com.google.common.base.Function; import com.google.common.collect.Lists; +import com.cloud.util.NuageVspEntityBuilder; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; import org.apache.cloudstack.api.InternalIdentity; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.network.ExternalNetworkDeviceManager; +import org.apache.cloudstack.resourcedetail.VpcDetailVO; +import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao; import org.apache.log4j.Logger; +import javax.annotation.Nullable; import javax.inject.Inject; import javax.naming.ConfigurationException; import java.util.ArrayList; @@ -126,9 +131,9 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider @Inject NetworkDao _networkDao; @Inject - protected DomainDao _domainDao; + DomainDao _domainDao; @Inject - protected DataCenterDao _dcDao; + DataCenterDao _dcDao; @Inject IPAddressDao _ipAddressDao; @Inject @@ -157,6 +162,10 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider PhysicalNetworkDao _physicalNetworkDao; @Inject NetworkACLItemDao _networkACLItemDao; + @Inject + NuageVspEntityBuilder _nuageVspEntityBuilder; + @Inject + VpcDetailsDao _vpcDetailsDao; @Override public boolean applyIps(Network network, List ipAddress, Set service) throws ResourceUnavailableException { @@ -242,53 +251,21 @@ public boolean implement(Network network, NetworkOffering offering, DeployDestin return false; } - boolean egressDefaultPolicy = offering.getEgressDefaultPolicy(); - Domain networkDomain = _domainDao.findById(network.getDomainId()); - boolean isFirewallServiceSupported = _networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Service.Firewall); - List dnsServers = _nuageVspManager.getDnsDetails(network); - - boolean isL2Network = false, isL3Network = false, isShared = false; - String subnetUuid = network.getUuid(); - if (offering.getGuestType() == Network.GuestType.Shared) { - isShared = true; - subnetUuid = networkDomain.getUuid(); - } else if (_ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(offering.getId(), Service.SourceNat) - || _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(offering.getId(), Service.StaticNat) - || _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(offering.getId(), Service.Connectivity)) { - isL3Network = true; - } else { - isL2Network = true; - } - String preConfiguredDomainTemplateName = NuageVspUtil.getPreConfiguredDomainTemplateName(_configDao, network, offering); - List> ingressFirewallRules = getFirewallRulesToApply(network.getId(), FirewallRule.TrafficType.Ingress, egressDefaultPolicy); - List> egressFirewallRules = getFirewallRulesToApply(network.getId(), FirewallRule.TrafficType.Egress, egressDefaultPolicy); + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network, false); + List dnsServers = _nuageVspManager.getDnsDetails(network); + List ingressFirewallRules = getFirewallRulesToApply(network, FirewallRule.TrafficType.Ingress); + List egressFirewallRules = getFirewallRulesToApply(network, FirewallRule.TrafficType.Egress); List ips = _ipAddressDao.listStaticNatPublicIps(network.getId()); - List acsFipUuid = new ArrayList(); + List floatingIpUuids = new ArrayList(); for (IPAddressVO ip : ips) { - acsFipUuid.add(ip.getUuid()); + floatingIpUuids.add(ip.getUuid()); } HostVO nuageVspHost = getNuageVspHost(network.getPhysicalNetworkId()); - ImplementVspCommand.Builder cmdBuilder = new ImplementVspCommand.Builder() - .networkId(network.getId()) - .networkDomainUuid(networkDomain.getUuid()) - .networkUuid(network.getUuid()) - .networkName(network.getName()) - .vpcOrSubnetUuid(subnetUuid) - .isL2Network(isL2Network) - .isL3Network(isL3Network) - .isVpc(false) - .isShared(isShared) - .domainTemplateName(preConfiguredDomainTemplateName) - .isFirewallServiceSupported(isFirewallServiceSupported) - .dnsServers(dnsServers) - .ingressFirewallRules(ingressFirewallRules) - .egressFirewallRules(egressFirewallRules) - .acsFipUuid(acsFipUuid) - .egressDefaultPolicy(egressDefaultPolicy); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + ImplementVspCommand cmd = new ImplementVspCommand(vspNetwork, dnsServers, ingressFirewallRules, egressFirewallRules, floatingIpUuids); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("ImplementVspCommand for network " + network.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); if ((null != answer) && (null != answer.getDetails())) { @@ -302,23 +279,21 @@ public boolean implement(Network network, NetworkOffering offering, DeployDestin private boolean applyACLRulesForVpc(Network network, NetworkOffering offering) throws ResourceUnavailableException { List rules = _networkACLItemDao.listByACL(network.getNetworkACLId()); if (_networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Network.Service.NetworkACL)) { - applyACLRules(network, rules, true, null, false); + applyACLRules(network, rules, true, false); } return true; } - private List> getFirewallRulesToApply(long networkId, FirewallRule.TrafficType trafficType, final boolean egressDefaultPolicy) { - List firewallRulesToApply = _firewallRulesDao.listByNetworkPurposeTrafficType(networkId, FirewallRule.Purpose.Firewall, trafficType); + private List getFirewallRulesToApply(final Network network, FirewallRule.TrafficType trafficType) { + List firewallRulesToApply = _firewallRulesDao.listByNetworkPurposeTrafficType(network.getId(), FirewallRule.Purpose.Firewall, trafficType); + List vspAclRulesToApply = Lists.newArrayListWithExpectedSize(firewallRulesToApply.size()); + for (FirewallRuleVO rule : firewallRulesToApply) { - // load cidrs if any rule.setSourceCidrList(_firewallRulesCidrsDao.getSourceCidrs(rule.getId())); + VspAclRule vspAclRule = _nuageVspEntityBuilder.buildVspAclRule(rule, network); + vspAclRulesToApply.add(vspAclRule); } - return Lists.transform(firewallRulesToApply, new Function>() { - @Override - public Map apply(FirewallRuleVO firewallRuleVO) { - return getACLRuleDetails(firewallRuleVO, egressDefaultPolicy); - } - }); + return vspAclRulesToApply; } @Override @@ -463,48 +438,19 @@ public boolean removeDhcpSupportForSubnet(Network network) throws ResourceUnavai @Override public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { - //Check if the network is associated to a VPC - Long vpcId = config.getVpcId(); - String vpcOrSubnetUuid = null; - if (vpcId != null) { - Vpc vpcObj = _vpcDao.findById(vpcId); - vpcOrSubnetUuid = vpcObj.getUuid(); - } else { - vpcOrSubnetUuid = config.getUuid(); - } - Domain networkDomain = _domainDao.findById(config.getDomainId()); - - long networkOfferingId = _ntwkOfferingDao.findById(config.getNetworkOfferingId()).getId(); - boolean isL3Network = isL3Network(networkOfferingId); - - List> sourceNatDetails = new ArrayList>(); + List vspStaticNatDetails = new ArrayList(); for (StaticNat staticNat : rules) { - Map sourceNatDetail = new HashMap(); IPAddressVO sourceNatIp = _ipAddressDao.findById(staticNat.getSourceIpAddressId()); - VlanVO sourceNatVan = _vlanDao.findById(sourceNatIp.getVlanId()); + VlanVO sourceNatVlan = _vlanDao.findById(sourceNatIp.getVlanId()); NicVO nicVO = _nicDao.findByIp4AddressAndNetworkId(staticNat.getDestIpAddress(), staticNat.getNetworkId()); - //Just get all the information about the sourceNat which will be used by NuageVsp - //client to process the request - sourceNatDetail.put("sourceNatIpUuid", sourceNatIp.getUuid()); - sourceNatDetail.put("sourceNatIpAddress", sourceNatIp.getAddress().addr()); - sourceNatDetail.put("nicUuid", nicVO == null ? null : nicVO.getUuid()); - sourceNatDetail.put("nicMacAddress", nicVO == null ? null : nicVO.getMacAddress()); - sourceNatDetail.put("isRevoke", staticNat.isForRevoke()); - sourceNatDetail.put("sourceNatVlanUuid", sourceNatVan.getUuid()); - sourceNatDetail.put("sourceNatVlanGateway", sourceNatVan.getVlanGateway()); - sourceNatDetail.put("sourceNatVlanNetmask", sourceNatVan.getVlanNetmask()); - sourceNatDetails.add(sourceNatDetail); + VspStaticNat vspStaticNat = _nuageVspEntityBuilder.buildVspStaticNat(staticNat.isForRevoke(), sourceNatIp, sourceNatVlan, nicVO); + vspStaticNatDetails.add(vspStaticNat); } + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(config, false); HostVO nuageVspHost = getNuageVspHost(config.getPhysicalNetworkId()); - ApplyStaticNatVspCommand.Builder cmdBuilder = new ApplyStaticNatVspCommand.Builder() - .networkDomainUuid(networkDomain.getUuid()) - .networkUuid(config.getUuid()) - .vpcOrSubnetUuid(vpcOrSubnetUuid) - .isL3Network(isL3Network) - .isVpc(vpcId != null) - .staticNatDetails(sourceNatDetails); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + ApplyStaticNatVspCommand cmd = new ApplyStaticNatVspCommand(vspNetwork, vspStaticNatDetails); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("ApplyStaticNatNuageVspCommand for network " + config.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); if ((null != answer) && (null != answer.getDetails())) { @@ -534,44 +480,27 @@ public boolean applyFWRules(Network network, List rules) } s_logger.info("Applying " + rules.size() + " Firewall Rules for network " + network.getName()); - return applyACLRules(network, rules, false, rules.iterator().next().getTrafficType().equals(FirewallRule.TrafficType.Ingress), false); + return applyACLRules(network, rules, false, false); } - protected boolean applyACLRules(Network network, List rules, boolean isNetworkAcl, Boolean isAcsIngressAcl, boolean networkReset) + protected boolean applyACLRules(final Network network, List rules, boolean isNetworkAcl, boolean networkReset) throws ResourceUnavailableException { - Domain networksDomain = _domainDao.findById(network.getDomainId()); - NetworkOfferingVO networkOfferingVO = _ntwkOfferingDao.findById(network.getNetworkOfferingId()); - Long vpcId = network.getVpcId(); - String vpcOrSubnetUuid = null; - if (vpcId != null) { - Vpc vpcObj = _vpcDao.findById(vpcId); - vpcOrSubnetUuid = vpcObj.getUuid(); - } else { - vpcOrSubnetUuid = network.getUuid(); - } - boolean egressDefaultPolicy = networkOfferingVO.getEgressDefaultPolicy(); - List> aclRules = new ArrayList>(); - for (InternalIdentity acl : rules) { - aclRules.add(getACLRuleDetails(acl, egressDefaultPolicy)); - } + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network, false); + List vspAclRules = Lists.transform(rules, new Function() { + @Nullable + @Override + public VspAclRule apply(@Nullable InternalIdentity input) { + if (input instanceof FirewallRule) { + return _nuageVspEntityBuilder.buildVspAclRule((FirewallRule) input, network); + } + return _nuageVspEntityBuilder.buildVspAclRule((NetworkACLItem) input); + } + }); - boolean isL3Network = isL3Network(network.getNetworkOfferingId()); HostVO nuageVspHost = getNuageVspHost(network.getPhysicalNetworkId()); - String preConfiguredDomainTemplateName = NuageVspUtil.getPreConfiguredDomainTemplateName(_configDao, network, networkOfferingVO); - ApplyAclRuleVspCommand.Builder cmdBuilder = new ApplyAclRuleVspCommand.Builder() - .networkAcl(isNetworkAcl) - .networkUuid(network.getUuid()) - .networkDomainUuid(networksDomain.getUuid()) - .vpcOrSubnetUuid(vpcOrSubnetUuid) - .networkName(network.getName()) - .isL2Network(!isL3Network) - .aclRules(aclRules) - .networkId(network.getId()) - .egressDefaultPolicy(networkOfferingVO.getEgressDefaultPolicy()) - .acsIngressAcl(isAcsIngressAcl) - .networkReset(networkReset) - .domainTemplateName(preConfiguredDomainTemplateName); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + VspAclRule.ACLType vspAclType = isNetworkAcl ? VspAclRule.ACLType.NetworkACL : VspAclRule.ACLType.Firewall; + ApplyAclRuleVspCommand cmd = new ApplyAclRuleVspCommand(vspAclType, vspNetwork, vspAclRules, networkReset); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("ApplyAclRuleNuageVspCommand for network " + network.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); if ((null != answer) && (null != answer.getDetails())) { @@ -594,7 +523,7 @@ public boolean applyNetworkACLs(Network config, List r } if (rules != null) { s_logger.info("Applying " + rules.size() + " Network ACLs for network " + config.getName()); - applyACLRules(config, rules, true, null, rules.isEmpty()); + applyACLRules(config, rules, true, rules.isEmpty()); } return true; } @@ -625,12 +554,17 @@ public boolean shutdownVpc(Vpc vpc, ReservationContext context) throws Concurren if (vpc.getState().equals(Vpc.State.Inactive)) { Domain vpcDomain = _domainDao.findById(vpc.getDomainId()); HostVO nuageVspHost = getNuageVspHost(getPhysicalNetworkId(vpc.getZoneId())); - String preConfiguredDomainTemplateName = _configDao.getValue(NuageVspManager.NuageVspVpcDomainTemplateName.key()); - ShutDownVpcVspCommand.Builder cmdBuilder = new ShutDownVpcVspCommand.Builder() - .domainUuid(vpcDomain.getUuid()) - .vpcUuid(vpc.getUuid()) - .domainTemplateName(preConfiguredDomainTemplateName); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + + String preConfiguredDomainTemplateName; + VpcDetailVO domainTemplateNameDetail = _vpcDetailsDao.findDetail(vpc.getId(), NuageVspManager.nuageDomainTemplateDetailName); + if (domainTemplateNameDetail != null) { + preConfiguredDomainTemplateName = domainTemplateNameDetail.getValue(); + } else { + preConfiguredDomainTemplateName = _configDao.getValue(NuageVspManager.NuageVspVpcDomainTemplateName.key()); + } + + ShutDownVpcVspCommand cmd = new ShutDownVpcVspCommand(vpcDomain.getUuid(), vpc.getUuid(), preConfiguredDomainTemplateName); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("ShutDownVpcVspCommand for VPC " + vpc.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); if ((null != answer) && (null != answer.getDetails())) { @@ -707,50 +641,4 @@ private HostVO getNuageVspHost(Long physicalNetworkId) { } return nuageVspHost; } - - protected boolean isL3Network(Long offeringId) { - return _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(offeringId, Service.SourceNat) - || _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(offeringId, Service.StaticNat); - } - - private Map getACLRuleDetails(Object aclRule, boolean egressDefaultPolicy) { - Map aclDetails = new HashMap(); - if (aclRule instanceof FirewallRule) { - FirewallRule firewallRule = (FirewallRule)aclRule; - aclDetails.put("sourceCidrList", firewallRule.getSourceCidrList()); - aclDetails.put("uuid", firewallRule.getUuid()); - aclDetails.put("protocol", firewallRule.getProtocol()); - aclDetails.put("startPort", firewallRule.getSourcePortStart()); - aclDetails.put("endPort", firewallRule.getSourcePortEnd()); - aclDetails.put("state", firewallRule.getState().name()); - aclDetails.put("trafficType", firewallRule.getTrafficType().name()); - if (firewallRule.getSourceIpAddressId() != null) { - //add the source IP - IPAddressVO ipaddress = _ipAddressDao.findById(((FirewallRule)aclRule).getSourceIpAddressId()); - aclDetails.put("sourceIpAddress", ipaddress != null ? ipaddress.getVmIp() + "/32" : null); - } - if (firewallRule.getTrafficType().equals(FirewallRule.TrafficType.Egress) && egressDefaultPolicy) { - aclDetails.put("action", "Deny"); - } else { - aclDetails.put("action", "Allow"); - } - aclDetails.put("priority", -1); - aclDetails.put("type", "Firewall"); - } else { - NetworkACLItem networkAcl = (NetworkACLItem)aclRule; - aclDetails.put("sourceCidrList", networkAcl.getSourceCidrList()); - aclDetails.put("uuid", networkAcl.getUuid()); - aclDetails.put("protocol", networkAcl.getProtocol()); - aclDetails.put("startPort", networkAcl.getSourcePortStart()); - aclDetails.put("endPort", networkAcl.getSourcePortEnd()); - aclDetails.put("state", networkAcl.getState().name()); - aclDetails.put("trafficType", networkAcl.getTrafficType().name()); - //Set sourceIP to null as it is not applicable - aclDetails.put("sourceIpAddress", null); - aclDetails.put("action", networkAcl.getAction().name()); - aclDetails.put("priority", networkAcl.getNumber()); - aclDetails.put("type", "NetworkACL"); - } - return aclDetails; - } } \ No newline at end of file diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java index 2037d925ed..a6c17e3517 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java @@ -31,18 +31,14 @@ import com.cloud.dc.VlanVO; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; -import com.cloud.domain.Domain; -import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapacityException; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; -import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.GuestType; -import com.cloud.network.Network.Service; import com.cloud.network.Network.State; import com.cloud.network.NetworkProfile; import com.cloud.network.Networks; @@ -50,11 +46,12 @@ import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetwork.IsolationMethod; import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkDetailVO; +import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.NuageVspDao; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.manager.NuageVspManager; -import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -62,28 +59,25 @@ import com.cloud.user.Account; import com.cloud.user.AccountVO; import com.cloud.user.dao.AccountDao; -import com.cloud.util.NuageVspUtil; +import com.cloud.utils.StringUtils; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.net.NetUtils; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; -import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.google.common.base.Strings; -import org.apache.commons.lang.StringUtils; +import com.cloud.util.NuageVspEntityBuilder; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; +import net.nuage.vsp.acs.client.api.model.VspVm; +import org.apache.cloudstack.resourcedetail.VpcDetailVO; +import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao; import org.apache.log4j.Logger; import javax.inject.Inject; -import java.net.URI; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; import java.util.List; -import java.util.Set; -import java.util.TreeSet; public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { public static final Logger s_logger = Logger.getLogger(NuageVspGuestNetworkGuru.class); @@ -108,6 +102,12 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { NuageVspManager _nuageVspManager; @Inject ConfigurationManager _configMgr; + @Inject + NuageVspEntityBuilder _nuageVspEntityBuilder; + @Inject + NetworkDetailsDao _networkDetailsDao; + @Inject + VpcDetailsDao _vpcDetailsDao; public NuageVspGuestNetworkGuru() { super(); @@ -148,6 +148,15 @@ public Network implement(Network network, NetworkOffering offering, DeployDestin throw new IllegalStateException("Network " + networkId + " is not in expected state Implementing, but is in state " + network.getState()); } + //Get the Account details and find the type + AccountVO networksAccount = _accountDao.findById(network.getAccountId()); + if (networksAccount.getType() == Account.ACCOUNT_TYPE_PROJECT) { + String errorMessage = "Networks created by account " + networksAccount.getAccountName() + " of type Project (" + Account.ACCOUNT_TYPE_PROJECT + ") " + + "are not yet supported by NuageVsp provider"; + s_logger.error(errorMessage); + throw new InsufficientVirtualNetworkCapacityException(errorMessage, Account.class, network.getAccountId()); + } + long dcId = dest.getDataCenter().getId(); //Get physical network id Long physicalNetworkId = network.getPhysicalNetworkId(); @@ -155,80 +164,29 @@ public Network implement(Network network, NetworkOffering offering, DeployDestin if (physicalNetworkId == null) { physicalNetworkId = _networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType()); } - implemented = new NetworkVO(network.getTrafficType(), network.getMode(), network.getBroadcastDomainType(), network.getNetworkOfferingId(), State.Allocated, - network.getDataCenterId(), physicalNetworkId, offering.getRedundantRouter()); + + implemented = new NetworkVO(network.getId(), network, network.getNetworkOfferingId(), network.getGuruName(), network.getDomainId(), network.getAccountId(), + network.getRelated(), network.getName(), network.getDisplayText(), network.getNetworkDomain(), network.getGuestType(), network.getDataCenterId(), + physicalNetworkId, network.getAclType(), network.getSpecifyIpRanges(), network.getVpcId(), offering.getRedundantRouter()); + implemented.setUuid(network.getUuid()); + implemented.setState(State.Allocated); if (network.getGateway() != null) { implemented.setGateway(network.getGateway()); } if (network.getCidr() != null) { implemented.setCidr(network.getCidr()); } - List ipAddressRanges = new ArrayList(); - String virtualRouterIp = getVirtualRouterIP(network, ipAddressRanges); - String networkUuid = implemented.getUuid(); + + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(implemented, true); String tenantId = context.getDomain().getName() + "-" + context.getAccount().getAccountId(); - String broadcastUriStr = networkUuid + "/" + virtualRouterIp; + String broadcastUriStr = implemented.getUuid() + "/" + vspNetwork.getVirtualRouterIp(); implemented.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr)); implemented.setBroadcastDomainType(Networks.BroadcastDomainType.Vsp); - //Check if the network is associated to a VPC - Long vpcId = network.getVpcId(); - boolean isVpc = (vpcId != null); - //Check owner of the Network - Domain networksDomain = _domainDao.findById(network.getDomainId()); - //Get the Account details and find the type - AccountVO networksAccount = _accountDao.findById(network.getAccountId()); - if (networksAccount.getType() == Account.ACCOUNT_TYPE_PROJECT) { - String errorMessage = "Networks created by account " + networksAccount.getAccountName() + " of type Project (" + Account.ACCOUNT_TYPE_PROJECT + ") " + - "are not yet supported by NuageVsp provider"; - s_logger.error(errorMessage); - throw new InsufficientVirtualNetworkCapacityException(errorMessage, Account.class, network.getAccountId()); - } - String vpcName = null; - String vpcUuid = null; - String preConfiguredDomainTemplateName = NuageVspUtil.getPreConfiguredDomainTemplateName(_configDao, network, offering); - boolean isSharedNetwork = offering.getGuestType() == GuestType.Shared; - boolean isL3Network = !isVpc && (isSharedNetwork || isL3Network(network)); - - if (isVpc) { - Vpc vpcObj = _vpcDao.findById(vpcId); - vpcName = vpcObj.getName(); - vpcUuid = vpcObj.getUuid(); - } - - if (isSharedNetwork) { - List vlans = _vlanDao.listVlansByNetworkId(network.getId()); - for (VlanVO vlan : vlans) { - boolean isIpv4 = StringUtils.isNotBlank(vlan.getIpRange()); - String[] range = isIpv4 ? vlan.getIpRange().split("-") : vlan.getIp6Range().split("-"); - ipAddressRanges.add(range); - } - } HostVO nuageVspHost = getNuageVspHost(physicalNetworkId); List dnsServers = _nuageVspManager.getDnsDetails(network); - List gatewaySystemIds = _nuageVspManager.getGatewaySystemIds(); - ImplementNetworkVspCommand.Builder cmdBuilder = new ImplementNetworkVspCommand.Builder() - .networkDomainName(networksDomain.getName()) - .networkDomainPath(networksDomain.getPath()) - .networkDomainUuid(networksDomain.getUuid()) - .networkAccountName(networksAccount.getAccountName()) - .networkAccountUuid(networksAccount.getUuid()) - .networkName(network.getName()) - .networkCidr(network.getCidr()) - .networkGateway(network.getGateway()) - .networkAclId(network.getNetworkACLId()) - .dnsServers(dnsServers) - .gatewaySystemIds(gatewaySystemIds) - .networkUuid(network.getUuid()) - .isL3Network(isL3Network) - .isVpc(isVpc) - .isSharedNetwork(isSharedNetwork) - .vpcName(vpcName) - .vpcUuid(vpcUuid) - .defaultEgressPolicy(offering.getEgressDefaultPolicy()) - .ipAddressRange(ipAddressRanges) - .domainTemplateName(preConfiguredDomainTemplateName); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + ImplementNetworkVspCommand cmd = new ImplementNetworkVspCommand(vspNetwork, dnsServers); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("ImplementNetworkVspCommand for network " + network.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); @@ -237,7 +195,18 @@ public Network implement(Network network, NetworkOffering offering, DeployDestin } return null; } - s_logger.info("Implemented OK, network " + networkUuid + " in tenant " + tenantId + " linked to " + implemented.getBroadcastUri()); + + if (StringUtils.isNotBlank(vspNetwork.getDomainTemplateName())) { + if (network.getVpcId() != null) { + VpcDetailVO vpcDetail = new VpcDetailVO(network.getVpcId(), NuageVspManager.nuageDomainTemplateDetailName, vspNetwork.getDomainTemplateName(), false); + _vpcDetailsDao.persist(vpcDetail); + } else { + NetworkDetailVO networkDetail = new NetworkDetailVO(implemented.getId(), NuageVspManager.nuageDomainTemplateDetailName, vspNetwork.getDomainTemplateName(), false); + _networkDetailsDao.persist(networkDetail); + } + } + + s_logger.info("Implemented OK, network " + implemented.getUuid() + " in tenant " + tenantId + " linked to " + implemented.getBroadcastUri()); } finally { _networkDao.releaseFromLockTable(network.getId()); } @@ -262,68 +231,38 @@ public void reserve(NicProfile nic, Network network, VirtualMachineProfile vm, D if (s_logger.isDebugEnabled()) { s_logger.debug("Handling reserve() call back to with Create a new VM or add an interface to existing VM in network " + network.getName()); } - nic.setBroadcastUri(network.getBroadcastUri()); - nic.setIsolationUri(network.getBroadcastUri()); + DataCenter dc = _dcDao.findById(network.getDataCenterId()); - Account networksAccount = _accountDao.findById(network.getAccountId()); - DomainVO networksDomain = _domainDao.findById(network.getDomainId()); - //Get the Account details and find the type - long networkOwnedBy = network.getAccountId(); - AccountVO neworkAccountDetails = _accountDao.findById(networkOwnedBy); + AccountVO neworkAccountDetails = _accountDao.findById(network.getAccountId()); if (neworkAccountDetails.getType() == Account.ACCOUNT_TYPE_PROJECT) { throw new InsufficientVirtualNetworkCapacityException("CS project support is not yet implemented in NuageVsp", DataCenter.class, dc.getId()); } - //NicProfile does not contain the NIC UUID. We need this information to set it in the VMInterface and VPort - //that we create in VSP - NicVO nicFrmDB = _nicDao.findById(nic.getId()); - NetworkOffering networkOffering = _ntwkOfferingDao.findById(network.getNetworkOfferingId()); - boolean isDomainRouter = vm.getType().equals(VirtualMachine.Type.DomainRouter); - URI broadcastUri = network.getBroadcastUri(); - if (Strings.isNullOrEmpty(broadcastUri.getPath()) || !broadcastUri.getPath().startsWith("/")) { + if (Strings.isNullOrEmpty(network.getBroadcastUri().getPath()) || !network.getBroadcastUri().getPath().startsWith("/")) { throw new IllegalStateException("The broadcast URI path " + network.getBroadcastUri() + " is empty or in an incorrect format."); } - String domainRouterIp = network.getBroadcastUri().getPath().substring(1); - boolean isL3Network = isL3Network(network); - boolean isSharedNetwork = networkOffering.getGuestType() == GuestType.Shared; - Long vpcId = network.getVpcId(); - String vpcUuid = null; - if (vpcId != null) { - Vpc vpcObj = _vpcDao.findById(vpcId); - vpcUuid = vpcObj.getUuid(); - } - HostVO nuageVspHost = getNuageVspHost(network.getPhysicalNetworkId()); + + nic.setBroadcastUri(network.getBroadcastUri()); + nic.setIsolationUri(network.getBroadcastUri()); + + //NicProfile does not contain the NIC UUID. We need this information to set it in the VMInterface and VPort + //that we create in VSP + NicVO nicFromDb = _nicDao.findById(nic.getId()); IPAddressVO staticNatIp = _ipAddressDao.findByVmIdAndNetworkId(network.getId(), vm.getId()); - ReserveVmInterfaceVspCommand.Builder cmdBuilder = new ReserveVmInterfaceVspCommand.Builder() - .nicUuid(nicFrmDB.getUuid()) - .nicMacAddress(nic.getMacAddress()) - .networkUuid(network.getUuid()) - .isL3Network(isL3Network) - .isSharedNetwork(isSharedNetwork) - .vpcUuid(vpcUuid) - .networkDomainUuid(networksDomain.getUuid()) - .networksAccountUuid(networksAccount.getUuid()) - .isDomainRouter(isDomainRouter) - .domainRouterIp(domainRouterIp) - .vmInstanceName(vm.getInstanceName()) - .vmUuid(vm.getUuid()) - .vmUserName(networksDomain.getUuid()) - .vmUserDomainName(networksAccount.getUuid()) - .useStaticIp(true) - .staticIp(nic.getIPv4Address()); + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network, false); + VspVm vspVm = _nuageVspEntityBuilder.buildVspVm(vm.getVirtualMachine(), network); + VspNic vspNic = _nuageVspEntityBuilder.buildVspNic(nicFromDb.getUuid(), nic); + VspStaticNat vspStaticNat = null; if (staticNatIp != null) { VlanVO staticNatVlan = _vlanDao.findById(staticNatIp.getVlanId()); - cmdBuilder = cmdBuilder.staticNatIpUuid(staticNatIp.getUuid()) - .staticNatIpAddress(staticNatIp.getAddress().addr()) - .isStaticNatIpAllocated(staticNatIp.getState().equals(IpAddress.State.Allocated)) - .isOneToOneNat(staticNatIp.isOneToOneNat()) - .staticNatVlanUuid(staticNatVlan.getUuid()) - .staticNatVlanGateway(staticNatVlan.getVlanGateway()) - .staticNatVlanNetmask(staticNatVlan.getVlanNetmask()); + vspStaticNat = _nuageVspEntityBuilder.buildVspStaticNat(null, staticNatIp, staticNatVlan, null); } - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + HostVO nuageVspHost = getNuageVspHost(network.getPhysicalNetworkId()); + ReserveVmInterfaceVspCommand cmd = new ReserveVmInterfaceVspCommand(vspNetwork, vspVm, vspNic, vspStaticNat); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); + if (answer == null || !answer.getResult()) { s_logger.error("ReserveVmInterfaceNuageVspCommand failed for NIC " + nic.getId() + " attached to VM " + vm.getId() + " in network " + network.getId()); if ((null != answer) && (null != answer.getDetails())) { @@ -332,8 +271,8 @@ public void reserve(NicProfile nic, Network network, VirtualMachineProfile vm, D throw new InsufficientVirtualNetworkCapacityException("Failed to reserve VM in Nuage VSP.", Network.class, network.getId()); } - if (isDomainRouter) { - nic.setIPv4Address(domainRouterIp); + if (vspVm.getDomainRouter() == Boolean.TRUE) { + nic.setIPv4Address(vspVm.getDomainRouterIp()); } } finally { @@ -378,32 +317,16 @@ public void deallocate(Network network, NicProfile nic, VirtualMachineProfile vm s_logger.debug("Handling deallocate() call back, which is called when a VM is destroyed or interface is removed, " + "to delete VM Interface with IP " + nic.getIPv4Address() + " from a VM " + vm.getInstanceName() + " with state " + vm.getVirtualMachine().getState()); } - DomainVO networksDomain = _domainDao.findById(network.getDomainId()); - NicVO nicFrmDd = _nicDao.findById(nic.getId()); - NetworkOffering networkOffering = _ntwkOfferingDao.findById(network.getNetworkOfferingId()); - boolean isL3Network = isL3Network(network); - boolean isSharedNetwork = networkOffering.getGuestType() == GuestType.Shared; - boolean isExpunging = vm.getVirtualMachine().getState() == VirtualMachine.State.Expunging; - Long vpcId = network.getVpcId(); - String vpcUuid = null; - if (vpcId != null) { - Vpc vpcObj = _vpcDao.findById(vpcId); - vpcUuid = vpcObj.getUuid(); - } + + NicVO nicFromDb = _nicDao.findById(nic.getId()); + + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network, false); + VspVm vspVm = _nuageVspEntityBuilder.buildVspVm(vm.getVirtualMachine(), network); + VspNic vspNic = _nuageVspEntityBuilder.buildVspNic(nicFromDb.getUuid(), nic); HostVO nuageVspHost = getNuageVspHost(network.getPhysicalNetworkId()); - DeallocateVmVspCommand.Builder cmdBuilder = new DeallocateVmVspCommand.Builder() - .networkUuid(network.getUuid()) - .nicFromDbUuid(nicFrmDd.getUuid()) - .nicMacAddress(nic.getMacAddress()) - .nicIp4Address(nic.getIPv4Address()) - .isL3Network(isL3Network) - .isSharedNetwork(isSharedNetwork) - .vpcUuid(vpcUuid) - .networksDomainUuid(networksDomain.getUuid()) - .vmInstanceName(vm.getInstanceName()) - .vmUuid(vm.getUuid()) - .isExpungingState(isExpunging); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + + DeallocateVmVspCommand cmd = new DeallocateVmVspCommand(vspNetwork, vspVm, vspNic); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("DeallocateVmNuageVspCommand for VM " + vm.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); if ((null != answer) && (null != answer.getDetails())) { @@ -451,27 +374,10 @@ public boolean trash(Network network, NetworkOffering offering) { if (s_logger.isDebugEnabled()) { s_logger.debug("Handling trash() call back to delete the network " + network.getName() + " with uuid " + network.getUuid() + " from VSP"); } - long domainId = network.getDomainId(); - Domain domain = _domainDao.findById(domainId); - boolean isL3Network = isL3Network(network); - boolean isSharedNetwork = offering.getGuestType() == GuestType.Shared; - Long vpcId = network.getVpcId(); - String vpcUuid = null; - if (vpcId != null) { - Vpc vpcObj = _vpcDao.findById(vpcId); - vpcUuid = vpcObj.getUuid(); - } - - String preConfiguredDomainTemplateName = NuageVspUtil.getPreConfiguredDomainTemplateName(_configDao, network, offering); + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network, false); HostVO nuageVspHost = getNuageVspHost(network.getPhysicalNetworkId()); - TrashNetworkVspCommand.Builder cmdBuilder = new TrashNetworkVspCommand.Builder() - .domainUuid(domain.getUuid()) - .networkUuid(network.getUuid()) - .isL3Network(isL3Network) - .isSharedNetwork(isSharedNetwork) - .vpcUuid(vpcUuid) - .domainTemplateName(preConfiguredDomainTemplateName); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + TrashNetworkVspCommand cmd = new TrashNetworkVspCommand(vspNetwork); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("TrashNetworkNuageVspCommand for network " + network.getUuid() + " failed"); if ((null != answer) && (null != answer.getDetails())) { @@ -485,51 +391,6 @@ public boolean trash(Network network, NetworkOffering offering) { return super.trash(network, offering); } - private String getVirtualRouterIP(Network network, Collection ipAddressRanges) throws InsufficientVirtualNetworkCapacityException { - String virtualRouterIp; - //Check if the subnet has minimum 5 host in it. - String subnet = NetUtils.getCidrSubNet(network.getCidr()); - String netmask = NetUtils.getCidrNetmask(network.getCidr()); - long cidrSize = NetUtils.getCidrSize(netmask); - - Set allIPsInCidr = NetUtils.getAllIpsFromCidr(subnet, cidrSize, new HashSet()); - if (allIPsInCidr == null || !(allIPsInCidr instanceof TreeSet)) { - throw new IllegalStateException("The IPs in CIDR for subnet " + subnet + " where null or returned in a non-ordered set."); - } - - if (allIPsInCidr.size() > 3) { - //get the second IP and see if it the networks GatewayIP - Iterator ipIterator = allIPsInCidr.iterator(); - long vip = ipIterator.next(); - if (NetUtils.ip2Long(network.getGateway()) == vip) { - vip = ipIterator.next(); - virtualRouterIp = NetUtils.long2Ip(vip); - if (s_logger.isDebugEnabled()) { - s_logger.debug("1st IP is used as gateway IP. Reserving " + virtualRouterIp + " for the Virtual Router IP for Network(" + network.getName() + ")"); - } - } else { - virtualRouterIp = NetUtils.long2Ip(vip); - if (s_logger.isDebugEnabled()) { - s_logger.debug("1st IP is not used as the gateway IP. Reserving" + virtualRouterIp + " for the Virtual Router IP for Network(" + network.getName() + ")"); - } - } - ipAddressRanges.add(new String[] { - NetUtils.long2Ip(ipIterator.next()), - NetUtils.getIpRangeEndIpFromCidr(subnet, cidrSize) - }); - return virtualRouterIp; - } - - throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " So, subnet should have atleast minimum 4 hosts ", Network.class, - network.getId()); - } - - private boolean isL3Network(Network network) { - return _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Service.SourceNat) - || _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Service.StaticNat) - || network.getGuestType() == GuestType.Shared; - } - private HostVO getNuageVspHost(long physicalNetworkId) { HostVO nuageVspHost; List nuageVspDevices = _nuageVspDao.listByPhysicalNetwork(physicalNetworkId); diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManager.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManager.java index 0aae22ccce..4861fb240d 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManager.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManager.java @@ -40,6 +40,8 @@ public interface NuageVspManager extends PluggableService { static final String nuageVPCOfferingDisplayText = "Nuage VSP VPC Offering"; + static final String nuageDomainTemplateDetailName = "domainTemplateName"; + static final ConfigKey NuageVspConfigDns = new ConfigKey(Boolean.class, "nuagevsp.configure.dns", "Advanced", "true", "Defines if NuageVsp plugin needs to configure DNS setting for a VM or not. True will configure the DNS and false will not configure the DNS settings", true, Scope.Global, null); diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java index f38a9c702c..04b1ccc9f9 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java @@ -27,8 +27,8 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.PingNuageVspCommand; import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.manager.GetClientDefaultsAnswer; -import com.cloud.agent.api.manager.GetClientDefaultsCommand; +import com.cloud.agent.api.manager.GetApiDefaultsAnswer; +import com.cloud.agent.api.manager.GetApiDefaultsCommand; import com.cloud.agent.api.manager.SupportedApiVersionCommand; import com.cloud.agent.api.sync.SyncDomainAnswer; import com.cloud.agent.api.sync.SyncDomainCommand; @@ -37,7 +37,6 @@ import com.cloud.api.ApiDBUtils; import com.cloud.api.commands.AddNuageVspDeviceCmd; import com.cloud.api.commands.DeleteNuageVspDeviceCmd; -import com.cloud.api.commands.IssueNuageVspResourceRequestCmd; import com.cloud.api.commands.ListNuageVspDevicesCmd; import com.cloud.api.commands.UpdateNuageVspDeviceCmd; import com.cloud.api.response.NuageVspDeviceResponse; @@ -70,7 +69,6 @@ import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.resource.NuageVspResource; -import com.cloud.network.sync.NuageVspSync; import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.VpcOffering; import com.cloud.network.vpc.VpcOfferingServiceMapVO; @@ -106,7 +104,10 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.cloud.util.NuageVspEntityBuilder; import net.nuage.vsp.acs.NuageVspPluginClientLoader; +import net.nuage.vsp.acs.client.api.model.VspApiDefaults; +import net.nuage.vsp.acs.client.api.model.VspDomain; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -127,7 +128,6 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.ExecutionException; -import java.util.concurrent.ScheduledExecutorService; import static com.cloud.agent.api.sync.SyncNuageVspCmsIdCommand.SyncType; @@ -135,8 +135,6 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager, private static final Logger s_logger = Logger.getLogger(NuageVspManagerImpl.class); - private static final int ONE_MINUTE_MULTIPLIER = 60 * 1000; - public static final Map> NUAGE_VSP_VPC_SERVICE_MAP; private static final ConfigKey[] NUAGE_VSP_CONFIG_KEYS = new ConfigKey[] { NuageVspConfigDns, NuageVspDnsExternal, NuageVspConfigGateway, NuageVspSharedNetworkDomainTemplateName, NuageVspVpcDomainTemplateName, NuageVspIsolatedNetworkDomainTemplateName }; @@ -164,8 +162,6 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager, @Inject NuageVspDao _nuageVspDao; @Inject - NuageVspSync _nuageVspSync; - @Inject DataCenterDao _dataCenterDao; @Inject ConfigurationDao _configDao; @@ -187,8 +183,8 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager, NetworkOfferingDao _networkOfferingDao; @Inject NetworkOfferingServiceMapDao _networkOfferingServiceMapDao; - - private ScheduledExecutorService scheduler; + @Inject + NuageVspEntityBuilder _nuageVspEntityBuilder; @Inject MessageBus _messageBus; @@ -212,7 +208,7 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager, @Override public List> getCommands() { return Lists.>newArrayList(AddNuageVspDeviceCmd.class, DeleteNuageVspDeviceCmd.class, ListNuageVspDevicesCmd.class, - IssueNuageVspResourceRequestCmd.class, UpdateNuageVspDeviceCmd.class); + UpdateNuageVspDeviceCmd.class); } @Override @@ -242,21 +238,21 @@ public NuageVspDeviceVO addNuageVspDevice(AddNuageVspDeviceCmd cmd) { } try { - NuageVspPluginClientLoader clientLoader = NuageVspPluginClientLoader.getClientLoader(null, null, 1, 1, null); + NuageVspPluginClientLoader clientLoader = NuageVspPluginClientLoader.getClientLoader(null, null, null, null, 1, 1, null); - Map clientDefaults = clientLoader.getNuageVspManagerClient().getClientDefaults(); - String apiVersion = MoreObjects.firstNonNull(cmd.getApiVersion(), (String) clientDefaults.get("CURRENT_API_VERSION")); + VspApiDefaults apiDefaults = clientLoader.getNuageVspManagerClient().getApiDefaults(); + String apiVersion = MoreObjects.firstNonNull(cmd.getApiVersion(), apiDefaults.getVersion()); if (!clientLoader.getNuageVspManagerClient().isSupportedApiVersion(apiVersion)) { throw new CloudRuntimeException("Unsupported API version : " + apiVersion); } int port = cmd.getPort(); if (0 == port) { - port = 8443; + port = 443; } String cmsUserPasswordBase64 = NuageVspUtil.encodePassword(cmd.getPassword()); - String retryCount = String.valueOf(MoreObjects.firstNonNull(cmd.getApiRetryCount(), clientDefaults.get("DEFAULT_API_RETRY_COUNT"))); - String retryInterval = String.valueOf(MoreObjects.firstNonNull(cmd.getApiRetryInterval(), clientDefaults.get("DEFAULT_API_RETRY_INTERVAL"))); + String retryCount = String.valueOf(MoreObjects.firstNonNull(cmd.getApiRetryCount(), apiDefaults.getRetryCount())); + String retryInterval = String.valueOf(MoreObjects.firstNonNull(cmd.getApiRetryInterval(), apiDefaults.getRetryInterval())); NuageVspResource.Configuration resourceConfiguration = new NuageVspResource.Configuration() .name("Nuage VSD - " + cmd.getHostName()) .guid(UUID.randomUUID().toString()) @@ -284,22 +280,33 @@ public NuageVspDeviceVO addNuageVspDevice(AddNuageVspDeviceCmd cmd) { _hostDetailsDao.persist(detail); ConfigurationVO cmsIdConfig = _configDao.findByName("nuagevsp.cms.id"); + NuageVspDeviceVO matchingNuageVspDevice = findMatchingNuageVspDevice(nuageVspDevice); + String cmsId; + if (matchingNuageVspDevice != null) { + cmsId = findNuageVspCmsIdForDevice(matchingNuageVspDevice.getId(), cmsIdConfig); + } else { + SyncNuageVspCmsIdCommand syncCmd = new SyncNuageVspCmsIdCommand(SyncType.REGISTER, null); + SyncNuageVspCmsIdAnswer answer = (SyncNuageVspCmsIdAnswer) _agentMgr.easySend(nuageVspDevice.getHostId(), syncCmd); + if (answer != null && answer.getSuccess()) { + cmsId = answer.getNuageVspCmsId(); + } else { + throw new CloudRuntimeException("Failed to register CMS ID"); + } + } + host = findNuageVspHost(nuageVspDevice.getHostId()); - SyncNuageVspCmsIdCommand syncCmd = new SyncNuageVspCmsIdCommand(SyncType.REGISTER, null); - SyncNuageVspCmsIdAnswer answer = (SyncNuageVspCmsIdAnswer) _agentMgr.easySend(nuageVspDevice.getHostId(), syncCmd); - if (answer != null && answer.getSuccess()) { - registerNewNuageVspDevice(cmsIdConfig, nuageVspDevice.getId() + ":" + answer.getNuageVspCmsId()); + registerNewNuageVspDevice(cmsIdConfig, nuageVspDevice.getId() + ":" + cmsId); - detail = new DetailVO(host.getId(), "nuagevspcmsid", answer.getNuageVspCmsId()); - _hostDetailsDao.persist(detail); + detail = new DetailVO(host.getId(), "nuagevspcmsid", cmsId); + _hostDetailsDao.persist(detail); - resourceConfiguration.nuageVspCmsId(answer.getNuageVspCmsId()); - resource.configure(cmd.getHostName(), Maps.newHashMap(resourceConfiguration.build())); + resourceConfiguration.nuageVspCmsId(cmsId); + resource.configure(cmd.getHostName(), Maps.newHashMap(resourceConfiguration.build())); + if (matchingNuageVspDevice == null) { auditDomainsOnVsp((HostVO) host, true, false); - } else { - throw new CloudRuntimeException("Failed to register CMS ID"); } + return nuageVspDevice; } catch (ConfigurationException e) { s_logger.error("Failed to configure Nuage VSD resource " + cmd.getHostName(), e); @@ -372,13 +379,13 @@ public NuageVspDeviceVO updateNuageVspDevice(UpdateNuageVspDeviceCmd command) { updateRequired = true; } - GetClientDefaultsCommand getClientDefaultsCmd = new GetClientDefaultsCommand(); - GetClientDefaultsAnswer getClientDefaultsAnswer = (GetClientDefaultsAnswer) _agentMgr.easySend(nuageVspHost.getId(), getClientDefaultsCmd); + GetApiDefaultsCommand apiDefaultsCmd = new GetApiDefaultsCommand(); + GetApiDefaultsAnswer apiDefaultsAnswer = (GetApiDefaultsAnswer) _agentMgr.easySend(nuageVspHost.getId(), apiDefaultsCmd); String apiVersion = MoreObjects.firstNonNull(command.getApiVersion(), resourceConfiguration.apiVersion()); SupportedApiVersionCommand supportedApiVersionCmd = new SupportedApiVersionCommand(apiVersion); Answer supportedApiVersionAnswer = _agentMgr.easySend(nuageVspHost.getId(), supportedApiVersionCmd); if (!supportedApiVersionAnswer.getResult()) { - throw new CloudRuntimeException("Incorrect API version: Nuage plugin only supports " + getClientDefaultsAnswer.getCurrentApiVersion()); + throw new CloudRuntimeException("Incorrect API version: Nuage plugin only supports " + apiDefaultsAnswer.getApiDefaults().getVersion()); } String apiRelativePath = "/nuage/api/" + apiVersion; @@ -474,25 +481,31 @@ public boolean deleteNuageVspDevice(DeleteNuageVspDeviceCmd cmd) { } } + NuageVspDeviceVO matchingNuageVspDevice = findMatchingNuageVspDevice(nuageVspDevice); ConfigurationVO cmsIdConfig = _configDao.findByName("nuagevsp.cms.id"); HostVO host = findNuageVspHost(nuageVspDevice.getHostId()); - if (!auditDomainsOnVsp(host, false, true)) { - return false; - } - String nuageVspCmsId = findNuageVspCmsIdForDevice(nuageVspDevice.getId(), cmsIdConfig); - SyncNuageVspCmsIdCommand syncCmd = new SyncNuageVspCmsIdCommand(SyncType.UNREGISTER, nuageVspCmsId); - SyncNuageVspCmsIdAnswer answer = (SyncNuageVspCmsIdAnswer) _agentMgr.easySend(nuageVspDevice.getHostId(), syncCmd); - if (answer != null && answer.getSuccess()) { - String currentValue = cmsIdConfig.getValue(); - String newValue = currentValue.replace(nuageVspDevice.getId() + ":" + answer.getNuageVspCmsId(), ""); - if (!Strings.isNullOrEmpty(newValue) && newValue.startsWith(";")) { - newValue = newValue.substring(1); + if (matchingNuageVspDevice == null) { + if (!auditDomainsOnVsp(host, false, true)) { + return false; } - _configDao.update("nuagevsp.cms.id", newValue); - } else { - return false; + + SyncNuageVspCmsIdCommand syncCmd = new SyncNuageVspCmsIdCommand(SyncType.UNREGISTER, nuageVspCmsId); + SyncNuageVspCmsIdAnswer answer = (SyncNuageVspCmsIdAnswer) _agentMgr.easySend(nuageVspDevice.getHostId(), syncCmd); + if (answer == null || !answer.getSuccess()) { + return false; + } + } + + String newValue = cmsIdConfig.getValue().replace(nuageVspDevice.getId() + ":" + nuageVspCmsId, ""); + if (newValue.startsWith(";")) { + newValue = newValue.substring(1); } + if (newValue.endsWith(";")) { + newValue = newValue.substring(0, newValue.length() - 1); + } + newValue = newValue.replaceAll(";+", ";"); + _configDao.update("nuagevsp.cms.id", newValue); HostVO nuageHost = _hostDao.findById(nuageVspDevice.getHostId()); Long hostId = nuageHost.getId(); @@ -505,6 +518,22 @@ public boolean deleteNuageVspDevice(DeleteNuageVspDeviceCmd cmd) { return true; } + private NuageVspDeviceVO findMatchingNuageVspDevice(NuageVspDeviceVO nuageVspDevice) { + List otherNuageVspDevices = _nuageVspDao.listAll(); + for (NuageVspDeviceVO otherNuageVspDevice : otherNuageVspDevices) { + if (otherNuageVspDevice.getId() == nuageVspDevice.getId()) continue; + + HostVO nuageVspDeviceHost = findNuageVspHost(nuageVspDevice.getHostId()); + HostVO otherNuageVspDeviceHost = findNuageVspHost(otherNuageVspDevice.getHostId()); + String nuageVspDeviceHostName = nuageVspDeviceHost.getDetail("hostname"); + String otherNuageVspDeviceHostName = otherNuageVspDeviceHost.getDetail("hostname"); + if (otherNuageVspDeviceHostName != null && otherNuageVspDeviceHostName.equals(nuageVspDeviceHostName)) { + return otherNuageVspDevice; + } + } + return null; + } + @Override public List listNuageVspDevices(ListNuageVspDevicesCmd cmd) { Long physicalNetworkId = cmd.getPhysicalNetworkId(); @@ -551,6 +580,8 @@ private void registerNewNuageVspDevice(ConfigurationVO currentConfig, String reg } private void auditHost(HostVO host) { + if (host == null) return; + _hostDao.loadDetails(host); boolean validateDomains = true; @@ -585,7 +616,8 @@ private boolean auditDomainsOnVsp(HostVO host, boolean add, boolean remove) { _hostDao.loadDetails(host); List allDomains = _domainDao.listAll(); for (DomainVO domain : allDomains) { - SyncDomainCommand cmd = new SyncDomainCommand(domain.getUuid(), domain.getName(), domain.getPath(), add, remove); + VspDomain vspDomain = _nuageVspEntityBuilder.buildVspDomain(domain); + SyncDomainCommand cmd = new SyncDomainCommand(vspDomain, add, remove); SyncDomainAnswer answer = (SyncDomainAnswer) _agentMgr.easySend(host.getId(), cmd); return answer.getSuccess(); } @@ -683,7 +715,8 @@ public void onPublishMessage(String senderAddress, String subject, Object args) List nuageVspDevices = _nuageVspDao.listAll(); for (NuageVspDeviceVO nuageVspDevice : nuageVspDevices) { HostVO host = findNuageVspHost(nuageVspDevice.getHostId()); - SyncDomainCommand cmd = new SyncDomainCommand(domain.getUuid(), domain.getName(), domain.getPath(), true, false); + VspDomain vspDomain = _nuageVspEntityBuilder.buildVspDomain(domain); + SyncDomainCommand cmd = new SyncDomainCommand(vspDomain, true, false); _agentMgr.easySend(host.getId(), cmd); } } finally { @@ -700,7 +733,8 @@ public void onPublishMessage(String senderAddress, String subject, Object args) List nuageVspDevices = _nuageVspDao.listAll(); for (NuageVspDeviceVO nuageVspDevice : nuageVspDevices) { HostVO host = findNuageVspHost(nuageVspDevice.getHostId()); - SyncDomainCommand cmd = new SyncDomainCommand(domain.getUuid(), domain.getName(), domain.getPath(), false, true); + VspDomain vspDomain = _nuageVspEntityBuilder.buildVspDomain(domain); + SyncDomainCommand cmd = new SyncDomainCommand(vspDomain, false, true); _agentMgr.easySend(host.getId(), cmd); } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java index 8e142372d6..677fa9fce3 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java @@ -30,8 +30,6 @@ import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupVspCommand; -import com.cloud.agent.api.VspResourceAnswer; -import com.cloud.agent.api.VspResourceCommand; import com.cloud.agent.api.element.ApplyAclRuleVspCommand; import com.cloud.agent.api.element.ApplyStaticNatVspCommand; import com.cloud.agent.api.element.ImplementVspCommand; @@ -40,14 +38,13 @@ import com.cloud.agent.api.guru.ImplementNetworkVspCommand; import com.cloud.agent.api.guru.ReserveVmInterfaceVspCommand; import com.cloud.agent.api.guru.TrashNetworkVspCommand; -import com.cloud.agent.api.manager.GetClientDefaultsAnswer; -import com.cloud.agent.api.manager.GetClientDefaultsCommand; +import com.cloud.agent.api.manager.GetApiDefaultsAnswer; +import com.cloud.agent.api.manager.GetApiDefaultsCommand; import com.cloud.agent.api.manager.SupportedApiVersionCommand; import com.cloud.agent.api.sync.SyncDomainAnswer; import com.cloud.agent.api.sync.SyncDomainCommand; import com.cloud.agent.api.sync.SyncNuageVspCmsIdAnswer; import com.cloud.agent.api.sync.SyncNuageVspCmsIdCommand; -import com.cloud.agent.api.sync.SyncVspCommand; import com.cloud.host.Host; import com.cloud.resource.ServerResource; import com.cloud.util.NuageVspUtil; @@ -56,12 +53,11 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.google.common.base.Strings; import net.nuage.vsp.acs.NuageVspPluginClientLoader; -import net.nuage.vsp.acs.client.NuageVspApiClient; -import net.nuage.vsp.acs.client.NuageVspElementClient; -import net.nuage.vsp.acs.client.NuageVspGuruClient; -import net.nuage.vsp.acs.client.NuageVspManagerClient; -import net.nuage.vsp.acs.client.NuageVspSyncClient; -import org.apache.commons.lang3.tuple.Pair; +import net.nuage.vsp.acs.client.api.NuageVspApiClient; +import net.nuage.vsp.acs.client.api.NuageVspElementClient; +import net.nuage.vsp.acs.client.api.NuageVspGuruClient; +import net.nuage.vsp.acs.client.api.NuageVspManagerClient; +import net.nuage.vsp.acs.client.common.model.Pair; import org.apache.log4j.Logger; import javax.naming.ConfigurationException; @@ -91,7 +87,8 @@ public class NuageVspResource extends ManagerBase implements ServerResource { private String _name; private String _guid; private String _zoneId; - private String[] _cmsUserInfo; + private String _cmsUserLogin; + private String _cmsUserPassword; private String _hostName; private String _relativePath; private int _numRetries; @@ -102,7 +99,6 @@ public class NuageVspResource extends ManagerBase implements ServerResource { protected NuageVspApiClient _nuageVspApiClient; protected NuageVspGuruClient _nuageVspGuruClient; protected NuageVspElementClient _nuageVspElementClient; - protected NuageVspSyncClient _nuageVspSyncClient; protected NuageVspManagerClient _nuageVspManagerClient; protected boolean _isNuageVspClientLoaded; @@ -190,7 +186,8 @@ public boolean configure(String name, Map params) throws Configu _relativePath = new StringBuffer().append("https://").append(_hostName).append(":").append(port).append(apiRelativePath).toString(); String cmsUserPass = NuageVspUtil.decodePassword(cmsUserPassBase64); - _cmsUserInfo = new String[] {CMS_USER_ENTEPRISE_NAME, cmsUser, cmsUserPass}; + _cmsUserLogin = cmsUser; + _cmsUserPassword = cmsUserPass; _nuageVspCmsId = (String)params.get(NUAGE_VSP_CMS_ID); @@ -199,8 +196,8 @@ public boolean configure(String name, Map params) throws Configu try { login(); } catch (ExecutionException | ConfigurationException e) { - s_logger.error("Failed to login to Nuage VSD on " + name + " as user " + cmsUser, e); - throw new CloudRuntimeException("Failed to login to Nuage VSD on " + name + " as user " + cmsUser, e); + s_logger.error(e.getMessage(), e); + throw new CloudRuntimeException(e.getMessage(), e); } return true; @@ -211,23 +208,14 @@ protected void login() throws ConfigurationException, ExecutionException { _nuageVspApiClient.login(); } - protected void loadNuageClient() { - - try { - NuageVspPluginClientLoader clientLoader = NuageVspPluginClientLoader.getClientLoader(_relativePath, _cmsUserInfo, _numRetries, _retryInterval, _nuageVspCmsId); - _nuageVspApiClient = clientLoader.getNuageVspApiClient(); - _nuageVspSyncClient = clientLoader.getNuageVspSyncClient(); - _nuageVspGuruClient = clientLoader.getNuageVspGuruClient(); - _nuageVspElementClient = clientLoader.getNuageVspElementClient(); - _nuageVspManagerClient = clientLoader.getNuageVspManagerClient(); - _isNuageVspClientLoaded = true; - } catch (ConfigurationException e) { - _isNuageVspClientLoaded = false; - String errorMessage = "Nuage Vsp Plugin client is not yet installed. Please install NuageVsp plugin client to use NuageVsp plugin in Cloudstack. "; - s_logger.error(errorMessage, e); - throw new CloudRuntimeException(errorMessage, e); - } - + protected void loadNuageClient() { + NuageVspPluginClientLoader clientLoader = NuageVspPluginClientLoader.getClientLoader(_relativePath, CMS_USER_ENTEPRISE_NAME, + _cmsUserLogin, _cmsUserPassword, _numRetries, _retryInterval, _nuageVspCmsId); + _nuageVspApiClient = clientLoader.getNuageVspApiClient(); + _nuageVspGuruClient = clientLoader.getNuageVspGuruClient(); + _nuageVspElementClient = clientLoader.getNuageVspElementClient(); + _nuageVspManagerClient = clientLoader.getNuageVspManagerClient(); + _isNuageVspClientLoaded = true; } @Override @@ -265,12 +253,12 @@ public StartupCommand[] initialize() { @Override public PingCommand getCurrentStatus(long id) { - if (_relativePath == null || _relativePath.isEmpty()) { + if (Strings.isNullOrEmpty(_relativePath)) { s_logger.error("Refusing to ping Nuage VSD because the resource configuration is missing the relative path information"); _shouldAudit = true; return null; } - if (_cmsUserInfo == null || _cmsUserInfo.length < 2) { + if (Strings.isNullOrEmpty(_cmsUserLogin) || Strings.isNullOrEmpty(_cmsUserPassword)) { s_logger.error("Refusing to ping Nuage VSD because the resource configuration is missing the CMS user information"); _shouldAudit = true; return null; @@ -278,7 +266,7 @@ public PingCommand getCurrentStatus(long id) { try { login(); } catch (ExecutionException | ConfigurationException e) { - s_logger.error("Failed to ping to Nuage VSD on " + _name + " as user " + _cmsUserInfo[1], e); + s_logger.error("Failed to ping to Nuage VSD on " + _name + " as user " + _cmsUserLogin, e); _shouldAudit = true; return null; } @@ -293,8 +281,6 @@ public Answer executeRequest(Command cmd) { return executeRequest((ReadyCommand)cmd); } else if (cmd instanceof MaintainCommand) { return executeRequest((MaintainCommand)cmd); - } else if (cmd instanceof VspResourceCommand) { - return executeRequest((VspResourceCommand)cmd); } //Guru commands else if (cmd instanceof ImplementNetworkVspCommand) { @@ -317,16 +303,14 @@ else if (cmd instanceof ImplementVspCommand) { return executeRequest((ShutDownVpcVspCommand)cmd); } //Sync Commands - else if (cmd instanceof SyncVspCommand) { - return executeRequest((SyncVspCommand)cmd); - } else if (cmd instanceof SyncNuageVspCmsIdCommand) { + else if (cmd instanceof SyncNuageVspCmsIdCommand) { return executeRequest((SyncNuageVspCmsIdCommand)cmd); } else if (cmd instanceof SyncDomainCommand) { return executeRequest((SyncDomainCommand)cmd); } //Other commands - else if (cmd instanceof GetClientDefaultsCommand) { - return executeRequest((GetClientDefaultsCommand)cmd); + else if (cmd instanceof GetApiDefaultsCommand) { + return executeRequest((GetApiDefaultsCommand)cmd); } else if (cmd instanceof SupportedApiVersionCommand) { return executeRequest((SupportedApiVersionCommand)cmd); } @@ -357,29 +341,11 @@ private Answer executeRequest(MaintainCommand cmd) { return new MaintainAnswer(cmd); } - private Answer executeRequest(VspResourceCommand cmd) { - try { - isNuageVspApiLoaded(); - if (cmd.getRequestType().equalsIgnoreCase("GETALL") || cmd.getRequestType().equalsIgnoreCase("GET") || cmd.getRequestType().equalsIgnoreCase("GETRELATED")) { - String resourceInfo = _nuageVspApiClient.executeRestApi(cmd.getRequestType(), cmd.getResource(), cmd.getResourceId(), cmd.getChildResource(), - cmd.getEntityDetails(), cmd.getResourceFilter(), cmd.getProxyUserUuid(), cmd.getProxyUserDomainuuid()); - return new VspResourceAnswer(cmd, resourceInfo, "Executed Issue Resource command"); - } - return new VspResourceAnswer(cmd, false, cmd.getRequestType() + " is not yet supported"); - } catch (ExecutionException | ConfigurationException e) { - s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); - return new VspResourceAnswer(cmd, e); - } - } - private Answer executeRequest(ImplementNetworkVspCommand cmd) { try { isNuageVspGuruLoaded(); - _nuageVspGuruClient.implement(cmd.getNetworkDomainName(), cmd.getNetworkDomainPath(), cmd.getNetworkDomainUuid(), cmd.getNetworkAccountName(), - cmd.getNetworkAccountUuid(), cmd.getNetworkName(), cmd.getNetworkCidr(), cmd.getNetworkGateway(), cmd.getNetworkAclId(), cmd.getDnsServers(), - cmd.getGatewaySystemIds(), cmd.isL3Network(), cmd.isVpc(), cmd.isSharedNetwork(), cmd.getNetworkUuid(), cmd.getVpcName(), cmd.getVpcUuid(), - cmd.isDefaultEgressPolicy(), cmd.getIpAddressRange(), cmd.getDomainTemplateName()); - return new Answer(cmd, true, "Created network mapping to " + cmd.getNetworkName() + " on Nuage VSD " + _hostName); + _nuageVspGuruClient.implement(cmd.getNetwork(), cmd.getDnsServers()); + return new Answer(cmd, true, "Created network mapping to " + cmd.getNetwork().getName() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -389,11 +355,8 @@ private Answer executeRequest(ImplementNetworkVspCommand cmd) { private Answer executeRequest(ReserveVmInterfaceVspCommand cmd) { try { isNuageVspGuruLoaded(); - _nuageVspGuruClient.reserve(cmd.getNicUuid(), cmd.getNicMacAddress(), cmd.getNetworkUuid(), cmd.isL3Network(), - cmd.isSharedNetwork(), cmd.getVpcUuid(), cmd.getNetworkDomainUuid(), cmd.getNetworksAccountUuid(), cmd.isDomainRouter(), cmd.getDomainRouterIp(), - cmd.getVmInstanceName(), cmd.getVmUuid(), cmd.useStaticIp(), cmd.getStaticIp(), cmd.getStaticNatIpUuid(), cmd.getStaticNatIpAddress(), cmd.isStaticNatIpAllocated(), - cmd.isOneToOneNat(), cmd.getStaticNatVlanUuid(), cmd.getStaticNatVlanGateway(), cmd.getStaticNatVlanNetmask()); - return new Answer(cmd, true, "Created NIC that maps to nicUuid" + cmd.getNicUuid() + " on Nuage VSD " + _hostName); + _nuageVspGuruClient.reserve(cmd.getNetwork(), cmd.getVm(), cmd.getNic(), cmd.getStaticNat()); + return new Answer(cmd, true, "Created NIC that maps to nicUuid" + cmd.getNic().getUuid() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -403,9 +366,9 @@ private Answer executeRequest(ReserveVmInterfaceVspCommand cmd) { private Answer executeRequest(DeallocateVmVspCommand cmd) { try { isNuageVspGuruLoaded(); - _nuageVspGuruClient.deallocate(cmd.getNetworkUuid(), cmd.getNicFromDdUuid(), cmd.getNicMacAddress(), cmd.getNicIp4Address(), cmd.isL3Network(), cmd.isSharedNetwork(), - cmd.getVpcUuid(), cmd.getNetworksDomainUuid(), cmd.getVmInstanceName(), cmd.getVmUuid(), cmd.isExpungingState()); - return new Answer(cmd, true, "Deallocated VM " + cmd.getVmInstanceName() + " on Nuage VSD " + _hostName); + + _nuageVspGuruClient.deallocate(cmd.getNetwork(), cmd.getVm(), cmd.getNic()); + return new Answer(cmd, true, "Deallocated VM " + cmd.getVm().getName() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -415,8 +378,8 @@ private Answer executeRequest(DeallocateVmVspCommand cmd) { private Answer executeRequest(TrashNetworkVspCommand cmd) { try { isNuageVspGuruLoaded(); - _nuageVspGuruClient.trash(cmd.getDomainUuid(), cmd.getNetworkUuid(), cmd.isL3Network(), cmd.isSharedNetwork(), cmd.getVpcUuid(), cmd.getDomainTemplateName()); - return new Answer(cmd, true, "Deleted network mapping to " + cmd.getNetworkUuid() + " on Nuage VSD " + _hostName); + _nuageVspGuruClient.trash(cmd.getNetwork()); + return new Answer(cmd, true, "Deleted network mapping to " + cmd.getNetwork().getUuid() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -426,9 +389,8 @@ private Answer executeRequest(TrashNetworkVspCommand cmd) { private Answer executeRequest(ApplyStaticNatVspCommand cmd) { try { isNuageVspElementLoaded(); - _nuageVspElementClient.applyStaticNats(cmd.getNetworkDomainUuid(), cmd.getNetworkUuid(), cmd.getVpcOrSubnetUuid(), cmd.isL3Network(), - cmd.isVpc(), cmd.getStaticNatDetails()); - return new Answer(cmd, true, "Applied Static NAT to network mapping " + cmd.getVpcOrSubnetUuid() + " on Nuage VSD " + _hostName); + _nuageVspElementClient.applyStaticNats(cmd.getNetwork(), cmd.getStaticNatDetails()); + return new Answer(cmd, true, "Applied Static NAT to network mapping " + cmd.getNetwork().getUuid() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -438,10 +400,9 @@ private Answer executeRequest(ApplyStaticNatVspCommand cmd) { private Answer executeRequest(ImplementVspCommand cmd) { try { isNuageVspElementLoaded(); - boolean success = _nuageVspElementClient.implement(cmd.getNetworkId(), cmd.getNetworkDomainUuid(), cmd.getNetworkUuid(), cmd.getNetworkName(), cmd.getVpcOrSubnetUuid(), cmd.isL2Network(), - cmd.isL3Network(), cmd.isVpc(), cmd.isShared(), cmd.getDomainTemplateName(), cmd.isFirewallServiceSupported(), cmd.getDnsServers(), cmd.getIngressFirewallRules(), - cmd.getEgressFirewallRules(), cmd.getAcsFipUuid(), cmd.isEgressDefaultPolicy()); - return new Answer(cmd, success, "Implemented network " + cmd.getNetworkUuid() + " on Nuage VSD " + _hostName); + boolean success = _nuageVspElementClient.implement(cmd.getNetwork(), cmd.getDnsServers(), cmd.getIngressFirewallRules(), + cmd.getEgressFirewallRules(), cmd.getFloatingIpUuids()); + return new Answer(cmd, success, "Implemented network " + cmd.getNetwork().getUuid() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -451,9 +412,8 @@ private Answer executeRequest(ImplementVspCommand cmd) { private Answer executeRequest(ApplyAclRuleVspCommand cmd) { try { isNuageVspElementLoaded(); - _nuageVspElementClient.applyAclRules(cmd.isNetworkAcl(), cmd.getNetworkUuid(), cmd.getNetworkDomainUuid(), cmd.getVpcOrSubnetUuid(), cmd.getNetworkName(), - cmd.isL2Network(), cmd.getAclRules(), cmd.getNetworkId(), cmd.isEgressDefaultPolicy(), cmd.getAcsIngressAcl(), cmd.isNetworkReset(), cmd.getDomainTemplateName()); - return new Answer(cmd, true, "Applied ACL Rule to network mapping " + cmd.getVpcOrSubnetUuid() + " on Nuage VSD " + _hostName); + _nuageVspElementClient.applyAclRules(cmd.getAclType(), cmd.getNetwork(), cmd.getAclRules(), cmd.isNetworkReset()); + return new Answer(cmd, true, "Applied ACL Rule to network mapping " + cmd.getNetwork().getUuid() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -471,17 +431,6 @@ private Answer executeRequest(ShutDownVpcVspCommand cmd) { } } - private Answer executeRequest(SyncVspCommand cmd) { - try { - isNuageVspSyncLoaded(); - _nuageVspSyncClient.syncWithNuageVsp(cmd.getNuageVspEntity()); - return new Answer(cmd, true, "Synced " + cmd.getNuageVspEntity() + " on Nuage VSD " + _hostName); - } catch (ExecutionException | ConfigurationException e) { - s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); - return new Answer(cmd, e); - } - } - private Answer executeRequest(SyncNuageVspCmsIdCommand cmd) { try { isNuageVspManagerLoaded(); @@ -504,7 +453,7 @@ private Answer executeRequest(SyncNuageVspCmsIdCommand cmd) { private Answer executeRequest(SyncDomainCommand cmd) { try { isNuageVspManagerLoaded(); - boolean success = _nuageVspManagerClient.syncDomainWithNuageVsp(cmd.getDomainUuid(), cmd.getDomainName(), cmd.getDomainPath(), cmd.isToAdd(), cmd.isToRemove()); + boolean success = _nuageVspManagerClient.syncDomainWithNuageVsp(cmd.getDomain(), cmd.isToAdd(), cmd.isToRemove()); return new SyncDomainAnswer(success); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); @@ -512,14 +461,13 @@ private Answer executeRequest(SyncDomainCommand cmd) { } } - private Answer executeRequest(GetClientDefaultsCommand cmd) { + private Answer executeRequest(GetApiDefaultsCommand cmd) { try { isNuageVspManagerLoaded(); - Map clientDefaults = _nuageVspManagerClient.getClientDefaults(); - return new GetClientDefaultsAnswer(cmd, clientDefaults); + return new GetApiDefaultsAnswer(cmd, _nuageVspManagerClient.getApiDefaults()); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); - return new GetClientDefaultsAnswer(cmd, e); + return new GetApiDefaultsAnswer(cmd, e); } } @@ -552,12 +500,6 @@ protected void isNuageVspElementLoaded() throws ConfigurationException { } } - protected void isNuageVspSyncLoaded() throws ConfigurationException { - if (!_isNuageVspClientLoaded || _nuageVspSyncClient == null) { - throw new ConfigurationException(NUAGE_VSP_PLUGIN_ERROR_MESSAGE); - } - } - protected void isNuageVspManagerLoaded() throws ConfigurationException { if (!_isNuageVspClientLoaded || _nuageVspManagerClient == null) { throw new ConfigurationException(NUAGE_VSP_PLUGIN_ERROR_MESSAGE); diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java deleted file mode 100644 index 4e1cc431e7..0000000000 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java +++ /dev/null @@ -1,26 +0,0 @@ -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -package com.cloud.network.sync; - - -public interface NuageVspSync { - - public void syncWithNuageVsp(String nuageVspEntity); -} diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSyncImpl.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSyncImpl.java deleted file mode 100644 index 9180c17909..0000000000 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSyncImpl.java +++ /dev/null @@ -1,65 +0,0 @@ -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -package com.cloud.network.sync; - -import com.cloud.agent.AgentManager; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.sync.SyncVspCommand; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.network.NuageVspDeviceVO; -import com.cloud.network.dao.NuageVspDao; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import javax.inject.Inject; -import java.util.List; - -@Component -public class NuageVspSyncImpl implements NuageVspSync { - - private static final Logger s_logger = Logger.getLogger(NuageVspSyncImpl.class); - - @Inject - NuageVspDao _nuageVspDao; - @Inject - HostDao _hostDao; - @Inject - AgentManager _agentMgr; - - public void syncWithNuageVsp(String nuageVspEntity) { - //Get the NuageVspDevice and get the host information. - //This information is used to query VSP and synch the corresponding - //entities - List nuageVspDevices = _nuageVspDao.listAll(); - for (NuageVspDeviceVO nuageVspDevice : nuageVspDevices) { - HostVO nuageVspHost = _hostDao.findById(nuageVspDevice.getHostId()); - _hostDao.loadDetails(nuageVspHost); - SyncVspCommand cmd = new SyncVspCommand(nuageVspEntity); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); - if (answer == null || !answer.getResult()) { - s_logger.error("SyncNuageVspCommand for Nuage VSP Host " + nuageVspHost.getUuid() + " failed"); - if ((null != answer) && (null != answer.getDetails())) { - s_logger.error(answer.getDetails()); - } - } - } - } -} diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java new file mode 100644 index 0000000000..135a552e2d --- /dev/null +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java @@ -0,0 +1,368 @@ +// +// 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.util; + +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.VlanDao; +import com.cloud.domain.Domain; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.InsufficientVirtualNetworkCapacityException; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkDetailsDao; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.user.AccountVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.VirtualMachine; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspDomain; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; +import net.nuage.vsp.acs.client.api.model.VspVm; +import net.nuage.vsp.acs.client.common.model.Pair; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import javax.inject.Inject; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +public class NuageVspEntityBuilder { + private static final Logger s_logger = Logger.getLogger(NuageVspEntityBuilder.class); + + @Inject + VpcDao _vpcDao; + @Inject + DomainDao _domainDao; + @Inject + AccountDao _accountDao; + @Inject + NetworkOfferingDao _networkOfferingDao; + @Inject + NetworkOfferingServiceMapDao _networkOfferingServiceMapDao; + @Inject + NetworkModel _networkModel; + @Inject + VlanDao _vlanDao; + @Inject + ConfigurationDao _configurationDao; + @Inject + IPAddressDao _ipAddressDao; + @Inject + NetworkDetailsDao _networkDetailsDao; + + public VspDomain buildVspDomain(Domain domain) { + return new VspDomain.Builder() + .uuid(domain.getUuid()) + .name(domain.getName()) + .path(domain.getPath()) + .build(); + } + + public VspNetwork buildVspNetwork(Network network, boolean fillAddressRange) { + VspNetwork.Builder vspNetworkBuilder = new VspNetwork.Builder() + .id(network.getId()) + .uuid(network.getUuid()) + .name(network.getName()) + .cidr(network.getCidr()) + .gateway(network.getGateway()); + + DomainVO domain = _domainDao.findById(network.getDomainId()); + VspDomain vspDomain = buildVspDomain(domain); + vspNetworkBuilder.domain(vspDomain); + + AccountVO account = _accountDao.findById(network.getAccountId()); + vspNetworkBuilder.accountUuid(account.getUuid()).accountName(account.getAccountName()); + + NetworkOfferingVO networkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + vspNetworkBuilder.egressDefaultPolicy(networkOffering.getEgressDefaultPolicy()); + + if (network.getVpcId() != null) { + VpcVO vpc = _vpcDao.findById(network.getVpcId()); + vspNetworkBuilder.vpcUuid(vpc.getUuid()) + .vpcName(vpc.getName()) + .networkType(VspNetwork.NetworkType.Vpc); + } else { + if (networkOffering.getGuestType() == Network.GuestType.Shared) { + vspNetworkBuilder.networkType(VspNetwork.NetworkType.Shared); + } else if (_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Network.Service.SourceNat) + || _networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Network.Service.StaticNat)) { + vspNetworkBuilder.networkType(VspNetwork.NetworkType.L3); + } else { + vspNetworkBuilder.networkType(VspNetwork.NetworkType.L2); + } + } + + boolean firewallServiceSupported = _networkModel.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Network.Service.Firewall); + vspNetworkBuilder.firewallServiceSupported(firewallServiceSupported); + + String preConfiguredDomainTemplateName = NuageVspUtil.getPreConfiguredDomainTemplateName(_configurationDao, _networkDetailsDao, network, networkOffering); + vspNetworkBuilder.domainTemplateName(preConfiguredDomainTemplateName); + + if (fillAddressRange) { + try { + List> ipAddressRanges = getIpAddressRanges(networkOffering, network); + vspNetworkBuilder.ipAddressRanges(ipAddressRanges); + + String virtualRouterIp = getVirtualRouterIP(network, ipAddressRanges); + vspNetworkBuilder.virtualRouterIp(virtualRouterIp); + } catch (InsufficientVirtualNetworkCapacityException ex) { + s_logger.error("There is an insufficient network capacity in network " + network.getId(), ex); + throw new CloudRuntimeException("There is an insufficient network capacity in network " + network.getId(), ex); + } + } + + return vspNetworkBuilder.build(); + } + + private List> getIpAddressRanges(NetworkOfferingVO networkOffering, Network network) { + List> ipAddressRanges = Lists.newArrayList(); + if (networkOffering.getGuestType() == Network.GuestType.Shared) { + List vlans = _vlanDao.listVlansByNetworkId(network.getId()); + ipAddressRanges = Lists.newArrayList(); + for (VlanVO vlan : vlans) { + boolean isIpv4 = StringUtils.isNotBlank(vlan.getIpRange()); + String[] range = isIpv4 ? vlan.getIpRange().split("-") : vlan.getIp6Range().split("-"); + if (range.length == 2) { + ipAddressRanges.add(Pair.of(range[0], range[1])); + } + } + return ipAddressRanges; + } + + String subnet = NetUtils.getCidrSubNet(network.getCidr()); + String netmask = NetUtils.getCidrNetmask(network.getCidr()); + long cidrSize = NetUtils.getCidrSize(netmask); + Set allIPsInCidr = NetUtils.getAllIpsFromCidr(subnet, cidrSize, new HashSet()); + if (allIPsInCidr == null || !(allIPsInCidr instanceof TreeSet)) { + throw new IllegalStateException("The IPs in CIDR for subnet " + subnet + " where null or returned in a non-ordered set."); + } + + Iterator ipIterator = allIPsInCidr.iterator(); + long ip = ipIterator.next(); + if (NetUtils.ip2Long(network.getGateway()) == ip) { + ip = ipIterator.next(); + } + ipAddressRanges.add(Pair.of(NetUtils.long2Ip(ip), NetUtils.getIpRangeEndIpFromCidr(subnet, cidrSize))); + return ipAddressRanges; + } + + private String getVirtualRouterIP(Network network, List> ipAddressRanges) throws InsufficientVirtualNetworkCapacityException { + Pair lowestIpAddressRange = null; + if (ipAddressRanges.size() == 1) { + lowestIpAddressRange = Iterables.getOnlyElement(ipAddressRanges); + } else { + for (Pair ipAddressRange : ipAddressRanges) { + if (lowestIpAddressRange == null || NetUtils.ip2Long(ipAddressRange.getLeft()) < NetUtils.ip2Long(lowestIpAddressRange.getLeft())) { + lowestIpAddressRange = ipAddressRange; + } + } + } + + if (lowestIpAddressRange == null) { + throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " But no ip address ranges are specified", Network.class, + network.getId()); + } else if (NetUtils.ip2Long(lowestIpAddressRange.getRight()) - NetUtils.ip2Long(lowestIpAddressRange.getLeft()) < 2) { + throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " So, subnet should have atleast minimum 3 hosts", Network.class, + network.getId()); + } + + String virtualRouterIp = lowestIpAddressRange.getLeft(); + long lowestIp = NetUtils.ip2Long(lowestIpAddressRange.getLeft()); + lowestIp = lowestIp + 1; + lowestIpAddressRange.setLeft(NetUtils.long2Ip(lowestIp)); + return virtualRouterIp; + } + + public VspVm buildVspVm(VirtualMachine vm, Network network) { + VspVm.Builder vspVmBuilder = new VspVm.Builder() + .uuid(vm.getUuid()) + .name(vm.getInstanceName()); + + switch (vm.getState()) { + case Starting: + vspVmBuilder.state(VspVm.State.Starting); break; + case Running: + vspVmBuilder.state(VspVm.State.Running); break; + case Stopping: + vspVmBuilder.state(VspVm.State.Stopping); break; + case Stopped: + vspVmBuilder.state(VspVm.State.Stopped); break; + case Destroyed: + vspVmBuilder.state(VspVm.State.Destroyed); break; + case Expunging: + vspVmBuilder.state(VspVm.State.Expunging); break; + case Migrating: + vspVmBuilder.state(VspVm.State.Migrating); break; + case Error: + vspVmBuilder.state(VspVm.State.Error); break; + case Shutdowned: + vspVmBuilder.state(VspVm.State.Shutdowned); break; + default: + vspVmBuilder.state(VspVm.State.Unknown); + } + + boolean isDomainRouter = vm.getType().equals(VirtualMachine.Type.DomainRouter); + vspVmBuilder.domainRouter(isDomainRouter); + + if (network.getBroadcastUri() != null) { + String domainRouterIp = network.getBroadcastUri().getPath().substring(1); + vspVmBuilder.domainRouterIp(domainRouterIp); + } + + return vspVmBuilder.build(); + } + + public VspNic buildVspNic(String nicUuid, NicProfile nicProfile) { + VspNic.Builder vspNicBuilder = new VspNic.Builder() + .uuid(nicUuid) + .macAddress(nicProfile.getMacAddress()) + .useStaticIp(true) + .ip(nicProfile.getIPv4Address()); + return vspNicBuilder.build(); + } + + public VspNic buildVspNic(NicVO nic) { + VspNic.Builder vspNicBuilder = new VspNic.Builder() + .uuid(nic.getUuid()) + .macAddress(nic.getMacAddress()) + .useStaticIp(true) + .ip(nic.getIPv4Address()); + return vspNicBuilder.build(); + } + + public VspStaticNat buildVspStaticNat(Boolean forRevoke, IPAddressVO staticNatIp, VlanVO staticNatVlan, NicVO nic) { + VspStaticNat.Builder vspStaticNatBuilder = new VspStaticNat.Builder() + .ipUuid(staticNatIp.getUuid()) + .ipAddress(staticNatIp.getAddress().addr()) + .revoke(forRevoke) + .oneToOneNat(staticNatIp.isOneToOneNat()) + .vlanUuid(staticNatVlan.getUuid()) + .vlanGateway(staticNatVlan.getVlanGateway()) + .vlanNetmask(staticNatVlan.getVlanNetmask()); + + if (nic != null) { + VspNic vspNic = buildVspNic(nic); + vspStaticNatBuilder.nic(vspNic); + } + + return vspStaticNatBuilder.build(); + } + + public VspAclRule buildVspAclRule(FirewallRule firewallRule, Network network) { + VspAclRule.Builder vspAclRuleBuilder = new VspAclRule.Builder() + .uuid(firewallRule.getUuid()) + .protocol(firewallRule.getProtocol()) + .startPort(firewallRule.getSourcePortStart()) + .endPort(firewallRule.getSourcePortEnd()) + .sourceCidrList(firewallRule.getSourceCidrList()) + .priority(-1) + .type(VspAclRule.ACLType.Firewall); + + switch (firewallRule.getState()) { + case Active: + vspAclRuleBuilder.state(VspAclRule.ACLState.Active); break; + case Add: + vspAclRuleBuilder.state(VspAclRule.ACLState.Add); break; + case Revoke: + vspAclRuleBuilder.state(VspAclRule.ACLState.Revoke); + } + + switch (firewallRule.getTrafficType()) { + case Ingress: + vspAclRuleBuilder.trafficType(VspAclRule.ACLTrafficType.Ingress); break; + case Egress: + vspAclRuleBuilder.trafficType(VspAclRule.ACLTrafficType.Egress); + } + + NetworkOfferingVO networkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + if (firewallRule.getTrafficType() == FirewallRule.TrafficType.Egress && networkOffering.getEgressDefaultPolicy()) { + vspAclRuleBuilder.action(VspAclRule.ACLAction.Deny); + } else { + vspAclRuleBuilder.action(VspAclRule.ACLAction.Allow); + } + + if (firewallRule.getSourceIpAddressId() != null) { + IPAddressVO ipAddress = _ipAddressDao.findById(firewallRule.getSourceIpAddressId()); + if (ipAddress != null) { + vspAclRuleBuilder.sourceIpAddress(ipAddress.getVmIp() + "/32"); + } + } + + return vspAclRuleBuilder.build(); + } + + public VspAclRule buildVspAclRule(NetworkACLItem networkAcl) { + VspAclRule.Builder vspAclRuleBuilder = new VspAclRule.Builder() + .uuid(networkAcl.getUuid()) + .protocol(networkAcl.getProtocol()) + .startPort(networkAcl.getSourcePortStart()) + .endPort(networkAcl.getSourcePortEnd()) + .sourceIpAddress(null) + .sourceCidrList(networkAcl.getSourceCidrList()) + .priority(networkAcl.getNumber()) + .type(VspAclRule.ACLType.NetworkACL); + + switch (networkAcl.getState()) { + case Active: + vspAclRuleBuilder.state(VspAclRule.ACLState.Active); break; + case Add: + vspAclRuleBuilder.state(VspAclRule.ACLState.Add); break; + case Revoke: + vspAclRuleBuilder.state(VspAclRule.ACLState.Revoke); + } + + switch (networkAcl.getTrafficType()) { + case Ingress: + vspAclRuleBuilder.trafficType(VspAclRule.ACLTrafficType.Ingress); break; + case Egress: + vspAclRuleBuilder.trafficType(VspAclRule.ACLTrafficType.Egress); + } + + switch (networkAcl.getAction()) { + case Allow: + vspAclRuleBuilder.action(VspAclRule.ACLAction.Allow); break; + case Deny: + vspAclRuleBuilder.action(VspAclRule.ACLAction.Deny); + } + + return vspAclRuleBuilder.build(); + } +} diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspUtil.java b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspUtil.java index 23002892ce..fedf048db3 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspUtil.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspUtil.java @@ -20,6 +20,8 @@ package com.cloud.util; import com.cloud.network.Network; +import com.cloud.network.dao.NetworkDetailVO; +import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.manager.NuageVspManager; import com.cloud.offering.NetworkOffering; import com.cloud.utils.StringUtils; @@ -28,7 +30,12 @@ public class NuageVspUtil { - public static String getPreConfiguredDomainTemplateName(ConfigurationDao configDao, Network network, NetworkOffering networkOffering) { + public static String getPreConfiguredDomainTemplateName(ConfigurationDao configDao, NetworkDetailsDao networkDetailsDao, Network network, NetworkOffering networkOffering) { + NetworkDetailVO domainTemplateNetworkDetail = networkDetailsDao.findDetail(network.getId(), NuageVspManager.nuageDomainTemplateDetailName); + if (domainTemplateNetworkDetail != null) { + return domainTemplateNetworkDetail.getValue(); + } + String configKey; if (network.getVpcId() != null) { configKey = NuageVspManager.NuageVspVpcDomainTemplateName.key(); diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/NuageVspPluginClientLoader.java b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/NuageVspPluginClientLoader.java index 57935b9f05..72ce2909e2 100644 --- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/NuageVspPluginClientLoader.java +++ b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/NuageVspPluginClientLoader.java @@ -19,82 +19,53 @@ package net.nuage.vsp.acs; -import net.nuage.vsp.acs.client.NuageVspApiClient; -import net.nuage.vsp.acs.client.NuageVspElementClient; -import net.nuage.vsp.acs.client.NuageVspGuruClient; -import net.nuage.vsp.acs.client.NuageVspManagerClient; -import net.nuage.vsp.acs.client.NuageVspSyncClient; +import net.nuage.vsp.acs.client.api.NuageVspApiClient; +import net.nuage.vsp.acs.client.api.NuageVspElementClient; +import net.nuage.vsp.acs.client.api.NuageVspGuruClient; +import net.nuage.vsp.acs.client.api.NuageVspManagerClient; +import net.nuage.vsp.acs.client.api.impl.NuageVspApiClientImpl; +import net.nuage.vsp.acs.client.api.impl.NuageVspElementClientImpl; +import net.nuage.vsp.acs.client.api.impl.NuageVspGuruClientImpl; +import net.nuage.vsp.acs.client.api.impl.NuageVspManagerClientImpl; +import net.nuage.vsp.acs.client.api.model.VspHost; import org.apache.log4j.Logger; -import javax.naming.ConfigurationException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; public class NuageVspPluginClientLoader { - private ClassLoader _loader = null; private static final Logger s_logger = Logger.getLogger(NuageVspPluginClientLoader.class); private NuageVspApiClient _nuageVspApiClient; private NuageVspElementClient _nuageVspElementClient; private NuageVspGuruClient _nuageVspGuruClient; private NuageVspManagerClient _nuageVspManagerClient; - private NuageVspSyncClient _nuageVspSyncClient; - private static final String NUAGE_PLUGIN_CLIENT_JAR_FILE = "/usr/share/nuagevsp/lib/nuage-vsp-acs-client.jar"; - private static final String NUAGE_VSP_API_CLIENT_IMPL = "net.nuage.vsp.acs.client.impl.NuageVspApiClientImpl"; - private static final String NUAGE_VSP_SYNC_CLIENT_IMPL = "net.nuage.vsp.acs.client.impl.NuageVspSyncClientImpl"; - private static final String NUAGE_VSP_ELEMENT_CLIENT_IMPL = "net.nuage.vsp.acs.client.impl.NuageVspElementClientImpl"; - private static final String NUAGE_VSP_GURU_CLIENT_IMPL = "net.nuage.vsp.acs.client.impl.NuageVspGuruClientImpl"; - private static final String NUAGE_VSP_MANAGER_CLIENT_IMPL = "net.nuage.vsp.acs.client.impl.NuageVspManagerClientImpl"; + private NuageVspPluginClientLoader() { - private NuageVspPluginClientLoader(String nuagePluginClientJarLocation) { - try { - _loader = URLClassLoader.newInstance(new URL[] {new URL("jar:file:" + nuagePluginClientJarLocation + "!/")}, - getClass().getClassLoader()); - } catch (MalformedURLException e) { - throw new IllegalArgumentException(e); - } } - public static NuageVspPluginClientLoader getClientLoader(String relativePath, String[] cmsUserInfo, int numRetries, int retryInterval, - String nuageVspCmsId) throws ConfigurationException { - NuageVspPluginClientLoader nuageVspPluginClientClassloader = new NuageVspPluginClientLoader(NUAGE_PLUGIN_CLIENT_JAR_FILE); - nuageVspPluginClientClassloader.loadClasses(relativePath, cmsUserInfo, numRetries, retryInterval, nuageVspCmsId); + public static NuageVspPluginClientLoader getClientLoader(String relativePath, String cmsUserEnterprise, String cmsUserLogin, + String cmsUserPassword, int numRetries, int retryInterval, String nuageVspCmsId) { + NuageVspPluginClientLoader nuageVspPluginClientClassloader = new NuageVspPluginClientLoader(); + nuageVspPluginClientClassloader.loadClasses(relativePath, cmsUserEnterprise, cmsUserLogin, cmsUserPassword, numRetries, retryInterval, nuageVspCmsId); return nuageVspPluginClientClassloader; } - private void loadClasses(String relativePath, String[] cmsUserInfo, int numRetries, int retryInterval, String nuageVspCmsId) throws ConfigurationException { - try { - Class nuageVspApiClientClass = Class.forName(NUAGE_VSP_API_CLIENT_IMPL, true, _loader); - Class nuageVspSyncClientClass = Class.forName(NUAGE_VSP_SYNC_CLIENT_IMPL, true, _loader); - Class nuageVspGuruClientClass = Class.forName(NUAGE_VSP_GURU_CLIENT_IMPL, true, _loader); - Class nuageVspElementClientClass = Class.forName(NUAGE_VSP_ELEMENT_CLIENT_IMPL, true, _loader); - Class nuageVspManagerClientClass = Class.forName(NUAGE_VSP_MANAGER_CLIENT_IMPL, true, _loader); - - //Instantiate the instances - _nuageVspApiClient = (NuageVspApiClient)nuageVspApiClientClass.newInstance(); - _nuageVspApiClient.setNuageVspHost(relativePath, cmsUserInfo, numRetries, retryInterval, nuageVspCmsId); - _nuageVspSyncClient = (NuageVspSyncClient)nuageVspSyncClientClass.newInstance(); - _nuageVspSyncClient.setNuageVspApiClient(_nuageVspApiClient); - _nuageVspGuruClient = (NuageVspGuruClient)nuageVspGuruClientClass.newInstance(); - _nuageVspGuruClient.setNuageVspApiClient(_nuageVspApiClient); - _nuageVspElementClient = (NuageVspElementClient)nuageVspElementClientClass.newInstance(); - _nuageVspElementClient.setNuageVspApiClient(_nuageVspApiClient); - _nuageVspManagerClient = (NuageVspManagerClient)nuageVspManagerClientClass.newInstance(); - _nuageVspManagerClient.setNuageVspApiClient(_nuageVspApiClient); - } catch (ClassNotFoundException cnfe) { - s_logger.error("Error while loading classes of Nuage VSP client", cnfe); - throw new ConfigurationException("Error while loading classes of Nuage VSP client"); - } catch (InstantiationException ie) { - s_logger.error("Error while initializing classes of Nuage VSP client", ie); - throw new ConfigurationException("Error while initializing classes of Nuage VSP client"); - } catch (IllegalAccessException iae) { - s_logger.error("Error while accessing classes of Nuage VSP client", iae); - throw new ConfigurationException("Error while accessing classes of Nuage VSP client"); - } - + private void loadClasses(String relativePath, String cmsUserEnterprise, String cmsUserLogin, String cmsUserPassword, int numRetries, + int retryInterval, String nuageVspCmsId) { + VspHost vspHost = new VspHost.Builder() + .restRelativePath(relativePath) + .cmsUserEnterprise(cmsUserEnterprise) + .cmsUserLogin(cmsUserLogin) + .cmsUserPassword(cmsUserPassword) + .noofRetry(numRetries) + .retryInterval(retryInterval) + .nuageVspCmsId(nuageVspCmsId) + .build(); + _nuageVspApiClient = new NuageVspApiClientImpl(vspHost); + _nuageVspElementClient = new NuageVspElementClientImpl(_nuageVspApiClient); + _nuageVspGuruClient = new NuageVspGuruClientImpl(_nuageVspApiClient); + _nuageVspManagerClient = new NuageVspManagerClientImpl(_nuageVspApiClient); } public NuageVspApiClient getNuageVspApiClient() { @@ -112,8 +83,4 @@ public NuageVspGuruClient getNuageVspGuruClient() { public NuageVspManagerClient getNuageVspManagerClient() { return _nuageVspManagerClient; } - - public NuageVspSyncClient getNuageVspSyncClient() { - return _nuageVspSyncClient; - } } diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspApiClient.java b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspApiClient.java deleted file mode 100644 index d80daf9eef..0000000000 --- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspApiClient.java +++ /dev/null @@ -1,32 +0,0 @@ -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -package net.nuage.vsp.acs.client; - -import java.util.concurrent.ExecutionException; - -public interface NuageVspApiClient { - - void login() throws ExecutionException; - - void setNuageVspHost(String restRelativePath, String[] cmsUserInfo, int noofRetry, int retryInterval, String nuageVspCmsId); - - String executeRestApi(String method, String resource, String resourceId, String childResource, Object entityDetails, String resourceFilter, String proxyUserUuid, - String proxyUserDomainuuid) throws ExecutionException; -} diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspElementClient.java b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspElementClient.java deleted file mode 100644 index acd4256a50..0000000000 --- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspElementClient.java +++ /dev/null @@ -1,42 +0,0 @@ -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -package net.nuage.vsp.acs.client; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; - -public interface NuageVspElementClient { - - boolean implement(long networkId, String networkDomainUuid, String networkUuid, String networkName, String vpcOrSubnetUuid, boolean isL2Network, boolean isL3Network, - boolean isVpc, boolean isShared, String domainTemplateName, boolean isFirewallServiceSupported, List dnsServers, List> ingressFirewallRules, - List> egressFirewallRules, List acsFipUuid, boolean egressDefaultPolicy) throws ExecutionException; - - void applyStaticNats(String networkDomainUuid, String networkUuid, String vpcOrSubnetUuid, boolean isL3Network, boolean isVpc, - List> staticNatDetails) throws ExecutionException; - - void applyAclRules(boolean isNetworkAcl, String networkUuid, String networkDomainUuid, String vpcOrSubnetUuid, String networkName, boolean isL2Network, - List> rules, long networkId, boolean egressDefaultPolicy, Boolean isAcsIngressAcl, boolean networkReset, String domainTemplateName) throws ExecutionException; - - void shutdownVpc(String domainUuid, String vpcUuid, String domainTemplateName) throws ExecutionException; - - void setNuageVspApiClient(NuageVspApiClient nuageVspApiClient); - -} diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspGuruClient.java b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspGuruClient.java deleted file mode 100644 index 2b3a63a263..0000000000 --- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspGuruClient.java +++ /dev/null @@ -1,43 +0,0 @@ -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -package net.nuage.vsp.acs.client; - -import java.util.Collection; -import java.util.List; -import java.util.concurrent.ExecutionException; - -public interface NuageVspGuruClient { - - void implement(String networkDomainName, String networkDomainPath, String networkDomainUuid, String networkAccountName, String networkAccountUuid, String networkName, - String networkCidr, String networkGateway, Long networkAclId, List dnsServers, List gatewaySystemIds, boolean isL3Network, boolean isVpc, boolean isSharedNetwork, - String networkUuid, String vpcName, String vpcUuid, boolean defaultEgressPolicy, Collection ipAddressRange, String domainTemplateName) throws ExecutionException; - - void reserve(String nicUuid, String nicMacAddress, String networkUuid, boolean isL3Network, boolean isSharedNetwork, String vpcUuid, String networkDomainUuid, - String networksAccountUuid, boolean isDomainRouter, String domainRouterIp, String vmInstanceName, String vmUuid, boolean useStaticIp, String staticIp, String staticNatIpUuid, - String staticNatIpAddress, boolean isStaticNatIpAllocated, boolean isOneToOneNat, String staticNatVlanUuid, String staticNatVlanGateway, String staticNatVlanNetmask) throws ExecutionException; - - void deallocate(String networkUuid, String nicFrmDdUuid, String nicMacAddress, String nicIp4Address, boolean isL3Network, boolean isSharedNetwork, - String vpcUuid, String networksDomainUuid, String vmInstanceName, String vmUuid, boolean isExpungingState) throws ExecutionException; - - void trash(String domainUuid, String networkUuid, boolean isL3Network, boolean isSharedNetwork, String vpcUuid, String domainTemplateName) throws ExecutionException; - - void setNuageVspApiClient(NuageVspApiClient nuageVspApiClient); - -} diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspManagerClient.java b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspManagerClient.java deleted file mode 100644 index f134111bf7..0000000000 --- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspManagerClient.java +++ /dev/null @@ -1,42 +0,0 @@ -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -package net.nuage.vsp.acs.client; - -import org.apache.commons.lang3.tuple.Pair; - -import java.util.Map; -import java.util.concurrent.ExecutionException; - -public interface NuageVspManagerClient { - - Pair auditNuageVspCmsId(String nuageVspCmsId, boolean auditOnly) throws ExecutionException; - - String registerNuageVspCmsId() throws ExecutionException; - - boolean unregisterNuageVspCmsId(String nuageVspCmsId) throws ExecutionException; - - boolean isSupportedApiVersion(String version); - - Map getClientDefaults() throws ExecutionException; - - boolean syncDomainWithNuageVsp(String domainUuid, String domainName, String domainPath, boolean add, boolean remove) throws ExecutionException; - - void setNuageVspApiClient(NuageVspApiClient nuageVspApiClient); -} diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspSyncClient.java b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspSyncClient.java deleted file mode 100644 index 951ee5ad7e..0000000000 --- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspSyncClient.java +++ /dev/null @@ -1,29 +0,0 @@ -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -package net.nuage.vsp.acs.client; - -import java.util.concurrent.ExecutionException; - -public interface NuageVspSyncClient { - - void syncWithNuageVsp(String nuageVspEntity) throws ExecutionException; - - void setNuageVspApiClient(NuageVspApiClient nuageVspApiClient); -} \ No newline at end of file diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java new file mode 100644 index 0000000000..845a8be04f --- /dev/null +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java @@ -0,0 +1,157 @@ +// +// 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; + +import com.cloud.dc.VlanVO; +import com.cloud.domain.Domain; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.util.NuageVspEntityBuilder; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.VirtualMachine; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspDomain; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; +import net.nuage.vsp.acs.client.api.model.VspVm; +import net.nuage.vsp.acs.client.common.model.Pair; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.junit.Before; + +import java.util.ArrayList; + +import static com.cloud.network.manager.NuageVspManager.NuageVspIsolatedNetworkDomainTemplateName; +import static com.cloud.network.manager.NuageVspManager.NuageVspSharedNetworkDomainTemplateName; +import static com.cloud.network.manager.NuageVspManager.NuageVspVpcDomainTemplateName; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class NuageTest { + + protected static final long NETWORK_ID = 42L; + protected NetworkModel _networkModel = mock(NetworkModel.class); + protected ConfigurationDao _configurationDao = mock(ConfigurationDao.class); + protected NuageVspEntityBuilder _nuageVspEntityBuilder = mock(NuageVspEntityBuilder.class); + + @Before + public void setUp() throws Exception { + // Standard responses + when(_networkModel.isProviderForNetwork(Network.Provider.NuageVsp, NETWORK_ID)).thenReturn(true); + when(_configurationDao.getValue(NuageVspIsolatedNetworkDomainTemplateName.key())).thenReturn("IsolatedDomainTemplate"); + when(_configurationDao.getValue(NuageVspVpcDomainTemplateName.key())).thenReturn("VpcDomainTemplate"); + when(_configurationDao.getValue(NuageVspSharedNetworkDomainTemplateName.key())).thenReturn("SharedDomainTemplate"); + + when(_nuageVspEntityBuilder.buildVspDomain(any(Domain.class))).thenReturn(buildVspDomain()); + when(_nuageVspEntityBuilder.buildVspNetwork(any(Network.class), anyBoolean())).thenReturn(buildVspNetwork()); + when(_nuageVspEntityBuilder.buildVspVm(any(VirtualMachine.class), any(Network.class))).thenReturn(buildVspVm()); + when(_nuageVspEntityBuilder.buildVspNic(anyString(), any(NicProfile.class))).thenReturn(buildVspNic()); + when(_nuageVspEntityBuilder.buildVspNic(any(NicVO.class))).thenReturn(buildVspNic()); + when(_nuageVspEntityBuilder.buildVspStaticNat(anyBoolean(), any(IPAddressVO.class), any(VlanVO.class), any(NicVO.class))).thenReturn(buildVspStaticNat()); + when(_nuageVspEntityBuilder.buildVspAclRule(any(FirewallRule.class), any(Network.class))).thenReturn(buildVspAclRule()); + when(_nuageVspEntityBuilder.buildVspAclRule(any(NetworkACLItem.class))).thenReturn(buildVspAclRule()); + } + + protected VspDomain buildVspDomain() { + return new VspDomain.Builder() + .uuid("domainUuid") + .name("domainName") + .path("domainPath") + .build(); + } + + protected VspNetwork buildVspNetwork() { + return new VspNetwork.Builder() + .id(NETWORK_ID) + .uuid("networkUuid") + .name("networkName") + .domain(buildVspDomain()) + .accountUuid("networkAccountUuid") + .accountName("networkAccountName") + .vpcUuid("vpcUuid") + .vpcName("vpcName") + .networkType(VspNetwork.NetworkType.L3) + .firewallServiceSupported(true) + .egressDefaultPolicy(true) + .domainTemplateName("domainTemplateName") + .cidr("networkCidr") + .gateway("networkGateway") + .virtualRouterIp("virtualRouterIp") + .ipAddressRanges(new ArrayList>()) + .build(); + } + + protected VspVm buildVspVm() { + return new VspVm.Builder() + .state(VspVm.State.Running) + .uuid("vmUuid") + .name("vmName") + .domainRouter(true) + .domainRouterIp("domainRouterIp") + .build(); + } + + protected VspNic buildVspNic() { + return new VspNic.Builder() + .uuid("nicUuid") + .macAddress("macAddress") + .useStaticIp(true) + .ip("ip") + .build(); + } + + protected VspStaticNat buildVspStaticNat() { + return new VspStaticNat.Builder() + .state(VspStaticNat.State.Allocating) + .ipUuid("ipUuid") + .ipAddress("ipAddress") + .nic(buildVspNic()) + .revoke(false) + .oneToOneNat(true) + .vlanUuid("vlanUuid") + .vlanGateway("vlanGateway") + .vlanNetmask("vlanNetmask") + .build(); + } + + protected VspAclRule buildVspAclRule() { + return new VspAclRule.Builder() + .uuid("aclRuleUuid") + .protocol("protcol") + .startPort(1) + .endPort(9) + .state(VspAclRule.ACLState.Add) + .trafficType(VspAclRule.ACLTrafficType.Ingress) + .action(VspAclRule.ACLAction.Allow) + .sourceIpAddress("sourceIpAddress") + .sourceCidrList(new ArrayList()) + .priority(1) + .type(VspAclRule.ACLType.NetworkACL) + .build(); + } + +} diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/agent/api/CommandsTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/agent/api/CommandsTest.java index 817ab7a3bc..2a0b07ad99 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/agent/api/CommandsTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/agent/api/CommandsTest.java @@ -30,43 +30,41 @@ import com.cloud.agent.api.manager.SupportedApiVersionCommand; import com.cloud.agent.api.sync.SyncDomainCommand; import com.cloud.agent.api.sync.SyncNuageVspCmsIdCommand; -import com.cloud.agent.api.sync.SyncVspCommand; import com.google.common.collect.Maps; import com.google.common.testing.EqualsTester; import org.junit.Test; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.Map; public class CommandsTest { @Test public void testCommandEquals() throws IllegalAccessException, InvocationTargetException, InstantiationException { - ApplyAclRuleVspCommand applyAclRuleVspCommand = fillBuilderObject(new ApplyAclRuleVspCommand.Builder()).build(); - ApplyAclRuleVspCommand otherApplyAclRuleVspCommand = fillBuilderObject(new ApplyAclRuleVspCommand.Builder()).build(); + ApplyAclRuleVspCommand applyAclRuleVspCommand = fillObject(ApplyAclRuleVspCommand.class); + ApplyAclRuleVspCommand otherApplyAclRuleVspCommand = fillObject(ApplyAclRuleVspCommand.class); - ApplyStaticNatVspCommand applyStaticNatVspCommand = fillBuilderObject(new ApplyStaticNatVspCommand.Builder()).build(); - ApplyStaticNatVspCommand otherApplyStaticNatVspCommand = fillBuilderObject(new ApplyStaticNatVspCommand.Builder()).build(); + ApplyStaticNatVspCommand applyStaticNatVspCommand = fillObject(ApplyStaticNatVspCommand.class); + ApplyStaticNatVspCommand otherApplyStaticNatVspCommand = fillObject(ApplyStaticNatVspCommand.class); - ImplementVspCommand implementVspCommand = fillBuilderObject(new ImplementVspCommand.Builder()).build(); - ImplementVspCommand otherImplementVspCommand = fillBuilderObject(new ImplementVspCommand.Builder()).build(); + ImplementVspCommand implementVspCommand = fillObject(ImplementVspCommand.class); + ImplementVspCommand otherImplementVspCommand = fillObject(ImplementVspCommand.class); - ShutDownVpcVspCommand shutDownVpcVspCommand = fillBuilderObject(new ShutDownVpcVspCommand.Builder()).build(); - ShutDownVpcVspCommand otherShutDownVpcVspCommand = fillBuilderObject(new ShutDownVpcVspCommand.Builder()).build(); + ShutDownVpcVspCommand shutDownVpcVspCommand = fillObject(ShutDownVpcVspCommand.class); + ShutDownVpcVspCommand otherShutDownVpcVspCommand = fillObject(ShutDownVpcVspCommand.class); - DeallocateVmVspCommand deallocateVmVspCommand = fillBuilderObject(new DeallocateVmVspCommand.Builder()).build(); - DeallocateVmVspCommand otherDeallocateVmVspCommand = fillBuilderObject(new DeallocateVmVspCommand.Builder()).build(); + DeallocateVmVspCommand deallocateVmVspCommand = fillObject(DeallocateVmVspCommand.class); + DeallocateVmVspCommand otherDeallocateVmVspCommand = fillObject(DeallocateVmVspCommand.class); - ImplementNetworkVspCommand implementNetworkVspCommand = fillBuilderObject(new ImplementNetworkVspCommand.Builder()).build(); - ImplementNetworkVspCommand otherImplementNetworkVspCommand = fillBuilderObject(new ImplementNetworkVspCommand.Builder()).build(); + ImplementNetworkVspCommand implementNetworkVspCommand = fillObject(ImplementNetworkVspCommand.class); + ImplementNetworkVspCommand otherImplementNetworkVspCommand = fillObject(ImplementNetworkVspCommand.class); - ReserveVmInterfaceVspCommand reserveVmInterfaceVspCommand = fillBuilderObject(new ReserveVmInterfaceVspCommand.Builder()).build(); - ReserveVmInterfaceVspCommand otherReserveVmInterfaceVspCommand = fillBuilderObject(new ReserveVmInterfaceVspCommand.Builder()).build(); + ReserveVmInterfaceVspCommand reserveVmInterfaceVspCommand = fillObject(ReserveVmInterfaceVspCommand.class); + ReserveVmInterfaceVspCommand otherReserveVmInterfaceVspCommand = fillObject(ReserveVmInterfaceVspCommand.class); - TrashNetworkVspCommand trashNetworkVspCommand = fillBuilderObject(new TrashNetworkVspCommand.Builder()).build(); - TrashNetworkVspCommand otherTrashNetworkVspCommand = fillBuilderObject(new TrashNetworkVspCommand.Builder()).build(); + TrashNetworkVspCommand trashNetworkVspCommand = fillObject(TrashNetworkVspCommand.class); + TrashNetworkVspCommand otherTrashNetworkVspCommand = fillObject(TrashNetworkVspCommand.class); SupportedApiVersionCommand supportedApiVersionCommand = new SupportedApiVersionCommand("3.2"); SupportedApiVersionCommand otherSupportedApiVersionCommand = new SupportedApiVersionCommand("3.2"); @@ -77,15 +75,9 @@ public void testCommandEquals() throws IllegalAccessException, InvocationTargetE SyncNuageVspCmsIdCommand syncNuageVspCmsIdCommand = fillObject(SyncNuageVspCmsIdCommand.class); SyncNuageVspCmsIdCommand otherSyncNuageVspCmsIdCommand = fillObject(SyncNuageVspCmsIdCommand.class); - SyncVspCommand syncVspCommand = fillObject(SyncVspCommand.class); - SyncVspCommand otherSyncVspCommand = fillObject(SyncVspCommand.class); - PingNuageVspCommand pingNuageVspCommand = fillObject(PingNuageVspCommand.class); PingNuageVspCommand otherPingNuageVspCommand = fillObject(PingNuageVspCommand.class); - VspResourceCommand vspResourceCommand = fillObject(VspResourceCommand.class); - VspResourceCommand otherVspResourceCommand = fillObject(VspResourceCommand.class); - new EqualsTester() .addEqualityGroup(applyAclRuleVspCommand, otherApplyAclRuleVspCommand) .addEqualityGroup(applyStaticNatVspCommand, otherApplyStaticNatVspCommand) @@ -98,33 +90,10 @@ public void testCommandEquals() throws IllegalAccessException, InvocationTargetE .addEqualityGroup(supportedApiVersionCommand, otherSupportedApiVersionCommand) .addEqualityGroup(syncDomainCommand, otherSyncDomainCommand) .addEqualityGroup(syncNuageVspCmsIdCommand, otherSyncNuageVspCmsIdCommand) - .addEqualityGroup(syncVspCommand, otherSyncVspCommand) .addEqualityGroup(pingNuageVspCommand, otherPingNuageVspCommand) - .addEqualityGroup(vspResourceCommand, otherVspResourceCommand) .testEquals(); } - private T fillBuilderObject(T obj) throws IllegalAccessException, InvocationTargetException { - Class clazz = obj.getClass(); - for (Method method : clazz.getDeclaredMethods()) { - if (method.getParameterTypes().length == 1) { - Class paramType = method.getParameterTypes()[0]; - if (isNumericType(paramType)) { - if (Long.class.isAssignableFrom(paramType)) { - method.invoke(obj, Long.valueOf(method.getName().length())); - } else { - method.invoke(obj, method.getName().length()); - } - } else if (String.class.isAssignableFrom(paramType)) { - method.invoke(obj, method.getName()); - } else if (Boolean.class.isAssignableFrom(paramType) || boolean.class.isAssignableFrom(paramType)) { - method.invoke(obj, method.getName().length() % 2 == 0); - } - } - } - return obj; - } - private T fillObject(Class clazz) throws IllegalAccessException, InvocationTargetException, InstantiationException { Constructor constructor = clazz.getDeclaredConstructors()[0]; Object[] constructorArgs = new Object[constructor.getParameterTypes().length]; diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java index 2f5ce7d193..e9f92b6976 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java @@ -19,6 +19,7 @@ package com.cloud.network.element; +import com.cloud.NuageTest; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; @@ -35,7 +36,6 @@ import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; -import com.cloud.network.NetworkModel; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.NuageVspDeviceVO; @@ -59,15 +59,13 @@ import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.resource.ResourceManager; import com.cloud.user.Account; +import com.cloud.util.NuageVspEntityBuilder; import com.cloud.vm.ReservationContext; import com.google.common.collect.Lists; -import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao; import org.junit.Before; import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import javax.naming.ConfigurationException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; @@ -76,9 +74,6 @@ import java.util.HashSet; import java.util.Set; -import static com.cloud.network.manager.NuageVspManager.NuageVspIsolatedNetworkDomainTemplateName; -import static com.cloud.network.manager.NuageVspManager.NuageVspSharedNetworkDomainTemplateName; -import static com.cloud.network.manager.NuageVspManager.NuageVspVpcDomainTemplateName; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; @@ -86,55 +81,46 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class NuageVspElementTest { - - private static final long NETWORK_ID = 42L; - NuageVspElement element = new NuageVspElement(); - NetworkOrchestrationService networkManager = mock(NetworkOrchestrationService.class); - NetworkModel networkModel = mock(NetworkModel.class); - NetworkServiceMapDao ntwkSrvcDao = mock(NetworkServiceMapDao.class); - AgentManager agentManager = mock(AgentManager.class); - HostDao hostDao = mock(HostDao.class); - NuageVspDao nuageVspDao = mock(NuageVspDao.class); - DomainDao domainDao = mock(DomainDao.class); - NetworkOfferingDao ntwkOfferingDao = mock(NetworkOfferingDao.class); - NetworkOfferingServiceMapDao ntwkOfferingSrvcDao = mock(NetworkOfferingServiceMapDao.class); - ConfigurationDao configDao = mock(ConfigurationDao.class); - NuageVspManager nuageVspManager = mock(NuageVspManager.class); - FirewallRulesDao firewallRulesDao = mock(FirewallRulesDao.class); - IPAddressDao ipAddressDao = mock(IPAddressDao.class); - PhysicalNetworkDao physNetDao = mock(PhysicalNetworkDao.class); - - org.mockito.stubbing.Answer genericAnswer = new org.mockito.stubbing.Answer() { - public Object answer(InvocationOnMock invocation) { - return null; - } - }; +public class NuageVspElementTest extends NuageTest { + + private NuageVspElement _nuageVspElement = new NuageVspElement(); + + private NetworkServiceMapDao _networkServiceMapDao = mock(NetworkServiceMapDao.class); + private AgentManager _agentManager = mock(AgentManager.class); + private HostDao _hostDao = mock(HostDao.class); + private NuageVspDao _nuageVspDao = mock(NuageVspDao.class); + private DomainDao _domainDao = mock(DomainDao.class); + private NetworkOfferingDao _networkOfferingDao = mock(NetworkOfferingDao.class); + private NetworkOfferingServiceMapDao _networkOfferingServiceMapDao = mock(NetworkOfferingServiceMapDao.class); + private NuageVspManager _nuageVspManager = mock(NuageVspManager.class); + private FirewallRulesDao _firewallRulesDao = mock(FirewallRulesDao.class); + private IPAddressDao _ipAddressDao = mock(IPAddressDao.class); + private PhysicalNetworkDao _physicalNetworkDao = mock(PhysicalNetworkDao.class); + private NuageVspEntityBuilder _nuageVspEntityBuilder = mock(NuageVspEntityBuilder.class); + private VpcDetailsDao _vpcDetailsDao = mock(VpcDetailsDao.class); @Before - public void setUp() throws ConfigurationException { - element._resourceMgr = mock(ResourceManager.class); - element._ntwkSrvcDao = ntwkSrvcDao; - element._networkModel = networkModel; - element._agentMgr = agentManager; - element._hostDao = hostDao; - element._nuageVspDao = nuageVspDao; - element._ntwkOfferingSrvcDao = ntwkOfferingSrvcDao; - element._domainDao = domainDao; - element._ntwkOfferingDao = ntwkOfferingDao; - element._configDao = configDao; - element._nuageVspManager = nuageVspManager; - element._firewallRulesDao = firewallRulesDao; - element._ipAddressDao = ipAddressDao; - element._physicalNetworkDao = physNetDao; - - // Standard responses - when(networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(true); - when(configDao.getValue(NuageVspIsolatedNetworkDomainTemplateName.key())).thenReturn("IsolatedDomainTemplate"); - when(configDao.getValue(NuageVspVpcDomainTemplateName.key())).thenReturn("VpcDomainTemplate"); - when(configDao.getValue(NuageVspSharedNetworkDomainTemplateName.key())).thenReturn("SharedDomainTemplate"); - - element.configure("NuageVspTestElement", Collections. emptyMap()); + public void setUp() throws Exception { + super.setUp(); + + _nuageVspElement._resourceMgr = mock(ResourceManager.class); + _nuageVspElement._ntwkSrvcDao = _networkServiceMapDao; + _nuageVspElement._networkModel = _networkModel; + _nuageVspElement._agentMgr = _agentManager; + _nuageVspElement._hostDao = _hostDao; + _nuageVspElement._nuageVspDao = _nuageVspDao; + _nuageVspElement._ntwkOfferingSrvcDao = _networkOfferingServiceMapDao; + _nuageVspElement._domainDao = _domainDao; + _nuageVspElement._ntwkOfferingDao = _networkOfferingDao; + _nuageVspElement._configDao = _configurationDao; + _nuageVspElement._nuageVspManager = _nuageVspManager; + _nuageVspElement._firewallRulesDao = _firewallRulesDao; + _nuageVspElement._ipAddressDao = _ipAddressDao; + _nuageVspElement._physicalNetworkDao = _physicalNetworkDao; + _nuageVspElement._nuageVspEntityBuilder = _nuageVspEntityBuilder; + _nuageVspElement._vpcDetailsDao = _vpcDetailsDao; + + _nuageVspElement.configure("NuageVspTestElement", Collections.emptyMap()); } @Test @@ -147,29 +133,29 @@ public void testCanHandle() { final NetworkOfferingVO ntwkoffer = mock(NetworkOfferingVO.class); when(ntwkoffer.getId()).thenReturn(NETWORK_ID); when(ntwkoffer.getIsPersistent()).thenReturn(true); - when(ntwkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); - when(ntwkSrvcDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true); + when(_networkServiceMapDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true); // Golden path - assertTrue(element.canHandle(net, Service.Connectivity)); + assertTrue(_nuageVspElement.canHandle(net, Service.Connectivity)); when(net.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vlan); // Only broadcastdomaintype Vsp is supported - assertFalse(element.canHandle(net, Service.Connectivity)); + assertFalse(_nuageVspElement.canHandle(net, Service.Connectivity)); when(net.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vsp); - when(ntwkSrvcDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(false); + when(_networkServiceMapDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(false); // No NuageVsp provider in the network - assertFalse(element.canHandle(net, Service.Connectivity)); + assertFalse(_nuageVspElement.canHandle(net, Service.Connectivity)); - when(networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(false); - when(ntwkSrvcDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true); + when(_networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(false); + when(_networkServiceMapDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true); // NusageVsp provider does not provide Connectivity for this network - assertFalse(element.canHandle(net, Service.Connectivity)); + assertFalse(_nuageVspElement.canHandle(net, Service.Connectivity)); - when(networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(true); + when(_networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(true); // Only service Connectivity is supported - assertFalse(element.canHandle(net, Service.Dhcp)); + assertFalse(_nuageVspElement.canHandle(net, Service.Dhcp)); } @@ -182,8 +168,8 @@ public void testImplement() throws ConcurrentOperationException, ResourceUnavail when(network.getBroadcastUri()).thenReturn(new URI("")); when(network.getPhysicalNetworkId()).thenReturn(NETWORK_ID); when(network.getDomainId()).thenReturn(NETWORK_ID); - when(networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(true); - when(ntwkSrvcDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true); + when(_networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(true); + when(_networkServiceMapDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true); final NetworkOffering offering = mock(NetworkOffering.class); when(offering.getId()).thenReturn(NETWORK_ID); @@ -194,7 +180,7 @@ public void testImplement() throws ConcurrentOperationException, ResourceUnavail final DomainVO dom = mock(DomainVO.class); when(dom.getName()).thenReturn("domain"); - when(domainDao.findById(NETWORK_ID)).thenReturn(dom); + when(_domainDao.findById(NETWORK_ID)).thenReturn(dom); final Account acc = mock(Account.class); when(acc.getAccountName()).thenReturn("accountname"); final ReservationContext context = mock(ReservationContext.class); @@ -205,15 +191,15 @@ public void testImplement() throws ConcurrentOperationException, ResourceUnavail when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); - when(firewallRulesDao.listByNetworkPurposeTrafficType(NETWORK_ID, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Ingress)).thenReturn(new ArrayList()); - when(firewallRulesDao.listByNetworkPurposeTrafficType(NETWORK_ID, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Egress)).thenReturn(new ArrayList()); - when(ipAddressDao.listStaticNatPublicIps(NETWORK_ID)).thenReturn(new ArrayList()); - when(nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList()); + when(_firewallRulesDao.listByNetworkPurposeTrafficType(NETWORK_ID, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Ingress)).thenReturn(new ArrayList()); + when(_firewallRulesDao.listByNetworkPurposeTrafficType(NETWORK_ID, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Egress)).thenReturn(new ArrayList()); + when(_ipAddressDao.listStaticNatPublicIps(NETWORK_ID)).thenReturn(new ArrayList()); + when(_nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList()); - assertTrue(element.implement(network, offering, deployDest, context)); + assertTrue(_nuageVspElement.implement(network, offering, deployDest, context)); } @Test @@ -224,14 +210,14 @@ public void testVerifyServiceCombination() { services.add(Service.SourceNat); services.add(Service.Connectivity); services.add(Service.Firewall); - assertTrue(element.verifyServicesCombination(services)); + assertTrue(_nuageVspElement.verifyServicesCombination(services)); services = new HashSet(); services.add(Service.Dhcp); services.add(Service.StaticNat); services.add(Service.Connectivity); services.add(Service.Firewall); - assertFalse(element.verifyServicesCombination(services)); + assertFalse(_nuageVspElement.verifyServicesCombination(services)); } @Test @@ -244,25 +230,24 @@ public void testApplyStaticNats() throws CloudException { when(network.getDomainId()).thenReturn(NETWORK_ID); final DomainVO domVo = mock(DomainVO.class); - when(domainDao.findById(41l)).thenReturn(domVo); + when(_domainDao.findById(41l)).thenReturn(domVo); final NetworkOfferingVO ntwkoffer = mock(NetworkOfferingVO.class); when(ntwkoffer.getId()).thenReturn(NETWORK_ID); - when(ntwkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); - when(element.isL3Network(NETWORK_ID)).thenReturn(true); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); - when(domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); + when(_domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - assertTrue(element.applyStaticNats(network, new ArrayList())); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + assertTrue(_nuageVspElement.applyStaticNats(network, new ArrayList())); } @Test @@ -277,21 +262,21 @@ public void testApplyFWRules() throws Exception { final NetworkOfferingVO ntwkoffer = mock(NetworkOfferingVO.class); when(ntwkoffer.getId()).thenReturn(NETWORK_ID); when(ntwkoffer.getEgressDefaultPolicy()).thenReturn(true); - when(ntwkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); - when(domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); + when(_domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - assertTrue(element.applyFWRules(network, new ArrayList())); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + assertTrue(_nuageVspElement.applyFWRules(network, new ArrayList())); } @Test @@ -306,20 +291,20 @@ public void testApplyNetworkACL() throws Exception { final NetworkOfferingVO ntwkoffer = mock(NetworkOfferingVO.class); when(ntwkoffer.getId()).thenReturn(NETWORK_ID); when(ntwkoffer.getEgressDefaultPolicy()).thenReturn(true); - when(ntwkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); - when(domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); + when(_domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - assertTrue(element.applyNetworkACLs(network, new ArrayList())); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + assertTrue(_nuageVspElement.applyNetworkACLs(network, new ArrayList())); } @Test @@ -332,7 +317,7 @@ public void testShutdownVpc() throws Exception { final DomainVO dom = mock(DomainVO.class); when(dom.getName()).thenReturn("domain"); - when(domainDao.findById(NETWORK_ID)).thenReturn(dom); + when(_domainDao.findById(NETWORK_ID)).thenReturn(dom); final Account acc = mock(Account.class); when(acc.getAccountName()).thenReturn("accountname"); final ReservationContext context = mock(ReservationContext.class); @@ -342,18 +327,18 @@ public void testShutdownVpc() throws Exception { PhysicalNetworkVO physNet = mock(PhysicalNetworkVO.class); when(physNet.getIsolationMethods()).thenReturn(Lists.newArrayList(PhysicalNetwork.IsolationMethod.VSP.name())); when(physNet.getId()).thenReturn(NETWORK_ID); - when(physNetDao.listByZone(NETWORK_ID)).thenReturn(Lists.newArrayList(physNet)); + when(_physicalNetworkDao.listByZone(NETWORK_ID)).thenReturn(Lists.newArrayList(physNet)); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - assertTrue(element.shutdownVpc(vpc, context)); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + assertTrue(_nuageVspElement.shutdownVpc(vpc, context)); } } \ No newline at end of file diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java index c8d23ab047..f101e1e1a2 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java @@ -19,6 +19,7 @@ package com.cloud.network.guru; +import com.cloud.NuageTest; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; @@ -46,6 +47,7 @@ import com.cloud.network.NuageVspDeviceVO; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.NuageVspDao; import com.cloud.network.dao.PhysicalNetworkDao; @@ -64,7 +66,6 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.NicDao; -import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.junit.Before; import org.junit.Test; @@ -86,60 +87,61 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class NuageVspGuestNetworkGuruTest { +public class NuageVspGuestNetworkGuruTest extends NuageTest { private static final long NETWORK_ID = 42L; - PhysicalNetworkDao physnetdao = mock(PhysicalNetworkDao.class); - DataCenterDao dcdao = mock(DataCenterDao.class); - NetworkOfferingServiceMapDao nosd = mock(NetworkOfferingServiceMapDao.class); - AgentManager agentManager = mock(AgentManager.class); - NetworkOrchestrationService netmgr = mock(NetworkOrchestrationService.class); - NetworkModel networkModel = mock(NetworkModel.class); - AccountDao accountDao = mock(AccountDao.class); - DomainDao domainDao = mock(DomainDao.class); - NicDao nicDao = mock(NicDao.class); - NetworkOfferingDao ntwkOfferDao = mock(NetworkOfferingDao.class); - NuageVspDao nuageVspDao = mock(NuageVspDao.class); - HostDao hostDao = mock(HostDao.class); - NetworkDao networkDao = mock(NetworkDao.class); - ConfigurationDao configDao = mock(ConfigurationDao.class); - IPAddressDao ipAddressDao = mock(IPAddressDao.class); - NuageVspManager nuageVspManager = mock(NuageVspManager.class); - ConfigurationManager configurationManager = mock(ConfigurationManager.class); - - NetworkDao netdao = mock(NetworkDao.class); - NuageVspGuestNetworkGuru guru; + private PhysicalNetworkDao _physicalNetworkDao = mock(PhysicalNetworkDao.class); + private DataCenterDao _dataCenterDao = mock(DataCenterDao.class); + private NetworkOfferingServiceMapDao _networkOfferingServiceMapDao = mock(NetworkOfferingServiceMapDao.class); + private AgentManager _agentManager = mock(AgentManager.class); + private NetworkModel _networkModel = mock(NetworkModel.class); + private AccountDao _accountDao = mock(AccountDao.class); + private DomainDao _domainDao = mock(DomainDao.class); + private NicDao _nicDao = mock(NicDao.class); + private NetworkOfferingDao _networkOfferingDao = mock(NetworkOfferingDao.class); + private NuageVspDao _nuageVspDao = mock(NuageVspDao.class); + private HostDao _hostDao = mock(HostDao.class); + private NetworkDao _networkDao = mock(NetworkDao.class); + private ConfigurationDao _configurationDao = mock(ConfigurationDao.class); + private IPAddressDao _ipAddressDao = mock(IPAddressDao.class); + private NuageVspManager _nuageVspManager = mock(NuageVspManager.class); + private ConfigurationManager _configurationManager = mock(ConfigurationManager.class); + private NetworkDetailsDao _networkDetailsDao = mock(NetworkDetailsDao.class); + private NuageVspGuestNetworkGuru _nuageVspGuestNetworkGuru; @Before - public void setUp() { - guru = new NuageVspGuestNetworkGuru(); - guru._physicalNetworkDao = physnetdao; - guru._physicalNetworkDao = physnetdao; - guru._nuageVspDao = nuageVspDao; - guru._dcDao = dcdao; - guru._ntwkOfferingSrvcDao = nosd; - guru._networkModel = networkModel; - guru._hostDao = hostDao; - guru._agentMgr = agentManager; - guru._networkDao = netdao; - guru._networkDao = networkDao; - guru._accountDao = accountDao; - guru._domainDao = domainDao; - guru._nicDao = nicDao; - guru._ntwkOfferingDao = ntwkOfferDao; - guru._configDao = configDao; - guru._ipAddressDao = ipAddressDao; - guru._nuageVspManager = nuageVspManager; - guru._configMgr = configurationManager; + public void setUp() throws Exception { + super.setUp(); + + _nuageVspGuestNetworkGuru = new NuageVspGuestNetworkGuru(); + _nuageVspGuestNetworkGuru._physicalNetworkDao = _physicalNetworkDao; + _nuageVspGuestNetworkGuru._physicalNetworkDao = _physicalNetworkDao; + _nuageVspGuestNetworkGuru._nuageVspDao = _nuageVspDao; + _nuageVspGuestNetworkGuru._dcDao = _dataCenterDao; + _nuageVspGuestNetworkGuru._ntwkOfferingSrvcDao = _networkOfferingServiceMapDao; + _nuageVspGuestNetworkGuru._networkModel = _networkModel; + _nuageVspGuestNetworkGuru._hostDao = _hostDao; + _nuageVspGuestNetworkGuru._agentMgr = _agentManager; + _nuageVspGuestNetworkGuru._networkDao = _networkDao; + _nuageVspGuestNetworkGuru._accountDao = _accountDao; + _nuageVspGuestNetworkGuru._domainDao = _domainDao; + _nuageVspGuestNetworkGuru._nicDao = _nicDao; + _nuageVspGuestNetworkGuru._ntwkOfferingDao = _networkOfferingDao; + _nuageVspGuestNetworkGuru._configDao = _configurationDao; + _nuageVspGuestNetworkGuru._ipAddressDao = _ipAddressDao; + _nuageVspGuestNetworkGuru._nuageVspManager = _nuageVspManager; + _nuageVspGuestNetworkGuru._configMgr = _configurationManager; + _nuageVspGuestNetworkGuru._nuageVspEntityBuilder = _nuageVspEntityBuilder; + _nuageVspGuestNetworkGuru._networkDetailsDao = _networkDetailsDao; final DataCenterVO dc = mock(DataCenterVO.class); when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); when(dc.getGuestNetworkCidr()).thenReturn("10.1.1.1/24"); - when(dcdao.findById((Long)any())).thenReturn(dc); + when(_dataCenterDao.findById((Long)any())).thenReturn(dc); - when(configDao.getValue(NuageVspIsolatedNetworkDomainTemplateName.key())).thenReturn("IsolatedDomainTemplate"); - when(configDao.getValue(NuageVspVpcDomainTemplateName.key())).thenReturn("VpcDomainTemplate"); - when(configDao.getValue(NuageVspSharedNetworkDomainTemplateName.key())).thenReturn("SharedDomainTemplate"); + when(_configurationDao.getValue(NuageVspIsolatedNetworkDomainTemplateName.key())).thenReturn("IsolatedDomainTemplate"); + when(_configurationDao.getValue(NuageVspVpcDomainTemplateName.key())).thenReturn("VpcDomainTemplate"); + when(_configurationDao.getValue(NuageVspSharedNetworkDomainTemplateName.key())).thenReturn("SharedDomainTemplate"); } @Test @@ -149,47 +151,47 @@ public void testCanHandle() { when(offering.getTrafficType()).thenReturn(TrafficType.Guest); when(offering.getGuestType()).thenReturn(GuestType.Isolated); when(offering.getIsPersistent()).thenReturn(false); - when(configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(false); + when(_configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(false); final PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class); when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] {"VSP"})); when(physnet.getId()).thenReturn(NETWORK_ID); - when(nosd.areServicesSupportedByNetworkOffering(NETWORK_ID, Service.Connectivity)).thenReturn(true); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(NETWORK_ID, Service.Connectivity)).thenReturn(true); - assertTrue(guru.canHandle(offering, NetworkType.Advanced, physnet)); + assertTrue(_nuageVspGuestNetworkGuru.canHandle(offering, NetworkType.Advanced, physnet) == true); // Not supported TrafficType != Guest when(offering.getTrafficType()).thenReturn(TrafficType.Management); - assertFalse(guru.canHandle(offering, NetworkType.Advanced, physnet)); + assertFalse(_nuageVspGuestNetworkGuru.canHandle(offering, NetworkType.Advanced, physnet) == true); // Supported: GuestType Shared when(offering.getTrafficType()).thenReturn(TrafficType.Guest); when(offering.getGuestType()).thenReturn(GuestType.Shared); - assertTrue(guru.canHandle(offering, NetworkType.Advanced, physnet)); + assertTrue(_nuageVspGuestNetworkGuru.canHandle(offering, NetworkType.Advanced, physnet) == true); // Not supported: Basic networking when(offering.getGuestType()).thenReturn(GuestType.Isolated); - assertFalse(guru.canHandle(offering, NetworkType.Basic, physnet)); + assertFalse(_nuageVspGuestNetworkGuru.canHandle(offering, NetworkType.Basic, physnet) == true); // Not supported: IsolationMethod != STT when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] {"VLAN"})); - assertFalse(guru.canHandle(offering, NetworkType.Advanced, physnet)); + assertFalse(_nuageVspGuestNetworkGuru.canHandle(offering, NetworkType.Advanced, physnet) == true); // Not supported: Non-persistent VPC tier - when(configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(true); - assertFalse(guru.canHandle(offering, NetworkType.Advanced, physnet)); + when(_configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(true); + assertFalse(_nuageVspGuestNetworkGuru.canHandle(offering, NetworkType.Advanced, physnet)); } @Test public void testDesign() { final PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class); - when(physnetdao.findById((Long)any())).thenReturn(physnet); + when(_physicalNetworkDao.findById((Long)any())).thenReturn(physnet); when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] {"VSP"})); when(physnet.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO device = mock(NuageVspDeviceVO.class); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {device})); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{device})); when(device.getId()).thenReturn(1L); final NetworkOffering offering = mock(NetworkOffering.class); @@ -197,32 +199,32 @@ public void testDesign() { when(offering.getTrafficType()).thenReturn(TrafficType.Guest); when(offering.getGuestType()).thenReturn(GuestType.Isolated); when(offering.getIsPersistent()).thenReturn(false); - when(configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(false); + when(_configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(false); - when(nosd.areServicesSupportedByNetworkOffering(NETWORK_ID, Service.Connectivity)).thenReturn(true); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(NETWORK_ID, Service.Connectivity)).thenReturn(true); final DeploymentPlan plan = mock(DeploymentPlan.class); final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designednetwork = guru.design(offering, plan, network, account); + final Network designednetwork = _nuageVspGuestNetworkGuru.design(offering, plan, network, account); assertTrue(designednetwork != null); assertTrue(designednetwork.getBroadcastDomainType() == BroadcastDomainType.Vsp); // Can't design non-persistent VPC tier - when(configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(true); - assertNull(guru.design(offering, plan, network, account)); + when(_configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(true); + assertNull(_nuageVspGuestNetworkGuru.design(offering, plan, network, account)); } @Test public void testDesignNoElementOnPhysicalNetwork() { final PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class); - when(physnetdao.findById((Long)any())).thenReturn(physnet); + when(_physicalNetworkDao.findById((Long)any())).thenReturn(physnet); when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] {"STT"})); when(physnet.getId()).thenReturn(NETWORK_ID); mock(NuageVspDeviceVO.class); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Collections. emptyList()); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Collections.emptyList()); final NetworkOffering offering = mock(NetworkOffering.class); when(offering.getId()).thenReturn(NETWORK_ID); @@ -233,19 +235,19 @@ public void testDesignNoElementOnPhysicalNetwork() { final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designednetwork = guru.design(offering, plan, network, account); + final Network designednetwork = _nuageVspGuestNetworkGuru.design(offering, plan, network, account); assertTrue(designednetwork == null); } @Test public void testDesignNoIsolationMethodVSP() { final PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class); - when(physnetdao.findById((Long)any())).thenReturn(physnet); + when(_physicalNetworkDao.findById((Long)any())).thenReturn(physnet); when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] {"VLAN"})); when(physnet.getId()).thenReturn(NETWORK_ID); mock(NuageVspDeviceVO.class); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Collections. emptyList()); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Collections.emptyList()); final NetworkOffering offering = mock(NetworkOffering.class); when(offering.getId()).thenReturn(NETWORK_ID); @@ -256,7 +258,7 @@ public void testDesignNoIsolationMethodVSP() { final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designednetwork = guru.design(offering, plan, network, account); + final Network designednetwork = _nuageVspGuestNetworkGuru.design(offering, plan, network, account); assertTrue(designednetwork == null); } @@ -274,20 +276,20 @@ public void testReserve() throws InsufficientVirtualNetworkCapacityException, In when(network.getBroadcastUri()).thenReturn(new URI("vsp://aaaaaa-aavvv/10.1.1.1")); final DataCenterVO dataCenter = mock(DataCenterVO.class); - when(dcdao.findById(NETWORK_ID)).thenReturn(dataCenter); + when(_dataCenterDao.findById(NETWORK_ID)).thenReturn(dataCenter); final AccountVO networksAccount = mock(AccountVO.class); when(networksAccount.getUuid()).thenReturn("aaaa-abbbb"); when(networksAccount.getType()).thenReturn(Account.ACCOUNT_TYPE_NORMAL); - when(accountDao.findById(NETWORK_ID)).thenReturn(networksAccount); + when(_accountDao.findById(NETWORK_ID)).thenReturn(networksAccount); final DomainVO networksDomain = mock(DomainVO.class); when(networksDomain.getUuid()).thenReturn("aaaaa-bbbbb"); - when(domainDao.findById(NETWORK_ID)).thenReturn(networksDomain); + when(_domainDao.findById(NETWORK_ID)).thenReturn(networksDomain); final NicVO nicvo = mock(NicVO.class); when(nicvo.getId()).thenReturn(NETWORK_ID); when(nicvo.getMacAddress()).thenReturn("aa-aa-aa-aa-aa-aa"); when(nicvo.getUuid()).thenReturn("aaaa-fffff"); - when(nicDao.findById(NETWORK_ID)).thenReturn(nicvo); + when(_nicDao.findById(NETWORK_ID)).thenReturn(nicvo); final VirtualMachine vm = mock(VirtualMachine.class); when(vm.getId()).thenReturn(NETWORK_ID); @@ -306,24 +308,24 @@ public void testReserve() throws InsufficientVirtualNetworkCapacityException, In final NetworkOfferingVO ntwkoffering = mock(NetworkOfferingVO.class); when(ntwkoffering.getId()).thenReturn(NETWORK_ID); - when(ntwkOfferDao.findById(NETWORK_ID)).thenReturn(ntwkoffering); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffering); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); - when(networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); - when(ipAddressDao.findByVmIdAndNetworkId(NETWORK_ID, NETWORK_ID)).thenReturn(null); - when(domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); + when(_networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); + when(_ipAddressDao.findByVmIdAndNetworkId(NETWORK_ID, NETWORK_ID)).thenReturn(null); + when(_domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - guru.reserve(nicProfile, network, vmProfile, mock(DeployDestination.class), mock(ReservationContext.class)); + _nuageVspGuestNetworkGuru.reserve(nicProfile, network, vmProfile, mock(DeployDestination.class), mock(ReservationContext.class)); } @Test @@ -352,7 +354,7 @@ public void testImplementNetwork() throws URISyntaxException, InsufficientVirtua when(offering.getTags()).thenReturn("aaaa"); when(offering.getEgressDefaultPolicy()).thenReturn(true); - when(networkModel.findPhysicalNetworkId(NETWORK_ID, "aaa", TrafficType.Guest)).thenReturn(NETWORK_ID); + when(_networkModel.findPhysicalNetworkId(NETWORK_ID, "aaa", TrafficType.Guest)).thenReturn(NETWORK_ID); final ReservationContext reserveContext = mock(ReservationContext.class); final Domain domain = mock(Domain.class); @@ -362,29 +364,29 @@ public void testImplementNetwork() throws URISyntaxException, InsufficientVirtua when(account.getAccountId()).thenReturn(NETWORK_ID); when(reserveContext.getAccount()).thenReturn(account); final DomainVO domainVo = mock(DomainVO.class); - when(domainDao.findById(NETWORK_ID)).thenReturn(domainVo); + when(_domainDao.findById(NETWORK_ID)).thenReturn(domainVo); final AccountVO accountVo = mock(AccountVO.class); - when(accountDao.findById(NETWORK_ID)).thenReturn(accountVo); + when(_accountDao.findById(NETWORK_ID)).thenReturn(accountVo); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); - when(networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); - when(nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList()); - when(nuageVspManager.getGatewaySystemIds()).thenReturn(new ArrayList()); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); + when(_nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList()); + when(_nuageVspManager.getGatewaySystemIds()).thenReturn(new ArrayList()); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); final DataCenter dc = mock(DataCenter.class); when(dc.getId()).thenReturn(NETWORK_ID); final DeployDestination deployDest = mock(DeployDestination.class); when(deployDest.getDataCenter()).thenReturn(dc); - guru.implement(network, offering, deployDest, reserveContext); + _nuageVspGuestNetworkGuru.implement(network, offering, deployDest, reserveContext); } @Test @@ -396,22 +398,22 @@ public void testDeallocate() throws Exception { when(network.getPhysicalNetworkId()).thenReturn(NETWORK_ID); when(network.getVpcId()).thenReturn(null); when(network.getDomainId()).thenReturn(NETWORK_ID); - when(networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); + when(_networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); final NetworkOfferingVO offering = mock(NetworkOfferingVO.class); when(offering.getId()).thenReturn(NETWORK_ID); when(offering.getTrafficType()).thenReturn(TrafficType.Guest); - when(ntwkOfferDao.findById(NETWORK_ID)).thenReturn(offering); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(offering); final DomainVO domain = mock(DomainVO.class); when(domain.getUuid()).thenReturn("aaaaaa"); - when(domainDao.findById(NETWORK_ID)).thenReturn(domain); + when(_domainDao.findById(NETWORK_ID)).thenReturn(domain); final NicVO nic = mock(NicVO.class); when(nic.getId()).thenReturn(NETWORK_ID); when(nic.getIPv4Address()).thenReturn("10.10.10.10"); when(nic.getMacAddress()).thenReturn("c8:60:00:56:e5:58"); - when(nicDao.findById(NETWORK_ID)).thenReturn(nic); + when(_nicDao.findById(NETWORK_ID)).thenReturn(nic); final NicProfile nicProfile = mock(NicProfile.class); when(nicProfile.getId()).thenReturn(NETWORK_ID); @@ -431,14 +433,14 @@ public void testDeallocate() throws Exception { when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - guru.deallocate(network, nicProfile, vmProfile); + _nuageVspGuestNetworkGuru.deallocate(network, nicProfile, vmProfile); } @Test @@ -451,31 +453,31 @@ public void testTrash() throws Exception { when(network.getNetworkOfferingId()).thenReturn(NETWORK_ID); when(network.getPhysicalNetworkId()).thenReturn(NETWORK_ID); when(network.getVpcId()).thenReturn(null); - when(networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); + when(_networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); final NetworkOfferingVO offering = mock(NetworkOfferingVO.class); when(offering.getId()).thenReturn(NETWORK_ID); when(offering.getTrafficType()).thenReturn(TrafficType.Guest); - when(ntwkOfferDao.findById(NETWORK_ID)).thenReturn(offering); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(offering); final DomainVO domain = mock(DomainVO.class); when(domain.getUuid()).thenReturn("aaaaaa"); - when(domainDao.findById(NETWORK_ID)).thenReturn(domain); + when(_domainDao.findById(NETWORK_ID)).thenReturn(domain); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); - when(nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList()); - when(nuageVspManager.getGatewaySystemIds()).thenReturn(new ArrayList()); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList()); + when(_nuageVspManager.getGatewaySystemIds()).thenReturn(new ArrayList()); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - assertTrue(guru.trash(network, offering)); + assertTrue(_nuageVspGuestNetworkGuru.trash(network, offering)); } } diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/manager/NuageVspManagerTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/manager/NuageVspManagerTest.java index a29e3d7894..ec16a974d0 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/manager/NuageVspManagerTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/manager/NuageVspManagerTest.java @@ -19,6 +19,7 @@ package com.cloud.network.manager; +import com.cloud.NuageTest; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Command; import com.cloud.agent.api.sync.SyncNuageVspCmsIdAnswer; @@ -35,6 +36,7 @@ import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.resource.ResourceManager; +import com.cloud.util.NuageVspEntityBuilder; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.config.impl.ConfigurationVO; import org.junit.Before; @@ -48,34 +50,37 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class NuageVspManagerTest { +public class NuageVspManagerTest extends NuageTest { private static final long NETWORK_ID = 42L; - PhysicalNetworkDao physicalNetworkDao = mock(PhysicalNetworkDao.class); - PhysicalNetworkServiceProviderDao physicalNetworkServiceProviderDao = mock(PhysicalNetworkServiceProviderDao.class); - ResourceManager resourceMgr = mock(ResourceManager.class); - HostDetailsDao hostDetailsDao = mock(HostDetailsDao.class); - NuageVspDao nuageVspDao = mock(NuageVspDao.class); - NetworkDao networkDao = mock(NetworkDao.class); - HostDao hostDao = mock(HostDao.class); - AgentManager agentManager = mock(AgentManager.class); - ConfigurationDao configDao = mock(ConfigurationDao.class); - - NuageVspManagerImpl manager; + private PhysicalNetworkDao _physicalNetworkDao = mock(PhysicalNetworkDao.class); + private PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao = mock(PhysicalNetworkServiceProviderDao.class); + private ResourceManager _resourceManager = mock(ResourceManager.class); + private HostDetailsDao _hostDetailsDao = mock(HostDetailsDao.class); + private NuageVspDao _nuageVspDao = mock(NuageVspDao.class); + private NetworkDao _networkDao = mock(NetworkDao.class); + private HostDao _hostDao = mock(HostDao.class); + private AgentManager _agentManager = mock(AgentManager.class); + private ConfigurationDao _configurationDao = mock(ConfigurationDao.class); + private NuageVspEntityBuilder _nuageVspEntityBuilder = mock(NuageVspEntityBuilder.class); + private NuageVspManagerImpl _nuageVspManager; @Before - public void setUp() { - manager = new NuageVspManagerImpl(); - - manager._physicalNetworkServiceProviderDao = physicalNetworkServiceProviderDao; - manager._physicalNetworkDao = physicalNetworkDao; - manager._resourceMgr = resourceMgr; - manager._hostDetailsDao = hostDetailsDao; - manager._nuageVspDao = nuageVspDao; - manager._networkDao = networkDao; - manager._hostDao = hostDao; - manager._agentMgr = agentManager; - manager._configDao = configDao; + public void setUp() throws Exception { + super.setUp(); + + _nuageVspManager = new NuageVspManagerImpl(); + + _nuageVspManager._physicalNetworkServiceProviderDao = _physicalNetworkServiceProviderDao; + _nuageVspManager._physicalNetworkDao = _physicalNetworkDao; + _nuageVspManager._resourceMgr = _resourceManager; + _nuageVspManager._hostDetailsDao = _hostDetailsDao; + _nuageVspManager._nuageVspDao = _nuageVspDao; + _nuageVspManager._networkDao = _networkDao; + _nuageVspManager._hostDao = _hostDao; + _nuageVspManager._agentMgr = _agentManager; + _nuageVspManager._configDao = _configurationDao; + _nuageVspManager._nuageVspEntityBuilder = _nuageVspEntityBuilder; } @Test @@ -84,31 +89,31 @@ public void testDeleteNuageVspDevice() throws ConfigurationException { final PhysicalNetworkVO physicalNetwork = mock(PhysicalNetworkVO.class); when(physicalNetwork.getDataCenterId()).thenReturn(NETWORK_ID); when(physicalNetwork.getId()).thenReturn(NETWORK_ID); - when(physicalNetworkDao.findById(NETWORK_ID)).thenReturn(physicalNetwork); + when(_physicalNetworkDao.findById(NETWORK_ID)).thenReturn(physicalNetwork); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getPhysicalNetworkId()).thenReturn(NETWORK_ID); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.findById(NETWORK_ID)).thenReturn(nuageVspDevice); + when(_nuageVspDao.findById(NETWORK_ID)).thenReturn(nuageVspDevice); - when(networkDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(new ArrayList()); + when(_networkDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(new ArrayList()); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); final DeleteNuageVspDeviceCmd cmd = mock(DeleteNuageVspDeviceCmd.class); when(cmd.getNuageVspDeviceId()).thenReturn(NETWORK_ID); ConfigurationVO cmsIdConfig = mock(ConfigurationVO.class); when(cmsIdConfig.getValue()).thenReturn("1:1"); - when(configDao.findByName("nuagevsp.cms.id")).thenReturn(cmsIdConfig); + when(_configurationDao.findByName("nuagevsp.cms.id")).thenReturn(cmsIdConfig); final SyncNuageVspCmsIdAnswer answer = mock(SyncNuageVspCmsIdAnswer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - manager.deleteNuageVspDevice(cmd); + _nuageVspManager.deleteNuageVspDevice(cmd); } @Test @@ -117,12 +122,12 @@ public void testListNuageVspDevices() { when(nuageVspDevice.getPhysicalNetworkId()).thenReturn(NETWORK_ID); final PhysicalNetworkVO phyNtwkVO = mock(PhysicalNetworkVO.class); - when(physicalNetworkDao.findById(NETWORK_ID)).thenReturn(phyNtwkVO); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(new ArrayList()); + when(_physicalNetworkDao.findById(NETWORK_ID)).thenReturn(phyNtwkVO); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(new ArrayList()); final ListNuageVspDevicesCmd cmd = mock(ListNuageVspDevicesCmd.class); when(cmd.getPhysicalNetworkId()).thenReturn(NETWORK_ID); when(cmd.getNuageVspDeviceId()).thenReturn(null); - manager.listNuageVspDevices(cmd); + _nuageVspManager.listNuageVspDevices(cmd); } } diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java index 770e13f0dc..9c51864e49 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java @@ -19,6 +19,7 @@ package com.cloud.network.resource; +import com.cloud.NuageTest; import com.cloud.agent.api.Answer; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.StartupCommand; @@ -29,13 +30,17 @@ import com.cloud.agent.api.guru.ImplementNetworkVspCommand; import com.cloud.agent.api.guru.ReserveVmInterfaceVspCommand; import com.cloud.agent.api.guru.TrashNetworkVspCommand; -import com.cloud.agent.api.sync.SyncVspCommand; import com.cloud.host.Host; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import net.nuage.vsp.acs.client.NuageVspApiClient; -import net.nuage.vsp.acs.client.NuageVspElementClient; -import net.nuage.vsp.acs.client.NuageVspGuruClient; -import net.nuage.vsp.acs.client.NuageVspSyncClient; +import net.nuage.vsp.acs.client.api.NuageVspApiClient; +import net.nuage.vsp.acs.client.api.NuageVspElementClient; +import net.nuage.vsp.acs.client.api.NuageVspGuruClient; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; +import net.nuage.vsp.acs.client.api.model.VspVm; import org.junit.Before; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; @@ -43,20 +48,20 @@ import javax.naming.ConfigurationException; import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.Map; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; -public class NuageVspResourceTest { - NuageVspResource _resource; - NuageVspApiClient _mockNuageVspApiClient = mock(NuageVspApiClient.class); - NuageVspElementClient _mockNuageVspElementClient = mock(NuageVspElementClient.class); - NuageVspGuruClient _mockNuageVspGuruClient = mock(NuageVspGuruClient.class); - NuageVspSyncClient _mockNuageVspSyncClient = mock(NuageVspSyncClient.class); - NuageVspResource.Configuration _resourceConfiguration; - Map _hostDetails; +public class NuageVspResourceTest extends NuageTest { + private NuageVspResource _resource; + private NuageVspApiClient _mockNuageVspApiClient = mock(NuageVspApiClient.class); + private NuageVspElementClient _mockNuageVspElementClient = mock(NuageVspElementClient.class); + private NuageVspGuruClient _mockNuageVspGuruClient = mock(NuageVspGuruClient.class); + private NuageVspResource.Configuration _resourceConfiguration; + private Map _hostDetails; org.mockito.stubbing.Answer genericAnswer = new org.mockito.stubbing.Answer() { public Object answer(InvocationOnMock invocation) { @@ -66,6 +71,8 @@ public Object answer(InvocationOnMock invocation) { @Before public void setUp() throws Exception { + super.setUp(); + _resource = new NuageVspResource() { @Override @@ -74,8 +81,6 @@ protected void loadNuageClient() { _nuageVspApiClient = _mockNuageVspApiClient; _nuageVspElementClient = _mockNuageVspElementClient; _nuageVspGuruClient = _mockNuageVspGuruClient; - _nuageVspSyncClient = _mockNuageVspSyncClient; - } protected void isNuageVspApiLoaded() throws ConfigurationException { @@ -87,9 +92,6 @@ protected void isNuageVspGuruLoaded() throws ConfigurationException { protected void isNuageVspElementLoaded() throws ConfigurationException { } - protected void isNuageVspSyncLoaded() throws ConfigurationException { - } - protected void login() throws ConfigurationException { } @@ -148,15 +150,10 @@ public void testPingCommandStatus() throws Exception { public void testImplementNetworkVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - ImplementNetworkVspCommand.Builder cmdBuilder = new ImplementNetworkVspCommand.Builder().networkDomainName("networkDomainName").networkDomainPath("networkDomainPath") - .networkDomainUuid("networkDomainUuid").networkAccountName("networkAccountName").networkAccountUuid("networkAccountUuid").networkName("networkName") - .networkCidr("networkCidr").networkGateway("networkGateway").networkAclId(0L).dnsServers(new ArrayList()).gatewaySystemIds(new ArrayList()) - .networkUuid("networkUuid").isL3Network(true).isVpc(true).isSharedNetwork(true).vpcName("vpcName").vpcUuid("vpcUuid").defaultEgressPolicy(true) - .ipAddressRange(new ArrayList()).domainTemplateName("domainTemplateName"); - doAnswer(genericAnswer).when(_mockNuageVspGuruClient).implement("networkDomainName", "networkDomainPath", "networkDomainUuid", "networkAccountName", - "networkAccountUuid", "networkName", "networkCidr", "networkGateway", 0L, new ArrayList(), new ArrayList(), true, true, true, "networkUuid", - "vpcName", "vpcUuid", true, new ArrayList(), "domainTemplateName"); - com.cloud.agent.api.Answer implNtwkAns = _resource.executeRequest(cmdBuilder.build()); + VspNetwork vspNetwork = buildVspNetwork(); + ImplementNetworkVspCommand cmd = new ImplementNetworkVspCommand(vspNetwork, new ArrayList()); + doAnswer(genericAnswer).when(_mockNuageVspGuruClient).implement(vspNetwork, new ArrayList()); + com.cloud.agent.api.Answer implNtwkAns = _resource.executeRequest(cmd); assertTrue(implNtwkAns.getResult()); } @@ -164,16 +161,13 @@ public void testImplementNetworkVspCommand() throws Exception { public void testReserveVmInterfaceVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - ReserveVmInterfaceVspCommand.Builder cmdBuilder = new ReserveVmInterfaceVspCommand.Builder().nicUuid("nicUuid").nicMacAddress("nicMacAddress") - .networkUuid("networkUuid").isL3Network(true).isSharedNetwork(true).vpcUuid("vpcUuid").networkDomainUuid("networkDomainUuid") - .networksAccountUuid("networksAccountUuid").isDomainRouter(false).domainRouterIp("domainRouterIp").vmInstanceName("vmInstanceName").vmUuid("vmUuid") - .vmUserName("vmUserName").vmUserDomainName("vmUserDomainName").useStaticIp(true).staticIp("staticIp").staticNatIpUuid("staticNatIpUuid") - .staticNatIpAddress("staticNatIpAddress").isStaticNatIpAllocated(true).isOneToOneNat(true).staticNatVlanUuid("staticNatVlanUuid") - .staticNatVlanGateway("staticNatVlanGateway").staticNatVlanNetmask("staticNatVlanNetmask"); - doAnswer(genericAnswer).when(_mockNuageVspGuruClient).reserve("nicUuid", "nicMacAddress", "networkUuid", true, true, "vpcUuid", "networkDomainUuid", - "networksAccountUuid", false, "domainRouterIp", "vmInstanceName", "vmUuid", true, "staticIp", "staticNatIpUuid", "staticNatIpAddress", - true, true, "staticNatVlanUuid", "staticNatVlanGateway", "staticNatVlanNetmask"); - Answer rsrvVmInfAns = _resource.executeRequest(cmdBuilder.build()); + VspNetwork vspNetwork = buildVspNetwork(); + VspVm vspVm = buildVspVm(); + VspNic vspNic = buildVspNic(); + VspStaticNat vspStaticNat = buildVspStaticNat(); + ReserveVmInterfaceVspCommand cmd = new ReserveVmInterfaceVspCommand(vspNetwork, vspVm, vspNic, vspStaticNat); + doAnswer(genericAnswer).when(_mockNuageVspGuruClient).reserve(vspNetwork, vspVm, vspNic, vspStaticNat); + Answer rsrvVmInfAns = _resource.executeRequest(cmd); assertTrue(rsrvVmInfAns.getResult()); } @@ -181,12 +175,12 @@ public void testReserveVmInterfaceVspCommand() throws Exception { public void testDeallocateVmVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - DeallocateVmVspCommand.Builder cmdBuilder = new DeallocateVmVspCommand.Builder().networkUuid("networkUuid").nicFromDbUuid("nicFromDbUuid") - .nicMacAddress("nicMacAddress").nicIp4Address("nicIp4Address").isL3Network(true).isSharedNetwork(true).vpcUuid("vpcUuid") - .networksDomainUuid("networksDomainUuid").vmInstanceName("vmInstanceName").vmUuid("vmUuid").isExpungingState(true); - doAnswer(genericAnswer).when(_mockNuageVspGuruClient).deallocate("networkUuid", "nicFrmDdUuid", "nicMacAddress", "nicIp4Address", true, true, "vpcUuid", "networksDomainUuid", - "vmInstanceName", "vmUuid", true); - Answer dellocateVmAns = _resource.executeRequest(cmdBuilder.build()); + VspNetwork vspNetwork = buildVspNetwork(); + VspVm vspVm = buildVspVm(); + VspNic vspNic = buildVspNic(); + DeallocateVmVspCommand cmd = new DeallocateVmVspCommand(vspNetwork, vspVm, vspNic); + doAnswer(genericAnswer).when(_mockNuageVspGuruClient).deallocate(vspNetwork, vspVm, vspNic); + Answer dellocateVmAns = _resource.executeRequest(cmd); assertTrue(dellocateVmAns.getResult()); } @@ -194,10 +188,10 @@ public void testDeallocateVmVspCommand() throws Exception { public void testTrashNetworkVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - TrashNetworkVspCommand.Builder cmdBuilder = new TrashNetworkVspCommand.Builder().domainUuid("domainUuid").networkUuid("networkUuid") - .isL3Network(true).isSharedNetwork(true).vpcUuid("vpcUuid").domainTemplateName("domainTemplateName"); - doAnswer(genericAnswer).when(_mockNuageVspGuruClient).trash("domainUuid", "networkUuid", true, true, "vpcUuid", "domainTemplateName"); - Answer trashNtwkAns = _resource.executeRequest(cmdBuilder.build()); + VspNetwork vspNetwork = buildVspNetwork(); + TrashNetworkVspCommand cmd = new TrashNetworkVspCommand(vspNetwork); + doAnswer(genericAnswer).when(_mockNuageVspGuruClient).trash(vspNetwork); + Answer trashNtwkAns = _resource.executeRequest(cmd); assertTrue(trashNtwkAns.getResult()); } @@ -205,10 +199,11 @@ public void testTrashNetworkVspCommand() throws Exception { public void testApplyStaticNatVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - ApplyStaticNatVspCommand.Builder cmdBuilder = new ApplyStaticNatVspCommand.Builder().networkDomainUuid("networkDomainUuid").networkUuid("networkUuid") - .vpcOrSubnetUuid("vpcOrSubnetUuid").isL3Network(true).isVpc(true).staticNatDetails(new ArrayList>()); - doAnswer(genericAnswer).when(_mockNuageVspElementClient).applyStaticNats("networkDomainUuid", "networkUuid", "vpcOrSubnetUuid", true, true, new ArrayList>()); - Answer applyNatAns = _resource.executeRequest(cmdBuilder.build()); + VspNetwork vspNetwork = buildVspNetwork(); + List vspStaticNatDetails = Lists.newArrayList(buildVspStaticNat()); + ApplyStaticNatVspCommand cmd = new ApplyStaticNatVspCommand(vspNetwork, vspStaticNatDetails); + doAnswer(genericAnswer).when(_mockNuageVspElementClient).applyStaticNats(vspNetwork, vspStaticNatDetails); + Answer applyNatAns = _resource.executeRequest(cmd); assertTrue(applyNatAns.getResult()); } @@ -216,12 +211,11 @@ public void testApplyStaticNatVspCommand() throws Exception { public void testApplyAclRuleVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - ApplyAclRuleVspCommand.Builder cmdBuilder = new ApplyAclRuleVspCommand.Builder().networkAcl(true).networkUuid("networkUuid").networkDomainUuid("networkDomainUuid") - .vpcOrSubnetUuid("vpcOrSubnetUuid").networkName("networkName").isL2Network(true).aclRules(new ArrayList>()).networkId(100) - .egressDefaultPolicy(false).acsIngressAcl(true).networkReset(true).domainTemplateName("domainTemplateName"); - doAnswer(genericAnswer).when(_mockNuageVspElementClient).applyAclRules(true, "networkUuid", "networkDomainUuid", "vpcOrSubnetUuid", "networkName", true, - new ArrayList>(), 100, false, true, true, "domainTemplateName"); - Answer applyAclAns = _resource.executeRequest(cmdBuilder.build()); + VspNetwork vspNetwork = buildVspNetwork(); + List vspAclRules = Lists.newArrayList(buildVspAclRule()); + ApplyAclRuleVspCommand cmd = new ApplyAclRuleVspCommand(VspAclRule.ACLType.NetworkACL, vspNetwork, vspAclRules, false); + doAnswer(genericAnswer).when(_mockNuageVspElementClient).applyAclRules(VspAclRule.ACLType.NetworkACL, vspNetwork, vspAclRules, false); + Answer applyAclAns = _resource.executeRequest(cmd); assertTrue(applyAclAns.getResult()); } @@ -229,19 +223,9 @@ public void testApplyAclRuleVspCommand() throws Exception { public void testShutDownVpcVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - ShutDownVpcVspCommand.Builder cmdBuilder = new ShutDownVpcVspCommand.Builder().domainUuid("domainUuid").vpcUuid("vpcUuid").domainTemplateName("domainTemplateName"); + ShutDownVpcVspCommand cmd = new ShutDownVpcVspCommand("domainUuid", "vpcUuid", "domainTemplateName"); doAnswer(genericAnswer).when(_mockNuageVspElementClient).shutdownVpc("domainUuid", "vpcUuid", "domainTemplateName"); - Answer shutVpcAns = _resource.executeRequest(cmdBuilder.build()); - assertTrue(shutVpcAns.getResult()); - } - - @Test - public void testSyncVspCommand() throws Exception { - _resource.configure("NuageVspResource", _hostDetails); - - SyncVspCommand shutVpcCmd = new SyncVspCommand("nuageVspEntity"); - doAnswer(genericAnswer).when(_mockNuageVspSyncClient).syncWithNuageVsp("nuageVspEntity"); - Answer shutVpcAns = _resource.executeRequest(shutVpcCmd); + Answer shutVpcAns = _resource.executeRequest(cmd); assertTrue(shutVpcAns.getResult()); } } diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/sync/NuageVspSyncTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/sync/NuageVspSyncTest.java deleted file mode 100644 index 23430d4685..0000000000 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/sync/NuageVspSyncTest.java +++ /dev/null @@ -1,72 +0,0 @@ -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -package com.cloud.network.sync; - -import com.cloud.agent.AgentManager; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.Command; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.network.NuageVspDeviceVO; -import com.cloud.network.dao.NuageVspDao; -import org.junit.Before; -import org.junit.Test; - -import java.util.Arrays; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class NuageVspSyncTest { - private static final long NETWORK_ID = 42L; - NuageVspDao nuageVspDao = mock(NuageVspDao.class); - AgentManager agentManager = mock(AgentManager.class); - HostDao hostDao = mock(HostDao.class); - - NuageVspSyncImpl sync; - - @Before - public void setUp() { - sync = new NuageVspSyncImpl(); - sync._nuageVspDao = nuageVspDao; - sync._agentMgr = agentManager; - sync._hostDao = hostDao; - } - - @Test - public void testSyncWithNuageVsp() { - final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); - when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDevice.getId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listAll()).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - - final HostVO host = mock(HostVO.class); - when(host.getId()).thenReturn(NETWORK_ID); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); - - final Answer answer = mock(Answer.class); - when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - - sync.syncWithNuageVsp("users"); - } -} diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/util/NuageVspEntityBuilderTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/util/NuageVspEntityBuilderTest.java new file mode 100644 index 0000000000..1ddc106877 --- /dev/null +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/util/NuageVspEntityBuilderTest.java @@ -0,0 +1,412 @@ +// +// 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.util; + +import com.cloud.NuageTest; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.VlanDao; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.network.Network; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkDetailsDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.user.AccountVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.net.Ip; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.VirtualMachine; +import com.google.common.collect.Lists; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspDomain; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; +import net.nuage.vsp.acs.client.api.model.VspVm; +import net.nuage.vsp.acs.client.common.model.Pair; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class NuageVspEntityBuilderTest extends NuageTest { + + private static final long DOMAIN_ID = 1L; + private static final long ACCOUNT_ID = 1L; + private static final long NETWORK_OFFERING_ID = 1L; + private static final long SHARED_NETWORK_OFFERING_ID = 2L; + private static final long L2_NETWORK_OFFERING_ID = 3L; + private static final long VPC_ID = 1L; + private static final long SOURCE_IP_ADDRESS_ID = 1L; + + private VpcDao _vpcDao = mock(VpcDao.class); + private DomainDao _domainDao = mock(DomainDao.class); + private AccountDao _accountDao = mock(AccountDao.class); + private NetworkOfferingDao _networkOfferingDao = mock(NetworkOfferingDao.class); + private NetworkOfferingServiceMapDao _networkOfferingServiceMapDao = mock(NetworkOfferingServiceMapDao.class); + private VlanDao _vlanDao = mock(VlanDao.class); + private IPAddressDao _ipAddressDao = mock(IPAddressDao.class); + private NetworkDetailsDao _networkDetailsDao = mock(NetworkDetailsDao.class); + private NuageVspEntityBuilder _nuageVspEntityBuilder = new NuageVspEntityBuilder(); + + private DomainVO _mockedDomain = mock(DomainVO.class); + private AccountVO _mockedAccount = mock(AccountVO.class); + private NetworkOfferingVO _mockedNetworkOffering = mock(NetworkOfferingVO.class); + private NetworkOfferingVO _mockedSharedNetworkOffering = mock(NetworkOfferingVO.class); + private NetworkOfferingVO _mockedL2NetworkOffering = mock(NetworkOfferingVO.class); + private VlanVO _mockedVlan = mock(VlanVO.class); + private VpcVO _mockedVpc = mock(VpcVO.class); + private NetworkVO _mockedNetwork = mock(NetworkVO.class); + private NetworkVO _mockedVpcNetwork = mock(NetworkVO.class); + private NetworkVO _mockedSharedNetwork = mock(NetworkVO.class); + private NetworkVO _mockedL2Network = mock(NetworkVO.class); + private VirtualMachine _mockedUserVirtualMachine = mock(VirtualMachine.class); + private VirtualMachine _mockedDomainRouterVirtualMachine = mock(VirtualMachine.class); + private NicProfile _mockedNicProfile = mock(NicProfile.class); + private NicVO _mockedNic = mock(NicVO.class); + private IPAddressVO _mockedStaticNatIp = mock(IPAddressVO.class); + private VlanVO _mockedStaticNatVlan = mock(VlanVO.class); + private FirewallRule _mockedFirewallRule = mock(FirewallRule.class); + private NetworkACLItem _mockedNetworkAclItem = mock(NetworkACLItem.class); + + @Before + public void setUp() throws Exception { + super.setUp(); + + _nuageVspEntityBuilder._vpcDao = _vpcDao; + _nuageVspEntityBuilder._domainDao = _domainDao; + _nuageVspEntityBuilder._accountDao = _accountDao; + _nuageVspEntityBuilder._networkOfferingDao = _networkOfferingDao; + _nuageVspEntityBuilder._networkOfferingServiceMapDao = _networkOfferingServiceMapDao; + _nuageVspEntityBuilder._vlanDao = _vlanDao; + _nuageVspEntityBuilder._configurationDao = _configurationDao; + _nuageVspEntityBuilder._ipAddressDao = _ipAddressDao; + _nuageVspEntityBuilder._networkModel = _networkModel; + _nuageVspEntityBuilder._networkDetailsDao = _networkDetailsDao; + + setUpMockedDomain(); + setUpMockedAccount(); + setUpMockedNetworkOffering(_mockedNetworkOffering, Network.GuestType.Isolated); + setUpMockedNetworkOffering(_mockedSharedNetworkOffering, Network.GuestType.Shared); + setUpMockedNetworkOffering(_mockedL2NetworkOffering, Network.GuestType.Isolated); + setUpMockedVlan(); + setUpMockedVpc(); + setUpMockedNetwork(_mockedNetwork, NETWORK_OFFERING_ID, null); + setUpMockedNetwork(_mockedVpcNetwork, NETWORK_OFFERING_ID, VPC_ID); + setUpMockedNetwork(_mockedSharedNetwork, SHARED_NETWORK_OFFERING_ID, null); + setUpMockedNetwork(_mockedL2Network, L2_NETWORK_OFFERING_ID, null); + setUpMockedVirtualMachine(_mockedUserVirtualMachine, false); + setUpMockedVirtualMachine(_mockedDomainRouterVirtualMachine, true); + setUpMockedNicProfile(); + setUpMockedNic(); + setUpMockedStaticNatIp(); + setUpMockedStaticNatVlan(); + setUpMockedFirewallRule(); + setUpMockedNetworkAclItem(); + setUpMockedDaoCalls(); + } + + @Test + public void testBuildVspDomain() { + VspDomain vspDomain = _nuageVspEntityBuilder.buildVspDomain(_mockedDomain); + validateVspDomain(vspDomain); + } + + @Test + public void testBuildVspNetwork() { + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedL2Network, true); + validateVspNetwork(vspNetwork, true, false, false, false, "IsolatedDomainTemplate", true); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedL2Network, false); + validateVspNetwork(vspNetwork, true, false, false, false, "IsolatedDomainTemplate", false); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedNetwork, true); + validateVspNetwork(vspNetwork, false, true, false, false, "IsolatedDomainTemplate", true); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedNetwork, false); + validateVspNetwork(vspNetwork, false, true, false, false, "IsolatedDomainTemplate", false); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedVpcNetwork, true); + validateVspNetwork(vspNetwork, false, false, true, false, "VpcDomainTemplate", true); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedVpcNetwork, false); + validateVspNetwork(vspNetwork, false, false, true, false, "VpcDomainTemplate", false); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedSharedNetwork, true); + validateVspNetwork(vspNetwork, false, false, false, true, "SharedDomainTemplate", true); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedSharedNetwork, false); + validateVspNetwork(vspNetwork, false, false, false, true, "SharedDomainTemplate", false); + } + + @Test + public void testBuildVspVm() { + VspVm vspVm = _nuageVspEntityBuilder.buildVspVm(_mockedUserVirtualMachine, _mockedNetwork); + validateVspVm(vspVm, false); + + vspVm = _nuageVspEntityBuilder.buildVspVm(_mockedDomainRouterVirtualMachine, _mockedNetwork); + validateVspVm(vspVm, true); + } + + @Test + public void testBuildVspNic() { + VspNic vspNic = _nuageVspEntityBuilder.buildVspNic("nicUuid", _mockedNicProfile); + validateVspNic(vspNic); + + vspNic = _nuageVspEntityBuilder.buildVspNic(_mockedNic); + validateVspNic(vspNic); + } + + @Test + public void testBuildVspStaticNat() { + VspStaticNat vspStaticNat = _nuageVspEntityBuilder.buildVspStaticNat(true, _mockedStaticNatIp, _mockedStaticNatVlan, _mockedNic); + validateVspStaticNat(vspStaticNat, true); + } + + @Test + public void testBuildVspAclRule() { + VspAclRule vspAclRule = _nuageVspEntityBuilder.buildVspAclRule(_mockedFirewallRule, _mockedNetwork); + validateVspAclRule(vspAclRule, true); + + vspAclRule = _nuageVspEntityBuilder.buildVspAclRule(_mockedNetworkAclItem); + validateVspAclRule(vspAclRule, false); + } + + private void validateVspDomain(VspDomain vspDomain) { + assertEquals("domainUuid", vspDomain.getUuid()); + assertEquals("domainName", vspDomain.getName()); + assertEquals("domainPath", vspDomain.getPath()); + } + + private void validateVspNetwork(VspNetwork vspNetwork, boolean isL2, boolean isL3, boolean isVpc, boolean isShared, + String domainTemplateName, boolean hasAddressRanges) { + assertEquals(NETWORK_ID, vspNetwork.getId()); + assertEquals("networkUuid", vspNetwork.getUuid()); + assertEquals("networkName", vspNetwork.getName()); + assertNotNull(vspNetwork.getVspDomain()); + validateVspDomain(vspNetwork.getVspDomain()); + assertEquals("accountName", vspNetwork.getAccountName()); + assertEquals("accountUuid", vspNetwork.getAccountUuid()); + + if (isVpc) { + assertEquals("vpcUuid", vspNetwork.getVpcUuid()); + assertEquals("vpcName", vspNetwork.getVpcName()); + } else { + assertNull(vspNetwork.getVpcUuid()); + assertNull(vspNetwork.getVpcName()); + } + + assertEquals(isL2, vspNetwork.isL2()); + assertEquals(isL3, vspNetwork.isL3()); + assertEquals(isVpc, vspNetwork.isVpc()); + assertEquals(isShared, vspNetwork.isShared()); + assertEquals(true, vspNetwork.isFirewallServiceSupported()); + assertEquals(true, vspNetwork.isEgressDefaultPolicy()); + assertEquals(domainTemplateName, vspNetwork.getDomainTemplateName()); + assertEquals("10.10.10.0/24", vspNetwork.getCidr()); + assertEquals("10.10.10.1", vspNetwork.getGateway()); + + if (hasAddressRanges) { + if (isShared) { + assertEquals("192.168.2.2", vspNetwork.getVirtualRouterIp()); + } else { + assertEquals("10.10.10.2", vspNetwork.getVirtualRouterIp()); + } + + List> ipAddressRanges; + if (isShared) { + ipAddressRanges = Lists.newArrayList(Pair.of("192.168.2.3", "192.168.2.200")); + } else { + ipAddressRanges = Lists.newArrayList(Pair.of("10.10.10.3", "10.10.10.254")); + } + assertEquals(ipAddressRanges, vspNetwork.getIpAddressRanges()); + } + } + + private void validateVspVm(VspVm vspVm, boolean isDomainRouter) { + assertEquals("virtualMachineUuid", vspVm.getUuid()); + assertEquals("virtualMachineInstanceName", vspVm.getName()); + assertEquals(VspVm.State.Running, vspVm.getState()); + assertEquals(isDomainRouter, vspVm.getDomainRouter()); + } + + private void validateVspNic(VspNic vspNic) { + assertEquals("nicUuid", vspNic.getUuid()); + assertEquals("macAddress", vspNic.getMacAddress()); + assertEquals(true, vspNic.getUseStaticIp()); + assertEquals("10.10.10.2", vspNic.getIp()); + } + + private void validateVspStaticNat(VspStaticNat vspStaticNat, Boolean forRevoke) { + assertEquals("staticNatIpUuid", vspStaticNat.getIpUuid()); + assertEquals("10.10.10.2", vspStaticNat.getIpAddress()); + assertEquals(forRevoke, vspStaticNat.getRevoke()); + assertEquals(true, vspStaticNat.getOneToOneNat()); + assertEquals("staticNatVlanUuid", vspStaticNat.getVlanUuid()); + assertEquals("10.10.10.1", vspStaticNat.getVlanGateway()); + assertEquals("255.255.255.0", vspStaticNat.getVlanNetmask()); + } + + private void validateVspAclRule(VspAclRule vspAclRule, boolean isFirewall) { + assertEquals("aclUuid", vspAclRule.getUuid()); + assertEquals("aclProtocol", vspAclRule.getProtocol()); + assertEquals(new Integer(1), vspAclRule.getStartPort()); + assertEquals(new Integer(20), vspAclRule.getEndPort()); + assertEquals(Lists.newArrayList("10.10.0.0/16"), vspAclRule.getSourceCidrList()); + assertEquals(VspAclRule.ACLState.Active, vspAclRule.getState()); + assertEquals(VspAclRule.ACLTrafficType.Egress, vspAclRule.getTrafficType()); + + if (isFirewall) { + assertEquals(VspAclRule.ACLType.Firewall, vspAclRule.getType()); + assertEquals("192.168.0.24/32", vspAclRule.getSourceIpAddress()); + assertEquals(VspAclRule.ACLAction.Deny, vspAclRule.getAction()); + } else { + assertEquals(VspAclRule.ACLType.NetworkACL, vspAclRule.getType()); + assertNull(vspAclRule.getSourceIpAddress()); + assertEquals(VspAclRule.ACLAction.Allow, vspAclRule.getAction()); + } + } + + private void setUpMockedDomain() { + when(_mockedDomain.getUuid()).thenReturn("domainUuid"); + when(_mockedDomain.getName()).thenReturn("domainName"); + when(_mockedDomain.getPath()).thenReturn("domainPath"); + } + + private void setUpMockedAccount() { + when(_mockedAccount.getUuid()).thenReturn("accountUuid"); + when(_mockedAccount.getAccountName()).thenReturn("accountName"); + } + + private void setUpMockedNetworkOffering(NetworkOfferingVO networkOfferingToMock, Network.GuestType guestType) { + when(networkOfferingToMock.getEgressDefaultPolicy()).thenReturn(true); + when(networkOfferingToMock.getGuestType()).thenReturn(guestType); + } + + private void setUpMockedVlan() { + when(_mockedVlan.getIpRange()).thenReturn("192.168.2.2-192.168.2.200"); + } + + private void setUpMockedVpc() { + when(_mockedVpc.getUuid()).thenReturn("vpcUuid"); + when(_mockedVpc.getName()).thenReturn("vpcName"); + } + + private void setUpMockedNetwork(NetworkVO networkToMock, long networkOfferingId, Long vpcId) { + when(networkToMock.getId()).thenReturn(NETWORK_ID); + when(networkToMock.getUuid()).thenReturn("networkUuid"); + when(networkToMock.getName()).thenReturn("networkName"); + when(networkToMock.getCidr()).thenReturn("10.10.10.0/24"); + when(networkToMock.getGateway()).thenReturn("10.10.10.1"); + when(networkToMock.getDomainId()).thenReturn(DOMAIN_ID); + when(networkToMock.getAccountId()).thenReturn(ACCOUNT_ID); + when(networkToMock.getNetworkOfferingId()).thenReturn(networkOfferingId); + when(networkToMock.getVpcId()).thenReturn(vpcId != null ? vpcId : null); + } + + private void setUpMockedVirtualMachine(VirtualMachine virtualMachineToMock, boolean isDomainRouter) { + when(virtualMachineToMock.getUuid()).thenReturn("virtualMachineUuid"); + when(virtualMachineToMock.getInstanceName()).thenReturn("virtualMachineInstanceName"); + when(virtualMachineToMock.getState()).thenReturn(VirtualMachine.State.Running); + when(virtualMachineToMock.getType()).thenReturn(isDomainRouter ? VirtualMachine.Type.DomainRouter : VirtualMachine.Type.User); + } + + private void setUpMockedNicProfile() { + when(_mockedNicProfile.getMacAddress()).thenReturn("macAddress"); + when(_mockedNicProfile.getIPv4Address()).thenReturn("10.10.10.2"); + } + + private void setUpMockedNic() { + when(_mockedNic.getUuid()).thenReturn("nicUuid"); + when(_mockedNic.getMacAddress()).thenReturn("macAddress"); + when(_mockedNic.getIPv4Address()).thenReturn("10.10.10.2"); + } + + private void setUpMockedStaticNatIp() { + when(_mockedStaticNatIp.getUuid()).thenReturn("staticNatIpUuid"); + when(_mockedStaticNatIp.getAddress()).thenReturn(new Ip("10.10.10.2")); + when(_mockedStaticNatIp.isOneToOneNat()).thenReturn(true); + when(_mockedStaticNatIp.getVmIp()).thenReturn("192.168.0.24"); + } + + private void setUpMockedStaticNatVlan() { + when(_mockedStaticNatVlan.getUuid()).thenReturn("staticNatVlanUuid"); + when(_mockedStaticNatVlan.getVlanGateway()).thenReturn("10.10.10.1"); + when(_mockedStaticNatVlan.getVlanNetmask()).thenReturn("255.255.255.0"); + } + + private void setUpMockedFirewallRule() { + when(_mockedFirewallRule.getUuid()).thenReturn("aclUuid"); + when(_mockedFirewallRule.getProtocol()).thenReturn("aclProtocol"); + when(_mockedFirewallRule.getSourcePortStart()).thenReturn(1); + when(_mockedFirewallRule.getSourcePortEnd()).thenReturn(20); + when(_mockedFirewallRule.getSourceCidrList()).thenReturn(Lists.newArrayList("10.10.0.0/16")); + when(_mockedFirewallRule.getState()).thenReturn(FirewallRule.State.Active); + when(_mockedFirewallRule.getTrafficType()).thenReturn(FirewallRule.TrafficType.Egress); + when(_mockedFirewallRule.getSourceIpAddressId()).thenReturn(SOURCE_IP_ADDRESS_ID); + } + + private void setUpMockedNetworkAclItem() { + when(_mockedNetworkAclItem.getUuid()).thenReturn("aclUuid"); + when(_mockedNetworkAclItem.getProtocol()).thenReturn("aclProtocol"); + when(_mockedNetworkAclItem.getSourcePortStart()).thenReturn(1); + when(_mockedNetworkAclItem.getSourcePortEnd()).thenReturn(20); + when(_mockedNetworkAclItem.getSourceCidrList()).thenReturn(Lists.newArrayList("10.10.0.0/16")); + when(_mockedNetworkAclItem.getNumber()).thenReturn(1337); + when(_mockedNetworkAclItem.getState()).thenReturn(NetworkACLItem.State.Active); + when(_mockedNetworkAclItem.getTrafficType()).thenReturn(NetworkACLItem.TrafficType.Egress); + when(_mockedNetworkAclItem.getAction()).thenReturn(NetworkACLItem.Action.Allow); + } + + private void setUpMockedDaoCalls() { + when(_domainDao.findById(DOMAIN_ID)).thenReturn(_mockedDomain); + when(_accountDao.findById(ACCOUNT_ID)).thenReturn(_mockedAccount); + when(_networkOfferingDao.findById(NETWORK_OFFERING_ID)).thenReturn(_mockedNetworkOffering); + when(_networkOfferingDao.findById(SHARED_NETWORK_OFFERING_ID)).thenReturn(_mockedSharedNetworkOffering); + when(_networkOfferingDao.findById(L2_NETWORK_OFFERING_ID)).thenReturn(_mockedL2NetworkOffering); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(NETWORK_OFFERING_ID, Network.Service.SourceNat)).thenReturn(true); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(NETWORK_OFFERING_ID, Network.Service.StaticNat)).thenReturn(true); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(SHARED_NETWORK_OFFERING_ID, Network.Service.SourceNat)).thenReturn(true); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(SHARED_NETWORK_OFFERING_ID, Network.Service.StaticNat)).thenReturn(true); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(L2_NETWORK_OFFERING_ID, Network.Service.SourceNat)).thenReturn(false); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(L2_NETWORK_OFFERING_ID, Network.Service.StaticNat)).thenReturn(false); + when(_networkModel.areServicesSupportedByNetworkOffering(NETWORK_OFFERING_ID, Network.Service.Firewall)).thenReturn(true); + when(_networkModel.areServicesSupportedByNetworkOffering(SHARED_NETWORK_OFFERING_ID, Network.Service.Firewall)).thenReturn(true); + when(_networkModel.areServicesSupportedByNetworkOffering(L2_NETWORK_OFFERING_ID, Network.Service.Firewall)).thenReturn(true); + when(_vlanDao.listVlansByNetworkId(NETWORK_ID)).thenReturn(Lists.newArrayList(_mockedVlan)); + when(_vpcDao.findById(VPC_ID)).thenReturn(_mockedVpc); + when(_ipAddressDao.findById(SOURCE_IP_ADDRESS_ID)).thenReturn(_mockedStaticNatIp); + } +} diff --git a/plugins/pom.xml b/plugins/pom.xml index 25f06876fa..d05e630411 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -75,6 +75,7 @@ network-elements/palo-alto network-elements/netscaler network-elements/nicira-nvp + network-elements/nuage-vsp network-elements/bigswitch network-elements/brocade-vcs network-elements/midonet @@ -170,17 +171,6 @@ network-elements/juniper-srx - - nuagevsp - - - noredist - - - - network-elements/nuage-vsp - - vmware diff --git a/ui/scripts/system.js b/ui/scripts/system.js index d54428322b..642370feb2 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -7109,7 +7109,7 @@ }, apiversion: { label: 'label.api.version', - defaultValue: 'v1_0', + defaultValue: 'v3_2', validation: { required: true }, @@ -13185,7 +13185,7 @@ }, apiversion: { label: 'label.api.version', - defaultValue: 'v1_0' + defaultValue: 'v3_2' }, retrycount: { label: 'label.numretries', From 4b6179940d8f29873a0cc0b4b0bc5b2f8e248ca5 Mon Sep 17 00:00:00 2001 From: Nick Livens Date: Mon, 2 May 2016 10:16:06 +0200 Subject: [PATCH 186/203] CLOUDSTACK-9294 : Make sure to remove VR from VSD when removing the VPC --- .../src/com/cloud/vm/dao/DomainRouterDao.java | 2 ++ .../com/cloud/vm/dao/DomainRouterDaoImpl.java | 8 ++++++++ .../api/element/ShutDownVpcVspCommand.java | 13 +++++++++++- .../network/element/NuageVspElement.java | 20 ++++++++++++++++++- .../network/resource/NuageVspResource.java | 2 +- .../network/element/NuageVspElementTest.java | 11 +++++++++- .../resource/NuageVspResourceTest.java | 4 ++-- 7 files changed, 54 insertions(+), 6 deletions(-) diff --git a/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java b/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java index d555e7930d..ef8829ef01 100644 --- a/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java +++ b/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java @@ -156,4 +156,6 @@ public interface DomainRouterDao extends GenericDao { List listRunningByDataCenter(long dcId); List listStopped(long networkId); + + List listIncludingRemovedByVpcId(long vpcId); } diff --git a/engine/schema/src/com/cloud/vm/dao/DomainRouterDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/DomainRouterDaoImpl.java index 271644f836..85a8a936b5 100644 --- a/engine/schema/src/com/cloud/vm/dao/DomainRouterDaoImpl.java +++ b/engine/schema/src/com/cloud/vm/dao/DomainRouterDaoImpl.java @@ -432,4 +432,12 @@ public List listStopped(final long networkId) { sc.setParameters("states", State.Stopped); return listBy(sc); } + + @Override + public List listIncludingRemovedByVpcId(long vpcId) { + SearchCriteria sc = VpcSearch.create(); + sc.setParameters("vpcId", vpcId); + sc.setParameters("role", Role.VIRTUAL_ROUTER); + return listIncludingRemovedBy(sc); + } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java index d91734bcf0..6ad4ec6c40 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java @@ -21,17 +21,21 @@ import com.cloud.agent.api.Command; +import java.util.List; + public class ShutDownVpcVspCommand extends Command { private final String _domainUuid; private final String _vpcUuid; private final String _domainTemplateName; + private final List _domainRouterUuids; - public ShutDownVpcVspCommand(String domainUuid, String vpcUuid, String domainTemplateName) { + public ShutDownVpcVspCommand(String domainUuid, String vpcUuid, String domainTemplateName, List domainRouterUuids) { super(); this._domainUuid = domainUuid; this._vpcUuid = vpcUuid; this._domainTemplateName = domainTemplateName; + this._domainRouterUuids = domainRouterUuids; } public String getDomainUuid() { @@ -46,6 +50,10 @@ public String getDomainTemplateName() { return _domainTemplateName; } + public List getDomainRouterUuids() { + return _domainRouterUuids; + } + @Override public boolean executeInSequence() { return false; @@ -59,6 +67,8 @@ public boolean equals(Object o) { ShutDownVpcVspCommand that = (ShutDownVpcVspCommand) o; + if (_domainRouterUuids != null ? !_domainRouterUuids.equals(that._domainRouterUuids) : that._domainRouterUuids != null) + return false; if (_domainTemplateName != null ? !_domainTemplateName.equals(that._domainTemplateName) : that._domainTemplateName != null) return false; if (_domainUuid != null ? !_domainUuid.equals(that._domainUuid) : that._domainUuid != null) return false; @@ -73,6 +83,7 @@ public int hashCode() { result = 31 * result + (_domainUuid != null ? _domainUuid.hashCode() : 0); result = 31 * result + (_vpcUuid != null ? _vpcUuid.hashCode() : 0); result = 31 * result + (_domainTemplateName != null ? _domainTemplateName.hashCode() : 0); + result = 31 * result + (_domainRouterUuids != null ? _domainRouterUuids.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java index 531c8284ec..1f36ae0c3d 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java @@ -82,10 +82,12 @@ import com.cloud.resource.UnableDeleteHostException; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.DomainRouterVO; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; import com.google.common.base.Function; import com.google.common.collect.Lists; @@ -98,6 +100,7 @@ import org.apache.cloudstack.network.ExternalNetworkDeviceManager; import org.apache.cloudstack.resourcedetail.VpcDetailVO; import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import javax.annotation.Nullable; @@ -166,6 +169,8 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider NuageVspEntityBuilder _nuageVspEntityBuilder; @Inject VpcDetailsDao _vpcDetailsDao; + @Inject + DomainRouterDao _routerDao; @Override public boolean applyIps(Network network, List ipAddress, Set service) throws ResourceUnavailableException { @@ -552,6 +557,19 @@ public boolean implementVpc(Vpc vpc, DeployDestination dest, ReservationContext @Override public boolean shutdownVpc(Vpc vpc, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { if (vpc.getState().equals(Vpc.State.Inactive)) { + List routers = _routerDao.listByVpcId(vpc.getId()); + if (CollectionUtils.isEmpty(routers)) { + routers = _routerDao.listIncludingRemovedByVpcId(vpc.getId()); + } + + List domainRouterUuids = Lists.transform(routers, new Function() { + @Nullable + @Override + public String apply(@Nullable DomainRouterVO input) { + return input != null ? input.getUuid() : null; + } + }); + Domain vpcDomain = _domainDao.findById(vpc.getDomainId()); HostVO nuageVspHost = getNuageVspHost(getPhysicalNetworkId(vpc.getZoneId())); @@ -563,7 +581,7 @@ public boolean shutdownVpc(Vpc vpc, ReservationContext context) throws Concurren preConfiguredDomainTemplateName = _configDao.getValue(NuageVspManager.NuageVspVpcDomainTemplateName.key()); } - ShutDownVpcVspCommand cmd = new ShutDownVpcVspCommand(vpcDomain.getUuid(), vpc.getUuid(), preConfiguredDomainTemplateName); + ShutDownVpcVspCommand cmd = new ShutDownVpcVspCommand(vpcDomain.getUuid(), vpc.getUuid(), preConfiguredDomainTemplateName, domainRouterUuids); Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("ShutDownVpcVspCommand for VPC " + vpc.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java index 677fa9fce3..bdcb481a01 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java @@ -423,7 +423,7 @@ private Answer executeRequest(ApplyAclRuleVspCommand cmd) { private Answer executeRequest(ShutDownVpcVspCommand cmd) { try { isNuageVspElementLoaded(); - _nuageVspElementClient.shutdownVpc(cmd.getDomainUuid(), cmd.getVpcUuid(), cmd.getDomainTemplateName()); + _nuageVspElementClient.shutdownVpc(cmd.getDomainUuid(), cmd.getVpcUuid(), cmd.getDomainTemplateName(), cmd.getDomainRouterUuids()); return new Answer(cmd, true, "Shutdown VPC " + cmd.getVpcUuid() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java index e9f92b6976..85cbb361c9 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java @@ -60,7 +60,9 @@ import com.cloud.resource.ResourceManager; import com.cloud.user.Account; import com.cloud.util.NuageVspEntityBuilder; +import com.cloud.vm.DomainRouterVO; import com.cloud.vm.ReservationContext; +import com.cloud.vm.dao.DomainRouterDao; import com.google.common.collect.Lists; import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao; import org.junit.Before; @@ -98,6 +100,7 @@ public class NuageVspElementTest extends NuageTest { private PhysicalNetworkDao _physicalNetworkDao = mock(PhysicalNetworkDao.class); private NuageVspEntityBuilder _nuageVspEntityBuilder = mock(NuageVspEntityBuilder.class); private VpcDetailsDao _vpcDetailsDao = mock(VpcDetailsDao.class); + private DomainRouterDao _domainRouterDao = mock(DomainRouterDao.class); @Before public void setUp() throws Exception { @@ -119,6 +122,7 @@ public void setUp() throws Exception { _nuageVspElement._physicalNetworkDao = _physicalNetworkDao; _nuageVspElement._nuageVspEntityBuilder = _nuageVspEntityBuilder; _nuageVspElement._vpcDetailsDao = _vpcDetailsDao; + _nuageVspElement._routerDao = _domainRouterDao; _nuageVspElement.configure("NuageVspTestElement", Collections.emptyMap()); } @@ -314,6 +318,7 @@ public void testShutdownVpc() throws Exception { when(vpc.getState()).thenReturn(Vpc.State.Inactive); when(vpc.getDomainId()).thenReturn(NETWORK_ID); when(vpc.getZoneId()).thenReturn(NETWORK_ID); + when(vpc.getId()).thenReturn(NETWORK_ID); final DomainVO dom = mock(DomainVO.class); when(dom.getName()).thenReturn("domain"); @@ -333,9 +338,13 @@ public void testShutdownVpc() throws Exception { when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Lists.newArrayList(nuageVspDevice)); when(_hostDao.findById(NETWORK_ID)).thenReturn(host); + DomainRouterVO domainRouter = mock(DomainRouterVO.class); + when(domainRouter.getUuid()).thenReturn("aaaaaa"); + when(_domainRouterDao.listByVpcId(NETWORK_ID)).thenReturn(Lists.newArrayList(domainRouter)); + final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java index 9c51864e49..66d26323aa 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java @@ -223,8 +223,8 @@ public void testApplyAclRuleVspCommand() throws Exception { public void testShutDownVpcVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - ShutDownVpcVspCommand cmd = new ShutDownVpcVspCommand("domainUuid", "vpcUuid", "domainTemplateName"); - doAnswer(genericAnswer).when(_mockNuageVspElementClient).shutdownVpc("domainUuid", "vpcUuid", "domainTemplateName"); + ShutDownVpcVspCommand cmd = new ShutDownVpcVspCommand("domainUuid", "vpcUuid", "domainTemplateName", Lists.newArrayList()); + doAnswer(genericAnswer).when(_mockNuageVspElementClient).shutdownVpc("domainUuid", "vpcUuid", "domainTemplateName", Lists.newArrayList()); Answer shutVpcAns = _resource.executeRequest(cmd); assertTrue(shutVpcAns.getResult()); } From d862a09771dca8d71da1727fdd09234d602d573b Mon Sep 17 00:00:00 2001 From: Nick Livens Date: Mon, 2 May 2016 10:16:21 +0200 Subject: [PATCH 187/203] Nuage VSP : Fix for NPE while cleaning up account when there are still resources belonging to that account --- .../nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java index 135a552e2d..8757ad0212 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java @@ -109,7 +109,9 @@ public VspNetwork buildVspNetwork(Network network, boolean fillAddressRange) { vspNetworkBuilder.domain(vspDomain); AccountVO account = _accountDao.findById(network.getAccountId()); - vspNetworkBuilder.accountUuid(account.getUuid()).accountName(account.getAccountName()); + if (account != null) { + vspNetworkBuilder.accountUuid(account.getUuid()).accountName(account.getAccountName()); + } NetworkOfferingVO networkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId()); vspNetworkBuilder.egressDefaultPolicy(networkOffering.getEgressDefaultPolicy()); From 2ca0d9b0e105e9b6d5462319e0ada716d3b66e55 Mon Sep 17 00:00:00 2001 From: Prashanth Manthena Date: Mon, 2 May 2016 10:16:34 +0200 Subject: [PATCH 188/203] Nuage VSP : Extending Marvin test coverage --- .../plugins/nuagevsp/nuageTestCase.py | 8 ++++-- .../nuagevsp/test_nuage_vpc_network.py | 28 +++++++++++++++---- tools/marvin/marvin/deployDataCenter.py | 17 ++++++++++- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/test/integration/plugins/nuagevsp/nuageTestCase.py b/test/integration/plugins/nuagevsp/nuageTestCase.py index 9d0d07743a..11032a62f1 100644 --- a/test/integration/plugins/nuagevsp/nuageTestCase.py +++ b/test/integration/plugins/nuagevsp/nuageTestCase.py @@ -50,7 +50,7 @@ class nuageTestCase(cloudstackTestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls, zone=None): cls.debug("setUpClass nuageTestCase") # We want to fail quicker, if it's a failure @@ -60,9 +60,11 @@ def setUpClass(cls): cls.api_client = test_client.getApiClient() cls.db_client = test_client.getDbConnection() cls.test_data = test_client.getParsedTestDataConfig() - # Get Zone, Domain and templates - cls.zone = get_zone(cls.api_client) + cls.zone = get_zone(cls.api_client, + zone_name=zone.name if zone else None, + zone_id=zone.id if zone else None + ) cls.domain = get_domain(cls.api_client) cls.template = get_template(cls.api_client, cls.zone.id, diff --git a/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py b/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py index a8361d0e0b..15134b628b 100644 --- a/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py +++ b/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py @@ -15,22 +15,22 @@ # specific language governing permissions and limitations # under the License. -""" Tests for basic VPC Network functionality with Nuage VSP SDN plugin +""" Component tests for basic VPC Network functionality with Nuage VSP SDN plugin """ # Import Local Modules from nuageTestCase import nuageTestCase -from marvin.lib.base import Account +from marvin.lib.base import Account, Zone # Import System Modules from nose.plugins.attrib import attr -class TestVpcNetworkNuage(nuageTestCase): +class TestNuageVpcNetwork(nuageTestCase): """ Test basic VPC Network functionality with Nuage VSP SDN plugin """ @classmethod - def setUpClass(cls): - super(TestVpcNetworkNuage, cls).setUpClass() + def setUpClass(cls, zone=None): + super(TestNuageVpcNetwork, cls).setUpClass(zone=zone) return def setUp(self): @@ -45,7 +45,7 @@ def setUp(self): @attr(tags=["advanced", "nuagevsp"], required_hardware="false") def test_nuage_vpc_network(self): - """ Test Basic VPC Network Functionality with Nuage VSP SDN plugin + """ Test basic VPC Network functionality with Nuage VSP SDN plugin """ # 1. Create Nuage VSP VPC offering, check if it is successfully created and enabled. @@ -97,3 +97,19 @@ def test_nuage_vpc_network(self): # VSD verification for ACL item self.verify_vsp_firewall_rule(acl_item) + + @attr(tags=["advanced", "nuagevsp", "multizone"], required_hardware="false") + def test_nuage_vpc_network_multizone(self): + """ Test basic VPC Network functionality with Nuage VSP SDN plugin on multiple zones + """ + + # Repeat the tests in the above testcase "test_nuage_vpc_network" on multiple zones + + self.debug("Testing basic VPC Network functionality with Nuage VSP SDN plugin on multiple zones...") + zones = Zone.list(self.api_client) + if len(zones) == 1: + self.skipTest("There is only one Zone configured: skipping test") + for zone in zones: + self.debug("Zone - %s" % zone.name) + self.setUpClass(zone=zone) + self.test_nuage_vpc_network() diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py index 889aab510b..24133289ed 100644 --- a/tools/marvin/marvin/deployDataCenter.py +++ b/tools/marvin/marvin/deployDataCenter.py @@ -561,7 +561,7 @@ def configureProviders(self, phynetwrk, providers): netprov.physicalnetworkid = phynetwrk.id result = self.__apiClient.addNetworkServiceProvider(netprov) self.enableProvider(result.id) - elif provider.name in ['Netscaler', 'JuniperSRX', 'F5BigIp', 'NiciraNvp']: + elif provider.name in ['Netscaler', 'JuniperSRX', 'F5BigIp', 'NiciraNvp', 'NuageVsp']: netprov = addNetworkServiceProvider.\ addNetworkServiceProviderCmd() netprov.name = provider.name @@ -631,6 +631,21 @@ def configureProviders(self, phynetwrk, providers): self.__tcRunLogger.\ debug("==== AddNiciraNvp Successful =====") self.__addToCleanUp("NiciraNvp", ret.id) + elif provider.name == 'NuageVsp': + dev = addNuageVspDevice.addNuageVspDeviceCmd() + dev.hostname = device.hostname + dev.port = device.port + dev.username = device.username + dev.password = device.password + dev.retrycount = device.retrycount + dev.retryinterval = device.retryinterval + dev.physicalnetworkid = phynetwrk.id + ret = self.__apiClient.addNuageVspDevice(dev) + if ret.id: + self.__tcRunLogger.\ + debug("==== addNuageVspDevice " + "Successful=====") + self.__addToCleanUp("addNuageVspDevice", ret.id) else: raise InvalidParameterException( "Device %s doesn't match " From d8767ec13e84b7b95c1c94c0669fc82cf48dfd08 Mon Sep 17 00:00:00 2001 From: Milamber Date: Fri, 20 May 2016 09:20:12 +0100 Subject: [PATCH 189/203] Add Java Default Certificat Authorities into the keystore if using a custom cert SSL Related to CLOUDSTACK-1475 Fix some english message --- systemvm/scripts/config_ssl.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/systemvm/scripts/config_ssl.sh b/systemvm/scripts/config_ssl.sh index 9dfb927f16..86358871c9 100755 --- a/systemvm/scripts/config_ssl.sh +++ b/systemvm/scripts/config_ssl.sh @@ -16,9 +16,6 @@ # specific language governing permissions and limitations # under the License. - - - help() { printf " -c use customized key/cert\n" printf " -k path of private key\n" @@ -123,6 +120,8 @@ customCACert= publicIp= hostName= keyStore=$(dirname $0)/certs/realhostip.keystore +defaultJavaKeyStoreFile=/etc/ssl/certs/java/cacerts +defaultJavaKeyStorePass="changeit" aliasName="CPVMCertificate" storepass="vmops.com" while getopts 'i:h:k:p:t:u:c' OPTION @@ -167,13 +166,13 @@ then fi if [ ! -f "$customPrivKey" ] then - printf "priviate key file is not exist\n" + printf "private key file does not exist\n" exit 2 fi if [ ! -f "$customPrivCert" ] then - printf "public certificate is not exist\n" + printf "public certificate does not exist\n" exit 3 fi @@ -181,7 +180,7 @@ then then if [ ! -f "$customCertChain" ] then - printf "certificate chain is not exist\n" + printf "certificate chain does not exist\n" exit 4 fi fi @@ -204,6 +203,7 @@ if [ -f "$customCACert" ] then keytool -delete -alias $aliasName -keystore $keyStore -storepass $storepass -noprompt keytool -import -alias $aliasName -keystore $keyStore -storepass $storepass -noprompt -file $customCACert + keytool -importkeystore -srckeystore $defaultJavaKeyStoreFile -destkeystore $keyStore -srcstorepass $defaultJavaKeyStorePass -deststorepass $storepass -noprompt fi if [ -d /etc/apache2 ] From e363fd27021c77e515b0fe3bf25585d3c9818dda Mon Sep 17 00:00:00 2001 From: sanjeev Date: Wed, 25 May 2016 14:57:29 +0530 Subject: [PATCH 190/203] CLOUDSTACK-9388: Remove string conversion in assertion statement --- test/integration/component/test_blocker_bugs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/component/test_blocker_bugs.py b/test/integration/component/test_blocker_bugs.py index c229d38f45..c1aa1f034e 100644 --- a/test/integration/component/test_blocker_bugs.py +++ b/test/integration/component/test_blocker_bugs.py @@ -409,7 +409,7 @@ def test_01_firewall_rules_port_fw(self): ) self.assertEqual( firewall_response[0].startport, - str(self.services["firewall_rule"]["startport"]), + self.services["firewall_rule"]["startport"], "Firewall rule is not with specific port" ) From 26227768a10c4a7ced0fc08d0ce567b6ffcc31ea Mon Sep 17 00:00:00 2001 From: Syed Date: Tue, 23 Feb 2016 10:14:33 -0500 Subject: [PATCH 191/203] [CLOUDSTACK-9296] Start ipsec for client VPN --- .../debian/config/opt/cloud/bin/configure.py | 1 + .../integration/component/test_vpn_service.py | 212 ++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 test/integration/component/test_vpn_service.py diff --git a/systemvm/patches/debian/config/opt/cloud/bin/configure.py b/systemvm/patches/debian/config/opt/cloud/bin/configure.py index b5f65e733c..595b071773 100755 --- a/systemvm/patches/debian/config/opt/cloud/bin/configure.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/configure.py @@ -612,6 +612,7 @@ def process(self): #Enable remote access vpn if vpnconfig['create']: logging.debug("Enabling remote access vpn on "+ public_ip) + CsHelper.start_if_stopped("ipsec") self.configure_l2tpIpsec(public_ip, self.dbag[public_ip]) logging.debug("Remote accessvpn data bag %s", self.dbag) self.remoteaccessvpn_iptables(public_ip, self.dbag[public_ip]) diff --git a/test/integration/component/test_vpn_service.py b/test/integration/component/test_vpn_service.py new file mode 100644 index 0000000000..8d27624b76 --- /dev/null +++ b/test/integration/component/test_vpn_service.py @@ -0,0 +1,212 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" P1 tests for VPN service +""" +# Import Local Modules +from nose.plugins.attrib import attr +from marvin.cloudstackException import CloudstackAPIException +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.lib.base import ( + Account, + ServiceOffering, + VirtualMachine, + PublicIPAddress, + Vpn, + VpnUser, + Configurations, + NATRule + ) +from marvin.lib.common import (get_domain, + get_zone, + get_template + ) +from marvin.lib.utils import cleanup_resources + + +class Services: + """Test VPN Service + """ + + def __init__(self): + self.services = { + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended for unique + # username + "password": "password", + }, + "service_offering": { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 100, # in MHz + "memory": 128, # In MBs + }, + "disk_offering": { + "displaytext": "Small Disk Offering", + "name": "Small Disk Offering", + "disksize": 1 + }, + "virtual_machine": { + "displayname": "TestVM", + "username": "root", + "password": "password", + "ssh_port": 22, + "hypervisor": 'KVM', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "vpn_user": { + "username": "test", + "password": "test", + }, + "natrule": { + "privateport": 1701, + "publicport": 1701, + "protocol": "UDP" + }, + "ostype": 'CentOS 5.5 (64-bit)', + "sleep": 60, + "timeout": 10, + # Networking mode: Advanced, Basic + } + + +class TestVPNService(cloudstackTestCase): + @classmethod + def setUpClass(cls): + cls.testClient = super(TestVPNService, cls).getClsTestClient() + cls.api_client = cls.testClient.getApiClient() + + cls.services = Services().services + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client) + cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) + + cls.services["mode"] = cls.zone.networktype + + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) + + cls._cleanup = [cls.service_offering, ] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + try: + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.account = Account.create( + self.apiclient, + self.services["account"], + domainid=self.domain.id + ) + self.cleanup = [ + self.account, + ] + self.virtual_machine = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + templateid=self.template.id, + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id + ) + self.public_ip = PublicIPAddress.create( + self.apiclient, + accountid=self.virtual_machine.account, + zoneid=self.virtual_machine.zoneid, + domainid=self.virtual_machine.domainid, + services=self.services["virtual_machine"] + ) + return + except CloudstackAPIException as e: + self.tearDown() + raise e + + def tearDown(self): + try: + # Clean up, terminate the created instance, volumes and snapshots + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def create_VPN(self, public_ip): + """Creates VPN for the network""" + + self.debug("Creating VPN with public IP: %s" % public_ip.ipaddress.id) + try: + # Assign VPN to Public IP + vpn = Vpn.create(self.apiclient, + self.public_ip.ipaddress.id, + account=self.account.name, + domainid=self.account.domainid) + + self.debug("Verifying the remote VPN access") + vpns = Vpn.list(self.apiclient, + publicipid=public_ip.ipaddress.id, + listall=True) + self.assertEqual( + isinstance(vpns, list), + True, + "List VPNs shall return a valid response" + ) + return vpn + except Exception as e: + self.fail("Failed to create remote VPN access: %s" % e) + + + @attr(tags=["advanced", "advancedns"]) + def test_01_VPN_service(self): + """Tests if VPN service is running""" + + # Validate if IPSEC is running on the public + # IP by using ike-scan + + self.create_VPN(self.public_ip) + + cmd = ['ike-scan', self.public_ip, '-s', '4534'] # Random port + + stdout = subprocess.check_output(cmd) + + if "1 returned handshake" not in stdout: + self.fail("Unable to connect to VPN service") + + return From a59ee03fd79806dcb3a8842c318e2cd06895183f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Aur=C3=A8le=20Brothier?= Date: Fri, 27 May 2016 08:16:05 +0200 Subject: [PATCH 192/203] Fix URL length to 2048 for all url fields in VO --- .../engine/datacenter/entity/api/db/EngineHostVO.java | 2 +- engine/schema/src/com/cloud/host/HostVO.java | 2 +- engine/schema/src/com/cloud/storage/UploadVO.java | 2 +- engine/schema/src/com/cloud/storage/VMTemplateHostVO.java | 2 +- engine/schema/src/com/cloud/storage/VMTemplateVO.java | 2 +- engine/schema/src/com/cloud/storage/VolumeHostVO.java | 2 +- .../apache/cloudstack/storage/datastore/db/ImageStoreVO.java | 2 +- .../cloudstack/storage/datastore/db/TemplateDataStoreVO.java | 4 ++-- .../cloudstack/storage/datastore/db/VolumeDataStoreVO.java | 4 ++-- .../org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java | 2 +- server/src/com/cloud/api/query/vo/ImageStoreJoinVO.java | 2 +- setup/db/db/schema-471to480.sql | 2 ++ 12 files changed, 15 insertions(+), 13 deletions(-) diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineHostVO.java b/engine/orchestration/src/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineHostVO.java index efa34dfec9..eece93a867 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineHostVO.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineHostVO.java @@ -329,7 +329,7 @@ public void setHostTags(List hostTags) { @Column(name = "cpus") private Integer cpus; - @Column(name = "url") + @Column(name = "url", length = 2048) private String storageUrl; @Column(name = "speed") diff --git a/engine/schema/src/com/cloud/host/HostVO.java b/engine/schema/src/com/cloud/host/HostVO.java index c5938d6522..4d1896ce79 100644 --- a/engine/schema/src/com/cloud/host/HostVO.java +++ b/engine/schema/src/com/cloud/host/HostVO.java @@ -337,7 +337,7 @@ public void setGpuGroups(HashMap> groupDe @Column(name = "cpus") private Integer cpus; - @Column(name = "url") + @Column(name = "url", length = 2048) private String storageUrl; @Column(name = "speed") diff --git a/engine/schema/src/com/cloud/storage/UploadVO.java b/engine/schema/src/com/cloud/storage/UploadVO.java index c49b28b679..dda5c38b59 100644 --- a/engine/schema/src/com/cloud/storage/UploadVO.java +++ b/engine/schema/src/com/cloud/storage/UploadVO.java @@ -77,7 +77,7 @@ public class UploadVO implements Upload { @Column(name = "job_id") private String jobId; - @Column(name = "url") + @Column(name = "url", length = 2048) private String uploadUrl; @Column(name = "install_path") diff --git a/engine/schema/src/com/cloud/storage/VMTemplateHostVO.java b/engine/schema/src/com/cloud/storage/VMTemplateHostVO.java index 4ba5088583..fc4d9c1599 100644 --- a/engine/schema/src/com/cloud/storage/VMTemplateHostVO.java +++ b/engine/schema/src/com/cloud/storage/VMTemplateHostVO.java @@ -84,7 +84,7 @@ public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc, DataObj @Column(name = "install_path") private String installPath; - @Column(name = "url") + @Column(name = "url", length = 2048) private String downloadUrl; @Column(name = "is_copy") diff --git a/engine/schema/src/com/cloud/storage/VMTemplateVO.java b/engine/schema/src/com/cloud/storage/VMTemplateVO.java index dd2b35aef9..d28c23b1a5 100644 --- a/engine/schema/src/com/cloud/storage/VMTemplateVO.java +++ b/engine/schema/src/com/cloud/storage/VMTemplateVO.java @@ -63,7 +63,7 @@ public class VMTemplateVO implements VirtualMachineTemplate { @Column(name = "type") private Storage.TemplateType templateType; - @Column(name = "url") + @Column(name = "url", length = 2048) private String url = null; @Column(name = "hvm") diff --git a/engine/schema/src/com/cloud/storage/VolumeHostVO.java b/engine/schema/src/com/cloud/storage/VolumeHostVO.java index 56a9a9285c..d086f2dd0a 100644 --- a/engine/schema/src/com/cloud/storage/VolumeHostVO.java +++ b/engine/schema/src/com/cloud/storage/VolumeHostVO.java @@ -93,7 +93,7 @@ public class VolumeHostVO implements InternalIdentity, DataObjectInStore { @Column(name = "install_path") private String installPath; - @Column(name = "url") + @Column(name = "url", length = 2048) private String downloadUrl; @Column(name = "format") diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreVO.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreVO.java index 2d1a3eddd6..2c706774a4 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreVO.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreVO.java @@ -51,7 +51,7 @@ public class ImageStoreVO implements ImageStore { @Column(name = "protocol", nullable = false) private String protocol; - @Column(name = "url", nullable = false) + @Column(name = "url", nullable = false, length = 2048) private String url; @Column(name = "image_provider_name", nullable = false) diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java index bb05300e21..024f05604c 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java @@ -95,10 +95,10 @@ public class TemplateDataStoreVO implements StateObject Date: Fri, 27 May 2016 08:26:09 +0200 Subject: [PATCH 193/203] not needed on host table --- .../engine/datacenter/entity/api/db/EngineHostVO.java | 2 +- engine/schema/src/com/cloud/host/HostVO.java | 2 +- setup/db/db/schema-471to480.sql | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineHostVO.java b/engine/orchestration/src/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineHostVO.java index eece93a867..efa34dfec9 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineHostVO.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineHostVO.java @@ -329,7 +329,7 @@ public void setHostTags(List hostTags) { @Column(name = "cpus") private Integer cpus; - @Column(name = "url", length = 2048) + @Column(name = "url") private String storageUrl; @Column(name = "speed") diff --git a/engine/schema/src/com/cloud/host/HostVO.java b/engine/schema/src/com/cloud/host/HostVO.java index 4d1896ce79..c5938d6522 100644 --- a/engine/schema/src/com/cloud/host/HostVO.java +++ b/engine/schema/src/com/cloud/host/HostVO.java @@ -337,7 +337,7 @@ public void setGpuGroups(HashMap> groupDe @Column(name = "cpus") private Integer cpus; - @Column(name = "url", length = 2048) + @Column(name = "url") private String storageUrl; @Column(name = "speed") diff --git a/setup/db/db/schema-471to480.sql b/setup/db/db/schema-471to480.sql index 4eb924d988..5db5ac642a 100644 --- a/setup/db/db/schema-471to480.sql +++ b/setup/db/db/schema-471to480.sql @@ -28,4 +28,3 @@ ALTER TABLE `cloud`.`template_store_ref` MODIFY COLUMN `url` varchar(2048); ALTER TABLE `cloud`.`volume_store_ref` MODIFY COLUMN `url` varchar(2048); ALTER TABLE `cloud`.`volume_store_ref` MODIFY COLUMN `download_url` varchar(2048); ALTER TABLE `cloud`.`upload` MODIFY COLUMN `url` varchar(2048); -ALTER TABLE `cloud`.`host` MODIFY COLUMN `url` varchar(2048); From bded5e98ec14dec18545c6dffa81b36dee37235a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Aur=C3=A8le=20Brothier?= Date: Fri, 27 May 2016 08:38:24 +0200 Subject: [PATCH 194/203] API: update url field max length --- .../cloudstack/api/command/admin/storage/AddImageStoreCmd.java | 2 +- .../command/admin/storage/CreateSecondaryStagingStoreCmd.java | 2 +- .../apache/cloudstack/api/command/user/iso/ExtractIsoCmd.java | 2 +- .../apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java | 2 +- .../cloudstack/api/command/user/template/CreateTemplateCmd.java | 1 + .../api/command/user/template/ExtractTemplateCmd.java | 2 +- .../api/command/user/template/RegisterTemplateCmd.java | 1 + .../cloudstack/api/command/user/volume/ExtractVolumeCmd.java | 2 +- .../cloudstack/api/command/user/volume/UploadVolumeCmd.java | 1 + 9 files changed, 9 insertions(+), 6 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java index 6b673cf632..839d64dcf9 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java @@ -49,7 +49,7 @@ public class AddImageStoreCmd extends BaseCmd { @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the name for the image store") private String name; - @Parameter(name = ApiConstants.URL, type = CommandType.STRING, description = "the URL for the image store") + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, length = 2048, description = "the URL for the image store") private String url; @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, description = "the Zone ID for the image store") diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateSecondaryStagingStoreCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateSecondaryStagingStoreCmd.java index cfe4383578..194179d769 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateSecondaryStagingStoreCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateSecondaryStagingStoreCmd.java @@ -45,7 +45,7 @@ public class CreateSecondaryStagingStoreCmd extends BaseCmd { //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, description = "the URL for the staging store") + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, length = 2048, description = "the URL for the staging store") private String url; @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, description = "the Zone ID for the staging store") diff --git a/api/src/org/apache/cloudstack/api/command/user/iso/ExtractIsoCmd.java b/api/src/org/apache/cloudstack/api/command/user/iso/ExtractIsoCmd.java index 85f6008598..a400a014b6 100644 --- a/api/src/org/apache/cloudstack/api/command/user/iso/ExtractIsoCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/iso/ExtractIsoCmd.java @@ -49,7 +49,7 @@ public class ExtractIsoCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = TemplateResponse.class, required = true, description = "the ID of the ISO file") private Long id; - @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = false, description = "the URL to which the ISO would be extracted") + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = false, length = 2048, description = "the URL to which the ISO would be extracted") private String url; @Parameter(name = ApiConstants.ZONE_ID, diff --git a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java index a1cb4780c7..599aac1fd0 100644 --- a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java @@ -78,7 +78,7 @@ public class RegisterIsoCmd extends BaseCmd { description = "the ID of the OS type that best represents the OS of this ISO. If the ISO is bootable this parameter needs to be passed") private Long osTypeId; - @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, description = "the URL to where the ISO is currently being hosted") + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, length = 2048, description = "the URL to where the ISO is currently being hosted") private String url; @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class, diff --git a/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java index c8d6ce338c..59c4abe002 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java @@ -113,6 +113,7 @@ public class CreateTemplateCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.URL, type = CommandType.STRING, + length = 2048, description = "Optional, only for baremetal hypervisor. The directory name where template stored on CIFS server") private String url; diff --git a/api/src/org/apache/cloudstack/api/command/user/template/ExtractTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/ExtractTemplateCmd.java index c88b5e334b..48d3e1405a 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/ExtractTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/ExtractTemplateCmd.java @@ -49,7 +49,7 @@ public class ExtractTemplateCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = TemplateResponse.class, required = true, description = "the ID of the template") private Long id; - @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = false, description = "the url to which the ISO would be extracted") + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = false, length = 2048, description = "the url to which the ISO would be extracted") private String url; @Parameter(name = ApiConstants.ZONE_ID, diff --git a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java index 8de30f690e..8ff0b6b449 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java @@ -104,6 +104,7 @@ public class RegisterTemplateCmd extends BaseCmd { @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, + length = 2048, description = "the URL of where the template is hosted. Possible URL include http:// and https://") private String url; diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ExtractVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ExtractVolumeCmd.java index 049396c370..fc536d3f03 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/ExtractVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/ExtractVolumeCmd.java @@ -54,7 +54,7 @@ public class ExtractVolumeCmd extends BaseAsyncCmd { required=true, description="the ID of the volume") private Long id; - @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = false, description = "the url to which the volume would be extracted") + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = false, length = 2048, description = "the url to which the volume would be extracted") private String url; @Parameter(name = ApiConstants.ZONE_ID, diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java index c360c146d6..2174961675 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java @@ -62,6 +62,7 @@ public class UploadVolumeCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, + length = 2048, description = "the URL of where the volume is hosted. Possible URL include http:// and https://") private String url; From 123e9f81ab2740340f31e39f1784c660fcf42f90 Mon Sep 17 00:00:00 2001 From: Will Stevens Date: Fri, 27 May 2016 16:32:20 -0400 Subject: [PATCH 195/203] fixed a variable name broken by merge conflicts --- server/src/com/cloud/api/ApiServer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index 9c296cb4b5..0651d1671c 100644 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -1003,7 +1003,7 @@ public ResponseObject loginUser(final HttpSession session, final String username final Map requestParameters) throws CloudAuthenticationException { // We will always use domainId first. If that does not exist, we will use domain name. If THAT doesn't exist // we will default to ROOT - final Domain userDomain = _domainMgr.findDomainByIdOrPath(domainId, domainPath); + final Domain userDomain = domainMgr.findDomainByIdOrPath(domainId, domainPath); if (userDomain == null || userDomain.getId() < 1L) { throw new CloudAuthenticationException("Unable to find the domain from the path " + domainPath); } else { From 7914cdc2bed1f51834ab292a23bb52d047cca309 Mon Sep 17 00:00:00 2001 From: Pierre-Luc Dion Date: Sat, 28 May 2016 11:03:11 -0400 Subject: [PATCH 196/203] fix noredist build because of missing maven dependency of vmware 6.0 lib --- deps/install-non-oss.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/deps/install-non-oss.sh b/deps/install-non-oss.sh index 7d38d53760..2f5027cd4c 100755 --- a/deps/install-non-oss.sh +++ b/deps/install-non-oss.sh @@ -35,3 +35,6 @@ mvn install:install-file -Dfile=vim25_51.jar -DgroupId=com.cloud.com.vmwa # From https://my.vmware.com/group/vmware/get-download?downloadGroup=WEBSDK550 mvn install:install-file -Dfile=vim25_55.jar -DgroupId=com.cloud.com.vmware -DartifactId=vmware-vim25 -Dversion=5.5 -Dpackaging=jar + +# From https://my.vmware.com VMware-vSphere-SDK-6.0.0-3634981.zip +mvn install:install-file -Dfile=vim25_60.jar -DgroupId=com.cloud.com.vmware -DartifactId=vmware-vim25 -Dversion=6.0 -Dpackaging=jar From 91c9fc9f6ef5c09e788c20dececd0ee4d7325d29 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Sun, 29 May 2016 16:14:28 +0530 Subject: [PATCH 197/203] travis: use ipmitool from ubuntu repository Signed-off-by: Rohit Yadav --- tools/travis/before_install.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/travis/before_install.sh b/tools/travis/before_install.sh index 44ead5ad56..99195c265a 100755 --- a/tools/travis/before_install.sh +++ b/tools/travis/before_install.sh @@ -91,15 +91,11 @@ if [[ $? -ne 0 ]]; then echo -e "\napt-get packages failed to install" fi -# Use latest ipmitool 1.8.16 dependencies +# Use latest ipmitool 1.8.16 sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1397BC53640DB551 sudo sh -c 'echo "deb http://archive.ubuntu.com/ubuntu xenial main universe" >> /etc/apt/sources.list' sudo apt-get update -q -y > /dev/null -sudo apt-get -q -y -V install freeipmi-common libfreeipmi16 libgcrypt20 libgpg-error-dev libgpg-error0 libopenipmi0 --no-install-recommends > /dev/null - -# Installed version 1.8.16 with patch: https://bugzilla.redhat.com/show_bug.cgi?id=1286035 -wget http://packages.shapeblue.com/contribs/ipmitool_1.8.16_travis_amd64.deb -O ipmitool.deb > /dev/null -sudo dpkg -i ipmitool.deb +sudo apt-get -q -y -V install freeipmi-common libfreeipmi16 libgcrypt20 libgpg-error-dev libgpg-error0 libopenipmi0 ipmitool --no-install-recommends > /dev/null ipmitool -V From 620a9bb1a91d331bdd30363a3306ae086b14c9c9 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Sun, 29 May 2016 16:25:53 +0530 Subject: [PATCH 198/203] travis: add one more smoke test Adds a login smoke test to Travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9ff6f18c54..34220fe05b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,7 +37,7 @@ env: - PATH=$HOME/.local/bin:$PATH matrix: - TESTS="smoke/test_affinity_groups smoke/test_affinity_groups_projects smoke/test_dynamicroles smoke/test_deploy_vgpu_enabled_vm smoke/test_deploy_vm_iso smoke/test_deploy_vm_root_resize smoke/test_deploy_vm_with_userdata smoke/test_deploy_vms_with_varied_deploymentplanners smoke/test_disk_offerings smoke/test_global_settings smoke/test_guest_vlan_range" - - TESTS="smoke/test_hosts smoke/test_internal_lb smoke/test_iso smoke/test_list_ids_parameter smoke/test_loadbalance smoke/test_multipleips_per_nic smoke/test_network smoke/test_network_acl smoke/test_nic smoke/test_nic_adapter_type smoke/test_non_contigiousvlan" + - TESTS="smoke/test_hosts smoke/test_internal_lb smoke/test_iso smoke/test_list_ids_parameter smoke/test_loadbalance smoke/test_login smoke/test_multipleips_per_nic smoke/test_network smoke/test_network_acl smoke/test_nic smoke/test_nic_adapter_type smoke/test_non_contigiousvlan" - TESTS="smoke/test_outofbandmanagement smoke/test_over_provisioning smoke/test_password_server smoke/test_portable_publicip smoke/test_primary_storage smoke/test_privategw_acl smoke/test_public_ip_range smoke/test_pvlan smoke/test_regions smoke/test_reset_vm_on_reboot smoke/test_resource_detail" - TESTS="smoke/test_router_dhcphosts smoke/test_routers smoke/test_routers_iptables_default_policy smoke/test_routers_network_ops smoke/test_staticroles smoke/test_scale_vm smoke/test_secondary_storage smoke/test_service_offerings smoke/test_snapshots smoke/test_ssvm smoke/test_templates" - TESTS="smoke/test_usage_events smoke/test_vm_life_cycle smoke/test_vm_snapshots smoke/test_volumes smoke/test_vpc_redundant smoke/test_vpc_router_nics smoke/test_vpc_vpn smoke/misc/test_deploy_vm smoke/misc/test_vm_ha smoke/misc/test_escalations_templates smoke/misc/test_vm_sync" From c9567495aba6894b80f95917a220dc3b40f33cf1 Mon Sep 17 00:00:00 2001 From: Nick Livens Date: Tue, 31 May 2016 14:39:43 +0200 Subject: [PATCH 199/203] Make sure that the DB drivers are loaded before initiating connections --- .../src/com/cloud/utils/db/DriverLoader.java | 69 +++++++++++++++++++ .../com/cloud/utils/db/TransactionLegacy.java | 18 +---- 2 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 framework/db/src/com/cloud/utils/db/DriverLoader.java diff --git a/framework/db/src/com/cloud/utils/db/DriverLoader.java b/framework/db/src/com/cloud/utils/db/DriverLoader.java new file mode 100644 index 0000000000..06c8da5c35 --- /dev/null +++ b/framework/db/src/com/cloud/utils/db/DriverLoader.java @@ -0,0 +1,69 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.utils.db; + +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.log4j.Logger; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class DriverLoader { + + private static final Logger LOGGER = Logger.getLogger(DriverLoader.class.getName()); + private static final List LOADED_DRIVERS; + private static final Map DRIVERS; + + static { + DRIVERS = new HashMap(); + DRIVERS.put("jdbc:mysql", "com.mysql.jdbc.Driver"); + DRIVERS.put("jdbc:postgresql", "org.postgresql.Driver"); + DRIVERS.put("jdbc:h2", "org.h2.Driver"); + + LOADED_DRIVERS = new ArrayList(); + } + + + public static void loadDriver(String dbDriver) { + String driverClass = DRIVERS.get(dbDriver); + if (driverClass == null) { + LOGGER.error("DB driver type " + dbDriver + " is not supported!"); + throw new CloudRuntimeException("DB driver type " + dbDriver + " is not supported!"); + } + + if (LOADED_DRIVERS.contains(dbDriver)) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("DB driver " + driverClass + " was already loaded."); + } + return; + } + + try { + Class.forName(driverClass).newInstance(); + LOADED_DRIVERS.add(dbDriver); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Successfully loaded DB driver " + driverClass); + } + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + LOGGER.error("Failed to load DB driver " + driverClass); + throw new CloudRuntimeException("Failed to load DB driver " + driverClass, e); + } + } + +} diff --git a/framework/db/src/com/cloud/utils/db/TransactionLegacy.java b/framework/db/src/com/cloud/utils/db/TransactionLegacy.java index 523162e222..847ec1ee29 100644 --- a/framework/db/src/com/cloud/utils/db/TransactionLegacy.java +++ b/framework/db/src/com/cloud/utils/db/TransactionLegacy.java @@ -20,8 +20,6 @@ import java.io.File; import java.io.IOException; import java.sql.Connection; -import java.sql.Driver; -import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -1078,7 +1076,7 @@ public static void initDataSource(Properties dbProps) { final String cloudConnectionUri = cloudDriver + "://" + cloudHost + (s_dbHAEnabled ? "," + cloudSlaves : "") + ":" + cloudPort + "/" + cloudDbName + "?autoReconnect=" + cloudAutoReconnect + (url != null ? "&" + url : "") + (useSSL ? "&useSSL=true" : "") + (s_dbHAEnabled ? "&" + cloudDbHAParams : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : ""); - loadDbDriver(cloudConnectionUri); + DriverLoader.loadDriver(cloudDriver); final ConnectionFactory cloudConnectionFactory = new DriverManagerConnectionFactory(cloudConnectionUri, cloudUsername, cloudPassword); @@ -1109,7 +1107,7 @@ public static void initDataSource(Properties dbProps) { final String usageConnectionUri = usageDriver + "://" + usageHost + (s_dbHAEnabled ? "," + dbProps.getProperty("db.cloud.slaves") : "") + ":" + usagePort + "/" + usageDbName + "?autoReconnect=" + usageAutoReconnect + (usageUrl != null ? "&" + usageUrl : "") + (s_dbHAEnabled ? "&" + getDBHAParams("usage", dbProps) : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : ""); - loadDbDriver(usageConnectionUri); + DriverLoader.loadDriver(usageDriver); final ConnectionFactory usageConnectionFactory = new DriverManagerConnectionFactory(usageConnectionUri, usageUsername, usagePassword); @@ -1137,7 +1135,7 @@ public static void initDataSource(Properties dbProps) { final String simulatorConnectionUri = simulatorDriver + "://" + simulatorHost + ":" + simulatorPort + "/" + simulatorDbName + "?autoReconnect=" + simulatorAutoReconnect; - loadDbDriver(simulatorConnectionUri); + DriverLoader.loadDriver(simulatorDriver); final ConnectionFactory simulatorConnectionFactory = new DriverManagerConnectionFactory(simulatorConnectionUri, simulatorUsername, simulatorPassword); @@ -1157,16 +1155,6 @@ public static void initDataSource(Properties dbProps) { } } - private static void loadDbDriver(String dbConnectionUri) { - try { - Driver driver = DriverManager.getDriver(dbConnectionUri); - s_logger.debug("Successfully loaded DB driver " + driver.getClass().getName() + " for connection " + dbConnectionUri); - } catch (SQLException e) { - s_logger.error("Failed to load DB driver for connection " + dbConnectionUri, e); - throw new CloudRuntimeException("Failed to load DB driver for connection " + dbConnectionUri, e); - } - } - private static String getDBHAParams(String dbName, Properties dbProps) { StringBuilder sb = new StringBuilder(); sb.append("failOverReadOnly=" + dbProps.getProperty("db." + dbName + ".failOverReadOnly")); From fd67871a27dcb2b2a67e36e4f96ea1b0f07f0ede Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Wed, 8 Jun 2016 11:20:46 +0900 Subject: [PATCH 200/203] CLOUDSTACK-9409: Add role_id to cloud_usage.account Adds role_id column to cloud_usage.account, fixes UsageDaoImpl to insert Accounts with role_id from account table. Signed-off-by: Rohit Yadav --- .../src/com/cloud/upgrade/dao/Upgrade481to490.java | 8 +++++++- .../schema/src/com/cloud/usage/dao/UsageDaoImpl.java | 11 ++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java index d1240ecf2c..1c6ce38bd7 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java @@ -103,10 +103,16 @@ private void setupRolesAndPermissionsForDynamicChecker(final Connection conn) { s_logger.warn("cloud.account table already has the role_id column, skipping altering table and migration of accounts"); return; } else { - throw new CloudRuntimeException("Unable to create column quota_calculated in table cloud_usage.cloud_usage", e); + throw new CloudRuntimeException("Unable to create column role_id in table cloud.account", e); } } + try (final PreparedStatement pstmt = conn.prepareStatement("ALTER TABLE `cloud_usage`.`account` ADD COLUMN `role_id` bigint(20) unsigned AFTER `type`")) { + pstmt.executeUpdate(); + } catch (SQLException e) { + throw new CloudRuntimeException("Unable to create column role_id in table cloud_usage.account", e); + } + migrateAccountsToDefaultRoles(conn); final Map apiMap = PropertiesUtil.processConfigFile(new String[] { PropertiesUtil.getDefaultApiCommandsFileName() }); diff --git a/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java index 9c9ab0bbc0..39f57df714 100644 --- a/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java +++ b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java @@ -49,7 +49,7 @@ public class UsageDaoImpl extends GenericDaoBase implements Usage private static final String DELETE_ALL = "DELETE FROM cloud_usage"; private static final String DELETE_ALL_BY_ACCOUNTID = "DELETE FROM cloud_usage WHERE account_id = ?"; private static final String DELETE_ALL_BY_INTERVAL = "DELETE FROM cloud_usage WHERE end_date < DATE_SUB(CURRENT_DATE(), INTERVAL ? DAY)"; - private static final String INSERT_ACCOUNT = "INSERT INTO cloud_usage.account (id, account_name, type, domain_id, removed, cleanup_needed) VALUES (?,?,?,?,?,?)"; + private static final String INSERT_ACCOUNT = "INSERT INTO cloud_usage.account (id, account_name, type, role_id, domain_id, removed, cleanup_needed) VALUES (?,?,?,?,?,?,?)"; private static final String INSERT_USER_STATS = "INSERT INTO cloud_usage.user_statistics (id, data_center_id, account_id, public_ip_address, device_id, device_type, network_id, net_bytes_received," + " net_bytes_sent, current_bytes_received, current_bytes_sent, agg_bytes_received, agg_bytes_sent) VALUES (?,?,?,?,?,?,?,?,?,?, ?, ?, ?)"; @@ -113,16 +113,17 @@ public void saveAccounts(List accounts) { pstmt.setLong(1, acct.getId()); pstmt.setString(2, acct.getAccountName()); pstmt.setShort(3, acct.getType()); - pstmt.setLong(4, acct.getDomainId()); + pstmt.setLong(4, acct.getRoleId()); + pstmt.setLong(5, acct.getDomainId()); Date removed = acct.getRemoved(); if (removed == null) { - pstmt.setString(5, null); + pstmt.setString(6, null); } else { - pstmt.setString(5, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), acct.getRemoved())); + pstmt.setString(6, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), acct.getRemoved())); } - pstmt.setBoolean(6, acct.getNeedsCleanup()); + pstmt.setBoolean(7, acct.getNeedsCleanup()); pstmt.addBatch(); } From ffe72ca227a518907bca396603a2641e10c5d02d Mon Sep 17 00:00:00 2001 From: Nick Livens Date: Fri, 3 Jun 2016 11:04:09 +0200 Subject: [PATCH 201/203] CLOUDSTACK-9399 : NPE during deletion of host when clusterId is null --- server/src/com/cloud/resource/ResourceManagerImpl.java | 6 ++++-- ui/scripts/system.js | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 89893a2f80..2bb1596ed1 100644 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -847,7 +847,7 @@ protected boolean doDeleteHost(final long hostId, final boolean isForced, final return true; } - long clusterId = host.getClusterId(); + Long clusterId = host.getClusterId(); _agentMgr.notifyMonitorsOfHostAboutToBeRemoved(host.getId()); @@ -927,7 +927,9 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } }); - _agentMgr.notifyMonitorsOfRemovedHost(host.getId(), clusterId); + if (clusterId != null) { + _agentMgr.notifyMonitorsOfRemovedHost(host.getId(), clusterId); + } return true; } diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 642370feb2..2eef6b1908 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -13256,7 +13256,7 @@ dataType: "json", async: false, success: function(json) { - var items = json.listnuagevspdeviceresponse.nuagevspdevice; + var items = json.listnuagevspdevicesresponse.nuagevspdevice; args.response.success({ data: items }); @@ -13325,7 +13325,7 @@ dataType: "json", async: true, success: function(json) { - var item = json.listnuagevspdeviceresponse.nuagevspdevice[0]; + var item = json.listnuagevspdevicesresponse.nuagevspdevice[0]; args.response.success({ data: item }); From e972273bf17bedd089b0ef0716615b183dec4135 Mon Sep 17 00:00:00 2001 From: Prashanth Manthena Date: Fri, 3 Jun 2016 20:51:25 +0200 Subject: [PATCH 202/203] CLOUDSTACK-9399 : Marvin test coverage for Nuage VSP device CRUD operations --- .../plugins/nuagevsp/test_nuage_vsp.py | 93 ++++++++++++++++++- 1 file changed, 89 insertions(+), 4 deletions(-) diff --git a/test/integration/plugins/nuagevsp/test_nuage_vsp.py b/test/integration/plugins/nuagevsp/test_nuage_vsp.py index ca2a28e276..0227ce5c8e 100644 --- a/test/integration/plugins/nuagevsp/test_nuage_vsp.py +++ b/test/integration/plugins/nuagevsp/test_nuage_vsp.py @@ -19,9 +19,11 @@ """ # Import Local Modules from nuageTestCase import nuageTestCase -from marvin.lib.base import Account +from marvin.lib.base import Account, Nuage +from marvin.cloudstackAPI import deleteNuageVspDevice # Import System Modules from nose.plugins.attrib import attr +import copy class TestNuageVsp(nuageTestCase): @@ -43,6 +45,91 @@ def setUp(self): self.cleanup = [self.account] return + # validate_NuageVspDevice - Validates the addition of Nuage VSP device in the Nuage VSP Physical Network + def validate_NuageVspDevice(self): + """Validates the addition of Nuage VSP device in the Nuage VSP Physical Network""" + self.debug("Validating the addition of Nuage VSP device in the Nuage VSP Physical Network - %s" % + self.vsp_physical_network.id) + nuage_vsp_device = Nuage.list(self.api_client, + physicalnetworkid=self.vsp_physical_network.id + ) + self.assertEqual(isinstance(nuage_vsp_device, list), True, + "List Nuage VSP device should return a valid list" + ) + self.debug("Successfully validated the addition of Nuage VSP device in the Nuage VSP Physical Network - %s" % + self.vsp_physical_network.id) + + # delete_NuageVspDevice - Deletes the Nuage VSP device in the Nuage VSP Physical Network + def delete_NuageVspDevice(self): + """Deletes the Nuage VSP device in the Nuage VSP Physical Network""" + self.debug("Deleting the Nuage VSP device in the Nuage VSP Physical Network - %s" % + self.vsp_physical_network.id) + nuage_vsp_device = Nuage.list(self.api_client, + physicalnetworkid=self.vsp_physical_network.id + )[0] + cmd = deleteNuageVspDevice.deleteNuageVspDeviceCmd() + cmd.vspdeviceid = nuage_vsp_device.vspdeviceid + self.api_client.deleteNuageVspDevice(cmd) + self.debug("Successfully deleted the Nuage VSP device in the Nuage VSP Physical Network - %s" % + self.vsp_physical_network.id) + + @attr(tags=["advanced", "nuagevsp"], required_hardware="false") + def test_nuage_vsp_device(self): + """ Test Nuage VSP device in the Nuage VSP Physical Network + """ + + # 1. Verify that the Nuage VSP network service provider is successfully created and enabled in the Nuage VSP + # Physical Network. + # 2. Verify that the Nuage VSP device is successfully created in the Nuage VSP Physical Network. + # 3. Delete the Nuage VSP device in the Nuage VSP Physical Network, verify that the Nuage VSP device is + # successfully deleted in the Nuage VSP Physical Network. + # 4. Add the Nuage VSP device in the Nuage VSP Physical Network with invalid VSD credentials, verify that the + # Nuage VSP device failed to add in the Nuage VSP Physical Network. + # 5. Add the Nuage VSP device in the Nuage VSP Physical Network with valid VSD credentials, verify that the + # Nuage VSP device is successfully added in the Nuage VSP Physical Network. + + # Nuage VSP network service provider validation + self.debug("Validating the Nuage VSP network service provider in the Nuage VSP Physical Network...") + self.validate_NetworkServiceProvider("NuageVsp", state="Enabled") + + # Nuage VSP device validation + self.debug("Validating the Nuage VSP device in the Nuage VSP Physical Network...") + self.validate_NuageVspDevice() + + # Nuage VSP device deletion + self.debug("Deleting the Nuage VSP device in the Nuage VSP Physical Network...") + self.delete_NuageVspDevice() + + # Nuage VSP device validation + self.debug("Validating the Nuage VSP device in the Nuage VSP Physical Network...") + with self.assertRaises(Exception): + self.validate_NuageVspDevice() + self.debug("Successfully deleted the Nuage VSP device in the Nuage VSP Physical Network") + + # Adding the Nuage VSP device with invalid VSD credentials + self.debug("Adding the Nuage VSP device in the Nuage VSP Physical Network with invalid VSD credentials...") + vsd_info = self.nuage_vsp_device.__dict__ + invalid_vsd_info = copy.deepcopy(vsd_info) + invalid_vsd_info["password"] = "" + with self.assertRaises(Exception): + Nuage.add(self.api_client, invalid_vsd_info, self.vsp_physical_network.id) + self.debug("Failed to add the Nuage VSP device in the Nuage VSP Physical Network due to invalid VSD " + "credentials") + + # Nuage VSP device validation + self.debug("Validating the Nuage VSP device in the Nuage VSP Physical Network...") + with self.assertRaises(Exception): + self.validate_NuageVspDevice() + self.debug("The Nuage VSP device is not added in the Nuage VSP Physical Network") + + # Adding the Nuage VSP device with valid VSD credentials + self.debug("Adding the Nuage VSP device in the Nuage VSP Physical Network with valid VSD credentials...") + Nuage.add(self.api_client, vsd_info, self.vsp_physical_network.id) + + # Nuage VSP device validation + self.debug("Validating the Nuage VSP device in the Nuage VSP Physical Network...") + self.validate_NuageVspDevice() + @attr(tags=["advanced", "nuagevsp"], required_hardware="false") def test_nuage_vsp(self): """ Test Nuage VSP SDN plugin with basic Isolated Network functionality @@ -58,9 +145,7 @@ def test_nuage_vsp(self): # "Running" state. # 6. Delete the created Isolated Network after destroying its VMs, check if the Isolated network is successfully # deleted. - - self.debug("Validating the Nuage VSP network service provider...") - self.validate_NetworkServiceProvider("NuageVsp", state="Enabled") + # 7. Delete all the created objects (cleanup). # Creating a network offering self.debug("Creating and enabling Nuage VSP Isolated Network offering...") From 7531f24d7374be18eac04000ffac12ee5c462953 Mon Sep 17 00:00:00 2001 From: Prashanth Manthena Date: Wed, 8 Jun 2016 15:35:33 +0200 Subject: [PATCH 203/203] Nuage VSP : Enhancing Marvin test coverage --- .../plugins/nuagevsp/nuageTestCase.py | 530 ++++++++++-------- .../nuagevsp/test_nuage_password_reset.py | 321 ++++++----- .../nuagevsp/test_nuage_vpc_internal_lb.py | 471 ++++++++-------- .../nuagevsp/test_nuage_vpc_network.py | 9 +- .../plugins/nuagevsp/test_nuage_vsp.py | 10 +- 5 files changed, 704 insertions(+), 637 deletions(-) diff --git a/test/integration/plugins/nuagevsp/nuageTestCase.py b/test/integration/plugins/nuagevsp/nuageTestCase.py index 11032a62f1..a71945c472 100644 --- a/test/integration/plugins/nuagevsp/nuageTestCase.py +++ b/test/integration/plugins/nuagevsp/nuageTestCase.py @@ -21,6 +21,7 @@ from marvin.cloudstackTestCase import cloudstackTestCase, unittest from marvin.lib.base import (EgressFireWallRule, FireWallRule, + Host, Hypervisor, Network, NetworkACL, @@ -45,6 +46,8 @@ import importlib import logging import socket +import sys +import time class nuageTestCase(cloudstackTestCase): @@ -60,6 +63,7 @@ def setUpClass(cls, zone=None): cls.api_client = test_client.getApiClient() cls.db_client = test_client.getDbConnection() cls.test_data = test_client.getParsedTestDataConfig() + # Get Zone, Domain and templates cls.zone = get_zone(cls.api_client, zone_name=zone.name if zone else None, @@ -79,6 +83,9 @@ def setUpClass(cls, zone=None): ) cls._cleanup = [cls.service_offering] + # Check if the host hypervisor type is simulator + cls.isSimulator = Hypervisor.list(cls.api_client, zoneid=cls.zone.id)[0].name == "Simulator" + # Get configured Nuage VSP device details try: physical_networks = PhysicalNetwork.list(cls.api_client, zoneid=cls.zone.id) @@ -97,42 +104,44 @@ def setUpClass(cls, zone=None): cls.cms_id = cls.nuage_vsp_device.cmsid except Exception as e: cls.tearDownClass() - raise unittest.SkipTest("Warning: Couldn't get configured Nuage VSP device details: %s" % e) - - # Check if the host hypervisor type is simulator - cls.isSimulator = Hypervisor.list(cls.api_client, zoneid=cls.zone.id)[0].name == "Simulator" + raise unittest.SkipTest("Warning: Could not get configured Nuage VSP device details - %s" % e) # VSD is a programmable policy and analytics engine of Nuage VSP SDN platform # vspk is a Python SDK for Nuage VSP's VSD - # cms_vspk_wrapper is a library that wraps vspk package + # libVSD is a library that wraps vspk package try: vspk_module = "vspk." + cls.nuage_vsp_device.apiversion if int(cls.nuage_vsp_device.apiversion[1]) >= 4 \ else "vspk.vsdk." + cls.nuage_vsp_device.apiversion cls.vsdk = importlib.import_module(vspk_module) - vspk_utils_module = "vspk.utils" if int(cls.nuage_vsp_device.apiversion[1]) >= 4 \ - else "vspk.vsdk." + cls.nuage_vsp_device.apiversion + ".utils" - vsdk_utils = importlib.import_module(vspk_utils_module) - set_log_level = getattr(vsdk_utils, "set_log_level") - from cms_vspk_wrapper.cms_vspk_wrapper import Cms_vspk_wrapper - except: - raise unittest.SkipTest("vspk (and/or) cms_vspk_wrapper import failure") + from libVSD import ApiClient, VSDHelpers + except Exception as e: + cls.tearDownClass() + raise unittest.SkipTest("Warning: vspk (and/or) libVSD package import failure - %s" % e) # Configure VSD session cls._session = cls.vsdk.NUVSDSession(username=cls.nuage_vsp_device.username, password=cls.nuage_vsp_device.password, - enterprise="csp", api_url="https://%s:%d" % - (cls.nuage_vsp_device.hostname, + enterprise="csp", + api_url="https://%s:%d" % (cls.nuage_vsp_device.hostname, cls.nuage_vsp_device.port) ) cls._session.start() - # Configure cms_vspk_wrapper session - cls.log_handler = logging.getLogger("CSLog").handlers[0] + # Configure libVSD session + root = logging.getLogger() + log_handler = logging.StreamHandler(sys.stdout) + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + log_handler.setFormatter(formatter) + root.addHandler(log_handler) vsd_info = cls.nuage_vsp_device.__dict__ - vsd_info["port"] = str(vsd_info["port"]) - cls.vsd = Cms_vspk_wrapper(vsd_info, cls.log_handler) - - set_log_level(logging.INFO) + cls.debug("Nuage VSP device (VSD) details - %s" % vsd_info) + vsd_api_client = ApiClient(address=vsd_info["hostname"], + user=vsd_info["username"], + password=vsd_info["password"], + version=vsd_info["apiversion"][1] + "." + vsd_info["apiversion"][3] + ) + vsd_api_client.new_session() + cls.vsd = VSDHelpers(vsd_api_client) cls.debug("setUpClass nuageTestCase [DONE]") @@ -180,17 +189,23 @@ def create_VpcOffering(self, vpc_offering, suffix=None): return vpc_off # create_Vpc - Creates VPC with the given VPC offering - def create_Vpc(self, vpc_offering, cidr="10.1.1.1/16", cleanup=True): - self.debug("Creating a VPC in the account - %s" % self.account.name) - self.test_data["vpc"]["name"] = "TestVPC" - self.test_data["vpc"]["displaytext"] = "TestVPC" - self.test_data["vpc"]["cidr"] = cidr + def create_Vpc(self, vpc_offering, cidr='10.1.0.0/16', testdata=None, account=None, networkDomain=None, + cleanup=True): + if not account: + account = self.account + self.debug("Creating a VPC in the account - %s" % account.name) + if not testdata: + testdata = self.test_data["vpc"] + testdata["name"] = "TestVPC-" + cidr + "-" + str(vpc_offering.name) + testdata["displaytext"] = "Test VPC" + testdata["cidr"] = cidr vpc = VPC.create(self.api_client, - self.test_data["vpc"], + testdata, vpcofferingid=vpc_offering.id, zoneid=self.zone.id, - account=self.account.name, - domainid=self.account.domainid + account=account.name, + domainid=account.domainid, + networkDomain=networkDomain ) self.debug("Created VPC with ID - %s" % vpc.id) if cleanup: @@ -223,13 +238,20 @@ def create_NetworkOffering(self, net_offering, suffix=None, conserve_mode=False) return nw_off # create_Network - Creates network with the given Network offering - def create_Network(self, nw_off, gateway="10.1.1.1", netmask="255.255.255.0", vpc=None, acl_list=None): - self.debug("Creating a network in the account - %s" % self.account.name) - self.test_data["network"]["netmask"] = netmask + def create_Network(self, nw_off, gateway="10.1.1.1", netmask="255.255.255.0", vpc=None, acl_list=None, + testdata=None, account=None, cleanup=True): + if not account: + account = self.account + self.debug("Creating a network in the account - %s" % account.name) + if not testdata: + testdata = self.test_data["network"] + testdata["name"] = "TestNetwork-" + gateway + "-" + str(nw_off.name) + testdata["displaytext"] = "Test Network" + testdata["netmask"] = netmask network = Network.create(self.api_client, - self.test_data["network"], - accountid=self.account.name, - domainid=self.account.domainid, + testdata, + accountid=account.name, + domainid=account.domainid, networkofferingid=nw_off.id, zoneid=self.zone.id, gateway=gateway, @@ -237,7 +259,8 @@ def create_Network(self, nw_off, gateway="10.1.1.1", netmask="255.255.255.0", vp aclid=acl_list.id if acl_list else None ) self.debug("Created network with ID - %s" % network.id) - self.cleanup.append(network) + if cleanup: + self.cleanup.append(network) return network # upgrade_Network - Upgrades the given network @@ -259,25 +282,74 @@ def delete_Network(self, network): self.cleanup.remove(network) self.debug("Deleted Network with ID - %s" % network.id) - # create_VM - Creates VM in the given network, vm_key - Key for the services on the VM - def create_VM(self, network, vm_key="virtual_machine", host_id=None, start_vm=True): - self.debug("Creating VM in network with ID - %s" % network.id) - self.debug("Passed vm_key - %s" % vm_key) - self.test_data[vm_key]["zoneid"] = self.zone.id - self.test_data[vm_key]["template"] = self.template.id + # create_VM - Creates VM in the given network(s) + def create_VM(self, network_list, host_id=None, start_vm=True, testdata=None, account=None, cleanup=True): + network_ids = [] + if isinstance(network_list, list): + for network in network_list: + network_ids.append(str(network.id)) + else: + network_ids.append(str(network_list.id)) + if not account: + account = self.account + self.debug("Creating VM in network(s) with ID(s) - %s in the account - %s" % (network_ids, account.name)) + if not testdata: + testdata = self.test_data["virtual_machine"] vm = VirtualMachine.create(self.api_client, - self.test_data[vm_key], - accountid=self.account.name, - domainid=self.account.domainid, + testdata, + accountid=account.name, + domainid=account.domainid, serviceofferingid=self.service_offering.id, - networkids=[str(network.id)], + templateid=self.template.id, + zoneid=self.zone.id, + networkids=network_ids, startvm=start_vm, hostid=host_id ) - self.debug("Created VM with ID - %s in network with ID - %s" % (vm.id, network.id)) - self.cleanup.append(vm) + self.debug("Created VM with ID - %s in network(s) with ID(s) - %s" % (vm.id, network_ids)) + if cleanup: + self.cleanup.append(vm) return vm + # nic_operation_VM - Performs NIC operations such as add, remove, and update default NIC in the given VM and network + def nic_operation_VM(self, vm, network, operation="update"): + self.debug("Performing %s NIC operation in VM with ID - %s and network with ID - %s" % + (operation, vm.id, network.id)) + for nic in vm.nic: + if nic.networkid == network.id: + nic_id = nic.id + if operation is "update": + vm.update_default_nic(self.api_client, nic_id) + self.debug("Updated default NIC to NIC with ID - %s in VM with ID - %s and network with ID - %s" % + (nic_id, vm.id, network.id)) + if operation is "remove": + vm.remove_nic(self.api_client, nic_id) + self.debug("Removed NIC with ID - %s in VM with ID - %s and network with ID - %s" % + (nic_id, vm.id, network.id)) + if operation is "add": + vm.add_nic(self.api_client, network.id) + self.debug("Added NIC with ID - %s in VM with ID - %s and network with ID - %s" % + (nic_id, vm.id, network.id)) + + # migrate_VM - Migrates VM to another host, if available + def migrate_VM(self, vm): + self.debug("Checking if a host is available for migration...") + hosts = Host.listForMigration(self.api_client, virtualmachineid=vm.id) + self.assertEqual(isinstance(hosts, list), True, + "List hosts should return a valid list" + ) + # Remove the host of current VM from the hosts list + hosts[:] = [host for host in hosts if host.id != vm.hostid] + if len(hosts) <= 0: + self.skipTest("No host available for migration. Test requires at-least 2 hosts") + host = hosts[0] + self.debug("Migrating VM with ID: %s to Host: %s" % (vm.id, host.id)) + try: + vm.migrate(self.api_client, hostid=host.id) + except Exception as e: + self.fail("Failed to migrate instance, %s" % e) + self.debug("Migrated VM with ID: %s to Host: %s" % (vm.id, host.id)) + # delete_VM - Deletes the given VM def delete_VM(self, vm, expunge=True): self.debug("Deleting VM with ID - %s" % vm.id) @@ -299,12 +371,14 @@ def get_Router(self, network): return routers[0] # acquire_PublicIPAddress - Acquires public IP address for the given network/VPC - def acquire_PublicIPAddress(self, network, vpc=None): - self.debug("Associating public IP for network with ID - %s" % network.id) + def acquire_PublicIPAddress(self, network, vpc=None, account=None): + if not account: + account = self.account + self.debug("Associating public IP for network with ID - %s in the account - %s" % (network.id, account.name)) public_ip = PublicIPAddress.create(self.api_client, - accountid=self.account.name, + accountid=account.name, + domainid=account.domainid, zoneid=self.zone.id, - domainid=self.account.domainid, networkid=network.id if vpc is None else None, vpcid=vpc.id if vpc else self.vpc.id if hasattr(self, "vpc") else None ) @@ -312,31 +386,34 @@ def acquire_PublicIPAddress(self, network, vpc=None): (public_ip.ipaddress.ipaddress, network.id)) return public_ip - # create_StaticNatRule_For_VM - Creates static NAT rule on the given public IP for the given network and VM + # create_StaticNatRule_For_VM - Creates Static NAT rule on the given public IP for the given VM in the given network def create_StaticNatRule_For_VM(self, vm, public_ip, network, vmguestip=None): - self.debug("Enabling static NAT for public IP - %s" % public_ip.ipaddress.ipaddress) - StaticNATRule.enable(self.api_client, - ipaddressid=public_ip.ipaddress.id, - virtualmachineid=vm.id, - networkid=network.id, - vmguestip=vmguestip - ) - self.debug("Static NAT enabled for public IP - %s" % public_ip.ipaddress.ipaddress) + self.debug("Enabling Static NAT rule on public IP - %s for VM with ID - %s in network with ID - %s" % + (public_ip.ipaddress.ipaddress, vm.id, network.id)) + static_nat_rule = StaticNATRule.enable(self.api_client, + ipaddressid=public_ip.ipaddress.id, + virtualmachineid=vm.id, + networkid=network.id, + vmguestip=vmguestip + ) + self.debug("Static NAT rule enabled on public IP - %s for VM with ID - %s in network with ID - %s" % + (public_ip.ipaddress.ipaddress, vm.id, network.id)) + return static_nat_rule - # delete_StaticNatRule_For_VM - Deletes static NAT rule on the given public IP for the given VM - def delete_StaticNatRule_For_VM(self, vm, public_ip): - self.debug("Disabling static NAT for public IP - %s" % public_ip.ipaddress.ipaddress) + # delete_StaticNatRule_For_VM - Deletes Static NAT rule on the given public IP + def delete_StaticNatRule_For_VM(self, public_ip): + self.debug("Disabling Static NAT rule on public IP - %s" % public_ip.ipaddress.ipaddress) StaticNATRule.disable(self.api_client, - ipaddressid=public_ip.ipaddress.id, - virtualmachineid=vm.id + ipaddressid=public_ip.ipaddress.id ) - self.debug("Static NAT disabled for public IP - %s" % public_ip.ipaddress.ipaddress) + self.debug("Static NAT rule disabled on public IP - %s" % public_ip.ipaddress.ipaddress) - # create_FirewallRule - Creates Ingress firewall rule on the given public IP + # create_FirewallRule - Creates (Ingress) Firewall rule on the given Static NAT rule enabled public IP for Isolated + # networks def create_FirewallRule(self, public_ip, rule=None): if not rule: rule = self.test_data["ingress_rule"] - self.debug("Adding an Ingress Firewall rule to make Guest VMs accessible through Static NAT - %s" % rule) + self.debug("Adding an (Ingress) Firewall rule to make Guest VMs accessible through Static NAT rule - %s" % rule) return FireWallRule.create(self.api_client, ipaddressid=public_ip.ipaddress.id, protocol=rule["protocol"], @@ -345,7 +422,7 @@ def create_FirewallRule(self, public_ip, rule=None): endport=rule["endport"] ) - # create_EgressFirewallRule - Creates Egress firewall rule on the given public IP + # create_EgressFirewallRule - Creates Egress Firewall rule in the given Isolated network def create_EgressFirewallRule(self, network, rule): self.debug("Adding an Egress Firewall rule to allow/deny outgoing traffic from Guest VMs - %s" % rule) return EgressFireWallRule.create(self.api_client, @@ -366,7 +443,7 @@ def create_NetworkAclList(self, name, description, vpc): vpcid=vpc.id ) - # create_NetworkAclRule - Creates Ingress/Egress network ACL rule in the given network/acl list + # create_NetworkAclRule - Creates Ingress/Egress Network ACL rule in the given VPC network/acl list def create_NetworkAclRule(self, rule, traffic_type="Ingress", network=None, acl_list=None): self.debug("Adding NetworkACL rule - %s" % rule) if acl_list: @@ -383,11 +460,23 @@ def create_NetworkAclRule(self, rule, traffic_type="Ingress", network=None, acl_ traffictype=traffic_type ) - # ssh_into_VM - Gets into the shell of the given VM - def ssh_into_VM(self, vm, public_ip): + # ssh_into_VM - Gets into the shell of the given VM using its public IP + def ssh_into_VM(self, vm, public_ip, reconnect=True): self.debug("SSH into VM with ID - %s on public IP address - %s" % (vm.id, public_ip.ipaddress.ipaddress)) - ssh_client = vm.get_ssh_client(ipaddress=public_ip.ipaddress.ipaddress) - return ssh_client + tries = 0 + while tries < 3: + try: + ssh_client = vm.get_ssh_client(ipaddress=public_ip.ipaddress.ipaddress, reconnect=reconnect) + except Exception as e: + self.debug("Failed to SSH into VM: %s" % e) + self.debug("Waiting for the VM to be fully resolved for SSH connection...") + time.sleep(120) + self.debug("Retrying SSH into VM...") + tries += 1 + continue + self.debug("Successful to SSH into VM with ID - %s on public IP address - %s" % + (vm.id, public_ip.ipaddress.ipaddress)) + return ssh_client # execute_cmd - Executes the given command on the given ssh client def execute_cmd(self, ssh_client, cmd): @@ -401,11 +490,12 @@ def execute_cmd(self, ssh_client, cmd): self.debug("SSH client executed command result is None") return ret_data - # wget_from_server - Fetches index.html file of web server running with the given public IP - def wget_from_server(self, public_ip): + # wget_from_server - Fetches index.html file from a web server listening on the given public IP address and port + def wget_from_server(self, public_ip, port): import urllib - self.debug("wget from a http server on public IP address - %s" % public_ip.ipaddress.ipaddress) - filename, headers = urllib.urlretrieve("http://%s/index.html" % public_ip.ipaddress.ipaddress, + self.debug("wget index.html file from a http web server listening on public IP address - %s and port - %s" % + (public_ip.ipaddress.ipaddress, port)) + filename, headers = urllib.urlretrieve("http://%s:%s/index.html" % (public_ip.ipaddress.ipaddress, port), filename="index.html" ) return filename, headers @@ -414,7 +504,7 @@ def wget_from_server(self, public_ip): # matches the given provider name and state against the list of providers fetched def validate_NetworkServiceProvider(self, provider_name, state=None): """Validates the Network Service Provider in the Nuage VSP Physical Network""" - self.debug("Check if the Network Service Provider is created successfully ?") + self.debug("Validating the creation and state of Network Service Provider - %s" % provider_name) providers = NetworkServiceProvider.list(self.api_client, name=provider_name, physicalnetworkid=self.vsp_physical_network.id) @@ -426,15 +516,15 @@ def validate_NetworkServiceProvider(self, provider_name, state=None): ) if state: self.assertEqual(providers[0].state, state, - "Network Service Provider state should be in state - %s" % state + "Network Service Provider state should be '%s'" % state ) - self.debug("Network Service Provider creation successfully validated for %s" % provider_name) + self.debug("Successfully validated the creation and state of Network Service Provider - %s" % provider_name) - # validate_VpcOffering - Validates the given VPC offering, - # matches the given VPC offering name and state against the list of VPC offerings fetched + # validate_VpcOffering - Validates the given VPC offering, matches the given VPC offering name and state against the + # list of VPC offerings fetched def validate_VpcOffering(self, vpc_offering, state=None): """Validates the VPC offering""" - self.debug("Check if the VPC offering is created successfully ?") + self.debug("Validating the creation and state of VPC offering - %s" % vpc_offering.name) vpc_offs = VpcOffering.list(self.api_client, id=vpc_offering.id ) @@ -446,15 +536,14 @@ def validate_VpcOffering(self, vpc_offering, state=None): ) if state: self.assertEqual(vpc_offs[0].state, state, - "VPC offering state should be in state - %s" % state + "VPC offering state should be '%s'" % state ) - self.debug("VPC offering creation successfully validated for %s" % vpc_offering.name) + self.debug("Successfully validated the creation and state of VPC offering - %s" % vpc_offering.name) - # validate_Vpc - Validates the given VPC, - # matches the given VPC name and state against the list of VPCs fetched + # validate_Vpc - Validates the given VPC, matches the given VPC name and state against the list of VPCs fetched def validate_Vpc(self, vpc, state=None): """Validates the VPC""" - self.debug("Check if the VPC is created successfully ?") + self.debug("Validating the creation and state of VPC - %s" % vpc.name) vpcs = VPC.list(self.api_client, id=vpc.id ) @@ -466,15 +555,15 @@ def validate_Vpc(self, vpc, state=None): ) if state: self.assertEqual(vpcs[0].state, state, - "VPC state should be in state - %s" % state + "VPC state should be '%s'" % state ) - self.debug("VPC creation successfully validated for %s" % vpc.name) + self.debug("Successfully validated the creation and state of VPC - %s" % vpc.name) - # validate_NetworkOffering - Validates the given Network offering, - # matches the given network offering name and state against the list of network offerings fetched + # validate_NetworkOffering - Validates the given Network offering, matches the given network offering name and state + # against the list of network offerings fetched def validate_NetworkOffering(self, net_offering, state=None): """Validates the Network offering""" - self.debug("Check if the Network offering is created successfully ?") + self.debug("Validating the creation and state of Network offering - %s" % net_offering.name) net_offs = NetworkOffering.list(self.api_client, id=net_offering.id ) @@ -486,15 +575,15 @@ def validate_NetworkOffering(self, net_offering, state=None): ) if state: self.assertEqual(net_offs[0].state, state, - "Network offering state should be in state - %s" % state + "Network offering state should be '%s'" % state ) - self.debug("Network offering creation successfully validated for %s" % net_offering.name) + self.debug("Successfully validated the creation and state of Network offering - %s" % net_offering.name) - # validate_Network - Validates the given network, - # matches the given network name and state against the list of networks fetched + # validate_Network - Validates the given network, matches the given network name and state against the list of + # networks fetched def validate_Network(self, network, state=None): - """Validates the Network""" - self.debug("Check if the network is created successfully ?") + """Validates the network""" + self.debug("Validating the creation and state of Network - %s" % network.name) networks = Network.list(self.api_client, id=network.id ) @@ -506,14 +595,14 @@ def validate_Network(self, network, state=None): ) if state: self.assertEqual(networks[0].state, state, - "Network state should be in state - %s" % state + "Network state should be '%s'" % state ) - self.debug("Network creation successfully validated for %s" % network.name) + self.debug("Successfully validated the creation and state of Network - %s" % network.name) # check_VM_state - Checks if the given VM is in the expected state form the list of fetched VMs def check_VM_state(self, vm, state=None): """Validates the VM state""" - self.debug("Check if the VM instance is in state - %s" % state) + self.debug("Validating the deployment and state of VM - %s" % vm.name) vms = VirtualMachine.list(self.api_client, id=vm.id, listall=True @@ -525,12 +614,12 @@ def check_VM_state(self, vm, state=None): self.assertEqual(vms[0].state, state, "Virtual machine is not in the expected state" ) - self.debug("Virtual machine instance - %s is in the expected state - %s" % (vm.name, state)) + self.debug("Successfully validated the deployment and state of VM - %s" % vm.name) # check_Router_state - Checks if the given router is in the expected state form the list of fetched routers def check_Router_state(self, router, state=None): """Validates the Router state""" - self.debug("Check if the virtual router instance is in state - %s" % state) + self.debug("Validating the deployment and state of Router - %s" % router.name) routers = Router.list(self.api_client, id=router.id, listall=True @@ -542,13 +631,13 @@ def check_Router_state(self, router, state=None): self.assertEqual(routers[0].state, state, "Virtual router is not in the expected state" ) - self.debug("Virtual router instance - %s is in the expected state - %s" % (router.name, state)) + self.debug("Successfully validated the deployment and state of Router - %s" % router.name) # validate_PublicIPAddress - Validates if the given public IP address is in the expected state form the list of # fetched public IP addresses def validate_PublicIPAddress(self, public_ip, network, static_nat=False, vm=None): """Validates the Public IP Address""" - self.debug("Check if the public IP is successfully assigned to the network ?") + self.debug("Validating the assignment and state of public IP address - %s" % public_ip.ipaddress.ipaddress) public_ips = PublicIPAddress.list(self.api_client, id=public_ip.ipaddress.id, networkid=network.id, @@ -566,20 +655,22 @@ def validate_PublicIPAddress(self, public_ip, network, static_nat=False, vm=None ) if static_nat and vm: self.assertEqual(public_ips[0].virtualmachineid, vm.id, - "Static NAT Rule not enabled for the VM using the assigned public IP" + "Static NAT rule is not enabled for the VM on the assigned public IP" ) - self.debug("Assigned Public IP address - %s is successfully validated" % public_ip.ipaddress.ipaddress) + self.debug("Successfully validated the assignment and state of public IP address - %s" % + public_ip.ipaddress.ipaddress) # VSD verifications # VSD is a programmable policy and analytics engine of Nuage VSP SDN platform - # get_externalID - Returns corresponding external ID of the given object in VSD - def get_externalID(self, object_id): - return object_id + "@" + self.cms_id + # get_externalID_filter - Returns corresponding external ID filter of the given object in VSD + def get_externalID_filter(self, object_id): + ext_id = object_id + "@" + self.cms_id + return self.vsd.set_externalID_filter(ext_id) # fetch_by_externalID - Returns VSD object with the given external ID def fetch_by_externalID(self, fetcher, *cs_objects): - """ Fetches a child object by external ID using the given fetcher, and uuids of the given cloudstack objects. + """ Fetches a child object by external id using the given fetcher, and uuids of the given cloudstack objects. E.G. - fetch_by_external_id(vsdk.NUSubnet(id="954de425-b860-410b-be09-c560e7dbb474").vms, cs_vm) - fetch_by_external_id(session.user.floating_ips, cs_network, cs_public_ip) @@ -589,162 +680,148 @@ def fetch_by_externalID(self, fetcher, *cs_objects): """ return fetcher.get_first(filter="externalID BEGINSWITH '%s'" % ":".join([o.id for o in cs_objects])) - # verify_vsp_network - Verifies the given domain and network/VPC - # against the corresponding installed enterprise, domain, zone, and subnet in VSD - def verify_vsp_network(self, domain_id, network, vpc=None): - vsd_enterprise = self.vsd.get_enterprise(name=domain_id) - if vpc: - ext_network_id = self.get_externalID(vpc.id) - else: - ext_network_id = self.get_externalID(network.id) - ext_subnet_id = self.get_externalID(network.id) - vsd_domain = self.vsd.get_domain(externalID=ext_network_id) - vsd_zone = self.vsd.get_zone(externalID=ext_network_id) - vsd_subnet = self.vsd.get_subnet(externalID=ext_subnet_id) - self.debug("SHOW ENTERPRISE DATA FORMAT IN VSD") - self.debug(vsd_enterprise) - self.assertNotEqual(vsd_enterprise, None, - "VSD Enterprise data format should not be a None type" - ) - self.debug("SHOW NETWORK DATA FORMAT IN VSD") - self.debug(vsd_domain) - self.debug(vsd_zone) - self.debug(vsd_subnet) + # verify_vsd_network - Verifies the given domain and network/VPC against the corresponding installed enterprise, + # domain, zone, and subnet in VSD + def verify_vsd_network(self, domain_id, network, vpc=None): + self.debug("Verifying the creation and state of Network - %s in VSD" % network.name) + vsd_enterprise = self.vsd.get_enterprise(filter=self.get_externalID_filter(domain_id)) + ext_network_filter = self.get_externalID_filter(vpc.id) if vpc else self.get_externalID_filter(network.id) + vsd_domain = self.vsd.get_domain(filter=ext_network_filter) + vsd_zone = self.vsd.get_zone(filter=ext_network_filter) + vsd_subnet = self.vsd.get_subnet(filter=self.get_externalID_filter(network.id)) + self.assertEqual(vsd_enterprise.name, domain_id, + "VSD enterprise name should match CloudStack domain uuid" + ) if vpc: - self.assertEqual(vsd_domain["description"], "VPC_" + vpc.name, + self.assertEqual(vsd_domain.description, "VPC_" + vpc.name, "VSD domain description should match VPC name in CloudStack" ) - self.assertEqual(vsd_zone["description"], "VPC_" + vpc.name, + self.assertEqual(vsd_zone.description, "VPC_" + vpc.name, "VSD zone description should match VPC name in CloudStack" ) else: - self.assertEqual(vsd_domain["description"], network.name, + self.assertEqual(vsd_domain.description, network.name, "VSD domain description should match network name in CloudStack" ) - self.assertEqual(vsd_zone["description"], network.name, + self.assertEqual(vsd_zone.description, network.name, "VSD zone description should match network name in CloudStack" ) - self.assertEqual(vsd_subnet["description"], network.name, + self.assertEqual(vsd_subnet.description, network.name, "VSD subnet description should match network name in CloudStack" ) - - # verify_vsp_vm - Verifies the given VM deployment and state in VSD - def verify_vsp_vm(self, vm, stopped=None): - ext_vm_id = self.get_externalID(vm.id) + self.debug("Successfully verified the creation and state of Network - %s in VSD" % network.name) + + # verify_vsd_vm - Verifies the given VM deployment and state in VSD + def verify_vsd_vm(self, vm, stopped=None): + self.debug("Verifying the deployment and state of VM - %s in VSD" % vm.name) + vsd_vm = self.vsd.get_vm(filter=self.get_externalID_filter(vm.id)) + self.assertNotEqual(vsd_vm, None, + "VM data format in VSD should not be of type None" + ) for nic in vm.nic: - ext_network_id = self.get_externalID(nic.networkid) - ext_nic_id = self.get_externalID(nic.id) - vsd_vport = self.vsd.get_vport(subnet_externalID=ext_network_id, vport_externalID=ext_nic_id) - vsd_vm_interface = self.vsd.get_vm_interface(externalID=ext_nic_id) - self.debug("SHOW VPORT and VM INTERFACE DATA FORMAT IN VSD") - self.debug(vsd_vport) - self.debug(vsd_vm_interface) - self.assertEqual(vsd_vport["active"], True, + vsd_subnet = self.vsd.get_subnet(filter=self.get_externalID_filter(nic.networkid)) + vsd_vport = self.vsd.get_vport(subnet=vsd_subnet, filter=self.get_externalID_filter(nic.id)) + vsd_vm_interface = self.vsd.get_vm_interface(filter=self.get_externalID_filter(nic.id)) + self.assertEqual(vsd_vport.active, True, "VSD VM vport should be active" ) - self.assertEqual(vsd_vm_interface["IPAddress"], nic.ipaddress, + self.assertEqual(vsd_vm_interface.ip_address, nic.ipaddress, "VSD VM interface IP address should match VM's NIC IP address in CloudStack" ) - vsd_vm = self.vsd.get_vm(externalID=ext_vm_id) - self.debug("SHOW VM DATA FORMAT IN VSD") - self.debug(vsd_vm) if not self.isSimulator: if stopped: - self.assertEqual(vsd_vm["status"], "DELETE_PENDING", + self.assertEqual(vsd_vm.status, "DELETE_PENDING", "VM state in VSD should be DELETE_PENDING" ) else: - self.assertEqual(vsd_vm["status"], vm.state.upper(), + self.assertEqual(vsd_vm.status, vm.state.upper(), "VM state in VSD should match its state in CloudStack" ) - - # verify_vsp_router - Verifies the given network router deployment and state in VSD - def verify_vsp_router(self, router, stopped=None): - ext_router_id = self.get_externalID(router.id) - vsd_router = self.vsd.get_vm(externalID=ext_router_id) - self.debug("SHOW VIRTUAL ROUTER DATA FORMAT IN VSD") - self.debug(vsd_router) + self.debug("Successfully verified the deployment and state of VM - %s in VSD" % vm.name) + + # verify_vsd_router - Verifies the given network router deployment and state in VSD + def verify_vsd_router(self, router, stopped=None): + self.debug("Verifying the deployment and state of Router - %s in VSD" % router.name) + vsd_router = self.vsd.get_vm(filter=self.get_externalID_filter(router.id)) + self.assertNotEqual(vsd_router, None, + "Router data format in VSD should not be of type None" + ) if not self.isSimulator: if stopped: - self.assertEqual(vsd_router["status"], "DELETE_PENDING", + self.assertEqual(vsd_router.status, "DELETE_PENDING", "Router state in VSD should be DELETE_PENDING" ) else: - self.assertEqual(vsd_router["status"], router.state.upper(), + self.assertEqual(vsd_router.status, router.state.upper(), "Router state in VSD should match its state in CloudStack" ) - - # verify_vsp_LB_device - Verifies the given LB device deployment and state in VSD - def verify_vsp_LB_device(self, lb_device, stopped=None): - ext_lb_device_id = self.get_externalID(lb_device.id) - vsd_lb_device = self.vsd.get_vm(externalID=ext_lb_device_id) - self.debug("SHOW LB Device DATA FORMAT IN VSD") - self.debug(vsd_lb_device) + self.debug("Successfully verified the deployment and state of Router - %s in VSD" % router.name) + + # verify_vsd_lb_device - Verifies the given LB device deployment and state in VSD + def verify_vsd_lb_device(self, lb_device, stopped=None): + self.debug("Verifying the deployment and state of LB device - %s in VSD" % lb_device.name) + vsd_lb_device = self.vsd.get_vm(filter=self.get_externalID_filter(lb_device.id)) + self.assertNotEqual(vsd_lb_device, None, + "LB device data format in VSD should not be of type None" + ) if not self.isSimulator: if stopped: - self.assertEqual(vsd_lb_device['status'], "DELETE_PENDING", + self.assertEqual(vsd_lb_device.status, "DELETE_PENDING", "LB device state in VSD should be DELETE_PENDING" ) else: - self.assertEqual(vsd_lb_device['status'], lb_device.state.upper(), + self.assertEqual(vsd_lb_device.status, lb_device.state.upper(), "LB device state in VSD should match its state in CloudStack" ) - - # verify_vsp_floating_ip - Verifies the static nat rule on the given public IP of the given network and VM - # against the corresponding installed FIP in VSD - def verify_vsp_floating_ip(self, network, vm, public_ipaddress, vpc=None): - if vpc: - ext_fip_id = self.get_externalID(vpc.id + ":" + public_ipaddress.id) - else: - ext_fip_id = self.get_externalID(network.id + ":" + public_ipaddress.id) - vsd_fip = self.vsd.get_floating_ip(externalID=ext_fip_id) - self.debug("SHOW FLOATING IP DATA FORMAT IN VSD") - self.debug(vsd_fip) - self.assertEqual(vsd_fip["address"], public_ipaddress.ipaddress, + self.debug("Successfully verified the deployment and state of LB device - %s in VSD" % lb_device.name) + + # verify_vsd_floating_ip - Verifies the Static NAT rule on the given public IP of the given VM in the given network + # against the corresponding installed Floating IP in VSD + def verify_vsd_floating_ip(self, network, vm, public_ipaddress, vpc=None): + self.debug("Verifying the assignment and state of public IP address - %s in VSD" % public_ipaddress.ipaddress) + ext_fip_filter = self.get_externalID_filter(vpc.id + ":" + public_ipaddress.id) if vpc else \ + self.get_externalID_filter(network.id + ":" + public_ipaddress.id) + vsd_fip = self.vsd.get_floating_ip(filter=ext_fip_filter) + self.assertEqual(vsd_fip.address, public_ipaddress.ipaddress, "Floating IP address in VSD should match acquired public IP address in CloudStack" ) - if vpc: - ext_network_id = self.get_externalID(vpc.id) - else: - ext_network_id = self.get_externalID(network.id) - vsd_domain = self.vsd.get_domain(externalID=ext_network_id) - self.debug("SHOW NETWORK DATA FORMAT IN VSD") - self.debug(vsd_domain) - self.assertEqual(vsd_domain["ID"], vsd_fip["parentID"], - "Floating IP in VSD should be associated with the correct VSD domain, " - "which in turn should correspond to the correct VPC (or) network in CloudStack" + self.assertEqual(vsd_fip.assigned, True, + "Floating IP in VSD should be assigned" + ) + ext_network_filter = self.get_externalID_filter(vpc.id) if vpc else self.get_externalID_filter(network.id) + vsd_domain = self.vsd.get_domain(filter=ext_network_filter) + self.assertEqual(vsd_domain.id, vsd_fip.parent_id, + "Floating IP in VSD should be associated with the correct VSD domain, which in turn should " + "correspond to the correct VPC (or) network in CloudStack" ) - ext_subnet_id = self.get_externalID(network.id) - vsd_subnet = self.vsd.get_subnet(externalID=ext_subnet_id) + vsd_subnet = self.vsd.get_subnet(filter=self.get_externalID_filter(network.id)) for nic in vm.nic: - if nic.networkname == vsd_subnet["description"]: - ext_network_id = self.get_externalID(nic.networkid) - ext_nic_id = self.get_externalID(nic.id) - vsd_vport = self.vsd.get_vport(subnet_externalID=ext_network_id, vport_externalID=ext_nic_id) - self.debug("SHOW VM VPORT DATA FORMAT IN VSD") - self.debug(vsd_vport) - self.assertEqual(vsd_vport["associatedFloatingIPID"], vsd_fip["ID"], - "Floating IP in VSD should be associated to the correct VSD vport, " - "which in turn should correspond to the correct Static NAT enabled VM " - "and network in CloudStack" + if nic.networkid == network.id: + vsd_vport = self.vsd.get_vport(subnet=vsd_subnet, filter=self.get_externalID_filter(nic.id)) + self.assertEqual(vsd_vport.associated_floating_ip_id, vsd_fip.id, + "Floating IP in VSD should be associated to the correct VSD vport, which in turn should " + "correspond to the correct Static NAT rule enabled VM and network in CloudStack" + ) + self.debug("Successfully verified the assignment and state of public IP address - %s in VSD" % + public_ipaddress.ipaddress) + + # verify_vsd_firewall_rule - Verifies the given Network Firewall (Ingress/Egress ACL) rule against the corresponding + # installed firewall rule in VSD + def verify_vsd_firewall_rule(self, firewall_rule, traffic_type="Ingress"): + self.debug("Verifying the creation and state of Network Firewall (Ingress/Egress ACL) rule with ID - %s in VSD" + % firewall_rule.id) + ext_fw_rule_filter = self.get_externalID_filter(firewall_rule.id) + vsd_fw_rule = self.vsd.get_egress_acl_entry(filter=ext_fw_rule_filter) if traffic_type is "Ingress" else \ + self.vsd.get_ingress_acl_entry(filter=ext_fw_rule_filter) + self.assertEqual(vsd_fw_rule.policy_state, "LIVE", + "Ingress/Egress ACL rule's policy state in VSD should be LIVE" ) - - # verify_vsp_firewall_rule - Verifies the given Ingress/Egress firewall rule - # against the corresponding installed firewall rule in VSD - def verify_vsp_firewall_rule(self, firewall_rule, traffic_type="Ingress"): - ext_fw_id = self.get_externalID(firewall_rule.id) - if traffic_type is "Ingress": - vsd_fw_rule = self.vsd.get_egress_acl_entry(externalID=ext_fw_id) - else: - vsd_fw_rule = self.vsd.get_ingress_acl_entry(externalID=ext_fw_id) - self.debug("SHOW ACL ENTRY IN VSD") - self.debug(vsd_fw_rule) dest_port = str(firewall_rule.startport) + "-" + str(firewall_rule.endport) - self.assertEqual(vsd_fw_rule["destinationPort"], dest_port, - "Destination port in VSD should match destination port in CloudStack" + self.assertEqual(vsd_fw_rule.destination_port, dest_port, + "Ingress/Egress ACL rule's destination port in VSD should match corresponding rule's " + "destination port in CloudStack" ) - vsd_protocol = str(vsd_fw_rule["protocol"]) - self.debug("vsd protocol - %s" % vsd_protocol) + vsd_protocol = int(vsd_fw_rule.protocol) protocol = "tcp" if vsd_protocol == 6: protocol = "tcp" @@ -753,5 +830,8 @@ def verify_vsp_firewall_rule(self, firewall_rule, traffic_type="Ingress"): elif vsd_protocol == 17: protocol = "udp" self.assertEqual(protocol, firewall_rule.protocol.lower(), - "Protocol in VSD should match protocol in CloudStack" + "Ingress/Egress ACL rule's protocol in VSD should match corresponding rule's protocol in " + "CloudStack" ) + self.debug("Successfully verified the creation and state of Network Firewall (Ingress/Egress ACL) rule with ID " + "- %s in VSD" % firewall_rule.id) diff --git a/test/integration/plugins/nuagevsp/test_nuage_password_reset.py b/test/integration/plugins/nuagevsp/test_nuage_password_reset.py index ee028c2c54..bd8bba6ac7 100644 --- a/test/integration/plugins/nuagevsp/test_nuage_password_reset.py +++ b/test/integration/plugins/nuagevsp/test_nuage_password_reset.py @@ -24,7 +24,6 @@ VirtualMachine, Volume) from marvin.lib.common import list_templates -from marvin.lib.utils import cleanup_resources from marvin.cloudstackAPI import updateTemplate # Import System Modules from nose.plugins.attrib import attr @@ -41,130 +40,100 @@ def setUpClass(cls): return def setUp(self): - self.cleanup = [] - self.apiclient = self.testClient.getApiClient() - - self.account = Account.create( - self.apiclient, - self.test_data["account"], - admin=True, - domainid=self.domain.id - ) - - self.cleanup.append(self.account) - self.remove_vm2 = False + # Create an account + self.account = Account.create(self.api_client, + self.test_data["account"], + admin=True, + domainid=self.domain.id + ) + self.cleanup = [self.account] return - # tearDown() - Cleans up the setup, removes the VMs - def tearDown(self): - self.debug("CLEANUP: TEARDOWN") - self.apiclient = self.testClient.getApiClient() - self.updateTemplate(self.defaultTemplateVal) - self.vm_1.delete(self.apiclient, expunge=True) - if self.remove_vm2: - self.vm_2.delete(self.apiclient, expunge=True) - try: - cleanup_resources(self.apiclient, self.cleanup) - except Exception as e: - self.debug("Warning: Exception during cleanup: %s" % e) - return - - # create_template - Creates template with the given VM object + # create_template - Creates guest VM template with the given VM object def create_template(self, vm): - self.debug("Creating template") - list_volume = Volume.list(self.apiclient, + self.debug("Creating guest VM template") + list_volume = Volume.list(self.api_client, virtualmachineid=vm.id, type='ROOT', - listall=True) + listall=True + ) if isinstance(list_volume, list): self.volume = list_volume[0] else: raise Exception("Exception: Unable to find root volume for VM with ID - %s" % vm.id) - self.pw_enabled_template = Template.create( - self.apiclient, - self.test_data["template"], - self.volume.id, - account=self.account.name, - domainid=self.account.domainid - ) - self.assertEqual(self.pw_enabled_template.passwordenabled, True, "template is not passwordenabled") + self.pw_enabled_template = Template.create(self.api_client, + self.test_data["template"], + self.volume.id, + account=self.account.name, + domainid=self.account.domainid + ) + self.assertEqual(self.pw_enabled_template.passwordenabled, True, + "template is not passwordenabled" + ) self.cleanup.append(self.pw_enabled_template) - self.debug("Created template") + self.debug("Created guest VM template") - # updateTemplate - Updates value of template's password enabled setting + # updateTemplate - Updates value of the guest VM template's password enabled setting def updateTemplate(self, value): - self.debug("Updating value of template's password enabled setting") + self.debug("Updating value of guest VM template's password enabled setting") cmd = updateTemplate.updateTemplateCmd() cmd.id = self.template.id cmd.passwordenabled = value - self.apiclient.updateTemplate(cmd) - list_template_response = list_templates(self.apiclient, + self.api_client.updateTemplate(cmd) + list_template_response = list_templates(self.api_client, templatefilter="all", id=self.template.id ) self.template = list_template_response[0] - self.debug("Updated template") - - # VM object is passed as an argument and its interface id is returned - def get_vm_interface_id(self, vm): - self.debug("GET VM INTERFACE ID") - nic_ext_id = self.get_externalID(vm.nic[0].id) - vm_interface = self.vsd.get_vm_interface(externalID=nic_ext_id) - vm_interface_id = vm_interface["ID"] - return vm_interface_id + self.debug("Updated guest VM template") - # VM object is passed as an argument and its userdata URL is returned + # get_userdata_url - Returns user data URL for the given VM object def get_userdata_url(self, vm): - self.debug("GET USER DATA URL") + self.debug("Getting user data url") nic = vm.nic[0] gateway = str(nic.gateway) - self.debug("GATEWAY: " + gateway) + self.debug("Gateway: " + gateway) user_data_url = 'curl "http://' + gateway + ':80/latest/user-data"' return user_data_url - # Creates and verifies the firewall rule + # create_and_verify_fw - Creates and verifies (Ingress) firewall rule with a Static NAT rule enabled public IP def create_and_verify_fw(self, vm, public_ip, network): - self.debug("Create and verify firewall rule") + self.debug("Creating and verifying firewall rule") self.create_StaticNatRule_For_VM(vm, public_ip, network) # VSD verification - self.verify_vsp_floating_ip(network, vm, public_ip.ipaddress) + self.verify_vsd_floating_ip(network, vm, public_ip.ipaddress) fw_rule = self.create_FirewallRule(public_ip, self.test_data["ingress_rule"]) - self.verify_vsp_firewall_rule(fw_rule) - vm_interface_id = self.get_vm_interface_id(vm) - pd = self.vsd.get_vm_interface_policydecisions(id=vm_interface_id) - self.debug(pd) - egressAcls = pd['egressACLs'][0]['entries'] - gotFirewallPolicy = False - for acl in egressAcls: - if acl['destinationPort'] == "22-22": - gotFirewallPolicy = True - break - if not gotFirewallPolicy: - raise ValueError('No firewall policy decision in vm interface') + # VSD verification + self.verify_vsd_firewall_rule(fw_rule) + self.debug("Successfully created and verified firewall rule") + + # stop_vm - Stops the given VM, and verifies its state def stop_vm(self, vm): self.debug("Stoping VM") - vm.stop(self.apiclient) - list_vm_response = VirtualMachine.list(self.apiclient, - id=vm.id) + vm.stop(self.api_client) + list_vm_response = VirtualMachine.list(self.api_client, + id=vm.id + ) if isinstance(list_vm_response, list): vm = list_vm_response[0] if vm.state != 'Stopped': - raise Exception("Failed to stop VM (ID: %s) " % - self.vm.id) + raise Exception("Failed to stop VM (ID: %s) " % self.vm.id) else: - raise Exception("Invalid response from list_virtual_machines VM (ID: %s) " % - self.vm.id) + raise Exception("Invalid response from list_virtual_machines VM (ID: %s) " % self.vm.id) + self.debug("Stopped VM") + # install_cloud_set_guest_password_script - Installs the cloud-set-guest-password script from people.apache.org in + # the given VM (SSH client) def install_cloud_set_guest_password_script(self, ssh_client): - self.debug("GET CLOUD-SET-GUEST-PASSWORD") + self.debug("Installing cloud-set-guest-password script") cmd = "cd /etc/init.d;wget http://people.apache.org/~tsp/cloud-set-guest-password" result = self.execute_cmd(ssh_client, cmd) - self.debug("WGET CLOUD-SET-GUEST-PASSWORD: " + result) + self.debug("wget file cloud-set-guest-password: " + result) if "200 OK" not in result: - self.fail("failed to get file cloud-set-guest-password") + self.fail("failed to wget file cloud-set-guest-password") cmds = ["chmod +x /etc/init.d/cloud-set-guest-password", "chkconfig --add cloud-set-guest-password" ] @@ -172,123 +141,145 @@ def install_cloud_set_guest_password_script(self, ssh_client): result = self.execute_cmd(ssh_client, c) self.debug("get_set_password_file cmd " + c) self.debug("get_set_password_file result " + result) + self.debug("Installed cloud-set-guest-password script") @attr(tags=["advanced", "nuagevsp"], required_hardware="true") def test_nuage_UserDataPasswordReset(self): """Test user data and password reset functionality with Nuage VSP SDN plugin """ - """ - Validate the following: - 1) user data - 2) reset vm password. - - Steps: - 1. Set password enabled to false in the template. - 2. Create an Isolated network - Test Network (10.1.1.1/24). - 3. Deploy VM1 in Test Network - 4. Verify domain,zone subnet, vm. - 5. create public IP, Create Static Nat rule firewall rule and verify - 6. SSH to VM should be successful - 7. verify userdata - 8. check cloud-set-guest-password exist. - 9. if cloud-set-guest-password exist. - 9.1 change template password enabled to true - 9.2 verify that template is password enbalded - 9.3 SSH with new password should be successful - 10. else cloud-set-guest-password does not exist. - 10.1 get the cloud-set-guest-password file - 10.2 stop vm - 10.3 create a new template with password enabled. Verify that template is password enabled. - 10.4 create vm 2 with new template in Test Network - 10.5 Verify vm. - 10.6 create public IP, Create Static Nat rule firewall rule and verify - 10.7 SSH to VM 2 should be successful - 11. Reset VM password (VM_1 if guest password file exist. else it is VM2) - 12 Starting VM and SSH to VM to verify new password - """ - - self.debug("TEST USER DATA & PASSWORD RESET ON VM") + # 1. Create an Isolated Network with Nuage VSP Isolated Network offering, check if it is successfully created + # and is in the "Allocated" state. + # 2. Set password enabled to false in the guest VM template. + # 3. Deploy a VM in the created Isolated network with user data, check if the Isolated network state is changed + # to "Implemented", and both the VM & VR are successfully deployed and are in the "Running" state. + # 4. Verify that the guest VM template is not password enabled by checking the deployed VM's password + # (password == "password"). + # 5. SSH into the deployed VM and verify its user data (expected user data == actual user data). + # 6. Check for cloud-set-guest-password script in the deployed VM for testing password reset functionality. + # 7. if cloud-set-guest-password script does not exist in the deployed VM: + # 7.1 Install the cloud-set-guest-password script from people.apache.org in the deployed VM. + # 7.2 Stop the deployed VM, and create a new password enabled guest VM template with it. + # 7.3 Deploy a new VM in the created Isolated network with the newly created guest VM template, + # check if the VM is successfully deployed and is in the "Running" state. + # 7.4 Verify that the new guest VM template is password enabled by checking the newly deployed VM's + # password (password != "password"). + # 7.5 SSH into the newly deployed VM for verifying its password. + # 8. else cloud-set-guest-password script exists in the deployed VM: + # 8.1 Change password enabled to true in the guest VM template. + # 8.2 Verify that the guest VM template is password enabled. + # 9. Reset VM password, and start the VM. + # 10. Verify that the new guest VM template is password enabled by checking the VM's password + # (password != "password"). + # 11. SSH into the VM for verifying its new password after its password reset. + # 12. Set password enabled to the default value in the guest VM template. + # 13. Delete all the created objects (cleanup). + + self.debug("Testing user data & password reset functionality in an Isolated network...") + + self.debug("Creating an Isolated network...") + net_off = self.create_NetworkOffering(self.test_data["nuagevsp"]["isolated_network_offering"]) + self.network = self.create_Network(net_off) + self.validate_Network(self.network, state="Allocated") + self.debug("Setting password enabled to false in the guest VM template...") self.defaultTemplateVal = self.template.passwordenabled if self.template.passwordenabled: self.updateTemplate(False) - self.debug("CREATE AN ISOLATED NETWORK") - net_off = self.create_NetworkOffering(self.test_data["nuagevsp"]["isolated_network_offering"]) - self.network_1 = self.create_Network(net_off) - self.cleanup.append(self.network_1) - expUserData = "hello world vm1" - userdata = base64.b64encode(expUserData) - self.test_data["virtual_machine_userdata"]["userdata"] = userdata - self.debug("DEPLOY VM 1 IN TEST NETWORK") - # Pass the network and name of the vm type from the testdata with the configuration for the vm - self.vm_1 = self.create_VM(self.network_1, vm_key="virtual_machine_userdata") - - self.vm_1.password = self.test_data["virtual_machine_userdata"]["password"] - user_data_cmd = self.get_userdata_url(self.vm_1) + self.debug("Deploying a VM in the created Isolated network with user data...") + expected_user_data = "hello world vm1" + user_data = base64.b64encode(expected_user_data) + self.test_data["virtual_machine_userdata"]["userdata"] = user_data + self.vm_1 = self.create_VM(self.network, testdata=self.test_data["virtual_machine_userdata"]) + self.validate_Network(self.network, state="Implemented") + vr = self.get_Router(self.network) + self.check_Router_state(vr, state="Running") + self.check_VM_state(self.vm_1, state="Running") # VSD verification - self.debug("VERIFY DOMAIN, ZONE, NETWORK , and VM 1") - self.verify_vsp_network(self.domain.id, self.network_1) - self.verify_vsp_vm(self.vm_1) - - self.debug("CREATE PUBLIC IP, STATIC NAT RULE, FLOATING IP, FIREWALL AND VERIFY") - public_ip_1 = self.acquire_PublicIPAddress(self.network_1) - self.create_and_verify_fw(self.vm_1, public_ip_1, self.network_1) - - self.debug("SSH TO VM") + self.verify_vsd_network(self.domain.id, self.network) + self.verify_vsd_router(vr) + self.verify_vsd_vm(self.vm_1) + + self.debug("verifying that the guest VM template is not password enabled...") + self.debug("VM - %s password - %s !" % (self.vm_1.name, self.vm_1.password)) + self.assertEqual(self.vm_1.password, self.test_data["virtual_machine_userdata"]["password"], + "Password is enabled for the VM (vm_1)" + ) + + self.debug("SSHing into the VM for verifying its user data...") + public_ip_1 = self.acquire_PublicIPAddress(self.network) + self.create_and_verify_fw(self.vm_1, public_ip_1, self.network) ssh = self.ssh_into_VM(self.vm_1, public_ip_1) - - self.debug("VERIFY USER DATA") - self.debug("Get User Data with command: " + user_data_cmd) - adata = self.execute_cmd(ssh, user_data_cmd) - actUserData = base64.b64decode(adata) - self.debug("Response User Data=" + actUserData + ", Expected=" + expUserData) - self.assertEqual(actUserData, expUserData, "User Data Did Not Match ") - - # check /etc/init.d/cloud-set-quest-password + user_data_cmd = self.get_userdata_url(self.vm_1) + self.debug("Getting user data with command: " + user_data_cmd) + actual_user_data = base64.b64decode(self.execute_cmd(ssh, user_data_cmd)) + self.debug("Actual user data - " + actual_user_data + ", Expected user data - " + expected_user_data) + self.assertEqual(actual_user_data, expected_user_data, + "Un-expected VM (VM_1) user data" + ) + + self.debug("Checking for cloud-set-guest-password script in the VM for testing password reset functionality...") ls_cmd = "ls /etc/init.d/cloud-set-guest-password" ls_result = self.execute_cmd(ssh, ls_cmd) ls_result = ls_result.lower() - self.debug("reponse from ls_cmd: " + ls_result) + self.debug("Response from ls_cmd: " + ls_result) if "no such file" in ls_result: - self.debug("NO CLOUD-SET_GUEST_PASSWORD FILE. NEED TO GET ONE") + self.debug("No cloud-set-guest-password script in the VM") + self.debug("Installing the cloud-set-guest-password script from people.apache.org in the VM...") self.install_cloud_set_guest_password_script(ssh) + self.debug("Stopping the VM, and creating a new password enabled guest VM template with it...") self.stop_vm(self.vm_1) self.create_template(self.vm_1) - self.debug("DEPLOY VM 2 IN TEST NETWORK WITH NEW TEMPLATE") - self.vm_2 = self.create_VM(self.network_1, vm_key="virtual_machine_userdata") - self.remove_vm2 = True - self.debug("STARTING VM_2 ") - vm_2a = self.vm_2.start(self.apiclient) + + self.debug("Deploying a new VM in the created Isolated network with the newly created guest VM template...") + self.vm_2 = self.create_VM(self.network, testdata=self.test_data["virtual_machine_userdata"]) + self.debug("Starting the VM...") + vm_2a = self.vm_2.start(self.api_client) self.vm_2.password = vm_2a.password.strip() self.vm_2.nic = vm_2a.nic + + # VSD verification + self.verify_vsd_vm(self.vm_2) + + self.debug("verifying that the guest VM template is password enabled...") self.debug("VM - %s password - %s !" % (self.vm_2.name, self.vm_2.password)) - self.assertNotEqual(self.vm_2.password, - self.test_data["virtual_machine_userdata"]["password"], - "Password enabled not working. Password same as virtual_machine password " + self.assertNotEqual(self.vm_2.password, self.test_data["virtual_machine_userdata"]["password"], + "Password is not enabled for the VM" ) - self.verify_vsp_vm(vm_2a) - self.debug("GET PUBLIC IP. CREATE AND VERIFIED FIREWALL RULES") - public_ip_2 = self.acquire_PublicIPAddress(self.network_1) - self.create_and_verify_fw(self.vm_2, public_ip_2, self.network_1) + self.debug("SSHing into the VM for verifying its password...") + public_ip_2 = self.acquire_PublicIPAddress(self.network) + self.create_and_verify_fw(self.vm_2, public_ip_2, self.network) self.ssh_into_VM(self.vm_2, public_ip_2) + vm_test = self.vm_2 vm_test_public_ip = public_ip_2 - else: - self.debug("UPDATE TEMPLATE TO PASSWORD ENABLED") + self.debug("Updating the guest VM template to password enabled") self.updateTemplate(True) - self.assertEqual(self.template.passwordenabled, True, "Template is not password enabled") + self.assertEqual(self.template.passwordenabled, True, + "Guest VM template is not password enabled" + ) vm_test = self.vm_1 vm_test_public_ip = public_ip_1 - self.debug("RESETTING VM PASSWORD for VM - %s" % vm_test.name) - vm_test.password = vm_test.resetPassword(self.apiclient) + self.debug("Resetting password for VM - %s" % vm_test.name) + vm_test.password = vm_test.resetPassword(self.api_client) self.debug("Password reset to - %s" % vm_test.password) - self.debug("STARTING VM AND SSH TO VM TO VERIFY NEW PASSWORD") - vm_test.start(self.apiclient) - self.debug("VM - %s started!" % vm_test.name) + + self.debug("Starting the VM") + vm_test.start(self.api_client) + + self.debug("verifying that the guest VM template is password enabled...") + self.debug("VM - %s password - %s !" % (vm_test.name, vm_test.password)) + self.assertNotEqual(vm_test.password, self.test_data["virtual_machine_userdata"]["password"], + "Password is not enabled for the VM" + ) + + self.debug("SSHing into the VM for verifying its new password after its password reset...") self.ssh_into_VM(vm_test, vm_test_public_ip) + + self.debug("Setting password enabled to the default value in the guest VM template...") + self.updateTemplate(self.defaultTemplateVal) diff --git a/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py b/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py index 5a0d759fdd..0814689759 100644 --- a/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py +++ b/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py @@ -136,7 +136,7 @@ def start_InternalLbVm(self, int_lb_vm): cmd.id = int_lb_vm.id self.api_client.startInternalLoadBalancerVM(cmd) - # check_InternalLbVm_state - Checks if the Internal LB VM instance of the given VPC network and source ip is in the + # check_InternalLbVm_state - Checks if the Internal LB VM instance of the given VPC network and source IP is in the # expected state form the list of fetched Internal LB VM instances def check_InternalLbVm_state(self, network, source_ip, state=None): self.debug("Check if the InternalLbVm is in state - %s" % state) @@ -220,7 +220,7 @@ def test_01_nuage_internallb_vpc_Offering(self): # 4. Create Nuage VSP VPC offering with LB service provider as "Netscaler", check if it is successfully # created and enabled. Verify that the VPC creation fails with this VPC offering as Nuage VSP does not # support provider "Netscaler" for service LB. - # 5. Delete the created VPC offerings (cleanup). + # 5. Delete all the created objects (cleanup). self.debug("Validating network service providers supported by Nuage VSP for VPC Internal LB functionality") providers = ["NuageVsp", "VpcVirtualRouter", "InternalLbVm"] @@ -271,7 +271,7 @@ def test_02_nuage_internallb_vpc_network_offering(self): """Test Nuage VSP VPC Network Offering with and without Internal LB service """ - # 1. Create Nuage Vsp VPC Network offering with LB Service Provider as "InternalLbVm" and LB Service Capability + # 1. Create Nuage VSP VPC Network offering with LB Service Provider as "InternalLbVm" and LB Service Capability # "lbSchemes" as "internal", check if it is successfully created and enabled. Verify that the VPC network # creation succeeds with this Network offering. # 2. Recreate above Network offering with ispersistent False, check if it is successfully created and enabled. @@ -279,17 +279,17 @@ def test_02_nuage_internallb_vpc_network_offering(self): # persistent VPC networks. # 3. Recreate above Network offering with conserve mode On, check if the network offering creation failed # as only networks with conserve mode Off can belong to VPC. - # 4. Create Nuage Vsp VPC Network offering with LB Service Provider as "InternalLbVm" and LB Service Capability + # 4. Create Nuage VSP VPC Network offering with LB Service Provider as "InternalLbVm" and LB Service Capability # "lbSchemes" as "public", check if the network offering creation failed as "public" lbScheme is not # supported for LB Service Provider "InternalLbVm". - # 5. Create Nuage Vsp VPC Network offering without Internal LB Service, check if it is successfully created and + # 5. Create Nuage VSP VPC Network offering without Internal LB Service, check if it is successfully created and # enabled. Verify that the VPC network creation succeeds with this Network offering. # 6. Recreate above Network offering with ispersistent False, check if it is successfully created and enabled. # Verify that the VPC network creation fails with this Network offering as Nuage VSP does not support non # persistent VPC networks. # 7. Recreate the above Network offering with conserve mode On, check if the network offering creation failed # as only networks with conserve mode Off can belong to VPC. - # 8. Delete the created Network offerings (cleanup). + # 8. Delete all the created objects (cleanup). # Creating VPC offering self.debug("Creating Nuage VSP VPC offering with Internal LB service...") @@ -328,7 +328,7 @@ def test_02_nuage_internallb_vpc_network_offering(self): self.debug("Network offering creation failed as public lbScheme is not supported for LB Service Provider " "InternalLbVm") - self.debug("Creating Nuage Vsp VPC Network offering without Internal LB service...") + self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...") net_off_3 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"]) self.validate_NetworkOffering(net_off_3, state="Enabled") @@ -351,8 +351,8 @@ def test_02_nuage_internallb_vpc_network_offering(self): self.check_Router_state(vr, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier, vpc) - self.verify_vsp_router(vr) + self.verify_vsd_network(self.domain.id, internal_tier, vpc) + self.verify_vsd_router(vr) self.debug("Creating a non persistent VPC network with Internal LB service...") with self.assertRaises(Exception): @@ -366,8 +366,8 @@ def test_02_nuage_internallb_vpc_network_offering(self): self.check_Router_state(vr, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, public_tier, vpc) - self.verify_vsp_router(vr) + self.verify_vsd_network(self.domain.id, public_tier, vpc) + self.verify_vsd_router(vr) self.debug("Creating a non persistent VPC network without Internal LB service...") with self.assertRaises(Exception): @@ -437,14 +437,14 @@ def test_03_nuage_internallb_vpc_networks(self): vr_1 = self.get_Router(internal_tier_1) self.check_Router_state(vr_1, state="Running") - self.debug("Deploying a VM in network - %s" % internal_tier_1.name) + self.debug("Deploying a VM in the created VPC network...") internal_vm_1 = self.create_VM(internal_tier_1) self.check_VM_state(internal_vm_1, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier_1, vpc_1) - self.verify_vsp_router(vr_1) - self.verify_vsp_vm(internal_vm_1) + self.verify_vsd_network(self.domain.id, internal_tier_1, vpc_1) + self.verify_vsd_router(vr_1) + self.verify_vsd_vm(internal_vm_1) self.debug("Creating one more VPC network in vpc_1 with Internal LB service...") internal_tier_2 = self.create_Network(net_off_1, gateway='10.1.2.1', vpc=vpc_1) @@ -452,14 +452,14 @@ def test_03_nuage_internallb_vpc_networks(self): vr_1 = self.get_Router(internal_tier_2) self.check_Router_state(vr_1, state="Running") - self.debug("Deploying a VM in network - %s" % internal_tier_2.name) + self.debug("Deploying a VM in the created VPC network...") internal_vm_2 = self.create_VM(internal_tier_2) self.check_VM_state(internal_vm_2, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier_2, vpc_1) - self.verify_vsp_router(vr_1) - self.verify_vsp_vm(internal_vm_2) + self.verify_vsd_network(self.domain.id, internal_tier_2, vpc_1) + self.verify_vsd_router(vr_1) + self.verify_vsd_vm(internal_vm_2) self.debug("Creating a VPC network in vpc_2 with Internal LB service...") with self.assertRaises(Exception): @@ -472,14 +472,14 @@ def test_03_nuage_internallb_vpc_networks(self): vr_1 = self.get_Router(public_tier_1) self.check_Router_state(vr_1, state="Running") - self.debug("Deploying a VM in network - %s" % public_tier_1.name) + self.debug("Deploying a VM in the created VPC network...") public_vm_1 = self.create_VM(public_tier_1) self.check_VM_state(public_vm_1, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, public_tier_1, vpc_1) - self.verify_vsp_router(vr_1) - self.verify_vsp_vm(public_vm_1) + self.verify_vsd_network(self.domain.id, public_tier_1, vpc_1) + self.verify_vsd_router(vr_1) + self.verify_vsd_vm(public_vm_1) self.debug("Creating a VPC network in vpc_2 without Internal LB service...") public_tier_2 = self.create_Network(net_off_2, gateway='10.1.1.1', vpc=vpc_2) @@ -487,14 +487,14 @@ def test_03_nuage_internallb_vpc_networks(self): vr_2 = self.get_Router(public_tier_2) self.check_Router_state(vr_2, state="Running") - self.debug("Deploying a VM in network - %s" % public_tier_2.name) + self.debug("Deploying a VM in the created VPC network...") public_vm_2 = self.create_VM(public_tier_2) self.check_VM_state(public_vm_2, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, public_tier_2, vpc_2) - self.verify_vsp_router(vr_2) - self.verify_vsp_vm(public_vm_2) + self.verify_vsd_network(self.domain.id, public_tier_2, vpc_2) + self.verify_vsd_router(vr_2) + self.verify_vsd_vm(public_vm_2) # Upgrading a VPC network self.debug("Upgrading a VPC network with Internal LB Service to one without Internal LB Service...") @@ -505,9 +505,9 @@ def test_03_nuage_internallb_vpc_networks(self): self.check_VM_state(internal_vm_2, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier_2, vpc_1) - self.verify_vsp_router(vr_1) - self.verify_vsp_vm(internal_vm_2) + self.verify_vsd_network(self.domain.id, internal_tier_2, vpc_1) + self.verify_vsd_router(vr_1) + self.verify_vsd_vm(internal_vm_2) self.debug("Upgrading a VPC network without Internal LB Service to one with Internal LB Service...") self.upgrade_Network(net_off_1, internal_tier_2) @@ -517,9 +517,9 @@ def test_03_nuage_internallb_vpc_networks(self): self.check_VM_state(internal_vm_2, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier_2, vpc_1) - self.verify_vsp_router(vr_1) - self.verify_vsp_vm(internal_vm_2) + self.verify_vsd_network(self.domain.id, internal_tier_2, vpc_1) + self.verify_vsd_router(vr_1) + self.verify_vsd_vm(internal_vm_2) # Deleting and re-creating a VPC network self.debug("Deleting a VPC network with Internal LB Service...") @@ -531,7 +531,7 @@ def test_03_nuage_internallb_vpc_networks(self): # VSD verification with self.assertRaises(Exception): - self.verify_vsp_network(self.domain.id, internal_tier_2, vpc_1) + self.verify_vsd_network(self.domain.id, internal_tier_2, vpc_1) self.debug("VPC network successfully deleted in VSD") self.debug("Recreating a VPC network with Internal LB Service...") @@ -543,9 +543,9 @@ def test_03_nuage_internallb_vpc_networks(self): self.check_VM_state(internal_vm_2, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier_2, vpc_1) - self.verify_vsp_router(vr_1) - self.verify_vsp_vm(internal_vm_2) + self.verify_vsd_network(self.domain.id, internal_tier_2, vpc_1) + self.verify_vsd_router(vr_1) + self.verify_vsd_vm(internal_vm_2) @attr(tags=["advanced", "nuagevsp"], required_hardware="false") def test_04_nuage_internallb_rules(self): @@ -576,6 +576,7 @@ def test_04_nuage_internallb_rules(self): # VM to it. # 11. Verify the failure of attaching a VM from a different tier to an Internal LB Rule created on a tier. # 12. Delete the above created Internal LB Rules, check if the Internal LB Rules are successfully deleted. + # 13. Delete all the created objects (cleanup). # Creating a VPC offering self.debug("Creating Nuage VSP VPC offering with Internal LB service...") @@ -604,14 +605,14 @@ def test_04_nuage_internallb_rules(self): vr = self.get_Router(internal_tier) self.check_Router_state(vr, state="Running") - self.debug("Deploying a VM in network - %s" % internal_tier.name) + self.debug("Deploying a VM in the created VPC network...") internal_vm = self.create_VM(internal_tier) self.check_VM_state(internal_vm, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(internal_vm) + self.verify_vsd_network(self.domain.id, internal_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(internal_vm) self.debug("Creating a VPC network without Internal LB service...") public_tier = self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc) @@ -619,14 +620,14 @@ def test_04_nuage_internallb_rules(self): vr = self.get_Router(public_tier) self.check_Router_state(vr, state="Running") - self.debug("Deploying a VM in network - %s" % public_tier.name) + self.debug("Deploying a VM in the created VPC network...") public_vm = self.create_VM(public_tier) self.check_VM_state(public_vm, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, public_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(public_vm) + self.verify_vsd_network(self.domain.id, public_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(public_vm) # Creating Internal LB Rules self.debug("Creating an Internal LB Rule without source IP Address specified...") @@ -691,8 +692,8 @@ def test_04_nuage_internallb_rules(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_2.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm_1) - self.verify_vsp_LB_device(int_lb_vm_2) + self.verify_vsd_lb_device(int_lb_vm_1) + self.verify_vsd_lb_device(int_lb_vm_2) self.debug('Removing VMs from the Internal LB Rules - %s, %s' % (int_lb_rule_1.name, int_lb_rule_2.name)) int_lb_rule_1.remove(self.api_client, vms=[internal_vm]) @@ -709,8 +710,8 @@ def test_04_nuage_internallb_rules(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_2.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm_1) - self.verify_vsp_LB_device(int_lb_vm_2) + self.verify_vsd_lb_device(int_lb_vm_1) + self.verify_vsd_lb_device(int_lb_vm_2) self.debug('Deleting the Internal LB Rules - %s, %s' % (int_lb_rule_1.name, int_lb_rule_2.name)) int_lb_rule_1.delete(self.api_client) @@ -732,10 +733,10 @@ def test_04_nuage_internallb_rules(self): # VSD Verification with self.assertRaises(Exception): - self.verify_vsp_LB_device(int_lb_vm_1) + self.verify_vsd_lb_device(int_lb_vm_1) self.debug("InternalLbVm successfully destroyed in VSD") with self.assertRaises(Exception): - self.verify_vsp_LB_device(int_lb_vm_2) + self.verify_vsd_lb_device(int_lb_vm_2) self.debug("InternalLbVm successfully destroyed in VSD") self.debug("Creating multiple Internal LB Rules with different ports but using the same Load Balancing source " @@ -754,7 +755,7 @@ def test_04_nuage_internallb_rules(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) self.debug('Removing VMs from the Internal LB Rules - %s, %s' % (int_lb_rule_1.name, int_lb_rule_2.name)) int_lb_rule_1.remove(self.api_client, vms=[internal_vm]) @@ -770,7 +771,7 @@ def test_04_nuage_internallb_rules(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) self.debug('Deleting the Internal LB Rules - %s, %s' % (int_lb_rule_1.name, int_lb_rule_2.name)) int_lb_rule_1.delete(self.api_client) @@ -789,10 +790,10 @@ def test_04_nuage_internallb_rules(self): # VSD Verification with self.assertRaises(Exception): - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) self.debug("InternalLbVm successfully destroyed in VSD") - self.debug("Creating multiple Internal LB Rules with same ports and using the same Load Balacing source IP " + self.debug("Creating multiple Internal LB Rules with same ports and using the same Load Balancing source IP " "Address...") int_lb_rule = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm]) self.validate_Internal_LB_Rule(int_lb_rule, state="Active", vm_array=[internal_vm]) @@ -805,7 +806,7 @@ def test_04_nuage_internallb_rules(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) self.debug('Removing VMs from the Internal LB Rule - %s' % int_lb_rule.name) int_lb_rule.remove(self.api_client, vms=[internal_vm]) @@ -817,7 +818,7 @@ def test_04_nuage_internallb_rules(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) self.debug('Deleting the Internal LB Rule - %s' % int_lb_rule.name) int_lb_rule.delete(self.api_client) @@ -832,7 +833,7 @@ def test_04_nuage_internallb_rules(self): # VSD Verification with self.assertRaises(Exception): - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) self.debug("InternalLbVm successfully destroyed in VSD") self.debug("Attaching a VM from a different tier to an Internal LB Rule created on a tier...") @@ -862,6 +863,7 @@ def test_05_nuage_internallb_traffic(self): # 8. Verify that the InternalLbVm gets destroyed when the last Internal LB rule is removed from the Internal # tier. # 9. Repeat the above steps for one more Internal tier as well, validate the Internal LB functionality. + # 10. Delete all the created objects (cleanup). # Creating a VPC offering self.debug("Creating Nuage VSP VPC offering with Internal LB service...") @@ -890,14 +892,14 @@ def test_05_nuage_internallb_traffic(self): vr = self.get_Router(internal_tier_1) self.check_Router_state(vr, state="Running") - self.debug("Deploying a VM in network - %s" % internal_tier_1.name) + self.debug("Deploying a VM in the created VPC network...") internal_vm_1 = self.create_VM(internal_tier_1) self.check_VM_state(internal_vm_1, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier_1, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(internal_vm_1) + self.verify_vsd_network(self.domain.id, internal_tier_1, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(internal_vm_1) self.debug("Creating one more VPC network with Internal LB service...") internal_tier_2 = self.create_Network(net_off_1, gateway='10.1.2.1', vpc=vpc) @@ -905,14 +907,14 @@ def test_05_nuage_internallb_traffic(self): vr = self.get_Router(internal_tier_2) self.check_Router_state(vr, state="Running") - self.debug("Deploying a VM in network - %s" % internal_tier_2.name) + self.debug("Deploying a VM in the created VPC network...") internal_vm_2 = self.create_VM(internal_tier_2) self.check_VM_state(internal_vm_2, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier_2, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(internal_vm_2) + self.verify_vsd_network(self.domain.id, internal_tier_2, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(internal_vm_2) self.debug("Creating a VPC network without Internal LB service...") public_tier = self.create_Network(net_off_2, gateway='10.1.3.1', vpc=vpc) @@ -920,14 +922,14 @@ def test_05_nuage_internallb_traffic(self): vr = self.get_Router(public_tier) self.check_Router_state(vr, state="Running") - self.debug("Deploying a VM in network - %s" % public_tier.name) + self.debug("Deploying a VM in the created VPC network...") public_vm = self.create_VM(public_tier) self.check_VM_state(public_vm, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, public_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(public_vm) + self.verify_vsd_network(self.domain.id, public_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(public_vm) # Creating Internal LB Rules in the Internal tiers self.debug("Creating two Internal LB Rules (SSH & HTTP) using the same Load Balancing source IP Address...") @@ -945,7 +947,7 @@ def test_05_nuage_internallb_traffic(self): self.check_InternalLbVm_state(internal_tier_1, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm_1) + self.verify_vsd_lb_device(int_lb_vm_1) # Deploying more VMs in the Internal tier self.debug("Deploying two more VMs in network - %s" % internal_tier_1.name) @@ -953,8 +955,8 @@ def test_05_nuage_internallb_traffic(self): internal_vm_1_2 = self.create_VM(internal_tier_1) # VSD verification - self.verify_vsp_vm(internal_vm_1_1) - self.verify_vsp_vm(internal_vm_1_2) + self.verify_vsd_vm(internal_vm_1_1) + self.verify_vsd_vm(internal_vm_1_2) # Adding newly deployed VMs to the created Internal LB rules self.debug("Adding two more virtual machines to the created Internal LB rules...") @@ -969,7 +971,7 @@ def test_05_nuage_internallb_traffic(self): self.check_InternalLbVm_state(internal_tier_1, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm_1) + self.verify_vsd_lb_device(int_lb_vm_1) # Adding Network ACL rules in the Internal tier self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...") @@ -977,8 +979,8 @@ def test_05_nuage_internallb_traffic(self): http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier_1) # VSD verification - self.verify_vsp_firewall_rule(ssh_rule) - self.verify_vsp_firewall_rule(http_rule) + self.verify_vsd_firewall_rule(ssh_rule) + self.verify_vsd_firewall_rule(http_rule) # Creating Internal LB Rules in the Internal tier self.debug("Creating two Internal LB Rules (SSH & HTTP) using the same Load Balancing source IP Address...") @@ -996,7 +998,7 @@ def test_05_nuage_internallb_traffic(self): self.check_InternalLbVm_state(internal_tier_2, int_lb_rule_3.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm_2) + self.verify_vsd_lb_device(int_lb_vm_2) # Deploying more VMs in the Internal tier self.debug("Deploying two more VMs in network - %s" % internal_tier_2.name) @@ -1004,8 +1006,8 @@ def test_05_nuage_internallb_traffic(self): internal_vm_2_2 = self.create_VM(internal_tier_2) # VSD verification - self.verify_vsp_vm(internal_vm_2_1) - self.verify_vsp_vm(internal_vm_2_2) + self.verify_vsd_vm(internal_vm_2_1) + self.verify_vsd_vm(internal_vm_2_2) # Adding newly deployed VMs to the created Internal LB rules self.debug("Adding two more virtual machines to the created Internal LB rules...") @@ -1020,7 +1022,7 @@ def test_05_nuage_internallb_traffic(self): self.check_InternalLbVm_state(internal_tier_2, int_lb_rule_3.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm_2) + self.verify_vsd_lb_device(int_lb_vm_2) # Adding Network ACL rules in the Internal tier self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...") @@ -1028,24 +1030,24 @@ def test_05_nuage_internallb_traffic(self): http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier_2) # VSD verification - self.verify_vsp_firewall_rule(ssh_rule) - self.verify_vsp_firewall_rule(http_rule) + self.verify_vsd_firewall_rule(ssh_rule) + self.verify_vsd_firewall_rule(http_rule) - # Creating Static NAT Rule for the VM in the Public tier + # Creating Static NAT rule for the VM in the Public tier public_ip = self.acquire_PublicIPAddress(public_tier, vpc) self.validate_PublicIPAddress(public_ip, public_tier) self.create_StaticNatRule_For_VM(public_vm, public_ip, public_tier) self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) # VSD verification - self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) # Adding Network ACL rule in the Public tier self.debug("Adding Network ACL rule to make the created NAT rule (SSH) accessible...") public_ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=public_tier) # VSD verification - self.verify_vsp_firewall_rule(public_ssh_rule) + self.verify_vsd_firewall_rule(public_ssh_rule) # Internal LB (wget) traffic tests ssh_client = self.ssh_into_VM(public_vm, public_ip) @@ -1074,6 +1076,7 @@ def test_06_nuage_internallb_algorithms_traffic(self): # 2. Least connections # 3. Source # Verify the above Internal LB algorithms by performing multiple (wget) traffic tests within a VPC. + # Delete all the created objects (cleanup). # Creating a VPC offering self.debug("Creating Nuage VSP VPC offering with Internal LB service...") @@ -1102,14 +1105,14 @@ def test_06_nuage_internallb_algorithms_traffic(self): vr = self.get_Router(internal_tier) self.check_Router_state(vr, state="Running") - self.debug("Deploying a VM in network - %s" % internal_tier.name) + self.debug("Deploying a VM in the created VPC network...") internal_vm = self.create_VM(internal_tier) self.check_VM_state(internal_vm, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(internal_vm) + self.verify_vsd_network(self.domain.id, internal_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(internal_vm) self.debug("Creating a VPC network without Internal LB service...") public_tier = self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc) @@ -1117,14 +1120,14 @@ def test_06_nuage_internallb_algorithms_traffic(self): vr = self.get_Router(public_tier) self.check_Router_state(vr, state="Running") - self.debug("Deploying a VM in network - %s" % public_tier.name) + self.debug("Deploying a VM in the created VPC network...") public_vm = self.create_VM(public_tier) self.check_VM_state(public_vm, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, public_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(public_vm) + self.verify_vsd_network(self.domain.id, public_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(public_vm) # Creating Internal LB Rules in the Internal tier with Round Robin Algorithm self.debug("Creating two Internal LB Rules (SSH & HTTP) with Round Robin Algorithm...") @@ -1142,7 +1145,7 @@ def test_06_nuage_internallb_algorithms_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm_1) + self.verify_vsd_lb_device(int_lb_vm_1) # Deploying more VMs in the Internal tier self.debug("Deploying two more VMs in network - %s" % internal_tier.name) @@ -1150,8 +1153,8 @@ def test_06_nuage_internallb_algorithms_traffic(self): internal_vm_2 = self.create_VM(internal_tier) # VSD verification - self.verify_vsp_vm(internal_vm_1) - self.verify_vsp_vm(internal_vm_2) + self.verify_vsd_vm(internal_vm_1) + self.verify_vsd_vm(internal_vm_2) # Adding newly deployed VMs to the created Internal LB rules self.debug("Adding two more virtual machines to the created Internal LB rules...") @@ -1166,7 +1169,7 @@ def test_06_nuage_internallb_algorithms_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm_1) + self.verify_vsd_lb_device(int_lb_vm_1) # Creating Internal LB Rules in the Internal tier with Least connections Algorithm self.debug("Creating two Internal LB Rules (SSH & HTTP) with Least connections Algorithm...") @@ -1191,7 +1194,7 @@ def test_06_nuage_internallb_algorithms_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_3.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm_2) + self.verify_vsd_lb_device(int_lb_vm_2) # Creating Internal LB Rules in the Internal tier with Source Algorithm self.debug("Creating two Internal LB Rules (SSH & HTTP) with Source Algorithm...") @@ -1216,7 +1219,7 @@ def test_06_nuage_internallb_algorithms_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_5.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm_3) + self.verify_vsd_lb_device(int_lb_vm_3) # Adding Network ACL rules in the Internal tier self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...") @@ -1224,24 +1227,24 @@ def test_06_nuage_internallb_algorithms_traffic(self): http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier) # VSD verification - self.verify_vsp_firewall_rule(ssh_rule) - self.verify_vsp_firewall_rule(http_rule) + self.verify_vsd_firewall_rule(ssh_rule) + self.verify_vsd_firewall_rule(http_rule) - # Creating Static NAT Rule for the VM in the Public tier + # Creating Static NAT rule for the VM in the Public tier public_ip = self.acquire_PublicIPAddress(public_tier, vpc) self.validate_PublicIPAddress(public_ip, public_tier) self.create_StaticNatRule_For_VM(public_vm, public_ip, public_tier) self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) # VSD verification - self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) # Adding Network ACL rule in the Public tier self.debug("Adding Network ACL rule to make the created NAT rule (SSH) accessible...") public_ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=public_tier) # VSD verification - self.verify_vsp_firewall_rule(public_ssh_rule) + self.verify_vsd_firewall_rule(public_ssh_rule) # Internal LB (wget) traffic tests with Round Robin Algorithm ssh_client = self.ssh_into_VM(public_vm, public_ip) @@ -1289,9 +1292,12 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): # tier. # 6. Start all the VMs configured with InternalLbVm, verify that the InternalLbVm gets deployed again in the # Internal tier. - # 7. Restart VPC, verify that the VPC VR gets rebooted and this restart has no effect on the InternalLbVm - # functionality. + # 7. Restart VPC (cleanup = false), verify that the VPC VR gets rebooted and this restart has no effect on the + # InternalLbVm functionality. + # 7. Restart VPC (cleanup = true), verify that the VPC VR gets rebooted and this restart has no effect on the + # InternalLbVm functionality. # Verify the above restarts of VPC networks (tiers) by performing (wget) traffic tests within a VPC. + # Delete all the created objects (cleanup). # Creating a VPC offering self.debug("Creating Nuage VSP VPC offering with Internal LB service...") @@ -1320,14 +1326,14 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): vr = self.get_Router(internal_tier) self.check_Router_state(vr, state="Running") - self.debug("Deploying a VM in network - %s" % internal_tier.name) + self.debug("Deploying a VM in the created VPC network...") internal_vm = self.create_VM(internal_tier) self.check_VM_state(internal_vm, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(internal_vm) + self.verify_vsd_network(self.domain.id, internal_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(internal_vm) self.debug("Creating a VPC network without Internal LB service...") public_tier = self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc) @@ -1335,14 +1341,14 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): vr = self.get_Router(public_tier) self.check_Router_state(vr, state="Running") - self.debug("Deploying a VM in network - %s" % public_tier.name) + self.debug("Deploying a VM in the created VPC network...") public_vm = self.create_VM(public_tier) self.check_VM_state(public_vm, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, public_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(public_vm) + self.verify_vsd_network(self.domain.id, public_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(public_vm) # Creating Internal LB Rules in the Internal tier self.debug("Creating two Internal LB Rules (SSH & HTTP) using the same Load Balancing source IP Address...") @@ -1360,7 +1366,7 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Deploying more VMs in the Internal tier self.debug("Deploying two more VMs in network - %s" % internal_tier.name) @@ -1368,8 +1374,8 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): internal_vm_2 = self.create_VM(internal_tier) # VSD verification - self.verify_vsp_vm(internal_vm_1) - self.verify_vsp_vm(internal_vm_2) + self.verify_vsd_vm(internal_vm_1) + self.verify_vsd_vm(internal_vm_2) # Adding newly deployed VMs to the created Internal LB rules self.debug("Adding two more virtual machines to the created Internal LB rules...") @@ -1384,7 +1390,7 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Adding Network ACL rules in the Internal tier self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...") @@ -1392,24 +1398,24 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier) # VSD verification - self.verify_vsp_firewall_rule(ssh_rule) - self.verify_vsp_firewall_rule(http_rule) + self.verify_vsd_firewall_rule(ssh_rule) + self.verify_vsd_firewall_rule(http_rule) - # Creating Static NAT Rule for the VM in the Public tier + # Creating Static NAT rule for the VM in the Public tier public_ip = self.acquire_PublicIPAddress(public_tier, vpc) self.validate_PublicIPAddress(public_ip, public_tier) self.create_StaticNatRule_For_VM(public_vm, public_ip, public_tier) self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) # VSD verification - self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) # Adding Network ACL rule in the Public tier self.debug("Adding Network ACL rule to make the created NAT rule (SSH) accessible...") public_ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=public_tier) # VSD verification - self.verify_vsp_firewall_rule(public_ssh_rule) + self.verify_vsd_firewall_rule(public_ssh_rule) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) @@ -1432,13 +1438,13 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): self.check_VM_state(internal_vm_2, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(internal_vm) - self.verify_vsp_vm(internal_vm_1) - self.verify_vsp_vm(internal_vm_2) - self.verify_vsp_firewall_rule(ssh_rule) - self.verify_vsp_firewall_rule(http_rule) + self.verify_vsd_network(self.domain.id, internal_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(internal_vm) + self.verify_vsd_vm(internal_vm_1) + self.verify_vsd_vm(internal_vm_2) + self.verify_vsd_firewall_rule(ssh_rule) + self.verify_vsd_firewall_rule(http_rule) # Validating InternalLbVm state # InternalLbVm gets destroyed and deployed again in the Internal tier @@ -1446,12 +1452,12 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) tries = 0 - while True: + while tries < 10: try: wget_file = self.wget_from_vm_cmd(ssh_client, int_lb_rule_1.sourceipaddress, @@ -1459,8 +1465,6 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): ) except Exception as e: self.debug("Failed to wget file via the InternalLbVm after re-starting the Internal tier: %s" % e) - if tries == 10: - break self.debug("Waiting for the InternalLbVm in the Internal tier to be fully resolved for (wget) traffic " "test...") time.sleep(30) @@ -1483,13 +1487,13 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): self.check_VM_state(internal_vm_2, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(internal_vm) - self.verify_vsp_vm(internal_vm_1) - self.verify_vsp_vm(internal_vm_2) - self.verify_vsp_firewall_rule(ssh_rule) - self.verify_vsp_firewall_rule(http_rule) + self.verify_vsd_network(self.domain.id, internal_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(internal_vm) + self.verify_vsd_vm(internal_vm_1) + self.verify_vsd_vm(internal_vm_2) + self.verify_vsd_firewall_rule(ssh_rule) + self.verify_vsd_firewall_rule(http_rule) # Validating InternalLbVm state # InternalLbVm gets destroyed and deployed again in the Internal tier @@ -1497,12 +1501,12 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) tries = 0 - while True: + while tries < 10: try: wget_file = self.wget_from_vm_cmd(ssh_client, int_lb_rule_1.sourceipaddress, @@ -1511,8 +1515,6 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): except Exception as e: self.debug("Failed to wget file via the InternalLbVm after re-starting the Internal tier with cleanup: " "%s" % e) - if tries == 10: - break self.debug("Waiting for the InternalLbVm in the Internal tier to be fully resolved for (wget) traffic " "test...") time.sleep(30) @@ -1534,17 +1536,17 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) # VSD verification - self.verify_vsp_network(self.domain.id, public_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(public_vm) - self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) - self.verify_vsp_firewall_rule(public_ssh_rule) + self.verify_vsd_network(self.domain.id, public_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(public_vm) + self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + self.verify_vsd_firewall_rule(public_ssh_rule) # Validating InternalLbVm state self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) @@ -1566,17 +1568,17 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) # VSD verification - self.verify_vsp_network(self.domain.id, public_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(public_vm) - self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) - self.verify_vsp_firewall_rule(public_ssh_rule) + self.verify_vsd_network(self.domain.id, public_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(public_vm) + self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + self.verify_vsd_firewall_rule(public_ssh_rule) # Validating InternalLbVm state self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) @@ -1601,19 +1603,19 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): self.check_VM_state(internal_vm_2, state="Stopped") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(internal_vm, stopped=True) - self.verify_vsp_vm(internal_vm_1, stopped=True) - self.verify_vsp_vm(internal_vm_2, stopped=True) - self.verify_vsp_firewall_rule(ssh_rule) - self.verify_vsp_firewall_rule(http_rule) + self.verify_vsd_network(self.domain.id, internal_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(internal_vm, stopped=True) + self.verify_vsd_vm(internal_vm_1, stopped=True) + self.verify_vsd_vm(internal_vm_2, stopped=True) + self.verify_vsd_firewall_rule(ssh_rule) + self.verify_vsd_firewall_rule(http_rule) # Validating InternalLbVm state self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) @@ -1637,24 +1639,24 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): self.check_VM_state(internal_vm_2, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(internal_vm) - self.verify_vsp_vm(internal_vm_1) - self.verify_vsp_vm(internal_vm_2) - self.verify_vsp_firewall_rule(ssh_rule) - self.verify_vsp_firewall_rule(http_rule) + self.verify_vsd_network(self.domain.id, internal_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(internal_vm) + self.verify_vsd_vm(internal_vm_1) + self.verify_vsd_vm(internal_vm_2) + self.verify_vsd_firewall_rule(ssh_rule) + self.verify_vsd_firewall_rule(http_rule) # Validating InternalLbVm state self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) tries = 0 - while True: + while tries < 10: try: wget_file = self.wget_from_vm_cmd(ssh_client, int_lb_rule_1.sourceipaddress, @@ -1663,8 +1665,6 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): except Exception as e: self.debug("Failed to wget file via the InternalLbVm after re-starting all the VMs in the Internal tier" ": %s" % e) - if tries == 10: - break self.debug("Waiting for the InternalLbVm and all the VMs in the Internal tier to be fully resolved for " "(wget) traffic test...") time.sleep(30) @@ -1693,23 +1693,23 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) # VSD verification - self.verify_vsp_network(self.domain.id, public_tier, vpc) - self.verify_vsp_network(self.domain.id, internal_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(public_vm) - self.verify_vsp_vm(internal_vm) - self.verify_vsp_vm(internal_vm_1) - self.verify_vsp_vm(internal_vm_2) - self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) - self.verify_vsp_firewall_rule(public_ssh_rule) - self.verify_vsp_firewall_rule(ssh_rule) - self.verify_vsp_firewall_rule(http_rule) + self.verify_vsd_network(self.domain.id, public_tier, vpc) + self.verify_vsd_network(self.domain.id, internal_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(public_vm) + self.verify_vsd_vm(internal_vm) + self.verify_vsd_vm(internal_vm_1) + self.verify_vsd_vm(internal_vm_2) + self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + self.verify_vsd_firewall_rule(public_ssh_rule) + self.verify_vsd_firewall_rule(ssh_rule) + self.verify_vsd_firewall_rule(http_rule) # Validating InternalLbVm state self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) @@ -1737,23 +1737,23 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self): self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) # VSD verification - self.verify_vsp_network(self.domain.id, public_tier, vpc) - self.verify_vsp_network(self.domain.id, internal_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(public_vm) - self.verify_vsp_vm(internal_vm) - self.verify_vsp_vm(internal_vm_1) - self.verify_vsp_vm(internal_vm_2) - self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) - self.verify_vsp_firewall_rule(public_ssh_rule) - self.verify_vsp_firewall_rule(ssh_rule) - self.verify_vsp_firewall_rule(http_rule) + self.verify_vsd_network(self.domain.id, public_tier, vpc) + self.verify_vsd_network(self.domain.id, internal_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(public_vm) + self.verify_vsd_vm(internal_vm) + self.verify_vsd_vm(internal_vm_1) + self.verify_vsd_vm(internal_vm_2) + self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + self.verify_vsd_firewall_rule(public_ssh_rule) + self.verify_vsd_firewall_rule(ssh_rule) + self.verify_vsd_firewall_rule(http_rule) # Validating InternalLbVm state self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) @@ -1781,6 +1781,7 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): # 6. Force stop the InternalLbVm when the VPC VR is in Running State # 7. Start the InternalLbVm when the VPC VR is in Running state # Verify the above restarts of VPC networks by performing (wget) traffic tests within a VPC. + # Delete all the created objects (cleanup). # Creating a VPC offering self.debug("Creating Nuage VSP VPC offering with Internal LB service...") @@ -1809,14 +1810,14 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): vr = self.get_Router(internal_tier) self.check_Router_state(vr, state="Running") - self.debug("Deploying a VM in network - %s" % internal_tier.name) + self.debug("Deploying a VM in the created VPC network...") internal_vm = self.create_VM(internal_tier) self.check_VM_state(internal_vm, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, internal_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(internal_vm) + self.verify_vsd_network(self.domain.id, internal_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(internal_vm) self.debug("Creating a VPC network without Internal LB service...") public_tier = self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc) @@ -1824,14 +1825,14 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): vr = self.get_Router(public_tier) self.check_Router_state(vr, state="Running") - self.debug("Deploying a VM in network - %s" % public_tier.name) + self.debug("Deploying a VM in the created VPC network...") public_vm = self.create_VM(public_tier) self.check_VM_state(public_vm, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, public_tier, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(public_vm) + self.verify_vsd_network(self.domain.id, public_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(public_vm) # Stopping the VPC VR # VPC VR has no effect on the InternalLbVm functionality @@ -1841,9 +1842,9 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): self.validate_Network(internal_tier, state="Implemented") # VSD verification - self.verify_vsp_router(vr, stopped=True) - self.verify_vsp_network(self.domain.id, public_tier, vpc) - self.verify_vsp_network(self.domain.id, internal_tier, vpc) + self.verify_vsd_router(vr, stopped=True) + self.verify_vsd_network(self.domain.id, public_tier, vpc) + self.verify_vsd_network(self.domain.id, internal_tier, vpc) # Creating Internal LB Rules in the Internal tier self.debug("Creating two Internal LB Rules (SSH & HTTP) using the same Load Balancing source IP Address...") @@ -1861,7 +1862,7 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Deploying more VMs in the Internal tier self.debug("Deploying two more VMs in network - %s" % internal_tier.name) @@ -1869,8 +1870,8 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): internal_vm_2 = self.create_VM(internal_tier) # VSD verification - self.verify_vsp_vm(internal_vm_1) - self.verify_vsp_vm(internal_vm_2) + self.verify_vsd_vm(internal_vm_1) + self.verify_vsd_vm(internal_vm_2) # Adding newly deployed VMs to the created Internal LB rules self.debug("Adding two more virtual machines to the created Internal LB rules...") @@ -1885,7 +1886,7 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Adding Network ACL rules in the Internal tier self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...") @@ -1893,24 +1894,24 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier) # VSD verification - self.verify_vsp_firewall_rule(ssh_rule) - self.verify_vsp_firewall_rule(http_rule) + self.verify_vsd_firewall_rule(ssh_rule) + self.verify_vsd_firewall_rule(http_rule) - # Creating Static NAT Rule for the VM in the Public tier + # Creating Static NAT rule for the VM in the Public tier public_ip = self.acquire_PublicIPAddress(public_tier, vpc) self.validate_PublicIPAddress(public_ip, public_tier) self.create_StaticNatRule_For_VM(public_vm, public_ip, public_tier) self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm) # VSD verification - self.verify_vsp_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) + self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc) # Adding Network ACL rule in the Public tier self.debug("Adding Network ACL rule to make the created NAT rule (SSH) accessible...") public_ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=public_tier) # VSD verification - self.verify_vsp_firewall_rule(public_ssh_rule) + self.verify_vsd_firewall_rule(public_ssh_rule) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) @@ -1927,7 +1928,7 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Stopped") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm, stopped=True) + self.verify_vsd_lb_device(int_lb_vm, stopped=True) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) @@ -1943,12 +1944,12 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) tries = 0 - while True: + while tries < 10: try: wget_file = self.wget_from_vm_cmd(ssh_client, int_lb_rule_1.sourceipaddress, @@ -1957,8 +1958,6 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): except Exception as e: self.debug("Failed to wget file via the InternalLbVm after re-starting the InternalLbVm appliance: %s" % e) - if tries == 10: - break self.debug("Waiting for the InternalLbVm to be fully resolved for (wget) traffic test...") time.sleep(30) tries += 1 @@ -1977,16 +1976,16 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): self.validate_Network(internal_tier, state="Implemented") # VSD verification - self.verify_vsp_router(vr) - self.verify_vsp_network(self.domain.id, public_tier, vpc) - self.verify_vsp_network(self.domain.id, internal_tier, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_network(self.domain.id, public_tier, vpc) + self.verify_vsd_network(self.domain.id, internal_tier, vpc) # # Stopping the InternalLbVm when the VPC VR is in Running state self.stop_InternalLbVm(int_lb_vm) self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Stopped") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm, stopped=True) + self.verify_vsd_lb_device(int_lb_vm, stopped=True) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) @@ -2002,12 +2001,12 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) tries = 0 - while True: + while tries < 10: try: wget_file = self.wget_from_vm_cmd(ssh_client, int_lb_rule_1.sourceipaddress, @@ -2016,8 +2015,6 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): except Exception as e: self.debug("Failed to wget file via the InternalLbVm after re-starting the InternalLbVm appliance: %s" % e) - if tries == 10: - break self.debug("Waiting for the InternalLbVm to be fully resolved for (wget) traffic test...") time.sleep(30) tries += 1 @@ -2033,7 +2030,7 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Stopped") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm, stopped=True) + self.verify_vsd_lb_device(int_lb_vm, stopped=True) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) @@ -2049,12 +2046,12 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running") # VSD Verification - self.verify_vsp_LB_device(int_lb_vm) + self.verify_vsd_lb_device(int_lb_vm) # Internal LB (wget) traffic test ssh_client = self.ssh_into_VM(public_vm, public_ip) tries = 0 - while True: + while tries < 10: try: wget_file = self.wget_from_vm_cmd(ssh_client, int_lb_rule_1.sourceipaddress, @@ -2063,8 +2060,6 @@ def test_08_nuage_internallb_appliance_operations_traffic(self): except Exception as e: self.debug("Failed to wget file via the InternalLbVm after re-starting the InternalLbVm appliance: %s" % e) - if tries == 10: - break self.debug("Waiting for the InternalLbVm to be fully resolved for (wget) traffic test...") time.sleep(30) tries += 1 diff --git a/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py b/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py index 15134b628b..7dec5a6a19 100644 --- a/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py +++ b/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py @@ -57,6 +57,7 @@ def test_nuage_vpc_network(self): # 6. Deploy a VM in the created VPC network, check if the VM is successfully deployed and is in the "Running" # state. # 7. Verify that the created ACL item is successfully implemented in Nuage VSP. + # 8. Delete all the created objects (cleanup). # Creating a VPC offering self.debug("Creating Nuage VSP VPC offering...") @@ -91,12 +92,12 @@ def test_nuage_vpc_network(self): self.check_VM_state(vm, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, vpc_network, vpc) - self.verify_vsp_router(vr) - self.verify_vsp_vm(vm) + self.verify_vsd_network(self.domain.id, vpc_network, vpc) + self.verify_vsd_router(vr) + self.verify_vsd_vm(vm) # VSD verification for ACL item - self.verify_vsp_firewall_rule(acl_item) + self.verify_vsd_firewall_rule(acl_item) @attr(tags=["advanced", "nuagevsp", "multizone"], required_hardware="false") def test_nuage_vpc_network_multizone(self): diff --git a/test/integration/plugins/nuagevsp/test_nuage_vsp.py b/test/integration/plugins/nuagevsp/test_nuage_vsp.py index 0227ce5c8e..d71d0c1b4a 100644 --- a/test/integration/plugins/nuagevsp/test_nuage_vsp.py +++ b/test/integration/plugins/nuagevsp/test_nuage_vsp.py @@ -166,16 +166,16 @@ def test_nuage_vsp(self): self.check_VM_state(vm_1, state="Running") # VSD verification - self.verify_vsp_network(self.domain.id, network) - self.verify_vsp_router(vr) - self.verify_vsp_vm(vm_1) + self.verify_vsd_network(self.domain.id, network) + self.verify_vsd_router(vr) + self.verify_vsd_vm(vm_1) # Deploying one more VM in the network vm_2 = self.create_VM(network) self.check_VM_state(vm_2, state="Running") # VSD verification - self.verify_vsp_vm(vm_2) + self.verify_vsd_vm(vm_2) # Deleting the network self.debug("Deleting the Isolated Network with Nuage VSP Isolated Network offering...") @@ -188,5 +188,5 @@ def test_nuage_vsp(self): # VSD verification with self.assertRaises(Exception): - self.verify_vsp_network(self.domain.id, network) + self.verify_vsd_network(self.domain.id, network) self.debug("Isolated Network successfully deleted in VSD")