From 5cd3608529cd630a102345c1b49930e5844ccf4e Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Wed, 10 Apr 2013 16:50:42 +0200 Subject: [PATCH 01/45] Remove the chmod solution and replace with an explicit call to /bin/bash. This way the file will only need read permissions. --- .../cloud/server/ConfigurationServerImpl.java | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index 53df3b970a8..596387f100e 100755 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -148,8 +148,6 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio @DB public void persistDefaultValues() throws InternalErrorException { - fixupScriptFileAttribute(); - // Create system user and admin user saveUser(); @@ -701,24 +699,6 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio } - private void fixupScriptFileAttribute() { - // TODO : this is a hacking fix to workaround that executable bit is not preserved in WAR package - String scriptPath = Script.findScript("", "scripts/vm/systemvm/injectkeys.sh"); - if(scriptPath != null) { - File file = new File(scriptPath); - if(!file.canExecute()) { - s_logger.info("Some of the shell script files may not have executable bit set. Fixup..."); - - String cmd = "sudo chmod ugo+x " + scriptPath; - s_logger.info("Executing " + cmd); - String result = Script.runSimpleBashScript(cmd); - if (result != null) { - s_logger.warn("Failed to fixup shell script executable bits " + result); - } - } - } - } - private void updateKeyPairsOnDisk(String homeDir) { File keyDir = new File(homeDir + "/.ssh"); Boolean devel = Boolean.valueOf(_configDao.getValue("developer")); @@ -749,7 +729,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio if (systemVmIsoPath == null) { throw new CloudRuntimeException("Unable to find systemvm iso vms/systemvm.iso"); } - final Script command = new Script(scriptPath, s_logger); + final Script command = new Script("/bin/bash " + scriptPath, s_logger); command.add(publicKeyPath); command.add(privKeyPath); command.add(systemVmIsoPath); From 91faf2d14aed94dbb403febf7d8a2c4b22cc7d1a Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 11 Apr 2013 15:23:04 +0530 Subject: [PATCH 02/45] appliance: Revertible patch to create half baked template for vmware This is to allow buildjob to produce semi-automate template for vmware. Signed-off-by: Rohit Yadav --- .../definitions/systemvmtemplate/postinstall.sh | 7 +++++-- .../definitions/systemvmtemplate/preseed.cfg | 11 +++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/tools/appliance/definitions/systemvmtemplate/postinstall.sh b/tools/appliance/definitions/systemvmtemplate/postinstall.sh index ae8f1adfb9c..a19f515c8a2 100644 --- a/tools/appliance/definitions/systemvmtemplate/postinstall.sh +++ b/tools/appliance/definitions/systemvmtemplate/postinstall.sh @@ -64,9 +64,9 @@ install_packages() { apt-get --no-install-recommends -q -y --force-yes install iptables-persistent # vmware tools - apt-get --no-install-recommends -q -y --force-yes install open-vm-tools + #apt-get --no-install-recommends -q -y --force-yes install open-vm-tools # commented installaion of vmware-tools as we are using the opensource open-vm-tools: - # apt-get --no-install-recommends -q -y --force-yes install build-essential linux-headers-`uname -r` + apt-get --no-install-recommends -q -y --force-yes install build-essential linux-headers-`uname -r` # df -h # PREVDIR=$PWD # cd /opt @@ -186,6 +186,9 @@ configure_services() { snapshot_dir="/opt/cloudstack*" cd /opt wget --no-check-certificate $snapshot_url -O cloudstack.tar.gz +} + +cfg_cloud_early() { tar -zxvf cloudstack.tar.gz cp -rv $snapshot_dir/patches/systemvm/debian/config/* / cp -rv $snapshot_dir/patches/systemvm/debian/vpn/* / diff --git a/tools/appliance/definitions/systemvmtemplate/preseed.cfg b/tools/appliance/definitions/systemvmtemplate/preseed.cfg index 6996565aaae..61a0b38f45a 100644 --- a/tools/appliance/definitions/systemvmtemplate/preseed.cfg +++ b/tools/appliance/definitions/systemvmtemplate/preseed.cfg @@ -136,7 +136,7 @@ d-i partman-auto/expert_recipe string \ use_filesystem{ } filesystem{ ext4 } \ mountpoint{ /boot } \ . \ - 300 40 400 ext4 \ + 500 40 400 ext4 \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext4 } \ mountpoint{ / } \ @@ -146,17 +146,12 @@ d-i partman-auto/expert_recipe string \ use_filesystem{ } filesystem{ ext4 } \ mountpoint{ /home } \ . \ - 650 20 1100 ext4 \ + 900 20 1100 ext4 \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext4 } \ mountpoint{ /usr } \ . \ - 400 40 500 ext4 \ - method{ format } format{ } \ - use_filesystem{ } filesystem{ ext4 } \ - mountpoint{ /opt } \ - . \ - 450 60 1000 ext4 \ + 400 60 1000 ext4 \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext4 } \ mountpoint{ /var } \ From d39a06c0e92236e7ece548dd9c77b946ae438da7 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 11 Apr 2013 15:35:28 +0530 Subject: [PATCH 03/45] Revert "appliance: Revertible patch to create half baked template for vmware" This reverts commit 91faf2d14aed94dbb403febf7d8a2c4b22cc7d1a. --- .../definitions/systemvmtemplate/postinstall.sh | 7 ++----- .../definitions/systemvmtemplate/preseed.cfg | 11 ++++++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tools/appliance/definitions/systemvmtemplate/postinstall.sh b/tools/appliance/definitions/systemvmtemplate/postinstall.sh index a19f515c8a2..ae8f1adfb9c 100644 --- a/tools/appliance/definitions/systemvmtemplate/postinstall.sh +++ b/tools/appliance/definitions/systemvmtemplate/postinstall.sh @@ -64,9 +64,9 @@ install_packages() { apt-get --no-install-recommends -q -y --force-yes install iptables-persistent # vmware tools - #apt-get --no-install-recommends -q -y --force-yes install open-vm-tools + apt-get --no-install-recommends -q -y --force-yes install open-vm-tools # commented installaion of vmware-tools as we are using the opensource open-vm-tools: - apt-get --no-install-recommends -q -y --force-yes install build-essential linux-headers-`uname -r` + # apt-get --no-install-recommends -q -y --force-yes install build-essential linux-headers-`uname -r` # df -h # PREVDIR=$PWD # cd /opt @@ -186,9 +186,6 @@ configure_services() { snapshot_dir="/opt/cloudstack*" cd /opt wget --no-check-certificate $snapshot_url -O cloudstack.tar.gz -} - -cfg_cloud_early() { tar -zxvf cloudstack.tar.gz cp -rv $snapshot_dir/patches/systemvm/debian/config/* / cp -rv $snapshot_dir/patches/systemvm/debian/vpn/* / diff --git a/tools/appliance/definitions/systemvmtemplate/preseed.cfg b/tools/appliance/definitions/systemvmtemplate/preseed.cfg index 61a0b38f45a..6996565aaae 100644 --- a/tools/appliance/definitions/systemvmtemplate/preseed.cfg +++ b/tools/appliance/definitions/systemvmtemplate/preseed.cfg @@ -136,7 +136,7 @@ d-i partman-auto/expert_recipe string \ use_filesystem{ } filesystem{ ext4 } \ mountpoint{ /boot } \ . \ - 500 40 400 ext4 \ + 300 40 400 ext4 \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext4 } \ mountpoint{ / } \ @@ -146,12 +146,17 @@ d-i partman-auto/expert_recipe string \ use_filesystem{ } filesystem{ ext4 } \ mountpoint{ /home } \ . \ - 900 20 1100 ext4 \ + 650 20 1100 ext4 \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext4 } \ mountpoint{ /usr } \ . \ - 400 60 1000 ext4 \ + 400 40 500 ext4 \ + method{ format } format{ } \ + use_filesystem{ } filesystem{ ext4 } \ + mountpoint{ /opt } \ + . \ + 450 60 1000 ext4 \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext4 } \ mountpoint{ /var } \ From ca8ac08cf37cd9ea8a50d323ac596da16319e7ab Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Thu, 11 Apr 2013 09:50:48 -0600 Subject: [PATCH 04/45] CLOUDSTACK-2003: When accounts and domains are deleted, cleanup can fail, leaving instances in eternal expunged state. This happens when a domain is deleted while a deleted account is cleaning up. The cleanup looks for the domain of the account and we hit a null pointer. Adding null pointer check. Signed-off-by: Marcus Sorensen 1365695448 -0600 --- server/src/com/cloud/domain/dao/DomainDaoImpl.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/server/src/com/cloud/domain/dao/DomainDaoImpl.java b/server/src/com/cloud/domain/dao/DomainDaoImpl.java index 79ef17ed2a6..c30ca5ef49a 100644 --- a/server/src/com/cloud/domain/dao/DomainDaoImpl.java +++ b/server/src/com/cloud/domain/dao/DomainDaoImpl.java @@ -262,11 +262,14 @@ public class DomainDaoImpl extends GenericDaoBase implements Dom public Set getDomainParentIds(long domainId) { Set parentDomains = new HashSet(); Domain domain = findById(domainId); - parentDomains.add(domain.getId()); - - while (domain.getParent() != null) { - domain = findById(domain.getParent()); + + if (domain != null) { parentDomains.add(domain.getId()); + + while (domain.getParent() != null) { + domain = findById(domain.getParent()); + parentDomains.add(domain.getId()); + } } return parentDomains; From 9a50d2bd3b592a673d1a4aa1492a8282f5dfd737 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 11 Apr 2013 11:14:04 -0700 Subject: [PATCH 05/45] CLOUDSTACK-1910: cloudstack UI - Regions menu - implement create GSLB action. --- ui/scripts/regions.js | 136 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 2 deletions(-) diff --git a/ui/scripts/regions.js b/ui/scripts/regions.js index 0aaece009f7..129fc7a2e86 100644 --- a/ui/scripts/regions.js +++ b/ui/scripts/regions.js @@ -216,6 +216,139 @@ fields: { name: { label: 'label.name' } }, + + //??? + actions: { + add: { + label: 'Add GSLB', + + messages: { + confirm: function(args) { + return 'Add GSLB'; + }, + notification: function(args) { + return 'Add GSLB'; + } + }, + + createForm: { + title: 'Add GSLB', + fields: { + name: { + label: 'label.name', + validation: { required: true } + }, + description: { + label: 'label.description' + }, + domainid: { + label: 'Domain', + select: function(args) { + if(isAdmin() || isDomainAdmin()) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + success: function(json) { + var array1 = [{id: '', description: ''}]; + var domains = json.listdomainsresponse.domain; + if(domains != null && domains.length > 0) { + for(var i = 0; i < domains.length; i++) { + array1.push({id: domains[i].id, description: domains[i].path}); + } + } + args.response.success({ + data: array1 + }); + } + }); + } + else { + args.response.success({ + data: null + }); + } + }, + isHidden: function(args) { + if(isAdmin() || isDomainAdmin()) + return false; + else + return true; + } + }, + account: { + label: 'Account', + isHidden: function(args) { + if(isAdmin() || isDomainAdmin()) + return false; + else + return true; + } + }, + gslblbmethod: { + label: 'Algorithm', + select: function(args) { + var array1 = [{id: 'roundrobin', description: 'roundrobin'}, {id: 'leastconn', description: 'leastconn'}, {id: 'proximity', description: 'proximity'}]; + args.response.success({ + data: array1 + }); + } + }, + gslbdomainname: { + label: 'Domain Name', + validation: { required: true } + }, + gslbservicetype: { + label: 'Service Type', + select: function(args) { + var array1 = [{id: 'tcp', description: 'tcp'}, {id: 'udp', description: 'udp'}]; + args.response.success({ + data: array1 + }); + }, + validation: { required: true } + } + } + }, + action: function(args) { + var data = { + name: args.data.name, + regionid: args.context.regions[0].id, + gslblbmethod: args.data.gslblbmethod, + gslbdomainname: args.data.gslbdomainname, + gslbservicetype: args.data.gslbservicetype + }; + if(args.data.description != null && args.data.description.length > 0) + $.extend(data, { description: args.data.description }); + if(args.data.domainid != null && args.data.domainid.length > 0) + $.extend(data, { domainid: args.data.domainid }); + if(args.data.account != null && args.data.account.length > 0) + $.extend(data, { account: args.data.account }); + + $.ajax({ + url: createURL('createGlobalLoadBalancerRule'), + data: data, + success: function(json) { + var item = json.creategloballoadbalancerruleresponse.globalloadbalancerrule; + args.response.success({data: item}); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + //??? + dataProvider: function(args) { if('regions' in args.context) { var data = { @@ -224,8 +357,7 @@ $.ajax({ url: createURL('listGlobalLoadBalancerRules'), data: data, - success: function(json) { - debugger; + success: function(json) { var items = json.listgloballoadbalancerrulesresponse.globalloadbalancerrule; args.response.success({ data: items From f35272b6c585f85c5c0f1e92f99b8224feceb29e Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Thu, 11 Apr 2013 11:41:10 -0700 Subject: [PATCH 06/45] Fix the systemvm packaging issue --- client/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/pom.xml b/client/pom.xml index b3d7acb08a8..cd61dfc8bef 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -284,7 +284,7 @@ --> copy-systemvm - package + process-resources run From 3bcec62e64900f6b5ed7246f8028736c280eac10 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Thu, 11 Apr 2013 12:24:05 -0700 Subject: [PATCH 07/45] List view: Fix broken add row action --- ui/scripts/ui/widgets/listView.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ui/scripts/ui/widgets/listView.js b/ui/scripts/ui/widgets/listView.js index 1c74056c75b..c5e0561606f 100644 --- a/ui/scripts/ui/widgets/listView.js +++ b/ui/scripts/ui/widgets/listView.js @@ -863,16 +863,14 @@ var uiCustom = listViewArgs.uiCustom; var subselect = uiCustom ? listViewArgs.listView.subselect : null; - if (!data || !data.length) { + if (!(data && data.length)) { if (!$tbody.find('tr').size()) { return [ - $('').addClass('empty').append( + $('').addClass('empty last').append( $('').html(_l('label.no.data')) ).appendTo($tbody) ]; } - - return $tbody.find('tr:last').addClass('last'); } $tbody.find('tr.empty').remove(); From 76d1ee54ded97836d685539937d7d497e29fa19b Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Thu, 11 Apr 2013 12:28:52 -0700 Subject: [PATCH 08/45] VM NICs list view: Fix 'VM name' field for VMs without name --- ui/scripts/network.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 6c311923faf..b6ed0fe9904 100755 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -1554,7 +1554,9 @@ data.queryasyncjobresultresponse.jobresult.nicsecondaryip, { zoneid: args.context.instances[0].zoneid, - virtualmachinedisplayname: args.context.instances[0].displayname + virtualmachinedisplayname: args.context.instances[0].displayname ? + args.context.instances[0].displayname : + args.context.instances[0].name } ); }, @@ -1587,7 +1589,9 @@ data: $(ips).map(function(index, ip) { return $.extend(ip, { zoneid: args.context.instances[0].zoneid, - virtualmachinedisplayname: args.context.instances[0].displayname + virtualmachinedisplayname: args.context.instances[0].displayname ? + args.context.instances[0].displayname : + args.context.instances[0].name }); }) }); From a4e61b71cc32b68f15dafa36147033b9844df4eb Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 11 Apr 2013 12:39:43 -0700 Subject: [PATCH 09/45] CLOUDSTACK-1910: cloudstack UI - Regions menu - create GSLB - (1) pass gslbstickysessionmethodname parameter to createGlobalLoadBalancerRule API. (2) Take async Job response. --- ui/scripts/regions.js | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/ui/scripts/regions.js b/ui/scripts/regions.js index 129fc7a2e86..10057a62a4a 100644 --- a/ui/scripts/regions.js +++ b/ui/scripts/regions.js @@ -214,10 +214,10 @@ id: 'GSLB', label: 'GSLB', fields: { - name: { label: 'label.name' } - }, - - //??? + name: { label: 'label.name' }, + gslbdomainname: { label: 'GSLB Domain Name' }, + gslblbmethod: { label: 'Algorithm' } + }, actions: { add: { label: 'Add GSLB', @@ -241,6 +241,7 @@ description: { label: 'label.description' }, + /* domainid: { label: 'Domain', select: function(args) { @@ -287,6 +288,7 @@ return true; } }, + */ gslblbmethod: { label: 'Algorithm', select: function(args) { @@ -297,7 +299,7 @@ } }, gslbdomainname: { - label: 'Domain Name', + label: 'GSLB Domain Name', validation: { required: true } }, gslbservicetype: { @@ -317,38 +319,43 @@ name: args.data.name, regionid: args.context.regions[0].id, gslblbmethod: args.data.gslblbmethod, + gslbstickysessionmethodname: 'sourceip', gslbdomainname: args.data.gslbdomainname, gslbservicetype: args.data.gslbservicetype }; if(args.data.description != null && args.data.description.length > 0) - $.extend(data, { description: args.data.description }); + $.extend(data, { description: args.data.description }); + /* if(args.data.domainid != null && args.data.domainid.length > 0) $.extend(data, { domainid: args.data.domainid }); if(args.data.account != null && args.data.account.length > 0) - $.extend(data, { account: args.data.account }); - + $.extend(data, { account: args.data.account }); + */ $.ajax({ url: createURL('createGlobalLoadBalancerRule'), data: data, - success: function(json) { - var item = json.creategloballoadbalancerruleresponse.globalloadbalancerrule; - args.response.success({data: item}); - }, - error: function(data) { - args.response.error(parseXMLHttpResponse(data)); + success: function(json) { + var jid = json.creategloballoadbalancerruleresponse.jobid; + args.response.success( + {_custom: + {jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.globalloadbalancerrule; + } + } + } + ); } }); }, - notification: { poll: function(args) { - args.complete(); + poll: pollAsyncJobResult } } } }, - //??? - + dataProvider: function(args) { if('regions' in args.context) { var data = { From 119c5ceada2ed40d65c723176a4d5f3af43a9026 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Mon, 25 Feb 2013 10:23:15 -0800 Subject: [PATCH 10/45] API changes for createAffinityGroup --- api/src/org/apache/cloudstack/api/BaseCmd.java | 9 +++++---- client/tomcatconf/commands.properties.in | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index 8fef422b915..c94f3fb3089 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -27,6 +27,7 @@ import java.util.regex.Pattern; import javax.inject.Inject; +import org.apache.cloudstack.affinity.AffinityGroupService; import org.apache.cloudstack.query.QueryService; import org.apache.cloudstack.usage.UsageService; import org.apache.log4j.Logger; @@ -60,7 +61,6 @@ import com.cloud.projects.ProjectService; import com.cloud.resource.ResourceService; import com.cloud.server.ManagementService; import com.cloud.server.TaggedResourceService; -import com.cloud.storage.DataStoreProviderApiService; import com.cloud.storage.StorageService; import com.cloud.storage.VolumeApiService; import com.cloud.storage.snapshot.SnapshotService; @@ -132,6 +132,7 @@ public abstract class BaseCmd { @Inject public VMSnapshotService _vmSnapshotService; @Inject public DataStoreProviderApiService dataStoreProviderApiService; @Inject public VpcProvisioningService _vpcProvSvc; + @Inject public AffinityGroupService _affinityGroupService; public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException; @@ -154,7 +155,7 @@ public abstract class BaseCmd { /** * For commands the API framework needs to know the owner of the object being acted upon. This method is * used to determine that information. - * + * * @return the id of the account that owns the object being acted upon */ public abstract long getEntityOwnerId(); @@ -467,7 +468,7 @@ public abstract class BaseCmd { if (!enabledOnly || account.getState() == Account.State.enabled) { return account.getId(); } else { - throw new PermissionDeniedException("Can't add resources to the account id=" + account.getId() + " in state=" + account.getState() + " as it's no longer active"); + throw new PermissionDeniedException("Can't add resources to the account id=" + account.getId() + " in state=" + account.getState() + " as it's no longer active"); } } else { // idList is not used anywhere, so removed it now @@ -484,7 +485,7 @@ public abstract class BaseCmd { return project.getProjectAccountId(); } else { PermissionDeniedException ex = new PermissionDeniedException("Can't add resources to the project with specified projectId in state=" + project.getState() + " as it's no longer active"); - ex.addProxyObject(project, projectId, "projectId"); + ex.addProxyObject(project, projectId, "projectId"); throw ex; } } else { diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 163c2cee861..e4823d9669d 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -568,3 +568,6 @@ revertToSnapshot=15 #### Baremetal commands addBaremetalHost=1 + +#### Affinity group commands +createAffinityGroup=15 From 1e205a3d0b8856ae6329930076dd77575e38fda6 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Wed, 27 Feb 2013 14:27:02 -0800 Subject: [PATCH 11/45] More API changes --- .../cloudstack/affinity/AffinityGroup.java | 15 ++ .../affinity/AffinityGroupResponse.java | 139 ++++++++++++++++++ .../affinity/AffinityGroupService.java | 54 +++++++ .../cloudstack/api/ResponseGenerator.java | 18 +-- .../affinitygroup/CreateAffinityGroupCmd.java | 126 ++++++++++++++++ .../src/com/cloud/api/ApiResponseHelper.java | 62 +++++++- .../affinity/AffinityGroupServiceImpl.java | 94 ++++++++++++ .../affinity/AffinityGroupVMMapVO.java | 74 ++++++++++ .../cloudstack/affinity/AffinityGroupVO.java | 107 ++++++++++++++ .../affinity/dao/AffinityGroupDao.java | 30 ++++ .../affinity/dao/AffinityGroupDaoImpl.java | 97 ++++++++++++ .../affinity/dao/AffinityGroupVMMapDao.java | 43 ++++++ .../dao/AffinityGroupVMMapDaoImpl.java | 120 +++++++++++++++ 13 files changed, 960 insertions(+), 19 deletions(-) create mode 100644 api/src/org/apache/cloudstack/affinity/AffinityGroup.java create mode 100644 api/src/org/apache/cloudstack/affinity/AffinityGroupResponse.java create mode 100644 api/src/org/apache/cloudstack/affinity/AffinityGroupService.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/affinitygroup/CreateAffinityGroupCmd.java create mode 100644 server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java create mode 100644 server/src/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java create mode 100644 server/src/org/apache/cloudstack/affinity/AffinityGroupVO.java create mode 100644 server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java create mode 100644 server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java create mode 100644 server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java create mode 100644 server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroup.java b/api/src/org/apache/cloudstack/affinity/AffinityGroup.java new file mode 100644 index 00000000000..b8215a279a8 --- /dev/null +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroup.java @@ -0,0 +1,15 @@ +package org.apache.cloudstack.affinity; + +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface AffinityGroup extends ControlledEntity, InternalIdentity, Identity { + + String getName(); + + String getDescription(); + + String getType(); + +} diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupResponse.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupResponse.java new file mode 100644 index 00000000000..073a82c4363 --- /dev/null +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupResponse.java @@ -0,0 +1,139 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT 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.affinity; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; +import org.apache.cloudstack.api.response.ControlledEntityResponse; +import org.apache.cloudstack.api.response.ControlledViewEntityResponse; + +import com.cloud.network.security.SecurityGroup; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("unused") +@EntityReference(value = AffinityGroup.class) +public class AffinityGroupResponse extends BaseResponse implements ControlledEntityResponse { + + @SerializedName(ApiConstants.ID) @Param(description="the ID of the affinity group") + private String id; + + @SerializedName(ApiConstants.NAME) @Param(description="the name of the affinity group") + private String name; + + @SerializedName(ApiConstants.DESCRIPTION) @Param(description="the description of the affinity group") + private String description; + + @SerializedName(ApiConstants.ACCOUNT) @Param(description="the account owning the affinity group") + private String accountName; + + @SerializedName(ApiConstants.DOMAIN_ID) @Param(description="the domain ID of the affinity group") + private String domainId; + + @SerializedName(ApiConstants.DOMAIN) @Param(description="the domain name of the affinity group") + private String domainName; + + @SerializedName(ApiConstants.TYPE) + @Param(description = "the type of the affinity group") + private String type; + + + public AffinityGroupResponse() { + } + + @Override + public String getObjectId() { + return this.getId(); + } + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + + public void setName(String name) { + this.name = name; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public void setDomainId(String domainId) { + this.domainId = domainId; + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.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; + AffinityGroupResponse other = (AffinityGroupResponse) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + return true; + } + + @Override + public void setProjectId(String projectId) { + // TODO Auto-generated method stub + + } + + @Override + public void setProjectName(String projectName) { + // TODO Auto-generated method stub + + } + +} diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java new file mode 100644 index 00000000000..83231766c83 --- /dev/null +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java @@ -0,0 +1,54 @@ +package org.apache.cloudstack.affinity; + +import java.util.List; + +public interface AffinityGroupService { + + /** + * Creates an affinity/anti-affinity group for the given account/domain. + * + * @param account + * @param domainId + * @param name + * @param type + * @param description + * @return AffinityGroup + */ + + AffinityGroup createAffinityGroup(String account, Long domainId, String affinityGroupName, + String affinityGroupType, String description); + + /** + * Creates an affinity/anti-affinity group. + * + * @param affinityGroupId + * @param account + * @param domainId + * @param affinityGroupName + * @param vmId + */ + void deleteAffinityGroup(Long affinityGroupId, String account, Long domainId, String affinityGroupName, Long vmId); + + /** + * Lists Affinity Groups + * + * @param account + * @param domainId + * @param affinityGroupId + * @param affinityGroupName + * @param affinityGroupType + * @param vmId + * @return + */ + List listAffinityGroups(String account, Long domainId, Long affinityGroupId, + String affinityGroupName, String affinityGroupType, Long vmId); + + + /** + * List group types available in deployment + * + * @return + */ + List listAffinityGroupTypes(); + +} diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java index d1e13023117..f09f8aeb080 100644 --- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java @@ -20,8 +20,8 @@ import java.text.DecimalFormat; import java.util.EnumSet; import java.util.List; -import org.apache.cloudstack.api.ApiConstants.HostDetails; -import org.apache.cloudstack.api.ApiConstants.VMDetails; +import org.apache.cloudstack.affinity.AffinityGroup; +import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.AsyncJobResponse; @@ -138,7 +138,6 @@ import com.cloud.org.Cluster; import com.cloud.projects.Project; import com.cloud.projects.ProjectAccount; import com.cloud.projects.ProjectInvitation; -import com.cloud.region.ha.GlobalLoadBalancerRule; import com.cloud.server.ResourceTag; import com.cloud.storage.*; import com.cloud.storage.snapshot.SnapshotPolicy; @@ -153,15 +152,7 @@ import com.cloud.vm.Nic; import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.VirtualMachine; -import org.apache.cloudstack.api.ApiConstants.HostDetails; -import org.apache.cloudstack.api.ApiConstants.VMDetails; -import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; import org.apache.cloudstack.api.response.*; -import org.apache.cloudstack.region.Region; - -import java.text.DecimalFormat; -import java.util.EnumSet; -import java.util.List; public interface ResponseGenerator { UserResponse createUserResponse(UserAccount user); @@ -384,12 +375,15 @@ public interface ResponseGenerator { GuestOSResponse createGuestOSResponse(GuestOS os); SnapshotScheduleResponse createSnapshotScheduleResponse(SnapshotSchedule sched); - + UsageRecordResponse createUsageResponse(Usage usageRecord); TrafficMonitorResponse createTrafficMonitorResponse(Host trafficMonitor); VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot); + NicSecondaryIpResponse createSecondaryIPToNicResponse(String ip, Long nicId, Long networkId); public NicResponse createNicResponse(Nic result); + + AffinityGroupResponse createAffinityGroupResponse(AffinityGroup group); } diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/CreateAffinityGroupCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/CreateAffinityGroupCmd.java new file mode 100644 index 00000000000..c38bcffaa76 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/CreateAffinityGroupCmd.java @@ -0,0 +1,126 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT 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.affinitygroup; + +import org.apache.cloudstack.affinity.AffinityGroup; +import org.apache.cloudstack.affinity.AffinityGroupResponse; +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.DomainResponse; +import org.apache.log4j.Logger; + +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "createAffinityGroup", responseObject = AffinityGroupResponse.class, description = "Creates an affinity/anti-affinity group") +public class CreateAffinityGroupCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(CreateAffinityGroupCmd.class.getName()); + + private static final String s_name = "createaffinitygroupresponse"; + + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = true, description = "an account for the affinity group. Must be used with domainId.") + private String accountName; + + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, description = "domainId of the account owning the affinity group", entityType = DomainResponse.class) + private Long domainId; + + @Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "optional description of the affinity group") + private String description; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "name of the affinity group") + private String affinityGroupName; + + @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, description = "Type of the affinity group from the available affinity/anti-affinity group types") + private String affinityGroupType; + + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + + public String getAccountName() { + return accountName; + } + + public String getDescription() { + return description; + } + + public Long getDomainId() { + return domainId; + } + + public String getAffinityGroupName() { + return affinityGroupName; + } + + public String getAffinityGroupType() { + return affinityGroupType; + } + + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + Account account = UserContext.current().getCaller(); + if ((account == null) || isAdmin(account.getType())) { + if ((domainId != null) && (accountName != null)) { + Account userAccount = _responseGenerator.findAccountByNameDomain(accountName, domainId); + if (userAccount != null) { + return userAccount.getId(); + } + } + } + + if (account != null) { + return account.getId(); + } + + return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this + // command to SYSTEM so ERROR events + // are tracked + } + + @Override + public void execute() { + AffinityGroup group = _affinityGroupService.createAffinityGroup(accountName, domainId, affinityGroupName, + affinityGroupType, description); + if (group != null) { + AffinityGroupResponse response = _responseGenerator.createAffinityGroupResponse(group); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create affinity group:" + + affinityGroupName); + } + } +} diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 93b755a665a..7b23b3b20cd 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -270,8 +270,41 @@ import com.cloud.vm.NicVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; +<<<<<<< HEAD import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.snapshot.VMSnapshot; +======= +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.affinity.AffinityGroup; +import org.apache.cloudstack.affinity.AffinityGroupResponse; +import org.apache.cloudstack.api.ApiConstants.HostDetails; +import org.apache.cloudstack.api.ApiConstants.VMDetails; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.ResponseGenerator; +import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; +import org.apache.cloudstack.api.response.*; +import org.apache.cloudstack.region.Region; +import org.apache.cloudstack.usage.Usage; +import org.apache.cloudstack.usage.UsageService; +import org.apache.cloudstack.usage.UsageTypes; +import com.cloud.vm.VmStats; +import com.cloud.vm.dao.UserVmData; +import com.cloud.vm.dao.UserVmData.NicData; +import com.cloud.vm.dao.UserVmData.SecurityGroupData; +import com.cloud.vm.snapshot.VMSnapshot; +import org.apache.cloudstack.api.ResponseGenerator; +import org.apache.cloudstack.api.response.VMSnapshotResponse; +import org.apache.log4j.Logger; + +import java.text.DecimalFormat; +import java.util.*; + +import javax.inject.Inject; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +>>>>>>> More API changes @Component public class ApiResponseHelper implements ResponseGenerator { @@ -439,7 +472,7 @@ public class ApiResponseHelper implements ResponseGenerator { vmSnapshotResponse.setCreated(vmSnapshot.getCreated()); vmSnapshotResponse.setDescription(vmSnapshot.getDescription()); vmSnapshotResponse.setDisplayName(vmSnapshot.getDisplayName()); - UserVm vm = ApiDBUtils.findUserVmById(vmSnapshot.getVmId()); + UserVm vm = ApiDBUtils.findUserVmById(vmSnapshot.getVmId()); if(vm!=null) vmSnapshotResponse.setVirtualMachineid(vm.getUuid()); if(vmSnapshot.getParent() != null) @@ -449,7 +482,7 @@ public class ApiResponseHelper implements ResponseGenerator { vmSnapshotResponse.setObjectName("vmsnapshot"); return vmSnapshotResponse; } - + @Override public SnapshotPolicyResponse createSnapshotPolicyResponse(SnapshotPolicy policy) { SnapshotPolicyResponse policyResponse = new SnapshotPolicyResponse(); @@ -546,7 +579,7 @@ public class ApiResponseHelper implements ResponseGenerator { vlanResponse.setIp6Gateway(vlan.getIp6Gateway()); vlanResponse.setIp6Cidr(vlan.getIp6Cidr()); - + String ip6Range = vlan.getIp6Range(); if (ip6Range != null) { String[] range = ip6Range.split("-"); @@ -2250,7 +2283,7 @@ public class ApiResponseHelper implements ResponseGenerator { if (((network.getCidr()) != null) && (network.getNetworkCidr() == null)) { response.setNetmask(NetUtils.cidr2Netmask(network.getCidr())); } - + response.setIp6Gateway(network.getIp6Gateway()); response.setIp6Cidr(network.getIp6Cidr()); @@ -2445,7 +2478,7 @@ public class ApiResponseHelper implements ResponseGenerator { List cidrs = ApiDBUtils.findFirewallSourceCidrs(fwRule.getId()); response.setCidrList(StringUtils.join(cidrs, ",")); - + if (fwRule.getTrafficType() == FirewallRule.TrafficType.Ingress) { IpAddress ip = ApiDBUtils.findIpAddressById(fwRule.getSourceIpAddressId()); response.setPublicIpAddressId(ip.getId()); @@ -3476,7 +3509,7 @@ public class ApiResponseHelper implements ResponseGenerator { return usageRecResponse; } - + public String getDateStringInternal(Date inputDate) { if (inputDate == null) return null; @@ -3560,7 +3593,7 @@ public class ApiResponseHelper implements ResponseGenerator { return sb.toString(); } - + @Override public TrafficMonitorResponse createTrafficMonitorResponse(Host trafficMonitor) { Map tmDetails = ApiDBUtils.findHostDetailsById(trafficMonitor.getId()); @@ -3620,4 +3653,19 @@ public class ApiResponseHelper implements ResponseGenerator { response.setIsDefault(result.isDefaultNic()); return response; } + + @Override + public AffinityGroupResponse createAffinityGroupResponse(AffinityGroup group) { + + AffinityGroupResponse response = new AffinityGroupResponse(); + + Account account = ApiDBUtils.findAccountById(group.getAccountId()); + response.setAccountName(account.getAccountName()); + response.setName(group.getName()); + response.setType(group.getType()); + response.setDescription(group.getDescription()); + // response.setDomainId(account.) + + return response; + } } diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java new file mode 100644 index 00000000000..eee3e6f37c3 --- /dev/null +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java @@ -0,0 +1,94 @@ +package org.apache.cloudstack.affinity; + +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; +import org.apache.log4j.Logger; + + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.UserContext; +import com.cloud.utils.component.Manager; +import com.cloud.utils.component.ManagerBase; + +@Local(value = { AffinityGroupService.class }) +public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGroupService, Manager { + + public static final Logger s_logger = Logger.getLogger(AffinityGroupServiceImpl.class); + private String _name; + + @Inject + AccountManager _accountMgr; + + @Inject + AffinityGroupDao _affinityGroupDao; + + @Override + public AffinityGroup createAffinityGroup(String account, Long domainId, String affinityGroupName, + String affinityGroupType, String description) { + + Account caller = UserContext.current().getCaller(); + Account owner = _accountMgr.finalizeOwner(caller, account, domainId, null); + + if (_affinityGroupDao.isNameInUse(owner.getId(), owner.getDomainId(), affinityGroupName)) { + throw new InvalidParameterValueException("Unable to create affinity group, a group with name " + + affinityGroupName + + " already exisits."); + } + + AffinityGroupVO group = new AffinityGroupVO(affinityGroupName, affinityGroupType, description, domainId, + owner.getId()); + _affinityGroupDao.persist(group); + + return group; + } + + @Override + public void deleteAffinityGroup(Long affinityGroupId, String account, Long domainId, String affinityGroupName, + Long vmId) { + // TODO Auto-generated method stub + + } + + @Override + public List listAffinityGroups(String account, Long domainId, Long affinityGroupId, + String affinityGroupName, String affinityGroupType, Long vmId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List listAffinityGroupTypes() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean configure(final String name, final Map params) throws ConfigurationException { + _name = name; + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return _name; + } + +} diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java new file mode 100644 index 00000000000..5401b4aef70 --- /dev/null +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java @@ -0,0 +1,74 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT 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.affinity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.SecondaryTable; +import javax.persistence.SecondaryTables; +import javax.persistence.Table; + +import org.apache.cloudstack.api.InternalIdentity; + +@Entity +@Table(name = ("affinity_group_vm_map")) +@SecondaryTables({ @SecondaryTable(name = "affinity_group", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "affinity_group_id", referencedColumnName = "id") }) }) +public class AffinityGroupVMMapVO implements InternalIdentity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "affinity_group_id") + private long affinityGroupId; + + @Column(name = "instance_id") + private long instanceId; + + @Column(name = "name", table = "affinity_group", insertable = false, updatable = false) + private String groupName; + + public AffinityGroupVMMapVO() { + } + + public AffinityGroupVMMapVO(long affinityGroupId, long instanceId) { + this.affinityGroupId = affinityGroupId; + this.instanceId = instanceId; + } + + public long getId() { + return id; + } + + public long getAffinityGroupId() { + return affinityGroupId; + } + + + public long getInstanceId() { + return instanceId; + } + + + public String getGroupName() { + return groupName; + } +} diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupVO.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupVO.java new file mode 100644 index 00000000000..fab3835feda --- /dev/null +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupVO.java @@ -0,0 +1,107 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT 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.affinity; + +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + + +@Entity +@Table(name = ("affinity_group")) +public class AffinityGroupVO implements AffinityGroup { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "name") + private String name; + + @Column(name = "type") + private String type; + + @Column(name = "description") + private String description; + + @Column(name = "domain_id") + private long domainId; + + @Column(name = "account_id") + private long accountId; + + @Column(name = "uuid") + private String uuid; + + public AffinityGroupVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public AffinityGroupVO(String name, String type, String description, long domainId, long accountId) { + this.name = name; + this.description = description; + this.domainId = domainId; + this.accountId = accountId; + this.uuid = UUID.randomUUID().toString(); + this.type = type; + } + + @Override + public long getId() { + return id; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public long getDomainId() { + return domainId; + } + + @Override + public long getAccountId() { + return accountId; + } + + @Override + public String getUuid() { + return this.uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + @Override + public String getType() { + return type; + } + +} diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java new file mode 100644 index 00000000000..296e7b1d043 --- /dev/null +++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.affinity.dao; + +import java.util.List; + +import org.apache.cloudstack.affinity.AffinityGroupVO; +import com.cloud.utils.db.GenericDao; + +public interface AffinityGroupDao extends GenericDao { + List listByAccountId(long accountId); + boolean isNameInUse(Long accountId, Long domainId, String name); + AffinityGroupVO findByAccountAndName(Long accountId, String name); + List findByAccountAndNames(Long accountId, String... names); + int removeByAccountId(long accountId); +} diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java new file mode 100644 index 00000000000..bfa06c7cbf3 --- /dev/null +++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.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 org.apache.cloudstack.affinity.dao; + +import java.util.List; + +import javax.ejb.Local; +import org.apache.cloudstack.affinity.AffinityGroupVO; +import org.springframework.stereotype.Component; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +@Local(value = { AffinityGroupDao.class }) +public class AffinityGroupDaoImpl extends GenericDaoBase implements AffinityGroupDao { + private SearchBuilder AccountIdSearch; + private SearchBuilder AccountIdNameSearch; + private SearchBuilder AccountIdNamesSearch; + + + protected AffinityGroupDaoImpl() { + AccountIdSearch = createSearchBuilder(); + AccountIdSearch.and("accountId", AccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ); + AccountIdSearch.done(); + + AccountIdNameSearch = createSearchBuilder(); + AccountIdNameSearch.and("accountId", AccountIdNameSearch.entity().getAccountId(), SearchCriteria.Op.EQ); + AccountIdNameSearch.and("name", AccountIdNameSearch.entity().getName(), SearchCriteria.Op.EQ); + + AccountIdNamesSearch = createSearchBuilder(); + AccountIdNamesSearch.and("accountId", AccountIdNamesSearch.entity().getAccountId(), SearchCriteria.Op.EQ); + AccountIdNamesSearch.and("groupNames", AccountIdNamesSearch.entity().getName(), SearchCriteria.Op.IN); + AccountIdNameSearch.done(); + } + + @Override + public List listByAccountId(long accountId) { + SearchCriteria sc = AccountIdSearch.create(); + sc.setParameters("accountId", accountId); + return listBy(sc); + } + + @Override + public boolean isNameInUse(Long accountId, Long domainId, String name) { + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("name", SearchCriteria.Op.EQ, name); + if (accountId != null) { + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + } else { + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + sc.addAnd("accountId", SearchCriteria.Op.NULL); + } + + List AffinityGroups = listBy(sc); + return ((AffinityGroups != null) && !AffinityGroups.isEmpty()); + } + + @Override + public AffinityGroupVO findByAccountAndName(Long accountId, String name) { + SearchCriteria sc = AccountIdNameSearch.create(); + sc.setParameters("accountId", accountId); + sc.setParameters("name", name); + + return findOneIncludingRemovedBy(sc); + } + + @Override + public List findByAccountAndNames(Long accountId, String... names) { + SearchCriteria sc = AccountIdNamesSearch.create(); + sc.setParameters("accountId", accountId); + + sc.setParameters("groupNames", (Object [])names); + + return listBy(sc); + } + @Override + public int removeByAccountId(long accountId) { + SearchCriteria sc = AccountIdSearch.create(); + sc.setParameters("accountId", accountId); + return expunge(sc); + } +} diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java new file mode 100644 index 00000000000..9841de44680 --- /dev/null +++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.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.affinity.dao; + +import java.util.List; + +import org.apache.cloudstack.affinity.AffinityGroupVMMapVO; + +import com.cloud.utils.Pair; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDao; +import com.cloud.vm.VirtualMachine.State; + +public interface AffinityGroupVMMapDao extends GenericDao { + + List listByInstanceId(long instanceId); + + Pair, Integer> listByInstanceId(long instanceId, Filter filter); + + List listByAffinityGroup(long affinityGroupId); + + List listVmIdsByAffinityGroup(long affinityGroupId); + + AffinityGroupVMMapVO findByVmIdGroupId(long instanceId, long affinityGroupId); + + long countAffinityGroupsForVm(long instanceId); + + int deleteVM(long instanceId); +} diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java new file mode 100644 index 00000000000..e9286dbc726 --- /dev/null +++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.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.affinity.dao; + +import java.util.List; + +import javax.ejb.Local; + +import org.apache.cloudstack.affinity.AffinityGroupVMMapVO; +import org.springframework.stereotype.Component; + +import com.cloud.utils.Pair; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Func; + +@Component +@Local(value = { AffinityGroupVMMapDao.class }) +public class AffinityGroupVMMapDaoImpl extends GenericDaoBase implements + AffinityGroupVMMapDao { + private SearchBuilder ListByVmId; + private SearchBuilder ListByVmIdGroupId; + protected GenericSearchBuilder CountSGForVm; + private GenericSearchBuilder ListVmIdByAffinityGroup; + private SearchBuilder ListByAffinityGroup; + + protected AffinityGroupVMMapDaoImpl() { + ListVmIdByAffinityGroup = createSearchBuilder(Long.class); + ListVmIdByAffinityGroup.and("affinityGroupId", ListVmIdByAffinityGroup.entity().getAffinityGroupId(), + SearchCriteria.Op.EQ); + ListVmIdByAffinityGroup.selectField(ListVmIdByAffinityGroup.entity().getInstanceId()); + ListVmIdByAffinityGroup.done(); + + ListByAffinityGroup = createSearchBuilder(); + ListByAffinityGroup.and("affinityGroupId", ListByAffinityGroup.entity().getAffinityGroupId(), + SearchCriteria.Op.EQ); + ListByAffinityGroup.done(); + + ListByVmId = createSearchBuilder(); + ListByVmId.and("instanceId", ListByVmId.entity().getInstanceId(), SearchCriteria.Op.EQ); + ListByVmId.done(); + + ListByVmIdGroupId = createSearchBuilder(); + ListByVmIdGroupId.and("instanceId", ListByVmIdGroupId.entity().getInstanceId(), SearchCriteria.Op.EQ); + ListByVmIdGroupId.and("affinityGroupId", ListByVmIdGroupId.entity().getAffinityGroupId(), SearchCriteria.Op.EQ); + ListByVmIdGroupId.done(); + + CountSGForVm = createSearchBuilder(Long.class); + CountSGForVm.select(null, Func.COUNT, null); + CountSGForVm.and("vmId", CountSGForVm.entity().getInstanceId(), SearchCriteria.Op.EQ); + CountSGForVm.done(); + } + + @Override + public List listByAffinityGroup(long affinityGroupId) { + SearchCriteria sc = ListByAffinityGroup.create(); + sc.setParameters("affinityGroupId", affinityGroupId); + return listBy(sc); + } + + @Override + public List listByInstanceId(long vmId) { + SearchCriteria sc = ListByVmId.create(); + sc.setParameters("instanceId", vmId); + return listBy(sc); + } + + @Override + public Pair, Integer> listByInstanceId(long instanceId, Filter filter) { + SearchCriteria sc = ListByVmId.create(); + sc.setParameters("instanceId", instanceId); + return this.searchAndCount(sc, filter); + } + + @Override + public int deleteVM(long instanceId) { + SearchCriteria sc = ListByVmId.create(); + sc.setParameters("instanceId", instanceId); + return super.expunge(sc); + } + + @Override + public List listVmIdsByAffinityGroup(long affinityGroupId) { + SearchCriteria sc = ListVmIdByAffinityGroup.create(); + sc.setParameters("affinityGroupId", affinityGroupId); + return customSearchIncludingRemoved(sc, null); + } + + @Override + public AffinityGroupVMMapVO findByVmIdGroupId(long instanceId, long affinityGroupId) { + SearchCriteria sc = ListByVmIdGroupId.create(); + sc.setParameters("affinityGroupId", affinityGroupId); + sc.setParameters("instanceId", instanceId); + return findOneIncludingRemovedBy(sc); + } + + @Override + public long countAffinityGroupsForVm(long instanceId) { + SearchCriteria sc = CountSGForVm.create(); + sc.setParameters("vmId", instanceId); + return customSearch(sc, null).get(0); + } +} From 50f53c86f59dd696f5f5315ba9a4c11b3f84c302 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 28 Feb 2013 13:42:33 -0800 Subject: [PATCH 12/45] DeleteAffinityGroup API changes --- api/src/com/cloud/event/EventTypes.java | 7 +- .../affinity/AffinityGroupService.java | 9 +- .../cloudstack/api/ResponseGenerator.java | 2 + .../affinitygroup/DeleteAffinityGroupCmd.java | 137 ++++++++++++++++++ server/src/com/cloud/api/ApiDBUtils.java | 14 +- .../src/com/cloud/api/ApiResponseHelper.java | 10 ++ .../affinity/AffinityGroupServiceImpl.java | 70 ++++++++- 7 files changed, 239 insertions(+), 10 deletions(-) create mode 100644 api/src/org/apache/cloudstack/api/command/user/affinitygroup/DeleteAffinityGroupCmd.java diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 5671f995c70..bd5f2204fcf 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -348,7 +348,7 @@ public class EventTypes { // tag related events public static final String EVENT_TAGS_CREATE = "CREATE_TAGS"; public static final String EVENT_TAGS_DELETE = "DELETE_TAGS"; - + // vm snapshot events public static final String EVENT_VM_SNAPSHOT_CREATE = "VMSNAPSHOT.CREATE"; public static final String EVENT_VM_SNAPSHOT_DELETE = "VMSNAPSHOT.DELETE"; @@ -382,6 +382,11 @@ public class EventTypes { public static final String EVENT_BAREMETAL_PXE_SERVER_ADD = "PHYSICAL.PXE.ADD"; public static final String EVENT_BAREMETAL_PXE_SERVER_DELETE = "PHYSICAL.PXE.DELETE"; + public static final String EVENT_AFFINITY_GROUP_CREATE = "AG.CREATE"; + public static final String EVENT_AFFINITY_GROUP_DELETE = "AG.DELETE"; + public static final String EVENT_AFFINITY_GROUP_ASSIGN = "AG.ASSIGN"; + public static final String EVENT_AFFINITY_GROUP_REMOVE = "AG.REMOVE"; + static { // TODO: need a way to force author adding event types to declare the entity details as well, with out braking diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java index 83231766c83..501280da9ac 100644 --- a/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java @@ -2,6 +2,8 @@ package org.apache.cloudstack.affinity; import java.util.List; +import com.cloud.exception.ResourceInUseException; + public interface AffinityGroupService { /** @@ -20,14 +22,15 @@ public interface AffinityGroupService { /** * Creates an affinity/anti-affinity group. - * + * * @param affinityGroupId * @param account * @param domainId * @param affinityGroupName - * @param vmId + * @throws ResourceInUseException */ - void deleteAffinityGroup(Long affinityGroupId, String account, Long domainId, String affinityGroupName, Long vmId); + boolean deleteAffinityGroup(Long affinityGroupId, String account, Long domainId, String affinityGroupName) + throws ResourceInUseException; /** * Lists Affinity Groups diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java index f09f8aeb080..977713005f2 100644 --- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java @@ -386,4 +386,6 @@ public interface ResponseGenerator { public NicResponse createNicResponse(Nic result); AffinityGroupResponse createAffinityGroupResponse(AffinityGroup group); + + Long getAffinityGroupId(String name, long entityOwnerId); } diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/DeleteAffinityGroupCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/DeleteAffinityGroupCmd.java new file mode 100644 index 00000000000..8ace2e57f8e --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/DeleteAffinityGroupCmd.java @@ -0,0 +1,137 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT 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.affinitygroup; + +import org.apache.cloudstack.affinity.AffinityGroupResponse; +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.DomainResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.log4j.Logger; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceInUseException; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "deleteAffinityGroup", description = "Deletes affinity group", responseObject = SuccessResponse.class) +public class DeleteAffinityGroupCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(DeleteAffinityGroupCmd.class.getName()); + private static final String s_name = "deleteaffinitygroupresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "the account of the affinity group. Must be specified with domain ID") + private String accountName; + + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, description = "the domain ID of account owning the affinity group", entityType = DomainResponse.class) + private Long domainId; + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, description = "The ID of the affinity group. Mutually exclusive with name parameter", entityType = AffinityGroupResponse.class) + private Long id; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "The ID of the affinity group. Mutually exclusive with id parameter") + private String name; + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getAccountName() { + return accountName; + } + + public Long getDomainId() { + return domainId; + } + + + public Long getId() { + if (id != null && name != null) { + throw new InvalidParameterValueException("name and id parameters are mutually exclusive"); + } + + if (name != null) { + id = _responseGenerator.getAffinityGroupId(name, getEntityOwnerId()); + if (id == null) { + throw new InvalidParameterValueException("Unable to find affinity group by name " + name + + " for the account id=" + getEntityOwnerId()); + } + } + + if (id == null) { + throw new InvalidParameterValueException( + "Either id or name parameter is requred by deleteAffinityGroup command"); + } + + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + Account account = UserContext.current().getCaller(); + if ((account == null) || isAdmin(account.getType())) { + if ((domainId != null) && (accountName != null)) { + Account userAccount = _responseGenerator.findAccountByNameDomain(accountName, domainId); + if (userAccount != null) { + return userAccount.getId(); + } + } + } + + if (account != null) { + return account.getId(); + } + + return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this + // command to SYSTEM so ERROR events + // are tracked + + } + + @Override + public void execute(){ + try{ + boolean result = _affinityGroupService.deleteAffinityGroup(id, accountName, domainId, name); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete affinity group"); + } + } catch (ResourceInUseException ex) { + s_logger.warn("Exception: ", ex); + throw new ServerApiException(ApiErrorCode.RESOURCE_IN_USE_ERROR, ex.getMessage()); + } + } +} diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index 7b441901d5e..d21e2c46a63 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -25,6 +25,8 @@ import java.util.Set; import javax.annotation.PostConstruct; import javax.inject.Inject; +import org.apache.cloudstack.affinity.AffinityGroup; +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; import org.apache.cloudstack.api.ApiConstants.HostDetails; import org.apache.cloudstack.api.ApiConstants.VMDetails; import org.apache.cloudstack.api.response.AccountResponse; @@ -284,7 +286,7 @@ public class ApiDBUtils { static NetworkModel _networkModel; static NetworkManager _networkMgr; static TemplateManager _templateMgr; - + static StatsCollector _statsCollector; static AccountDao _accountDao; @@ -379,6 +381,7 @@ public class ApiDBUtils { static ClusterDetailsDao _clusterDetailsDao; static NicSecondaryIpDao _nicSecondaryIpDao; static VpcProvisioningService _vpcProvSvc; + static AffinityGroupDao _affinityGroupDao; @Inject private ManagementServer ms; @Inject public AsyncJobManager asyncMgr; @@ -483,6 +486,8 @@ public class ApiDBUtils { @Inject private VMSnapshotDao vmSnapshotDao; @Inject private NicSecondaryIpDao nicSecondaryIpDao; @Inject private VpcProvisioningService vpcProvSvc; + @Inject private AffinityGroupDao affinityGroupDao; + @PostConstruct void init() { _ms = ms; @@ -585,6 +590,7 @@ public class ApiDBUtils { _vmSnapshotDao = vmSnapshotDao; _nicSecondaryIpDao = nicSecondaryIpDao; _vpcProvSvc = vpcProvSvc; + _affinityGroupDao = affinityGroupDao; // Note: stats collector should already have been initialized by this time, otherwise a null instance is returned _statsCollector = StatsCollector.getInstance(); } @@ -1579,7 +1585,7 @@ public class ApiDBUtils { public static DataCenterJoinVO newDataCenterView(DataCenter dc){ return _dcJoinDao.newDataCenterView(dc); } - + public static Map findHostDetailsById(long hostId){ return _hostDetailsDao.findDetails(hostId); } @@ -1587,4 +1593,8 @@ public class ApiDBUtils { public static List findNicSecondaryIps(long nicId) { return _nicSecondaryIpDao.listByNicId(nicId); } + + public static AffinityGroup getAffinityGroup(String groupName, long accountId) { + return _affinityGroupDao.findByAccountAndName(accountId, groupName); + } } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 7b23b3b20cd..d651f1f1c6a 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -3668,4 +3668,14 @@ public class ApiResponseHelper implements ResponseGenerator { return response; } + + @Override + public Long getAffinityGroupId(String groupName, long accountId) { + AffinityGroup ag = ApiDBUtils.getAffinityGroup(groupName, accountId); + if (ag == null) { + return null; + } else { + return ag.getId(); + } + } } diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java index eee3e6f37c3..f3b166f7ba7 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java @@ -8,15 +8,25 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.cloudstack.affinity.dao.AffinityGroupDao; +import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.log4j.Logger; +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceInUseException; +import com.cloud.network.security.SecurityGroupManager; +import com.cloud.network.security.SecurityGroupRuleVO; +import com.cloud.network.security.SecurityGroupVMMapVO; +import com.cloud.network.security.SecurityGroupVO; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.UserContext; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Transaction; @Local(value = { AffinityGroupService.class }) public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGroupService, Manager { @@ -30,6 +40,9 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro @Inject AffinityGroupDao _affinityGroupDao; + @Inject + AffinityGroupVMMapDao _affinityGroupVMMapDao; + @Override public AffinityGroup createAffinityGroup(String account, Long domainId, String affinityGroupName, String affinityGroupType, String description) { @@ -37,7 +50,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro Account caller = UserContext.current().getCaller(); Account owner = _accountMgr.finalizeOwner(caller, account, domainId, null); - if (_affinityGroupDao.isNameInUse(owner.getId(), owner.getDomainId(), affinityGroupName)) { + if (_affinityGroupDao.isNameInUse(owner.getAccountId(), owner.getDomainId(), affinityGroupName)) { throw new InvalidParameterValueException("Unable to create affinity group, a group with name " + affinityGroupName + " already exisits."); @@ -47,14 +60,63 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro owner.getId()); _affinityGroupDao.persist(group); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Created affinity group =" + affinityGroupName); + } + return group; } + @DB @Override - public void deleteAffinityGroup(Long affinityGroupId, String account, Long domainId, String affinityGroupName, - Long vmId) { - // TODO Auto-generated method stub + @ActionEvent(eventType = EventTypes.EVENT_SECURITY_GROUP_DELETE, eventDescription = "deleting affinity group") + public boolean deleteAffinityGroup(Long affinityGroupId, String account, Long domainId, String affinityGroupName) + throws ResourceInUseException { + Account caller = UserContext.current().getCaller(); + Account owner = _accountMgr.finalizeOwner(caller, account, domainId, null); + + AffinityGroupVO group = null; + if (affinityGroupId != null) { + group = _affinityGroupDao.findById(affinityGroupId); + if (group == null) { + throw new InvalidParameterValueException("Unable to find affinity group: " + affinityGroupId + + "; failed to delete group."); + } + } else if (affinityGroupName != null) { + group = _affinityGroupDao.findByAccountAndName(owner.getAccountId(), affinityGroupName); + if (group == null) { + throw new InvalidParameterValueException("Unable to find affinity group: " + affinityGroupName + + "; failed to delete group."); + } + } else { + throw new InvalidParameterValueException( + "Either the affinity group Id or group name must be specified to delete the group"); + } + + // check permissions + _accountMgr.checkAccess(caller, null, true, group); + + final Transaction txn = Transaction.currentTxn(); + txn.start(); + + group = _affinityGroupDao.lockRow(affinityGroupId, true); + if (group == null) { + throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId); + } + + List affinityGroupVmMap = _affinityGroupVMMapDao.listByAffinityGroup(affinityGroupId); + if (!affinityGroupVmMap.isEmpty()) { + throw new ResourceInUseException("Cannot delete affinity group when it's in use by virtual machines"); + } + + _affinityGroupDao.expunge(affinityGroupId); + txn.commit(); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Deleted affinity group id=" + affinityGroupId); + } + return true; } @Override From 1aed5bf9c2c75843c1d89973f467ec7c9128242d Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 28 Feb 2013 17:16:54 -0800 Subject: [PATCH 13/45] ListAffinityGroups API changes --- api/src/com/cloud/async/AsyncJob.java | 3 +- .../affinity/AffinityGroupService.java | 15 ++- .../affinitygroup/CreateAffinityGroupCmd.java | 49 +++++++- .../affinitygroup/DeleteAffinityGroupCmd.java | 21 +++- .../affinitygroup/ListAffinityGroupsCmd.java | 107 ++++++++++++++++++ .../affinity/AffinityGroupServiceImpl.java | 76 ++++++++++++- 6 files changed, 254 insertions(+), 17 deletions(-) create mode 100644 api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java diff --git a/api/src/com/cloud/async/AsyncJob.java b/api/src/com/cloud/async/AsyncJob.java index 8e4aec0739a..866429b6547 100644 --- a/api/src/com/cloud/async/AsyncJob.java +++ b/api/src/com/cloud/async/AsyncJob.java @@ -49,7 +49,8 @@ public interface AsyncJob extends Identity, InternalIdentity { AutoScalePolicy, AutoScaleVmProfile, AutoScaleVmGroup, - GlobalLoadBalancerRule + GlobalLoadBalancerRule, + AffinityGroup } long getUserId(); diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java index 501280da9ac..368abe28a8f 100644 --- a/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java @@ -3,6 +3,7 @@ package org.apache.cloudstack.affinity; import java.util.List; import com.cloud.exception.ResourceInUseException; +import com.cloud.utils.Pair; public interface AffinityGroupService { @@ -22,7 +23,7 @@ public interface AffinityGroupService { /** * Creates an affinity/anti-affinity group. - * + * * @param affinityGroupId * @param account * @param domainId @@ -32,19 +33,19 @@ public interface AffinityGroupService { boolean deleteAffinityGroup(Long affinityGroupId, String account, Long domainId, String affinityGroupName) throws ResourceInUseException; - /** - * Lists Affinity Groups - * + /** Lists Affinity Groups in your account * @param account * @param domainId * @param affinityGroupId * @param affinityGroupName * @param affinityGroupType * @param vmId + * @param startIndex + * @param pageSize * @return */ - List listAffinityGroups(String account, Long domainId, Long affinityGroupId, - String affinityGroupName, String affinityGroupType, Long vmId); + Pair, Integer> listAffinityGroups(Long affinityGroupId, String affinityGroupName, + String affinityGroupType, Long vmId, Long startIndex, Long pageSize); /** @@ -54,4 +55,6 @@ public interface AffinityGroupService { */ List listAffinityGroupTypes(); + AffinityGroup getAffinityGroup(Long groupId); + } diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/CreateAffinityGroupCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/CreateAffinityGroupCmd.java index c38bcffaa76..b46521457c5 100644 --- a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/CreateAffinityGroupCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/CreateAffinityGroupCmd.java @@ -21,17 +21,20 @@ import org.apache.cloudstack.affinity.AffinityGroupResponse; 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.BaseAsyncCreateCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.log4j.Logger; +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.ResourceAllocationException; import com.cloud.user.Account; import com.cloud.user.UserContext; @APICommand(name = "createAffinityGroup", responseObject = AffinityGroupResponse.class, description = "Creates an affinity/anti-affinity group") -public class CreateAffinityGroupCmd extends BaseCmd { +public class CreateAffinityGroupCmd extends BaseAsyncCreateCmd { public static final Logger s_logger = Logger.getLogger(CreateAffinityGroupCmd.class.getName()); private static final String s_name = "createaffinitygroupresponse"; @@ -112,8 +115,7 @@ public class CreateAffinityGroupCmd extends BaseCmd { @Override public void execute() { - AffinityGroup group = _affinityGroupService.createAffinityGroup(accountName, domainId, affinityGroupName, - affinityGroupType, description); + AffinityGroup group = _affinityGroupService.getAffinityGroup(getEntityId()); if (group != null) { AffinityGroupResponse response = _responseGenerator.createAffinityGroupResponse(group); response.setResponseName(getCommandName()); @@ -123,4 +125,43 @@ public class CreateAffinityGroupCmd extends BaseCmd { + affinityGroupName); } } + + @Override + public void create() throws ResourceAllocationException { + AffinityGroup result = _affinityGroupService.createAffinityGroup(accountName, domainId, affinityGroupName, + affinityGroupType, description); + if (result != null) { + setEntityId(result.getId()); + setEntityUuid(result.getUuid()); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create affinity group entity" + affinityGroupName); + } + + } + + @Override + public String getEventType() { + return EventTypes.EVENT_AFFINITY_GROUP_CREATE; + } + + @Override + public String getEventDescription() { + return "creating Affinity Group"; + } + + @Override + public String getCreateEventType() { + return EventTypes.EVENT_AFFINITY_GROUP_CREATE; + } + + @Override + public String getCreateEventDescription() { + return "creating Affinity Group"; + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.AffinityGroup; + } + } diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/DeleteAffinityGroupCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/DeleteAffinityGroupCmd.java index 8ace2e57f8e..4ceba29e63e 100644 --- a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/DeleteAffinityGroupCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/DeleteAffinityGroupCmd.java @@ -20,20 +20,22 @@ import org.apache.cloudstack.affinity.AffinityGroupResponse; 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.BaseAsyncCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.log4j.Logger; +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceInUseException; import com.cloud.user.Account; import com.cloud.user.UserContext; @APICommand(name = "deleteAffinityGroup", description = "Deletes affinity group", responseObject = SuccessResponse.class) -public class DeleteAffinityGroupCmd extends BaseCmd { +public class DeleteAffinityGroupCmd extends BaseAsyncCmd { public static final Logger s_logger = Logger.getLogger(DeleteAffinityGroupCmd.class.getName()); private static final String s_name = "deleteaffinitygroupresponse"; @@ -134,4 +136,19 @@ public class DeleteAffinityGroupCmd extends BaseCmd { throw new ServerApiException(ApiErrorCode.RESOURCE_IN_USE_ERROR, ex.getMessage()); } } + + @Override + public String getEventType() { + return EventTypes.EVENT_AFFINITY_GROUP_DELETE; + } + + @Override + public String getEventDescription() { + return "Deleting Affinity Group"; + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.AffinityGroup; + } } diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java new file mode 100644 index 00000000000..09d1f8f6635 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java @@ -0,0 +1,107 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT 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.affinitygroup; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.affinity.AffinityGroup; +import org.apache.cloudstack.affinity.AffinityGroupResponse; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.utils.Pair; + +@APICommand(name = "listAffinityGroups", description = "Lists affinity groups", responseObject = AffinityGroupResponse.class) +public class ListAffinityGroupsCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(ListAffinityGroupsCmd.class.getName()); + + private static final String s_name = "listaffinitygroupsresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "lists affinity groups by name") + private String affinityGroupName; + + @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, description = "lists affinity groups by virtual machine id", entityType = UserVmResponse.class) + private Long virtualMachineId; + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, description = "list the affinity group by the id provided", entityType = AffinityGroupResponse.class) + private Long id; + + @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "lists affinity groups by type") + private String affinityGroupType; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + public String getAffinityGroupName() { + return affinityGroupName; + } + + public Long getVirtualMachineId() { + return virtualMachineId; + } + + public Long getId(){ + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute(){ + + Pair, Integer> result = _affinityGroupService.listAffinityGroups(id, affinityGroupName, + affinityGroupType, virtualMachineId, this.getStartIndex(), this.getPageSizeVal()); + if (result != null) { + ListResponse response = new ListResponse(); + List groupResponses = new ArrayList(); + for (AffinityGroup group : result.first()) { + AffinityGroupResponse groupResponse = _responseGenerator.createAffinityGroupResponse(group); + groupResponses.add(groupResponse); + } + response.setResponses(groupResponses, result.second()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to search for affinity groups"); + } + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.AffinityGroup; + } +} diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java index f3b166f7ba7..994f2256552 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java @@ -1,5 +1,6 @@ package org.apache.cloudstack.affinity; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -12,10 +13,13 @@ import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.log4j.Logger; +import com.cloud.api.query.vo.SecurityGroupJoinVO; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceInUseException; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.security.SecurityGroupManager; import com.cloud.network.security.SecurityGroupRuleVO; import com.cloud.network.security.SecurityGroupVMMapVO; @@ -23,10 +27,19 @@ import com.cloud.network.security.SecurityGroupVO; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.UserContext; +import com.cloud.utils.Pair; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.JoinBuilder.JoinType; +import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.dao.UserVmDao; @Local(value = { AffinityGroupService.class }) public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGroupService, Manager { @@ -43,6 +56,9 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro @Inject AffinityGroupVMMapDao _affinityGroupVMMapDao; + @Inject + private UserVmDao _userVmDao; + @Override public AffinityGroup createAffinityGroup(String account, Long domainId, String affinityGroupName, String affinityGroupType, String description) { @@ -120,12 +136,59 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro } @Override - public List listAffinityGroups(String account, Long domainId, Long affinityGroupId, - String affinityGroupName, String affinityGroupType, Long vmId) { - // TODO Auto-generated method stub - return null; + public Pair, Integer> listAffinityGroups(Long affinityGroupId, String affinityGroupName, String affinityGroupType, Long vmId, Long startIndex, Long pageSize) { + Filter searchFilter = new Filter(AffinityGroupVO.class, "id", Boolean.TRUE, startIndex, pageSize); + + Account caller = UserContext.current().getCaller(); + + Long accountId = caller.getAccountId(); + Long domainId = caller.getDomainId(); + + SearchBuilder vmInstanceSearch = _affinityGroupVMMapDao.createSearchBuilder(); + vmInstanceSearch.and("instanceId", vmInstanceSearch.entity().getInstanceId(), SearchCriteria.Op.EQ); + + SearchBuilder groupSearch = _affinityGroupDao.createSearchBuilder(); + groupSearch.join("vmInstanceSearch", vmInstanceSearch, groupSearch.entity().getId(), vmInstanceSearch.entity() + .getAffinityGroupId(), JoinBuilder.JoinType.INNER); + + SearchCriteria sc = groupSearch.create(); + + if (accountId != null) { + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + } + + if (domainId != null) { + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + } + + if (affinityGroupId != null) { + sc.addAnd("id", SearchCriteria.Op.EQ, affinityGroupId); + } + + if (affinityGroupName != null) { + sc.addAnd("name", SearchCriteria.Op.EQ, affinityGroupName); + } + + if (affinityGroupType != null) { + sc.addAnd("type", SearchCriteria.Op.EQ, affinityGroupType); + } + + if (vmId != null) { + UserVmVO userVM = _userVmDao.findById(vmId); + if (userVM == null) { + throw new InvalidParameterValueException("Unable to list affinity groups for virtual machine instance " + + vmId + "; instance not found."); + } + _accountMgr.checkAccess(caller, null, true, userVM); + // add join to affinity_groups_vm_map + sc.setJoinParameters("vmInstanceSearch", "instanceId", vmId); + } + + Pair, Integer> result = _affinityGroupDao.searchAndCount(sc, searchFilter); + return new Pair, Integer>(result.first(), result.second()); } + @Override public List listAffinityGroupTypes() { // TODO Auto-generated method stub @@ -153,4 +216,9 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro return _name; } + @Override + public AffinityGroup getAffinityGroup(Long groupId) { + return _affinityGroupDao.findById(groupId); + } + } From fe2a86871fde27832b8ed99f5fe965b905b874c0 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Wed, 13 Mar 2013 13:57:47 -0700 Subject: [PATCH 14/45] Changes to add AffinityGroupprocessor, deployVM changes --- api/src/com/cloud/event/EventTypes.java | 1 + .../exception/AffinityConflictException.java | 18 ++ api/src/com/cloud/vm/UserVmService.java | 183 ++++++++++-------- .../affinity/AffinityGroupProcessor.java | 14 ++ .../affinity/AffinityGroupService.java | 3 + .../apache/cloudstack/api/ApiConstants.java | 2 + .../affinitygroup/ListAffinityGroupsCmd.java | 3 +- .../UpdateVMAffinityGroupCmd.java | 158 +++++++++++++++ .../api/command/user/vm/DeployVMCmd.java | 43 +++- .../deploy/UserPreferrenceProcessor.java | 27 +++ .../deploy/DeploymentPlanningManager.java | 29 +++ .../deploy/DeploymentPlanningManagerImpl.java | 80 ++++++++ .../src/com/cloud/vm/UserVmManagerImpl.java | 62 ++++-- .../cloud/vm/VirtualMachineManagerImpl.java | 97 +++++----- .../affinity/AffinityGroupServiceImpl.java | 71 +++++-- .../affinity/HostAntiAffinityProcessor.java | 66 +++++++ .../affinity/dao/AffinityGroupVMMapDao.java | 4 + .../dao/AffinityGroupVMMapDaoImpl.java | 43 ++++ .../com/cloud/vm/MockUserVmManagerImpl.java | 16 +- .../src/com/cloud/utils/SerialVersionUID.java | 1 + 20 files changed, 755 insertions(+), 166 deletions(-) create mode 100644 api/src/com/cloud/exception/AffinityConflictException.java create mode 100644 api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.java create mode 100644 api/src/org/apache/cloudstack/deploy/UserPreferrenceProcessor.java create mode 100644 server/src/com/cloud/deploy/DeploymentPlanningManager.java create mode 100644 server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java create mode 100644 server/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index bd5f2204fcf..6a26212ecc7 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -386,6 +386,7 @@ public class EventTypes { public static final String EVENT_AFFINITY_GROUP_DELETE = "AG.DELETE"; public static final String EVENT_AFFINITY_GROUP_ASSIGN = "AG.ASSIGN"; public static final String EVENT_AFFINITY_GROUP_REMOVE = "AG.REMOVE"; + public static final String EVENT_VM_AFFINITY_GROUP_UPDATE = "VM.AG.UPDATE"; static { diff --git a/api/src/com/cloud/exception/AffinityConflictException.java b/api/src/com/cloud/exception/AffinityConflictException.java new file mode 100644 index 00000000000..75df78419ab --- /dev/null +++ b/api/src/com/cloud/exception/AffinityConflictException.java @@ -0,0 +1,18 @@ +package com.cloud.exception; + +import com.cloud.exception.CloudException; +import com.cloud.utils.SerialVersionUID; + +public class AffinityConflictException extends CloudException { + + private static final long serialVersionUID = SerialVersionUID.AffinityConflictException; + + public AffinityConflictException(String message) { + super(message); + } + + public AffinityConflictException(String message, Throwable th) { + super(message, th); + } + +} diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index 2c33d41cd35..d963b74b080 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -26,9 +26,6 @@ import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; import org.apache.cloudstack.api.command.user.vm.*; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; -import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; - import com.cloud.dc.DataCenter; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; @@ -42,7 +39,6 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.Network.IpAddresses; import com.cloud.offering.ServiceOffering; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.uservm.UserVm; @@ -104,14 +100,14 @@ public interface UserVmService { * @return the vm object if successful, null otherwise */ UserVm addNicToVirtualMachine(AddNicToVMCmd cmd); - + /** * Removes a NIC on the given network from the virtual machine * @param cmd the command object that defines the vm and the given network * @return the vm object if successful, null otherwise */ UserVm removeNicFromVirtualMachine(RemoveNicFromVMCmd cmd); - + /** * Updates default Nic to the given network for given virtual machine * @param cmd the command object that defines the vm and the given network @@ -123,7 +119,8 @@ public interface UserVmService { /** - * Creates a Basic Zone User VM in the database and returns the VM to the caller. + * Creates a Basic Zone User VM in the database and returns the VM to the + * caller. * * @param zone * - availability zone for the virtual machine @@ -132,61 +129,69 @@ public interface UserVmService { * @param template * - the template for the virtual machine * @param securityGroupIdList - * - comma separated list of security groups id that going to be applied to the virtual machine + * - comma separated list of security groups id that going to be + * applied to the virtual machine * @param hostName * - host name for the virtual machine * @param displayName * - an optional user generated name for the virtual machine * @param diskOfferingId - * - the ID of the disk offering for the virtual machine. If the template is of ISO format, the - * diskOfferingId is - * for the root disk volume. Otherwise this parameter is used to indicate the offering for the data disk - * volume. - * If the templateId parameter passed is from a Template object, the diskOfferingId refers to a DATA Disk - * Volume - * created. If the templateId parameter passed is from an ISO object, the diskOfferingId refers to a ROOT - * Disk - * Volume created + * - the ID of the disk offering for the virtual machine. If the + * template is of ISO format, the diskOfferingId is for the root + * disk volume. Otherwise this parameter is used to indicate the + * offering for the data disk volume. If the templateId parameter + * passed is from a Template object, the diskOfferingId refers to + * a DATA Disk Volume created. If the templateId parameter passed + * is from an ISO object, the diskOfferingId refers to a ROOT + * Disk Volume created * @param diskSize - * - the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId + * - the arbitrary size for the DATADISK volume. Mutually + * exclusive with diskOfferingId * @param group * - an optional group for the virtual machine * @param hypervisor * - the hypervisor on which to deploy the virtual machine * @param userData - * - an optional binary data that can be sent to the virtual machine upon a successful deployment. This - * binary - * data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported. - * Using HTTP - * GET (via querystring), you can send up to 2KB of data after base64 encoding + * - an optional binary data that can be sent to the virtual + * machine upon a successful deployment. This binary data must be + * base64 encoded before adding it to the request. Currently only + * HTTP GET is supported. Using HTTP GET (via querystring), you + * can send up to 2KB of data after base64 encoding * @param sshKeyPair - * - name of the ssh key pair used to login to the virtual machine + * - name of the ssh key pair used to login to the virtual + * machine * @param requestedIps * TODO * @param defaultIp * TODO + * @param affinityGroupIdList * @param accountName - * - an optional account for the virtual machine. Must be used with domainId + * - an optional account for the virtual machine. Must be used + * with domainId * @param domainId - * - an optional domainId for the virtual machine. If the account parameter is used, domainId must also - * be used + * - an optional domainId for the virtual machine. If the account + * parameter is used, domainId must also be used * @return UserVm object if successful. * * @throws InsufficientCapacityException * if there is insufficient capacity to deploy the VM. * @throws ConcurrentOperationException - * if there are multiple users working on the same VM or in the same environment. + * if there are multiple users working on the same VM or in the + * same environment. * @throws ResourceUnavailableException - * if the resources required to deploy the VM is not currently available. + * if the resources required to deploy the VM is not currently + * available. * @throws InsufficientResourcesException */ UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIp, String keyboard) + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, + String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIp, + String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** - * Creates a User VM in Advanced Zone (Security Group feature is enabled) in the database and returns the VM to the - * caller. + * Creates a User VM in Advanced Zone (Security Group feature is enabled) in + * the database and returns the VM to the caller. * * @param zone * - availability zone for the virtual machine @@ -197,63 +202,69 @@ public interface UserVmService { * @param networkIdList * - list of network ids used by virtual machine * @param securityGroupIdList - * - comma separated list of security groups id that going to be applied to the virtual machine + * - comma separated list of security groups id that going to be + * applied to the virtual machine * @param hostName * - host name for the virtual machine * @param displayName * - an optional user generated name for the virtual machine * @param diskOfferingId - * - the ID of the disk offering for the virtual machine. If the template is of ISO format, the - * diskOfferingId is - * for the root disk volume. Otherwise this parameter is used to indicate the offering for the data disk - * volume. - * If the templateId parameter passed is from a Template object, the diskOfferingId refers to a DATA Disk - * Volume - * created. If the templateId parameter passed is from an ISO object, the diskOfferingId refers to a ROOT - * Disk - * Volume created + * - the ID of the disk offering for the virtual machine. If the + * template is of ISO format, the diskOfferingId is for the root + * disk volume. Otherwise this parameter is used to indicate the + * offering for the data disk volume. If the templateId parameter + * passed is from a Template object, the diskOfferingId refers to + * a DATA Disk Volume created. If the templateId parameter passed + * is from an ISO object, the diskOfferingId refers to a ROOT + * Disk Volume created * @param diskSize - * - the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId + * - the arbitrary size for the DATADISK volume. Mutually + * exclusive with diskOfferingId * @param group * - an optional group for the virtual machine * @param hypervisor * - the hypervisor on which to deploy the virtual machine * @param userData - * - an optional binary data that can be sent to the virtual machine upon a successful deployment. This - * binary - * data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported. - * Using HTTP - * GET (via querystring), you can send up to 2KB of data after base64 encoding + * - an optional binary data that can be sent to the virtual + * machine upon a successful deployment. This binary data must be + * base64 encoded before adding it to the request. Currently only + * HTTP GET is supported. Using HTTP GET (via querystring), you + * can send up to 2KB of data after base64 encoding * @param sshKeyPair - * - name of the ssh key pair used to login to the virtual machine + * - name of the ssh key pair used to login to the virtual + * machine * @param requestedIps * TODO * @param defaultIps * TODO + * @param affinityGroupIdList * @param accountName - * - an optional account for the virtual machine. Must be used with domainId + * - an optional account for the virtual machine. Must be used + * with domainId * @param domainId - * - an optional domainId for the virtual machine. If the account parameter is used, domainId must also - * be used + * - an optional domainId for the virtual machine. If the account + * parameter is used, domainId must also be used * @return UserVm object if successful. * * @throws InsufficientCapacityException * if there is insufficient capacity to deploy the VM. * @throws ConcurrentOperationException - * if there are multiple users working on the same VM or in the same environment. + * if there are multiple users working on the same VM or in the + * same environment. * @throws ResourceUnavailableException - * if the resources required to deploy the VM is not currently available. + * if the resources required to deploy the VM is not currently + * available. * @throws InsufficientResourcesException */ UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, - IpAddresses defaultIps, String keyboard) + IpAddresses defaultIps, String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** - * Creates a User VM in Advanced Zone (Security Group feature is disabled) in the database and returns the VM to the - * caller. - * + * Creates a User VM in Advanced Zone (Security Group feature is disabled) + * in the database and returns the VM to the caller. + * * @param zone * - availability zone for the virtual machine * @param serviceOffering @@ -267,49 +278,57 @@ public interface UserVmService { * @param displayName * - an optional user generated name for the virtual machine * @param diskOfferingId - * - the ID of the disk offering for the virtual machine. If the template is of ISO format, the - * diskOfferingId is - * for the root disk volume. Otherwise this parameter is used to indicate the offering for the data disk - * volume. - * If the templateId parameter passed is from a Template object, the diskOfferingId refers to a DATA Disk - * Volume - * created. If the templateId parameter passed is from an ISO object, the diskOfferingId refers to a ROOT - * Disk - * Volume created + * - the ID of the disk offering for the virtual machine. If the + * template is of ISO format, the diskOfferingId is for the root + * disk volume. Otherwise this parameter is used to indicate the + * offering for the data disk volume. If the templateId parameter + * passed is from a Template object, the diskOfferingId refers to + * a DATA Disk Volume created. If the templateId parameter passed + * is from an ISO object, the diskOfferingId refers to a ROOT + * Disk Volume created * @param diskSize - * - the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId + * - the arbitrary size for the DATADISK volume. Mutually + * exclusive with diskOfferingId * @param group * - an optional group for the virtual machine * @param hypervisor * - the hypervisor on which to deploy the virtual machine * @param userData - * - an optional binary data that can be sent to the virtual machine upon a successful deployment. This - * binary - * data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported. - * Using HTTP - * GET (via querystring), you can send up to 2KB of data after base64 encoding + * - an optional binary data that can be sent to the virtual + * machine upon a successful deployment. This binary data must be + * base64 encoded before adding it to the request. Currently only + * HTTP GET is supported. Using HTTP GET (via querystring), you + * can send up to 2KB of data after base64 encoding * @param sshKeyPair - * - name of the ssh key pair used to login to the virtual machine + * - name of the ssh key pair used to login to the virtual + * machine * @param requestedIps * TODO - * @param defaultIps TODO + * @param defaultIps + * TODO + * @param affinityGroupIdList * @param accountName - * - an optional account for the virtual machine. Must be used with domainId + * - an optional account for the virtual machine. Must be used + * with domainId * @param domainId - * - an optional domainId for the virtual machine. If the account parameter is used, domainId must also - * be used + * - an optional domainId for the virtual machine. If the account + * parameter is used, domainId must also be used * @return UserVm object if successful. - * + * * @throws InsufficientCapacityException * if there is insufficient capacity to deploy the VM. * @throws ConcurrentOperationException - * if there are multiple users working on the same VM or in the same environment. + * if there are multiple users working on the same VM or in the + * same environment. * @throws ResourceUnavailableException - * if the resources required to deploy the VM is not currently available. + * if the resources required to deploy the VM is not currently + * available. * @throws InsufficientResourcesException */ UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, String keyboard) + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, + String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, + String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java new file mode 100644 index 00000000000..e6c64b3ff9c --- /dev/null +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java @@ -0,0 +1,14 @@ +package org.apache.cloudstack.affinity; + +import org.apache.cloudstack.deploy.UserPreferrenceProcessor; + +public interface AffinityGroupProcessor extends UserPreferrenceProcessor { + + /** + * getType() should return the affinity/anti-affinity group being + * implemented + * + * @return String Affinity/Anti-affinity type + */ + String getType(); +} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java index 368abe28a8f..b6bf2ab1d78 100644 --- a/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java @@ -3,6 +3,7 @@ package org.apache.cloudstack.affinity; import java.util.List; import com.cloud.exception.ResourceInUseException; +import com.cloud.uservm.UserVm; import com.cloud.utils.Pair; public interface AffinityGroupService { @@ -57,4 +58,6 @@ public interface AffinityGroupService { AffinityGroup getAffinityGroup(Long groupId); + UserVm updateVMAffinityGroups(Long vmId, List affinityGroupIds); + } diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index c518830c92c..cfabc61d54c 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -473,6 +473,8 @@ public class ApiConstants { public static final String HEALTHCHECK_HEALTHY_THRESHOLD = "healthythreshold"; public static final String HEALTHCHECK_UNHEALTHY_THRESHOLD = "unhealthythreshold"; public static final String HEALTHCHECK_PINGPATH = "pingpath"; + public static final String AFFINITY_GROUP_IDS = "affinitygroupids"; + public static final String AFFINITY_GROUP_NAMES = "affinitygroupnames"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java index 09d1f8f6635..effbd869b95 100644 --- a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java @@ -83,7 +83,8 @@ public class ListAffinityGroupsCmd extends BaseListCmd { @Override public void execute(){ - Pair, Integer> result = _affinityGroupService.listAffinityGroups(id, affinityGroupName, + Pair, Integer> result = _affinityGroupService.listAffinityGroups(id, + affinityGroupName, affinityGroupType, virtualMachineId, this.getStartIndex(), this.getPageSizeVal()); if (result != null) { ListResponse response = new ListResponse(); diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.java new file mode 100644 index 00000000000..94f8446fa26 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.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.api.command.user.affinitygroup; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.affinity.AffinityGroupResponse; +import org.apache.cloudstack.api.ACL; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.user.UserContext; +import com.cloud.uservm.UserVm; + + +@APICommand(name = "updateVMAffinityGroup", description = "Updates the affinity/anti-affinity group associations of a virtual machine. The VM has to be stopped and restarted for the " + + "new properties to take effect.", responseObject = UserVmResponse.class) +public class UpdateVMAffinityGroupCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(UpdateVMAffinityGroupCmd.class.getName()); + private static final String s_name = "updatevirtualmachineresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + + @ACL + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=UserVmResponse.class, + required=true, description="The ID of the virtual machine") + private Long id; + + @ACL + @Parameter(name = ApiConstants.AFFINITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups id that are 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 securitygroupnames parameter") + private List affinityGroupIdList; + + @ACL + @Parameter(name = ApiConstants.AFFINITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups names that are 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 affinityGroupNameList; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public Long getId() { + return id; + } + + + public List getAffinityGroupIdList() { + if (affinityGroupNameList != null && affinityGroupIdList != null) { + throw new InvalidParameterValueException( + "affinitygroupids parameter is mutually exclusive with affinitygroupnames parameter"); + } + + // transform group names to ids here + if (affinityGroupNameList != null) { + List affinityGroupIds = new ArrayList(); + for (String groupName : affinityGroupNameList) { + Long groupId = _responseGenerator.getAffinityGroupId(groupName, getEntityOwnerId()); + if (groupId == null) { + throw new InvalidParameterValueException("Unable to find group by name " + groupName + + " for account " + getEntityOwnerId()); + } else { + affinityGroupIds.add(groupId); + } + } + return affinityGroupIds; + } else { + return affinityGroupIdList; + } + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + + @Override + public String getCommandName() { + return s_name; + } + + public static String getResultObjectName() { + return "virtualmachine"; + } + + @Override + public long getEntityOwnerId() { + UserVm userVm = _entityMgr.findById(UserVm.class, getId()); + if (userVm != null) { + return userVm.getAccountId(); + } + + return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked + } + + @Override + public void execute() throws ResourceUnavailableException, + InsufficientCapacityException, ServerApiException { + UserContext.current().setEventDetails("Vm Id: "+getId()); + UserVm result = _affinityGroupService.updateVMAffinityGroups(getId(), getAffinityGroupIdList()); + if (result != null){ + UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", result).get(0); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update vm's affinity groups"); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VM_AFFINITY_GROUP_UPDATE; + } + + @Override + public String getEventDescription() { + return "updating VM Affinity Group"; + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.AffinityGroup; + } + +} 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 21a45f8cc7f..22fe1ba3a08 100755 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Map; import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.ACL; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -172,6 +173,18 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { @Parameter(name=ApiConstants.START_VM, type=CommandType.BOOLEAN, description="true if network offering supports specifying ip ranges; defaulted to true if not specified") private Boolean startVm; + @ACL + @Parameter(name = ApiConstants.AFFINITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups id that are 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 securitygroupnames parameter") + private List affinityGroupIdList; + + @ACL + @Parameter(name = ApiConstants.AFFINITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups names that are 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 affinityGroupNameList; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -321,6 +334,30 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { return ip6Address.toLowerCase(); } + public List getAffinityGroupIdList() { + if (affinityGroupNameList != null && affinityGroupIdList != null) { + throw new InvalidParameterValueException( + "affinitygroupids parameter is mutually exclusive with affinitygroupnames parameter"); + } + + // transform group names to ids here + if (affinityGroupNameList != null) { + List affinityGroupIds = new ArrayList(); + for (String groupName : affinityGroupNameList) { + Long groupId = _responseGenerator.getAffinityGroupId(groupName, getEntityOwnerId()); + if (groupId == null) { + throw new InvalidParameterValueException("Unable to find group by name " + groupName + + " for account " + getEntityOwnerId()); + } else { + affinityGroupIds.add(groupId); + } + } + return affinityGroupIds; + } else { + return affinityGroupIdList; + } + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -447,18 +484,18 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { 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(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard); + displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList()); } } else { if (zone.isSecurityGroupEnabled()) { vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(), - owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard); + owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList()); } 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(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard); + diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList()); } } diff --git a/api/src/org/apache/cloudstack/deploy/UserPreferrenceProcessor.java b/api/src/org/apache/cloudstack/deploy/UserPreferrenceProcessor.java new file mode 100644 index 00000000000..ad26f0e06d8 --- /dev/null +++ b/api/src/org/apache/cloudstack/deploy/UserPreferrenceProcessor.java @@ -0,0 +1,27 @@ +package org.apache.cloudstack.deploy; + + +import com.cloud.deploy.DeploymentPlan; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.exception.AffinityConflictException; +import com.cloud.utils.component.Adapter; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; + +public interface UserPreferrenceProcessor extends Adapter { + + /** + * process() is called to apply any user preferences to the deployment plan + * and avoid set for the given VM placement. + * + * @param vm + * virtual machine. + * @param plan + * deployment plan that tells you where it's being deployed to. + * @param avoid + * avoid these data centers, pods, clusters, or hosts. + */ + void process(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) + throws AffinityConflictException; + +} \ No newline at end of file diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManager.java b/server/src/com/cloud/deploy/DeploymentPlanningManager.java new file mode 100644 index 00000000000..4ac71e3ac81 --- /dev/null +++ b/server/src/com/cloud/deploy/DeploymentPlanningManager.java @@ -0,0 +1,29 @@ +package com.cloud.deploy; + +import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.exception.AffinityConflictException; +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.utils.component.Manager; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; + +public interface DeploymentPlanningManager extends Manager { + + /** + * Manages vm deployment stages: First Process Affinity/Anti-affinity - Call + * the chain of AffinityGroupProcessor adapters to set deploymentplan scope + * and exclude list Secondly, Call DeploymentPlanner - to use heuristics to + * find the best spot to place the vm/volume. Planner will drill down to the + * write set of clusters to look for placement based on various heuristics. + * Lastly, Call Allocators - Given a cluster, allocators matches the + * requirements to capabilities of the physical resource (host, storage + * pool). + * + * @throws AffinityConflictException + * + * + * + */ + DeployDestination planDeployment(VirtualMachineProfile vmProfile, DeploymentPlan plan, + ExcludeList avoids) throws InsufficientServerCapacityException, AffinityConflictException; +} diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java new file mode 100644 index 00000000000..11e5b82d176 --- /dev/null +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -0,0 +1,80 @@ +package com.cloud.deploy; + +import java.util.List; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.cloudstack.affinity.AffinityGroupProcessor; +import org.apache.cloudstack.affinity.AffinityGroupVMMapVO; +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; +import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; +import org.apache.log4j.Logger; + +import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.exception.AffinityConflictException; +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.utils.component.Manager; +import com.cloud.utils.component.ManagerBase; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; + +@Local(value = { DeploymentPlanningManager.class }) +public class DeploymentPlanningManagerImpl extends ManagerBase implements DeploymentPlanningManager, Manager { + + private static final Logger s_logger = Logger.getLogger(DeploymentPlanningManagerImpl.class); + @Inject + protected UserVmDao _vmDao; + @Inject + protected VMInstanceDao _vmInstanceDao; + @Inject + protected AffinityGroupDao _affinityGroupDao; + @Inject + protected AffinityGroupVMMapDao _affinityGroupVMMapDao; + + @Inject + protected List _planners; + + @Inject + protected List _affinityProcessors; + + @Override + public DeployDestination planDeployment(VirtualMachineProfile vmProfile, + DeploymentPlan plan, ExcludeList avoids) throws InsufficientServerCapacityException, + AffinityConflictException { + + // call affinitygroup chain + VirtualMachine vm = vmProfile.getVirtualMachine(); + long vmGroupCount = _affinityGroupVMMapDao.countAffinityGroupsForVm(vm.getId()); + + if (vmGroupCount > 0) { + for (AffinityGroupProcessor processor : _affinityProcessors) { + processor.process(vmProfile, plan, avoids); + } + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Deploy avoids pods: " + avoids.getPodsToAvoid() + ", clusters: " + + avoids.getClustersToAvoid() + ", hosts: " + avoids.getHostsToAvoid()); + } + + // call planners + DeployDestination dest = null; + for (DeploymentPlanner planner : _planners) { + if (planner.canHandle(vmProfile, plan, avoids)) { + dest = planner.plan(vmProfile, plan, avoids); + } else { + continue; + } + if (dest != null) { + avoids.addHost(dest.getHost().getId()); + break; + } + + } + return dest; + } + +} diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 1c3764a8391..ca158f1995d 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -35,6 +35,9 @@ import javax.naming.ConfigurationException; import com.cloud.api.ApiDBUtils; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.affinity.AffinityGroupVO; +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; +import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; import org.apache.cloudstack.api.command.user.vm.*; @@ -369,7 +372,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use VpcManager _vpcMgr; @Inject TemplateManager templateMgr; - @Inject + @Inject protected GuestOSCategoryDao _guestOSCategoryDao; @Inject UsageEventDao _usageEventDao; @@ -378,6 +381,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @Inject protected VMSnapshotManager _vmSnapshotMgr; + @Inject + AffinityGroupVMMapDao _affinityGroupVMMapDao; + @Inject + AffinityGroupDao _affinityGroupDao; + @Inject List plannerSelectors; @@ -684,7 +692,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use try { VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid()); - status = vmEntity.stop(new Long(userId).toString()); + status = vmEntity.stop(new Long(userId).toString()); } catch (ResourceUnavailableException e) { s_logger.debug("Unable to stop due to ", e); status = false; @@ -1916,7 +1924,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @Override public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList, Account owner, - String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, String keyboard) + String hostName, + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, + String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, + String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = UserContext.current().getCaller(); @@ -1966,13 +1977,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, - diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard); + diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, + requestedIps, defaultIps, keyboard, affinityGroupIdList); } @Override public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, - String sshKeyPair, Map requestedIps, IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, + String sshKeyPair, Map requestedIps, + IpAddresses defaultIps, String keyboard, List affinityGroupIdList) + throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, + StorageUnavailableException, ResourceAllocationException { Account caller = UserContext.current().getCaller(); @@ -2018,7 +2033,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use isSecurityGroupEnabledNetworkUsed = true; } else { - // Verify that all the networks are Shared/Guest; can't create combination of SG enabled and disabled networks + // Verify that all the networks are Shared/Guest; can't create combination of SG enabled and disabled networks for (Long networkId : networkIdList) { NetworkVO network = _networkDao.findById(networkId); @@ -2034,7 +2049,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } isSecurityGroupEnabledNetworkUsed = true; - } + } if (!(network.getTrafficType() == TrafficType.Guest && network.getGuestType() == Network.GuestType.Shared)) { throw new InvalidParameterValueException("Can specify only Shared Guest networks when" + @@ -2079,12 +2094,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, - diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard); + diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, + requestedIps, defaultIps, keyboard, affinityGroupIdList); } @Override public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, String keyboard) + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, + String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, + String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = UserContext.current().getCaller(); @@ -2192,7 +2210,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } - return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard); + return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, + diskSize, networkList, null, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, + keyboard, affinityGroupIdList); } @@ -2205,7 +2225,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @DB @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true) protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, String hostName, String displayName, Account owner, Long diskOfferingId, - Long diskSize, List networkList, List securityGroupIdList, String group, String userData, String sshKeyPair, HypervisorType hypervisor, Account caller, Map requestedIps, IpAddresses defaultIps, String keyboard) + Long diskSize, List networkList, List securityGroupIdList, String group, String userData, + String sshKeyPair, HypervisorType hypervisor, Account caller, Map requestedIps, + IpAddresses defaultIps, String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { _accountMgr.checkAccess(caller, null, true, owner); @@ -2261,6 +2283,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } + // check that the affinity groups exist + for (Long affinityGroupId : affinityGroupIdList) { + AffinityGroupVO ag = _affinityGroupDao.findById(affinityGroupId); + if (ag == null) { + throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId); + } + } + if (template.getHypervisorType() != null && template.getHypervisorType() != HypervisorType.BareMetal) { // check if we have available pools for vm deployment long availablePools = _storagePoolDao.countPoolsByStatus(StoragePoolStatus.Up); @@ -2438,7 +2468,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use // * verify that there are no duplicates if (hostNames.contains(hostName)) { throw new InvalidParameterValueException("The vm with hostName " + hostName - + " already exists in the network domain: " + ntwkDomain + "; network=" + + " already exists in the network domain: " + ntwkDomain + "; network=" + _networkModel.getNetwork(ntwkId)); } } @@ -2510,7 +2540,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use List computeTags = new ArrayList(); computeTags.add(offering.getHostTag()); - List rootDiskTags = new ArrayList(); + List rootDiskTags = new ArrayList(); rootDiskTags.add(offering.getTags()); if(isIso){ @@ -2552,6 +2582,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _securityGroupMgr.addInstanceToGroups(vm.getId(), securityGroupIdList); + _affinityGroupVMMapDao.updateMap(vm.getId(), affinityGroupIdList); + return vm; } @@ -2829,7 +2861,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use try { VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid()); - vmEntity.stop(new Long(userId).toString()); + vmEntity.stop(new Long(userId).toString()); } catch (ResourceUnavailableException e) { throw new CloudRuntimeException( "Unable to contact the agent to stop the virtual machine " @@ -3044,7 +3076,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use try { VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid()); - status = vmEntity.destroy(new Long(userId).toString()); + status = vmEntity.destroy(new Long(userId).toString()); } catch (CloudException e) { CloudRuntimeException ex = new CloudRuntimeException( "Unable to destroy with specified vmId", e); diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index af2271660fa..08c6e7c1208 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -5,7 +5,7 @@ // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, @@ -68,7 +68,9 @@ import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner; import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.deploy.DeploymentPlanningManager; import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.AffinityConflictException; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConnectionException; @@ -226,8 +228,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Inject protected ResourceManager _resourceMgr; - - @Inject + + @Inject protected VMSnapshotManager _vmSnapshotMgr = null; @Inject protected ClusterDetailsDao _clusterDetailsDao; @@ -239,6 +241,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Inject VolumeManager volumeMgr; + @Inject + DeploymentPlanningManager _dpMgr; + Map> _vmGurus = new HashMap>(); protected StateMachine2 _stateMachine; @@ -586,7 +591,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac ConcurrentOperationException, ResourceUnavailableException { return advanceStart(vm, params, caller, account, null); } - + @Override public T advanceStart(T vm, Map params, User caller, Account account, DeploymentPlan planToDeploy) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { @@ -695,17 +700,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, offering, account, params); DeployDestination dest = null; - for (DeploymentPlanner planner : _planners) { - if (planner.canHandle(vmProfile, plan, avoids)) { - dest = planner.plan(vmProfile, plan, avoids); - } else { - continue; - } - if (dest != null) { - avoids.addHost(dest.getHost().getId()); - journal.record("Deployment found ", vmProfile, dest); - break; - } + try { + dest = _dpMgr.planDeployment(vmProfile, plan, avoids); + } catch (AffinityConflictException e2) { + // TODO Auto-generated catch block + e2.printStackTrace(); } if (dest == null) { @@ -739,7 +738,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac if (s_logger.isDebugEnabled()) { s_logger.debug("VM is being created in podId: " + vm.getPodIdToDeployIn()); } - _networkMgr.prepare(vmProfile, dest, ctx); + _networkMgr.prepare(vmProfile, dest, ctx); if (vm.getHypervisorType() != HypervisorType.BareMetal) { this.volumeMgr.prepare(vmProfile, dest); } @@ -797,7 +796,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac StopCommand cmd = new StopCommand(vm); StopAnswer answer = (StopAnswer) _agentMgr.easySend(destHostId, cmd); if (answer == null || !answer.getResult()) { - s_logger.warn("Unable to stop " + vm + " due to " + (answer != null ? answer.getDetails() : "no answers")); + s_logger.warn("Unable to stop " + vm + " due to " + (answer != null ? answer.getDetails() : "no answers")); _haMgr.scheduleStop(vm, destHostId, WorkType.ForceStop); throw new ExecutionException("Unable to stop " + vm + " so we are unable to retry the start operation"); } @@ -1144,7 +1143,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.error("State transit with event: " + e + " failed due to: " + vm.getInstanceName() + " has active VM snapshots tasks"); return false; } - + State oldState = vm.getState(); if (oldState == State.Starting) { if (e == Event.OperationSucceeded) { @@ -1179,12 +1178,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.debug("Unable to stop " + vm); return false; } - + if (!_vmSnapshotMgr.deleteAllVMSnapshots(vm.getId(),null)){ s_logger.debug("Unable to delete all snapshots for " + vm); return false; } - + try { if (!stateTransitTo(vm, VirtualMachine.Event.DestroyRequested, vm.getHostId())) { s_logger.debug("Unable to destroy the vm because it is not in the correct state: " + vm); @@ -1559,7 +1558,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Override public boolean isVirtualMachineUpgradable(VirtualMachine vm, ServiceOffering offering) { - boolean isMachineUpgradable = true; + boolean isMachineUpgradable = true; for(HostAllocator allocator : _hostAllocators) { isMachineUpgradable = allocator.isVirtualMachineUpgradable(vm, offering); if(isMachineUpgradable) @@ -1628,7 +1627,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac return new StopCommand(vmName); } - public Commands fullHostSync(final long hostId, StartupRoutingCommand startup) { + public Commands fullHostSync(final long hostId, StartupRoutingCommand startup) { Commands commands = new Commands(OnError.Continue); Map infos = convertToInfos(startup); @@ -1637,7 +1636,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.debug("Found " + vms.size() + " VMs for host " + hostId); for (VMInstanceVO vm : vms) { AgentVmInfo info = infos.remove(vm.getId()); - + // sync VM Snapshots related transient states List vmSnapshotsInTrasientStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging,VMSnapshot.State.Reverting, VMSnapshot.State.Creating); if(vmSnapshotsInTrasientStates.size() > 1){ @@ -1649,11 +1648,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.info("Successfully sync VM with transient snapshot: " + vm.getInstanceName()); } } - + VMInstanceVO castedVm = null; if (info == null) { info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped); - } + } castedVm = info.guru.findById(vm.getId()); HypervisorGuru hvGuru = _hvGuruMgr.getGuru(castedVm.getHypervisorType()); @@ -1767,7 +1766,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac for (VMInstanceVO vm : set_vms) { AgentVmInfo info = infos.remove(vm.getId()); VMInstanceVO castedVm = null; - + // sync VM Snapshots related transient states List vmSnapshotsInExpungingStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging, VMSnapshot.State.Creating,VMSnapshot.State.Reverting); if(vmSnapshotsInExpungingStates.size() > 0){ @@ -1785,9 +1784,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.info("Successfully sync VM with transient snapshot: " + vm.getInstanceName()); } } - - if ((info == null && (vm.getState() == State.Running || vm.getState() == State.Starting )) - || (info != null && (info.state == State.Running && vm.getState() == State.Starting))) + + if ((info == null && (vm.getState() == State.Running || vm.getState() == State.Starting )) + || (info != null && (info.state == State.Running && vm.getState() == State.Starting))) { s_logger.info("Found vm " + vm.getInstanceName() + " in inconsistent state. " + vm.getState() + " on CS while " + (info == null ? "Stopped" : "Running") + " on agent"); info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped); @@ -1925,7 +1924,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac return map; } - protected Map convertToInfos(StartupRoutingCommand cmd) { + protected Map convertToInfos(StartupRoutingCommand cmd) { final Map states = cmd.getVmStates(); final HashMap map = new HashMap(); if (states == null) { @@ -1989,7 +1988,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac * compareState does as its name suggests and compares the states between * management server and agent. It returns whether something should be * cleaned up - * + * */ protected Command compareState(long hostId, VMInstanceVO vm, final AgentVmInfo info, final boolean fullSync, boolean trackExternalChange) { State agentState = info.state; @@ -2192,7 +2191,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac List nics = _nicsDao.listByVmId(profile.getId()); for (NicVO nic : nics) { Network network = _networkModel.getNetwork(nic.getNetworkId()); - NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), null, + NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), null, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(profile.getHypervisorType(), network)); profile.addNic(nicProfile); } @@ -2319,7 +2318,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.fatal("The Cluster VM sync process failed for cluster id " + clusterId + " with ", e); } } - else { // for others KVM and VMWare + else { // for others KVM and VMWare StartupRoutingCommand startup = (StartupRoutingCommand) cmd; Commands commands = fullHostSync(agentId, startup); @@ -2492,7 +2491,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } @Override - public NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException, + public NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { s_logger.debug("Adding vm " + vm + " to network " + network + "; requested nic profile " + requested); @@ -2502,14 +2501,14 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } else { vmVO = _vmDao.findById(vm.getId()); } - ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM), + ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM), _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM)); - VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vmVO, null, + VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vmVO, null, null, null, null); DataCenter dc = _configMgr.getZone(network.getDataCenterId()); - Host host = _hostDao.findById(vm.getHostId()); + Host host = _hostDao.findById(vm.getHostId()); DeployDestination dest = new DeployDestination(dc, null, null, host); //check vm state @@ -2557,14 +2556,14 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac public boolean removeNicFromVm(VirtualMachine vm, NicVO nic) throws ConcurrentOperationException, ResourceUnavailableException { VMInstanceVO vmVO = _vmDao.findById(vm.getId()); NetworkVO network = _networkDao.findById(nic.getNetworkId()); - ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM), + ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM), _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM)); - VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vmVO, null, + VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vmVO, null, null, null, null); DataCenter dc = _configMgr.getZone(network.getDataCenterId()); - Host host = _hostDao.findById(vm.getHostId()); + Host host = _hostDao.findById(vm.getHostId()); DeployDestination dest = new DeployDestination(dc, null, null, host); VirtualMachineGuru vmGuru = getVmGuru(vmVO); HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vmProfile.getVirtualMachine().getHypervisorType()); @@ -2576,9 +2575,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac throw new CloudRuntimeException("Failed to remove nic from " + vm + " in " + network + ", nic is default."); } - NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), - _networkModel.getNetworkRate(network.getId(), vm.getId()), - _networkModel.isSecurityGroupSupportedInNetwork(network), + NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), + _networkModel.getNetworkRate(network.getId(), vm.getId()), + _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vmProfile.getVirtualMachine().getHypervisorType(), network)); //1) Unplug the nic @@ -2611,14 +2610,14 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Override public boolean removeVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException { VMInstanceVO vmVO = _vmDao.findById(vm.getId()); - ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM), + ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM), _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM)); - VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vmVO, null, + VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vmVO, null, null, null, null); DataCenter dc = _configMgr.getZone(network.getDataCenterId()); - Host host = _hostDao.findById(vm.getHostId()); + Host host = _hostDao.findById(vm.getHostId()); DeployDestination dest = new DeployDestination(dc, null, null, host); VirtualMachineGuru vmGuru = getVmGuru(vmVO); HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vmProfile.getVirtualMachine().getHypervisorType()); @@ -2643,9 +2642,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac throw new CloudRuntimeException("Failed to remove nic from " + vm + " in " + network + ", nic is default."); } - NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), - _networkModel.getNetworkRate(network.getId(), vm.getId()), - _networkModel.isSecurityGroupSupportedInNetwork(network), + NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), + _networkModel.getNetworkRate(network.getId(), vm.getId()), + _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vmProfile.getVirtualMachine().getHypervisorType(), network)); //1) Unplug the nic diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java index 994f2256552..f6c87cb9fe3 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java @@ -1,6 +1,5 @@ package org.apache.cloudstack.affinity; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -13,36 +12,34 @@ import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.log4j.Logger; -import com.cloud.api.query.vo.SecurityGroupJoinVO; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceInUseException; -import com.cloud.network.PhysicalNetwork; -import com.cloud.network.dao.PhysicalNetworkVO; -import com.cloud.network.security.SecurityGroupManager; -import com.cloud.network.security.SecurityGroupRuleVO; -import com.cloud.network.security.SecurityGroupVMMapVO; -import com.cloud.network.security.SecurityGroupVO; +import com.cloud.network.security.SecurityGroup; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.UserContext; +import com.cloud.uservm.UserVm; import com.cloud.utils.Pair; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; -import com.cloud.utils.db.JoinBuilder.JoinType; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; +import com.cloud.utils.fsm.StateListener; import com.cloud.vm.UserVmVO; -import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.Event; +import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.UserVmDao; @Local(value = { AffinityGroupService.class }) -public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGroupService, Manager { +public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGroupService, Manager, + StateListener { public static final Logger s_logger = Logger.getLogger(AffinityGroupServiceImpl.class); private String _name; @@ -221,4 +218,56 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro return _affinityGroupDao.findById(groupId); } + @Override + public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, + boolean status, Object opaque) { + return true; + } + + @Override + public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, + boolean status, Object opaque) { + if (!status) { + return false; + } + if ((newState == State.Expunging)) { + // cleanup all affinity groups associated to the Expunged VM + SearchCriteria sc = _affinityGroupVMMapDao.createSearchCriteria(); + sc.addAnd("instanceId", SearchCriteria.Op.EQ, vo.getId()); + _affinityGroupVMMapDao.expunge(sc); + } + return true; + } + + @Override + public UserVm updateVMAffinityGroups(Long vmId, List affinityGroupIds) { + // Verify input parameters + UserVmVO vmInstance = _userVmDao.findById(vmId); + if (vmInstance == null) { + throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId); + } + + // Check that the VM is stopped + if (!vmInstance.getState().equals(State.Stopped)) { + s_logger.warn("Unable to update affinity groups of the virtual machine " + vmInstance.toString() + + " in state " + vmInstance.getState()); + throw new InvalidParameterValueException("Unable update affinity groups of the virtual machine " + + vmInstance.toString() + " " + "in state " + vmInstance.getState() + + "; make sure the virtual machine is stopped and not in an error state before updating."); + } + + // check that the affinity groups exist + for (Long affinityGroupId : affinityGroupIds) { + AffinityGroupVO ag = _affinityGroupDao.findById(affinityGroupId); + if (ag == null) { + throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId); + } + } + _affinityGroupVMMapDao.updateMap(vmId, affinityGroupIds); + + // APIResponseHelper will pull out the updated affinitygroups. + return vmInstance; + + } + } diff --git a/server/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java b/server/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java new file mode 100644 index 00000000000..93bd3580f2f --- /dev/null +++ b/server/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java @@ -0,0 +1,66 @@ +package org.apache.cloudstack.affinity; + +import java.util.List; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; +import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; +import org.apache.log4j.Logger; + +import com.cloud.deploy.DeploymentPlan; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.exception.AffinityConflictException; +import com.cloud.utils.component.AdapterBase; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; + +@Local(value = AffinityGroupProcessor.class) +public class HostAntiAffinityProcessor extends AdapterBase implements AffinityGroupProcessor { + + private static final Logger s_logger = Logger.getLogger(HostAntiAffinityProcessor.class); + @Inject + protected UserVmDao _vmDao; + @Inject + protected VMInstanceDao _vmInstanceDao; + @Inject + protected AffinityGroupDao _affinityGroupDao; + @Inject + protected AffinityGroupVMMapDao _affinityGroupVMMapDao; + + @Override + public void process(VirtualMachineProfile vmProfile, DeploymentPlan plan, + ExcludeList avoid) + throws AffinityConflictException { + VirtualMachine vm = vmProfile.getVirtualMachine(); + AffinityGroupVMMapVO vmGroupMapping = _affinityGroupVMMapDao.findByVmIdType(vm.getId(), getType()); + + if (vmGroupMapping != null) { + AffinityGroupVO group = _affinityGroupDao.findById(vmGroupMapping.getAffinityGroupId()); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Processing affinity group " + group.getName() + " for VM Id: " + vm.getId()); + } + + List groupVMIds = _affinityGroupVMMapDao.listVmIdsByAffinityGroup(group.getId()); + + for (Long groupVMId : groupVMIds) { + VMInstanceVO groupVM = _vmInstanceDao.findById(groupVMId); + if (groupVM != null && !groupVM.isRemoved() && groupVM.getHostId() != null) { + avoid.addHost(groupVM.getHostId()); + } + } + } + + } + + @Override + public String getType() { + return "HostAntiAffinity"; + } + +} diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java index 9841de44680..a98ae0ff7bd 100644 --- a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java +++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java @@ -40,4 +40,8 @@ public interface AffinityGroupVMMapDao extends GenericDao affinityGroupIds); } diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java index e9286dbc726..0fb4e7902b4 100644 --- a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java +++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java @@ -19,17 +19,22 @@ package org.apache.cloudstack.affinity.dao; import java.util.List; import javax.ejb.Local; +import javax.inject.Inject; import org.apache.cloudstack.affinity.AffinityGroupVMMapVO; +import org.apache.cloudstack.affinity.AffinityGroupVO; import org.springframework.stereotype.Component; +import com.cloud.host.HostTagVO; import com.cloud.utils.Pair; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.JoinBuilder.JoinType; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; +import com.cloud.utils.db.Transaction; @Component @Local(value = { AffinityGroupVMMapDao.class }) @@ -40,6 +45,10 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase CountSGForVm; private GenericSearchBuilder ListVmIdByAffinityGroup; private SearchBuilder ListByAffinityGroup; + private SearchBuilder ListByVmIdType; + + @Inject + protected AffinityGroupDao _affinityGroupDao; protected AffinityGroupVMMapDaoImpl() { ListVmIdByAffinityGroup = createSearchBuilder(Long.class); @@ -62,6 +71,14 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase groupSearch = _affinityGroupDao.createSearchBuilder(); + groupSearch.and("type", groupSearch.entity().getType(), SearchCriteria.Op.EQ); + ListByVmIdType.join("groupSearch", groupSearch, ListByVmIdType.entity().getAffinityGroupId(), groupSearch + .entity().getId(), JoinType.INNER); + ListByVmIdType.done(); + CountSGForVm = createSearchBuilder(Long.class); CountSGForVm.select(null, Func.COUNT, null); CountSGForVm.and("vmId", CountSGForVm.entity().getInstanceId(), SearchCriteria.Op.EQ); @@ -117,4 +134,30 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase sc = ListByVmIdType.create(); + sc.setParameters("instanceId", instanceId); + sc.setJoinParameters("groupSearch", "type", type); + return customSearch(sc, null).get(0); + } + + @Override + public void updateMap(Long vmId, List affinityGroupIds) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("instanceId", SearchCriteria.Op.EQ, vmId); + expunge(sc); + + for (Long groupId : affinityGroupIds) { + AffinityGroupVMMapVO vo = new AffinityGroupVMMapVO(groupId, vmId); + persist(vo); + } + + txn.commit(); + + } } diff --git a/server/test/com/cloud/vm/MockUserVmManagerImpl.java b/server/test/com/cloud/vm/MockUserVmManagerImpl.java index dd8dd83df58..fd826d9e86e 100644 --- a/server/test/com/cloud/vm/MockUserVmManagerImpl.java +++ b/server/test/com/cloud/vm/MockUserVmManagerImpl.java @@ -253,13 +253,13 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, // TODO Auto-generated method stub return null; } - + @Override public UserVm removeNicFromVirtualMachine(RemoveNicFromVMCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, CloudRuntimeException { // TODO Auto-generated method stub return null; } - + @Override public UserVm updateDefaultNicForVirtualMachine(UpdateDefaultNicForVMCmd cmd) throws InvalidParameterValueException, CloudRuntimeException { // TODO Auto-generated method stub @@ -330,7 +330,9 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, @Override public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, - IpAddresses defaultIp, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, + IpAddresses defaultIp, + String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { // TODO Auto-generated method stub return null; @@ -339,7 +341,9 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, @Override public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, - String sshKeyPair, Map requestedIps, IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, + String sshKeyPair, Map requestedIps, + IpAddresses defaultIps, String keyboard, List affinityGroupIdList) + throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { // TODO Auto-generated method stub return null; @@ -348,7 +352,9 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, @Override public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, - String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { + String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, + ResourceAllocationException { // TODO Auto-generated method stub return null; } diff --git a/utils/src/com/cloud/utils/SerialVersionUID.java b/utils/src/com/cloud/utils/SerialVersionUID.java index 35e9446b17e..856d5639c50 100755 --- a/utils/src/com/cloud/utils/SerialVersionUID.java +++ b/utils/src/com/cloud/utils/SerialVersionUID.java @@ -61,4 +61,5 @@ public interface SerialVersionUID { public static final long CloudExecutionException = Base | 0x27; public static final long CallFailedException = Base | 0x28; public static final long UnableDeleteHostException = Base | 0x29; + public static final long AffinityConflictException = Base | 0x2a; } From bf9221a370da0c0720f1411f50738ab7d6d98ab5 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 14 Mar 2013 17:20:42 -0700 Subject: [PATCH 15/45] Separated out host anti-affinity as a plugin. --- .../host-anti-affinity/pom.xml | 33 +++++++++++++++++++ .../affinity/HostAntiAffinityProcessor.java | 0 plugins/pom.xml | 1 + 3 files changed, 34 insertions(+) create mode 100644 plugins/affinity-group-processors/host-anti-affinity/pom.xml rename {server => plugins/affinity-group-processors/host-anti-affinity}/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java (100%) diff --git a/plugins/affinity-group-processors/host-anti-affinity/pom.xml b/plugins/affinity-group-processors/host-anti-affinity/pom.xml new file mode 100644 index 00000000000..669febd7db8 --- /dev/null +++ b/plugins/affinity-group-processors/host-anti-affinity/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + cloud-plugin-host-anti-affinity + Apache CloudStack Plugin - Host Anti-Affinity Processor + + org.apache.cloudstack + cloudstack-plugins + 4.2.0-SNAPSHOT + ../../pom.xml + + + install + src + + diff --git a/server/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java b/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java similarity index 100% rename from server/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java rename to plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java diff --git a/plugins/pom.xml b/plugins/pom.xml index 607c50cff22..12c85fff38b 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -36,6 +36,7 @@ api/rate-limit api/discovery acl/static-role-based + affinity-group-processors/host-anti-affinity deployment-planners/user-concentrated-pod deployment-planners/user-dispersing host-allocators/random From d108fb46004aca4d134e67629044dbe91ed94c49 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 14 Mar 2013 17:22:06 -0700 Subject: [PATCH 16/45] Added apache license header --- .../affinity/HostAntiAffinityProcessor.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java b/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java index 93bd3580f2f..11b391b74c6 100644 --- a/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java +++ b/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.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 org.apache.cloudstack.affinity; import java.util.List; From 1ba6740fc1aa30a9111c8375e45646947962b384 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 14 Mar 2013 17:32:33 -0700 Subject: [PATCH 17/45] Schema changes to create affinity group tables --- setup/db/db/schema-410to420.sql | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index c7c8b5b49ca..77bb8d62f68 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -142,6 +142,29 @@ CREATE TABLE `cloud`.`user_vm_clone_setting` ( INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'UserVmManager', 'vmware.create.full.clone' , 'false', 'If set to true, creates VMs as full clones on ESX hypervisor'); +CREATE TABLE `cloud`.`affinity_group` ( + `id` bigint unsigned NOT NULL auto_increment, + `name` varchar(255) NOT NULL, + `type` varchar(255) NOT NULL, + `uuid` varchar(40), + `description` varchar(4096) NULL, + `domain_id` bigint unsigned NOT NULL, + `account_id` bigint unsigned NOT NULL, + UNIQUE (`name`, `account_id`), + PRIMARY KEY (`id`), + CONSTRAINT `fk_affinity_group__account_id` FOREIGN KEY(`account_id`) REFERENCES `account`(`id`), + CONSTRAINT `fk_affinity_group__domain_id` FOREIGN KEY(`domain_id`) REFERENCES `domain`(`id`), + CONSTRAINT `uc_affinity_group__uuid` UNIQUE (`uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`affinity_group_vm_map` ( + `id` bigint unsigned NOT NULL auto_increment, + `affinity_group_id` bigint unsigned NOT NULL, + `instance_id` bigint unsigned NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `fk_agvm__group_id` FOREIGN KEY(`affinity_group_id`) REFERENCES `affinity_group`(`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + -- Re-enable foreign key checking, at the end of the upgrade path SET foreign_key_checks = 1; From e9300d2676b72875e4de1bdb6c48ae853df99263 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Fri, 15 Mar 2013 15:06:17 -0700 Subject: [PATCH 18/45] DAO constructor should be lightweight to make Spring DI faster. --- .../cloudstack/affinity/dao/AffinityGroupDaoImpl.java | 8 +++++++- .../affinity/dao/AffinityGroupVMMapDaoImpl.java | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java index bfa06c7cbf3..f7db4184fd1 100644 --- a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java +++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java @@ -18,6 +18,7 @@ package org.apache.cloudstack.affinity.dao; import java.util.List; +import javax.annotation.PostConstruct; import javax.ejb.Local; import org.apache.cloudstack.affinity.AffinityGroupVO; import org.springframework.stereotype.Component; @@ -33,7 +34,12 @@ public class AffinityGroupDaoImpl extends GenericDaoBase private SearchBuilder AccountIdNamesSearch; - protected AffinityGroupDaoImpl() { + public AffinityGroupDaoImpl() { + + } + + @PostConstruct + protected void init() { AccountIdSearch = createSearchBuilder(); AccountIdSearch.and("accountId", AccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ); AccountIdSearch.done(); diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java index 0fb4e7902b4..ea315ac595c 100644 --- a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java +++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java @@ -18,6 +18,7 @@ package org.apache.cloudstack.affinity.dao; import java.util.List; +import javax.annotation.PostConstruct; import javax.ejb.Local; import javax.inject.Inject; @@ -50,7 +51,11 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase Date: Mon, 18 Mar 2013 11:09:29 -0700 Subject: [PATCH 19/45] Not using entity factory --- .../orchestration/CloudOrchestrator.java | 63 +++++++++---------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/engine/orchestration/src/org/apache/cloudstack/platform/orchestration/CloudOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/platform/orchestration/CloudOrchestrator.java index c07931befc8..963e4d7d967 100755 --- a/engine/orchestration/src/org/apache/cloudstack/platform/orchestration/CloudOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/platform/orchestration/CloudOrchestrator.java @@ -51,7 +51,6 @@ import com.cloud.user.dao.AccountDao; import com.cloud.utils.Pair; import com.cloud.utils.component.ComponentContext; import com.cloud.vm.NicProfile; -import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.dao.UserVmDao; @@ -66,25 +65,25 @@ public class CloudOrchestrator implements OrchestrationService { @Inject private VirtualMachineManager _itMgr; - + @Inject protected VMTemplateDao _templateDao = null; - + @Inject protected VMInstanceDao _vmDao; - + @Inject protected UserVmDao _userVmDao = null; - + @Inject protected ServiceOfferingDao _serviceOfferingDao; - + @Inject protected DiskOfferingDao _diskOfferingDao = null; - + @Inject protected NetworkDao _networkDao; - + @Inject protected AccountDao _accountDao = null; @@ -147,17 +146,17 @@ public class CloudOrchestrator implements OrchestrationService { @Override public VirtualMachineEntity createVirtualMachine( - String id, - String owner, - String templateId, - String hostName, + String id, + String owner, + String templateId, + String hostName, String displayName, String hypervisor, - int cpu, - int speed, + int cpu, + int speed, long memory, Long diskSize, - List computeTags, + List computeTags, List rootDiskTags, Map networkNicMap, DeploymentPlan plan) throws InsufficientCapacityException { @@ -173,22 +172,22 @@ public class CloudOrchestrator implements OrchestrationService { VirtualMachineEntityImpl vmEntity = ComponentContext.inject(VirtualMachineEntityImpl.class); vmEntity.init(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, new ArrayList(networkNicMap.keySet())); - - + + HypervisorType hypervisorType = HypervisorType.valueOf(hypervisor); //load vm instance and offerings and call virtualMachineManagerImpl VMInstanceVO vm = _vmDao.findByUuid(id); - + // If the template represents an ISO, a disk offering must be passed in, and will be used to create the root disk // Else, a disk offering is optional, and if present will be used to create the data disk Pair rootDiskOffering = new Pair(null, null); List> dataDiskOfferings = new ArrayList>(); - + ServiceOfferingVO offering = _serviceOfferingDao.findById(vm.getServiceOfferingId()); rootDiskOffering.first(offering); - + if(vm.getDiskOfferingId() != null){ DiskOfferingVO diskOffering = _diskOfferingDao.findById(vm.getDiskOfferingId()); if (diskOffering == null) { @@ -205,32 +204,32 @@ public class CloudOrchestrator implements OrchestrationService { } dataDiskOfferings.add(new Pair(diskOffering, size)); } - - - + + + if (_itMgr.allocate(_userVmDao.findById(vm.getId(), true), _templateDao.findById(new Long(templateId)), offering, rootDiskOffering, dataDiskOfferings, networkIpMap, null, plan, hypervisorType, _accountDao.findById(new Long(owner))) == null) { return null; } - + return vmEntity; } @Override public VirtualMachineEntity createVirtualMachineFromScratch(String id, String owner, String isoId, String hostName, String displayName, String hypervisor, String os, int cpu, int speed, long memory,Long diskSize, List computeTags, List rootDiskTags, Map networkNicMap, DeploymentPlan plan) throws InsufficientCapacityException { - + // VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks, vmEntityManager); VirtualMachineEntityImpl vmEntity = ComponentContext.inject(VirtualMachineEntityImpl.class); vmEntity.init(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, new ArrayList(networkNicMap.keySet())); //load vm instance and offerings and call virtualMachineManagerImpl VMInstanceVO vm = _vmDao.findByUuid(id); - - + + Pair rootDiskOffering = new Pair(null, null); ServiceOfferingVO offering = _serviceOfferingDao.findById(vm.getServiceOfferingId()); rootDiskOffering.first(offering); - + List> dataDiskOfferings = new ArrayList>(); Long diskOfferingId = vm.getDiskOfferingId(); if (diskOfferingId == null) { @@ -251,7 +250,7 @@ public class CloudOrchestrator implements OrchestrationService { } rootDiskOffering.first(diskOffering); rootDiskOffering.second(size); - + List> networkIpMap = new ArrayList>(); for (String uuid : networkNicMap.keySet()) { NetworkVO network = _networkDao.findByUuid(uuid); @@ -259,13 +258,13 @@ public class CloudOrchestrator implements OrchestrationService { networkIpMap.add(new Pair(network, networkNicMap.get(uuid))); } } - + HypervisorType hypervisorType = HypervisorType.valueOf(hypervisor); - + if (_itMgr.allocate(_userVmDao.findById(vm.getId(), true), _templateDao.findById(new Long(isoId)), offering, rootDiskOffering, dataDiskOfferings, networkIpMap, null, plan, hypervisorType, _accountDao.findById(new Long(owner))) == null) { return null; } - + return vmEntity; } From c8ae2a9d25128b692719d33cffaed2fe62f6a339 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Fri, 29 Mar 2013 00:15:23 -0700 Subject: [PATCH 20/45] API to list planners and set the planner in Service offering Conflicts: server/src/com/cloud/server/ManagementServerImpl.java setup/db/db/schema-410to420.sql --- .../com/cloud/server/ManagementService.java | 4 +- .../apache/cloudstack/api/ApiConstants.java | 1 + .../config/ListDeploymentPlannersCmd.java | 71 ++++++++++++++++++ .../offering/CreateServiceOfferingCmd.java | 7 ++ client/tomcatconf/componentContext.xml.in | 3 - .../configuration/ConfigurationManager.java | 3 +- .../ConfigurationManagerImpl.java | 6 +- .../cloud/server/ManagementServerImpl.java | 19 ++++- .../com/cloud/service/ServiceOfferingVO.java | 74 +++++++++++-------- .../vpc/MockConfigurationManagerImpl.java | 2 +- setup/db/db/schema-410to420.sql | 68 +++++++++++++++++ 11 files changed, 219 insertions(+), 39 deletions(-) create mode 100644 api/src/org/apache/cloudstack/api/command/admin/config/ListDeploymentPlannersCmd.java diff --git a/api/src/com/cloud/server/ManagementService.java b/api/src/com/cloud/server/ManagementService.java index 1e6ca8d0b67..6e6dbc36f0c 100755 --- a/api/src/com/cloud/server/ManagementService.java +++ b/api/src/com/cloud/server/ManagementService.java @@ -123,7 +123,7 @@ public interface ManagementService { /** * Searches for servers by the specified search criteria Can search by: "name", "type", "state", "dataCenterId", * "podId" - * + * * @param cmd * @return List of Hosts */ @@ -407,4 +407,6 @@ public interface ManagementService { */ List listTopConsumedResources(ListCapacityCmd cmd); + List listDeploymentPlanners(); + } diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index cfabc61d54c..dd8bfcdc67a 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -475,6 +475,7 @@ public class ApiConstants { public static final String HEALTHCHECK_PINGPATH = "pingpath"; public static final String AFFINITY_GROUP_IDS = "affinitygroupids"; public static final String AFFINITY_GROUP_NAMES = "affinitygroupnames"; + public static final String DEPLOYMENT_PLANNER = "deploymentplanner"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/ListDeploymentPlannersCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/ListDeploymentPlannersCmd.java new file mode 100644 index 00000000000..69004de2a6b --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/config/ListDeploymentPlannersCmd.java @@ -0,0 +1,71 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT 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.config; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.response.DeploymentPlannersResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.log4j.Logger; + +@APICommand(name = "listDeploymentPlanners", description = "Lists all DeploymentPlanners available.", responseObject = DeploymentPlannersResponse.class) +public class ListDeploymentPlannersCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(ListDeploymentPlannersCmd.class.getName()); + + private static final String s_name = "listdeploymentplannersresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute(){ + List planners = _mgr.listDeploymentPlanners(); + ListResponse response = new ListResponse(); + List plannerResponses = new ArrayList(); + + for (String planner : planners) { + DeploymentPlannersResponse plannerResponse = new DeploymentPlannersResponse(); + plannerResponse.setName(planner); + plannerResponse.setObjectName("deploymentPlanner"); + plannerResponses.add(plannerResponse); + } + + response.setResponses(plannerResponses); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java index e915c48e9b6..74392cd4299 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java @@ -84,6 +84,9 @@ public class CreateServiceOfferingCmd extends BaseCmd { @Parameter(name=ApiConstants.NETWORKRATE, type=CommandType.INTEGER, description="data transfer rate in megabits per second allowed. Supported only for non-System offering and system offerings having \"domainrouter\" systemvmtype") private Integer networkRate; + @Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, type = CommandType.STRING, description = "The deployment planner heuristics used to deploy a VM of this offering, default \"FirstFitPlanner\".") + private String deploymentPlanner; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -148,6 +151,10 @@ public class CreateServiceOfferingCmd extends BaseCmd { return networkRate; } + public String getDeploymentPlanner() { + return deploymentPlanner; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index bea2f787c17..1582e8bbc56 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -155,7 +155,6 @@ - @@ -248,6 +247,4 @@ - - diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index 20e98845ac0..c5f65e9d0fc 100644 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -78,10 +78,11 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * TODO * @param id * @param useVirtualNetwork + * @param deploymentPlanner * @return ID */ ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vm_typeType, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, - boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate); + boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate, String deploymentPlanner); /** * Creates a new disk offering diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 1526fb0e125..ceeae1ee910 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -1821,16 +1821,16 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } return createServiceOffering(userId, cmd.getIsSystem(), vmType, cmd.getServiceOfferingName(), cpuNumber.intValue(), memory.intValue(), cpuSpeed.intValue(), cmd.getDisplayText(), - localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), cmd.getNetworkRate()); + localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), cmd.getNetworkRate(), cmd.getDeploymentPlanner()); } @Override @ActionEvent(eventType = EventTypes.EVENT_SERVICE_OFFERING_CREATE, eventDescription = "creating service offering") public ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vm_type, String name, int cpu, int ramSize, int speed, String displayText, - boolean localStorageRequired, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate) { + boolean localStorageRequired, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate, String deploymentPlanner) { tags = cleanupTags(tags); ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, limitResourceUse, volatileVm, displayText, localStorageRequired, false, tags, isSystem, vm_type, - domainId, hostTag); + domainId, hostTag, deploymentPlanner); if ((offering = _serviceOfferingDao.persist(offering)) != null) { UserContext.current().setEventDetails("Service offering id=" + offering.getId()); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index af77ba5645f..01798cc5b87 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -107,7 +107,6 @@ import org.apache.cloudstack.api.response.ExtractResponse; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; - import com.cloud.agent.AgentManager; import com.cloud.agent.api.GetVncPortAnswer; import com.cloud.agent.api.GetVncPortCommand; @@ -136,6 +135,7 @@ import com.cloud.dc.*; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.dao.*; import com.cloud.deploy.DataCenterDeployment; +import com.cloud.deploy.DeploymentPlanner; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; @@ -460,6 +460,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe private List _userAuthenticators; private List _userPasswordEncoders; + @Inject + protected List _planners; + @Inject ClusterManager _clusterMgr; private String _hashKey = null; @@ -2301,6 +2304,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(AssignToGlobalLoadBalancerRuleCmd.class); cmdList.add(RemoveFromGlobalLoadBalancerRuleCmd.class); cmdList.add(ListStorageProvidersCmd.class); + cmdList.add(CreateAffinityGroupCmd.class); + cmdList.add(DeleteAffinityGroupCmd.class); + cmdList.add(ListAffinityGroupsCmd.class); + cmdList.add(UpdateVMAffinityGroupCmd.class); return cmdList; } @@ -3366,4 +3373,14 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } + @Override + public List listDeploymentPlanners() { + List plannersAvailable = new ArrayList(); + for (DeploymentPlanner planner : _planners) { + plannersAvailable.add(planner.getName()); + } + + return plannersAvailable; + } + } diff --git a/server/src/com/cloud/service/ServiceOfferingVO.java b/server/src/com/cloud/service/ServiceOfferingVO.java index 7be939c3a15..40f817d076b 100755 --- a/server/src/com/cloud/service/ServiceOfferingVO.java +++ b/server/src/com/cloud/service/ServiceOfferingVO.java @@ -34,25 +34,25 @@ import com.cloud.vm.VirtualMachine; public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering { @Column(name="cpu") private int cpu; - + @Column(name="speed") private int speed; - + @Column(name="ram_size") private int ramSize; - + @Column(name="nw_rate") private Integer rateMbps; - + @Column(name="mc_rate") private Integer multicastRateMbps; - + @Column(name="ha_enabled") private boolean offerHA; @Column(name="limit_cpu_use") - private boolean limitCpuUse; - + private boolean limitCpuUse; + @Column(name="is_volatile") private boolean volatileVm; @@ -64,10 +64,13 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering @Column(name="vm_type") private String vm_type; - + @Column(name="sort_key") int sortKey; - + + @Column(name = "deployment_planner") + private String deploymentPlanner = "FirstFitPlanner"; + protected ServiceOfferingVO() { super(); } @@ -80,7 +83,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering this.rateMbps = rateMbps; this.multicastRateMbps = multicastRateMbps; this.offerHA = offerHA; - this.limitCpuUse = false; + this.limitCpuUse = false; this.volatileVm = false; this.default_use = defaultUse; this.vm_type = vm_type == null ? null : vm_type.toString().toLowerCase(); @@ -94,7 +97,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering this.rateMbps = rateMbps; this.multicastRateMbps = multicastRateMbps; this.offerHA = offerHA; - this.limitCpuUse = limitCpuUse; + this.limitCpuUse = limitCpuUse; this.volatileVm = volatileVm; this.vm_type = vm_type == null ? null : vm_type.toString().toLowerCase(); } @@ -102,31 +105,40 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId, String hostTag) { this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, displayText, useLocalStorage, recreatable, tags, systemUse, vm_type, domainId); this.hostTag = hostTag; - } + } + + public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, + boolean offerHA, boolean limitResourceUse, boolean volatileVm, String displayText, boolean useLocalStorage, + boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId, + String hostTag, String deploymentPlanner) { + this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, + displayText, useLocalStorage, recreatable, tags, systemUse, vm_type, domainId, hostTag); + this.deploymentPlanner = deploymentPlanner; + } @Override public boolean getOfferHA() { return offerHA; } - + public void setOfferHA(boolean offerHA) { this.offerHA = offerHA; } - @Override + @Override public boolean getLimitCpuUse() { return limitCpuUse; } - + public void setLimitResourceUse(boolean limitCpuUse) { this.limitCpuUse = limitCpuUse; } - - @Override + + @Override public boolean getDefaultUse() { return default_use; } - + @Override @Transient public String[] getTagsArray() { @@ -134,15 +146,15 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering if (tags == null || tags.length() == 0) { return new String[0]; } - + return tags.split(","); } - + @Override public int getCpu() { return cpu; } - + public void setCpu(int cpu) { this.cpu = cpu; } @@ -154,17 +166,17 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering public void setRamSize(int ramSize) { this.ramSize = ramSize; } - + @Override public int getSpeed() { return speed; } - + @Override public int getRamSize() { return ramSize; } - + public void setRateMbps(Integer rateMbps) { this.rateMbps = rateMbps; } @@ -177,7 +189,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering public void setMulticastRateMbps(Integer multicastRateMbps) { this.multicastRateMbps = multicastRateMbps; } - + @Override public Integer getMulticastRateMbps() { return multicastRateMbps; @@ -185,12 +197,12 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering public void setHostTag(String hostTag) { this.hostTag = hostTag; - } - + } + public String getHostTag() { return hostTag; } - + public String getSystemVmType(){ return vm_type; } @@ -202,10 +214,14 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering public int getSortKey() { return sortKey; } - + @Override public boolean getVolatileVm() { return volatileVm; } + public String getDeploymentPlanner() { + return deploymentPlanner; + } + } diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java index d96e831cfeb..b0063fa2e2e 100644 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -433,7 +433,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu */ @Override public ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, Type vm_typeType, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, boolean offerHA, - boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate) { + boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate, String deploymentPlanner) { // TODO Auto-generated method stub return null; } diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 77bb8d62f68..0f6b41eb25d 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -165,6 +165,74 @@ CREATE TABLE `cloud`.`affinity_group_vm_map` ( CONSTRAINT `fk_agvm__group_id` FOREIGN KEY(`affinity_group_id`) REFERENCES `affinity_group`(`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE nic_secondary_ips ( + `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, + `uuid` varchar(40), + `vmId` bigint unsigned COMMENT 'vm instance id', + `nicId` bigint unsigned NOT NULL, + `ip4_address` char(40) COMMENT 'ip4 address', + `ip6_address` char(40) COMMENT 'ip6 address', + `network_id` bigint unsigned NOT NULL COMMENT 'network configuration id', + `created` datetime NOT NULL COMMENT 'date created', + `account_id` bigint unsigned NOT NULL COMMENT 'owner. foreign key to account table', + `domain_id` bigint unsigned NOT NULL COMMENT 'the domain that the owner belongs to', + PRIMARY KEY (`id`), + CONSTRAINT `fk_nic_secondary_ip__vmId` FOREIGN KEY `fk_nic_secondary_ip__vmId`(`vmId`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_nic_secondary_ip__networks_id` FOREIGN KEY `fk_nic_secondary_ip__networks_id`(`network_id`) REFERENCES `networks`(`id`), + CONSTRAINT `uc_nic_secondary_ip__uuid` UNIQUE (`uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `cloud`.`nics` ADD COLUMN secondary_ip SMALLINT DEFAULT '0' COMMENT 'secondary ips configured for the nic'; +ALTER TABLE `cloud`.`user_ip_address` ADD COLUMN dnat_vmip VARCHAR(40); + +ALTER TABLE `cloud`.`alert` ADD COLUMN `archived` tinyint(1) unsigned NOT NULL DEFAULT 0; +ALTER TABLE `cloud`.`event` ADD COLUMN `archived` tinyint(1) unsigned NOT NULL DEFAULT 0; +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'alert.purge.interval', '86400', 'The interval (in seconds) to wait before running the alert purge thread'); +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'alert.purge.delay', '0', 'Alerts older than specified number days will be purged. Set this value to 0 to never delete alerts'); + +DROP VIEW IF EXISTS `cloud`.`event_view`; +CREATE VIEW `cloud`.`event_view` AS + select + event.id, + event.uuid, + event.type, + event.state, + event.description, + event.created, + event.level, + event.parameters, + event.start_id, + eve.uuid start_uuid, + event.user_id, + event.archived, + user.username user_name, + account.id account_id, + account.uuid account_uuid, + account.account_name account_name, + account.type account_type, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path, + projects.id project_id, + projects.uuid project_uuid, + projects.name project_name + from + `cloud`.`event` + inner join + `cloud`.`account` ON event.account_id = account.id + inner join + `cloud`.`domain` ON event.domain_id = domain.id + inner join + `cloud`.`user` ON event.user_id = user.id + left join + `cloud`.`projects` ON projects.project_account_id = event.account_id + left join + `cloud`.`event` eve ON event.start_id = eve.id; + +ALTER TABLE `cloud`.`service_offering` ADD COLUMN `deployment_planner` varchar(255) NOT NULL DEFAULT 'FirstFitPlanner' COMMENT 'Planner heuristics used to deploy a VM of this offering'; + -- Re-enable foreign key checking, at the end of the upgrade path SET foreign_key_checks = 1; From 708157d33fd32b186f59687d176b9251bdb7d23c Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Fri, 22 Mar 2013 14:57:27 -0700 Subject: [PATCH 21/45] API changes to expose the commands --- .../affinitygroup/CreateAffinityGroupCmd.java | 4 +- .../response/DeploymentPlannersResponse.java | 37 +++++++++++++++++++ client/pom.xml | 5 +++ client/tomcatconf/commands.properties.in | 3 ++ .../affinity/AffinityGroupServiceImpl.java | 2 +- 5 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 api/src/org/apache/cloudstack/api/response/DeploymentPlannersResponse.java diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/CreateAffinityGroupCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/CreateAffinityGroupCmd.java index b46521457c5..96de4aa13c0 100644 --- a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/CreateAffinityGroupCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/CreateAffinityGroupCmd.java @@ -43,10 +43,10 @@ public class CreateAffinityGroupCmd extends BaseAsyncCreateCmd { // ////////////// API parameters ///////////////////// // /////////////////////////////////////////////////// - @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = true, description = "an account for the affinity group. Must be used with domainId.") + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an account for the affinity group. Must be used with domainId.") private String accountName; - @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, description = "domainId of the account owning the affinity group", entityType = DomainResponse.class) + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, description = "domainId of the account owning the affinity group", entityType = DomainResponse.class) private Long domainId; @Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "optional description of the affinity group") diff --git a/api/src/org/apache/cloudstack/api/response/DeploymentPlannersResponse.java b/api/src/org/apache/cloudstack/api/response/DeploymentPlannersResponse.java new file mode 100644 index 00000000000..a37800fd650 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/DeploymentPlannersResponse.java @@ -0,0 +1,37 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public class DeploymentPlannersResponse extends BaseResponse { + @SerializedName(ApiConstants.NAME) + @Param(description = "Deployment Planner name") + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/client/pom.xml b/client/pom.xml index cd61dfc8bef..08946b6d905 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -234,6 +234,11 @@ cloud-plugin-snmp-alerts ${project.version} + + org.apache.cloudstack + cloud-plugin-host-anti-affinity + ${project.version} + install diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index e4823d9669d..55fa599825f 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -571,3 +571,6 @@ addBaremetalHost=1 #### Affinity group commands createAffinityGroup=15 +deleteAffinityGroup=15 +listAffinityGroups=15 +updateVMAffinityGroup=15 diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java index f6c87cb9fe3..21052d0b3ab 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java @@ -231,7 +231,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro return false; } if ((newState == State.Expunging)) { - // cleanup all affinity groups associated to the Expunged VM + // cleanup all affinity groups associations of the Expunged VM SearchCriteria sc = _affinityGroupVMMapDao.createSearchCriteria(); sc.addAnd("instanceId", SearchCriteria.Op.EQ, vo.getId()); _affinityGroupVMMapDao.expunge(sc); From bb9bdf0173f7a225402a6640a0d8752155c9ee3c Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Mon, 25 Mar 2013 14:53:19 -0700 Subject: [PATCH 22/45] Changes to make affinity group types configurable. --- .../affinity/AffinityGroupTypeResponse.java | 48 +++++++++++++ .../ListAffinityGroupTypesCmd.java | 67 +++++++++++++++++++ client/tomcatconf/componentContext.xml.in | 9 +++ .../affinity/AffinityGroupServiceImpl.java | 64 +++++++++++++++++- 4 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 api/src/org/apache/cloudstack/affinity/AffinityGroupTypeResponse.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupTypesCmd.java diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupTypeResponse.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupTypeResponse.java new file mode 100644 index 00000000000..2d1cd25edda --- /dev/null +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupTypeResponse.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.affinity; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; +import org.apache.cloudstack.api.response.ControlledEntityResponse; +import org.apache.cloudstack.api.response.ControlledViewEntityResponse; + +import com.cloud.network.security.SecurityGroup; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("unused") +@EntityReference(value = AffinityGroup.class) +public class AffinityGroupTypeResponse extends BaseResponse { + + @SerializedName(ApiConstants.TYPE) + @Param(description = "the type of the affinity group") + private String type; + + + public AffinityGroupTypeResponse() { + } + + public void setType(String type) { + this.type = type; + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupTypesCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupTypesCmd.java new file mode 100644 index 00000000000..ce6e89a078c --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupTypesCmd.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.user.affinitygroup; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.affinity.AffinityGroupTypeResponse; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.log4j.Logger; + +import com.cloud.user.Account; + +@APICommand(name = "listAffinityGroupTypes", description = "Lists affinity group types available", responseObject = AffinityGroupTypeResponse.class) +public class ListAffinityGroupTypesCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(ListAffinityGroupTypesCmd.class.getName()); + + private static final String s_name = "listaffinitygrouptypesresponse"; + + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + List result = _affinityGroupService.listAffinityGroupTypes(); + ListResponse response = new ListResponse(); + ArrayList responses = new ArrayList(); + if (result != null) { + for (String type : result) { + AffinityGroupTypeResponse affinityTypeResponse = new AffinityGroupTypeResponse(); + affinityTypeResponse.setType(type); + affinityTypeResponse.setObjectName("affinityGroupType"); + responses.add(affinityTypeResponse); + } + } + response.setResponses(responses); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } +} diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 1582e8bbc56..7f3e02d879d 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -247,4 +247,13 @@ + + + + + + + diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java index 21052d0b3ab..853602231d1 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java @@ -1,7 +1,10 @@ package org.apache.cloudstack.affinity; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import javax.ejb.Local; import javax.inject.Inject; @@ -10,6 +13,7 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.affinity.dao.AffinityGroupDao; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.log4j.Logger; +import org.springframework.context.annotation.Primary; import com.cloud.event.ActionEvent; @@ -22,6 +26,7 @@ import com.cloud.user.AccountManager; import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; import com.cloud.utils.Pair; +import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; @@ -30,6 +35,7 @@ import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.StateListener; import com.cloud.vm.UserVmVO; import com.cloud.vm.VirtualMachine; @@ -69,7 +75,30 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro + " already exisits."); } - AffinityGroupVO group = new AffinityGroupVO(affinityGroupName, affinityGroupType, description, domainId, + + //validate the affinityGroupType + String internalAffinityType = null; + Map typeProcessorMap = getAffinityTypeToProcessorMap(); + if (typeProcessorMap != null && !typeProcessorMap.isEmpty()) { + if (!typeProcessorMap.containsKey(affinityGroupType)) { + throw new InvalidParameterValueException("Unable to create affinity group, invalid affinity group type" + + affinityGroupType); + } else { + AffinityGroupProcessor processor = typeProcessorMap.get(affinityGroupType); + internalAffinityType = processor.getType(); + } + } else { + throw new InvalidParameterValueException( + "Unable to create affinity group, no Affinity Group Types configured"); + } + + if (internalAffinityType == null) { + throw new InvalidParameterValueException( + "Unable to create affinity group, Affinity Group Processor for type " + affinityGroupType + + "is wrongly configured"); + } + + AffinityGroupVO group = new AffinityGroupVO(affinityGroupName, internalAffinityType, description, domainId, owner.getId()); _affinityGroupDao.persist(group); @@ -188,8 +217,37 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro @Override public List listAffinityGroupTypes() { - // TODO Auto-generated method stub - return null; + List types = new ArrayList(); + Map componentMap = ComponentContext.getComponentsOfType(AffinityGroupProcessor.class); + + if (componentMap.size() > 0) { + for (Entry entry : componentMap.entrySet()) { + Map params = entry.getValue().getConfigParams(); + if (params.containsKey("type")) { + types.add((String) params.get("type")); + } + + } + + } + return types; + } + + protected Map getAffinityTypeToProcessorMap() { + Map typeProcessorMap = new HashMap(); + Map componentMap = ComponentContext.getComponentsOfType(AffinityGroupProcessor.class); + + if (componentMap.size() > 0) { + for (Entry entry : componentMap.entrySet()) { + Map params = entry.getValue().getConfigParams(); + if (params.containsKey("type")) { + typeProcessorMap.put((String) params.get("type"), entry.getValue()); + } + + } + + } + return typeProcessorMap; } @Override From c7c899f62d9eb9d314718ae1e4d4822c3998864b Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Fri, 29 Mar 2013 00:17:44 -0700 Subject: [PATCH 23/45] Fixes after functional tests Conflicts: client/tomcatconf/commands.properties.in --- .../exception/AffinityConflictException.java | 4 +- .../affinity/AffinityGroupProcessor.java | 23 +++- .../affinity/AffinityProcessorBase.java | 28 +++++ .../deploy/UserPreferrenceProcessor.java | 27 ----- client/tomcatconf/commands.properties.in | 1 + .../cloud/entity/api/VMEntityManagerImpl.java | 82 ++++++++------ .../affinity/HostAntiAffinityProcessor.java | 8 +- .../src/com/cloud/deploy/FirstFitPlanner.java | 56 +++++----- .../cloud/server/ManagementServerImpl.java | 104 +++++------------- .../src/com/cloud/vm/UserVmManagerImpl.java | 14 ++- .../cloud/vm/VirtualMachineManagerImpl.java | 41 ++++--- .../affinity/AffinityGroupServiceImpl.java | 33 ++---- .../affinity/AffinityGroupVMMapVO.java | 8 -- .../dao/AffinityGroupVMMapDaoImpl.java | 10 +- 14 files changed, 202 insertions(+), 237 deletions(-) create mode 100644 api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java delete mode 100644 api/src/org/apache/cloudstack/deploy/UserPreferrenceProcessor.java diff --git a/api/src/com/cloud/exception/AffinityConflictException.java b/api/src/com/cloud/exception/AffinityConflictException.java index 75df78419ab..da7148f1e2d 100644 --- a/api/src/com/cloud/exception/AffinityConflictException.java +++ b/api/src/com/cloud/exception/AffinityConflictException.java @@ -1,9 +1,9 @@ package com.cloud.exception; -import com.cloud.exception.CloudException; import com.cloud.utils.SerialVersionUID; +import com.cloud.utils.exception.CloudRuntimeException; -public class AffinityConflictException extends CloudException { +public class AffinityConflictException extends CloudRuntimeException { private static final long serialVersionUID = SerialVersionUID.AffinityConflictException; diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java index e6c64b3ff9c..9bdd0515f47 100644 --- a/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java @@ -1,8 +1,27 @@ package org.apache.cloudstack.affinity; -import org.apache.cloudstack.deploy.UserPreferrenceProcessor; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.exception.AffinityConflictException; +import com.cloud.utils.component.Adapter; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; -public interface AffinityGroupProcessor extends UserPreferrenceProcessor { +public interface AffinityGroupProcessor extends Adapter { + + /** + * process() is called to apply any user preferences to the deployment plan + * and avoid set for the given VM placement. + * + * @param vm + * virtual machine. + * @param plan + * deployment plan that tells you where it's being deployed to. + * @param avoid + * avoid these data centers, pods, clusters, or hosts. + */ + void process(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) + throws AffinityConflictException; /** * getType() should return the affinity/anti-affinity group being diff --git a/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java b/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java new file mode 100644 index 00000000000..74fdde166eb --- /dev/null +++ b/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java @@ -0,0 +1,28 @@ +package org.apache.cloudstack.affinity; + +import com.cloud.deploy.DeploymentPlan; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.exception.AffinityConflictException; +import com.cloud.utils.component.AdapterBase; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; + +public class AffinityProcessorBase extends AdapterBase implements AffinityGroupProcessor { + + protected String _type; + + @Override + public void process(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) + throws AffinityConflictException { + + } + + @Override + public String getType() { + return _type; + } + + public void setType(String type) { + _type = type; + } +} diff --git a/api/src/org/apache/cloudstack/deploy/UserPreferrenceProcessor.java b/api/src/org/apache/cloudstack/deploy/UserPreferrenceProcessor.java deleted file mode 100644 index ad26f0e06d8..00000000000 --- a/api/src/org/apache/cloudstack/deploy/UserPreferrenceProcessor.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.apache.cloudstack.deploy; - - -import com.cloud.deploy.DeploymentPlan; -import com.cloud.deploy.DeploymentPlanner.ExcludeList; -import com.cloud.exception.AffinityConflictException; -import com.cloud.utils.component.Adapter; -import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachineProfile; - -public interface UserPreferrenceProcessor extends Adapter { - - /** - * process() is called to apply any user preferences to the deployment plan - * and avoid set for the given VM placement. - * - * @param vm - * virtual machine. - * @param plan - * deployment plan that tells you where it's being deployed to. - * @param avoid - * avoid these data centers, pods, clusters, or hosts. - */ - void process(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) - throws AffinityConflictException; - -} \ No newline at end of file diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 55fa599825f..4ce9fd3af5c 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -574,3 +574,4 @@ createAffinityGroup=15 deleteAffinityGroup=15 listAffinityGroups=15 updateVMAffinityGroup=15 +listAffinityGroupTypes=15 diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java index 0359db95a96..ec813b2e998 100755 --- a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java @@ -36,7 +36,9 @@ import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner; +import com.cloud.deploy.DeploymentPlanningManager; import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.exception.AffinityConflictException; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; @@ -55,7 +57,7 @@ import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; -import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.VirtualMachineProfile; @@ -69,42 +71,45 @@ public class VMEntityManagerImpl implements VMEntityManager { protected VMInstanceDao _vmDao; @Inject protected VMTemplateDao _templateDao = null; - + @Inject protected ServiceOfferingDao _serviceOfferingDao; - + @Inject protected DiskOfferingDao _diskOfferingDao = null; - + @Inject protected NetworkDao _networkDao; - + @Inject protected AccountDao _accountDao = null; @Inject protected UserDao _userDao = null; - @Inject + @Inject protected VMEntityDao _vmEntityDao; - - @Inject + + @Inject protected VMReservationDao _reservationDao; - + @Inject protected VirtualMachineManager _itMgr; - + @Inject protected List _planners; - + @Inject protected VolumeDao _volsDao; - + @Inject protected PrimaryDataStoreDao _storagePoolDao; @Inject DataStoreManager dataStoreMgr; - + + @Inject + DeploymentPlanningManager _dpMgr; + @Override public VMEntityVO loadVirtualMachine(String vmId) { // TODO Auto-generated method stub @@ -114,11 +119,11 @@ public class VMEntityManagerImpl implements VMEntityManager { @Override public void saveVirtualMachine(VMEntityVO entity) { _vmEntityDao.persist(entity); - + } @Override - public String reserveVirtualMachine(VMEntityVO vmEntityVO, String plannerToUse, DeploymentPlan planToDeploy, ExcludeList exclude) + public String reserveVirtualMachine(VMEntityVO vmEntityVO, String plannerToUse, DeploymentPlan planToDeploy, ExcludeList exclude) throws InsufficientCapacityException, ResourceUnavailableException { //call planner and get the deployDestination. @@ -130,12 +135,12 @@ public class VMEntityManagerImpl implements VMEntityManager { if(planToDeploy != null && planToDeploy.getDataCenterId() != 0){ plan = new DataCenterDeployment(planToDeploy.getDataCenterId(), planToDeploy.getPodId(), planToDeploy.getClusterId(), planToDeploy.getHostId(), planToDeploy.getPoolId(), planToDeploy.getPhysicalNetworkId()); } - + List vols = _volsDao.findReadyRootVolumesByInstance(vm.getId()); if(!vols.isEmpty()){ VolumeVO vol = vols.get(0); StoragePool pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(vol.getPoolId()); - + if (!pool.isInMaintenance()) { long rootVolDcId = pool.getDataCenterId(); Long rootVolPodId = pool.getPodId(); @@ -156,21 +161,21 @@ public class VMEntityManagerImpl implements VMEntityManager { } } - + + } + + DeployDestination dest; + try { + dest = _dpMgr.planDeployment(vmProfile, plan, exclude); + } catch (AffinityConflictException e) { + throw new CloudRuntimeException("Unable to create deployment, affinity rules associted to the VM conflict"); } - - DeploymentPlanner planner = ComponentContext.getComponent(plannerToUse); - DeployDestination dest = null; - - if (planner.canHandle(vmProfile, plan, exclude)) { - dest = planner.plan(vmProfile, plan, exclude); - } if (dest != null) { //save destination with VMEntityVO VMReservationVO vmReservation = new VMReservationVO(vm.getId(), dest.getDataCenter().getId(), dest.getPod().getId(), dest.getCluster().getId(), dest.getHost().getId()); Map volumeReservationMap = new HashMap(); - + if (vm.getHypervisorType() != HypervisorType.BareMetal) { for(Volume vo : dest.getStorageForDisks().keySet()){ volumeReservationMap.put(vo.getId(), dest.getStorageForDisks().get(vo).getId()); @@ -180,21 +185,21 @@ public class VMEntityManagerImpl implements VMEntityManager { vmEntityVO.setVmReservation(vmReservation); _vmEntityDao.persist(vmEntityVO); - + return vmReservation.getUuid(); }else{ throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile, DataCenter.class, plan.getDataCenterId()); } - + } @Override public void deployVirtualMachine(String reservationId, String caller, Map params) throws InsufficientCapacityException, ResourceUnavailableException{ //grab the VM Id and destination using the reservationId. - + VMReservationVO vmReservation = _reservationDao.findByReservationId(reservationId); long vmId = vmReservation.getVmId(); - + VMInstanceVO vm = _vmDao.findById(vmId); //Pass it down Long poolId = null; @@ -205,12 +210,17 @@ public class VMEntityManagerImpl implements VMEntityManager { poolId = storage.get(volIdList.get(0)); } } - - DataCenterDeployment plan = new DataCenterDeployment(vm.getDataCenterId(), vmReservation.getPodId(), vmReservation.getClusterId(), + + DataCenterDeployment reservedPlan = new DataCenterDeployment(vm.getDataCenterId(), vmReservation.getPodId(), vmReservation.getClusterId(), vmReservation.getHostId(), null , null); - - VMInstanceVO vmDeployed = _itMgr.start(vm, params, _userDao.findById(new Long(caller)), _accountDao.findById(vm.getAccountId()), plan); - + try{ + VMInstanceVO vmDeployed = _itMgr.start(vm, params, _userDao.findById(new Long(caller)), _accountDao.findById(vm.getAccountId()), reservedPlan); + }catch(Exception ex){ + //Retry the deployment without using the reservation plan + DataCenterDeployment plan = new DataCenterDeployment(vm.getDataCenterId(), null, null,null, null , null); + _itMgr.start(vm, params, _userDao.findById(new Long(caller)), _accountDao.findById(vm.getAccountId()), plan); + } + } @Override @@ -227,7 +237,7 @@ public class VMEntityManagerImpl implements VMEntityManager { VMInstanceVO vm = _vmDao.findByUuid(vmEntityVO.getUuid()); return _itMgr.destroy(vm, _userDao.findById(new Long(caller)), _accountDao.findById(vm.getAccountId())); - + } } diff --git a/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java b/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java index 11b391b74c6..88030f21799 100644 --- a/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java +++ b/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java @@ -28,7 +28,6 @@ import org.apache.log4j.Logger; import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.exception.AffinityConflictException; -import com.cloud.utils.component.AdapterBase; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; @@ -36,7 +35,7 @@ import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; @Local(value = AffinityGroupProcessor.class) -public class HostAntiAffinityProcessor extends AdapterBase implements AffinityGroupProcessor { +public class HostAntiAffinityProcessor extends AffinityProcessorBase implements AffinityGroupProcessor { private static final Logger s_logger = Logger.getLogger(HostAntiAffinityProcessor.class); @Inject @@ -74,9 +73,4 @@ public class HostAntiAffinityProcessor extends AdapterBase implements AffinityGr } - @Override - public String getType() { - return "HostAntiAffinity"; - } - } diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index 2dffe70fb46..1647cf7dba9 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -161,38 +161,44 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { + hostIdSpecified); } HostVO host = _hostDao.findById(hostIdSpecified); - if (s_logger.isDebugEnabled()) { - if(host == null){ - s_logger.debug("The specified host cannot be found"); - }else{ + if (host == null) { + s_logger.debug("The specified host cannot be found"); + } else if (avoid.shouldAvoid(host)) { + s_logger.debug("The specified host is in avoid set"); + } else { + if (s_logger.isDebugEnabled()) { s_logger.debug("Looking for suitable pools for this host under zone: "+host.getDataCenterId() +", pod: "+ host.getPodId()+", cluster: "+ host.getClusterId()); } - } - //search for storage under the zone, pod, cluster of the host. - DataCenterDeployment lastPlan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), hostIdSpecified, plan.getPoolId(), null, plan.getReservationContext()); + // search for storage under the zone, pod, cluster of the host. + DataCenterDeployment lastPlan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), + host.getClusterId(), hostIdSpecified, plan.getPoolId(), null, plan.getReservationContext()); - Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, lastPlan, avoid, HostAllocator.RETURN_UPTO_ALL); - Map> suitableVolumeStoragePools = result.first(); - List readyAndReusedVolumes = result.second(); + Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, + lastPlan, avoid, HostAllocator.RETURN_UPTO_ALL); + Map> suitableVolumeStoragePools = result.first(); + List readyAndReusedVolumes = result.second(); - //choose the potential pool for this VM for this host - if(!suitableVolumeStoragePools.isEmpty()){ - List suitableHosts = new ArrayList(); - suitableHosts.add(host); + // choose the potential pool for this VM for this host + if (!suitableVolumeStoragePools.isEmpty()) { + List suitableHosts = new ArrayList(); + suitableHosts.add(host); - Pair> potentialResources = findPotentialDeploymentResources(suitableHosts, suitableVolumeStoragePools); - if(potentialResources != null){ - Pod pod = _podDao.findById(host.getPodId()); - Cluster cluster = _clusterDao.findById(host.getClusterId()); - Map storageVolMap = potentialResources.second(); - // remove the reused vol<->pool from destination, since we don't have to prepare this volume. - for(Volume vol : readyAndReusedVolumes){ - storageVolMap.remove(vol); + Pair> potentialResources = findPotentialDeploymentResources( + suitableHosts, suitableVolumeStoragePools); + if (potentialResources != null) { + Pod pod = _podDao.findById(host.getPodId()); + Cluster cluster = _clusterDao.findById(host.getClusterId()); + Map storageVolMap = potentialResources.second(); + // remove the reused vol<->pool from destination, since + // we don't have to prepare this volume. + for (Volume vol : readyAndReusedVolumes) { + storageVolMap.remove(vol); + } + DeployDestination dest = new DeployDestination(dc, pod, cluster, host, storageVolMap); + s_logger.debug("Returning Deployment Destination: " + dest); + return dest; } - DeployDestination dest = new DeployDestination(dc, pod, cluster, host, storageVolMap); - s_logger.debug("Returning Deployment Destination: "+ dest); - return dest; } } s_logger.debug("Cannnot deploy to specified host, returning."); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 01798cc5b87..b869d1e21b3 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -37,14 +37,9 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import javax.annotation.PostConstruct; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.inject.Inject; -import javax.management.InstanceAlreadyExistsException; -import javax.management.MBeanRegistrationException; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; import javax.naming.ConfigurationException; import com.cloud.storage.dao.*; @@ -54,59 +49,43 @@ import org.apache.cloudstack.api.ApiConstants; import com.cloud.event.ActionEventUtils; import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd; import org.apache.cloudstack.api.command.admin.account.*; -import org.apache.cloudstack.api.command.admin.autoscale.*; -import org.apache.cloudstack.api.command.admin.cluster.*; -import org.apache.cloudstack.api.command.admin.config.*; import org.apache.cloudstack.api.command.admin.domain.*; import org.apache.cloudstack.api.command.admin.host.*; -import org.apache.cloudstack.api.command.admin.ldap.*; import org.apache.cloudstack.api.command.admin.network.*; import org.apache.cloudstack.api.command.admin.offering.*; -import org.apache.cloudstack.api.command.admin.pod.*; -import org.apache.cloudstack.api.command.admin.region.*; import org.apache.cloudstack.api.command.admin.resource.*; import org.apache.cloudstack.api.command.admin.router.*; import org.apache.cloudstack.api.command.admin.storage.*; -import org.apache.cloudstack.api.command.admin.swift.*; import org.apache.cloudstack.api.command.admin.systemvm.*; -import org.apache.cloudstack.api.command.admin.template.*; import org.apache.cloudstack.api.command.admin.usage.*; import org.apache.cloudstack.api.command.admin.user.*; -import org.apache.cloudstack.api.command.admin.vlan.*; -import org.apache.cloudstack.api.command.admin.vm.*; import org.apache.cloudstack.api.command.admin.vpc.*; -import org.apache.cloudstack.api.command.admin.zone.*; -import org.apache.cloudstack.api.command.user.account.*; -import org.apache.cloudstack.api.command.user.address.*; import org.apache.cloudstack.api.command.user.autoscale.*; -import org.apache.cloudstack.api.command.user.config.*; -import org.apache.cloudstack.api.command.user.event.*; import org.apache.cloudstack.api.command.user.firewall.*; -import org.apache.cloudstack.api.command.user.guest.*; import org.apache.cloudstack.api.command.user.iso.*; -import org.apache.cloudstack.api.command.user.job.*; import org.apache.cloudstack.api.command.user.loadbalancer.*; import org.apache.cloudstack.api.command.user.nat.*; import org.apache.cloudstack.api.command.user.network.*; -import org.apache.cloudstack.api.command.user.offering.*; import org.apache.cloudstack.api.command.user.project.*; -import org.apache.cloudstack.api.command.user.region.*; import org.apache.cloudstack.api.command.user.resource.*; import org.apache.cloudstack.api.command.user.securitygroup.*; import org.apache.cloudstack.api.command.user.snapshot.*; -import org.apache.cloudstack.api.command.user.ssh.*; -import org.apache.cloudstack.api.command.user.tag.*; import org.apache.cloudstack.api.command.user.template.*; import org.apache.cloudstack.api.command.user.vm.*; -import org.apache.cloudstack.api.command.user.vmgroup.*; import org.apache.cloudstack.api.command.user.volume.*; import org.apache.cloudstack.api.command.user.vpc.*; import org.apache.cloudstack.api.command.user.vpn.*; -import org.apache.cloudstack.api.command.user.zone.*; import org.apache.cloudstack.api.response.ExtractResponse; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; +import org.apache.cloudstack.affinity.AffinityGroupProcessor; +import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; + +import org.apache.cloudstack.api.command.user.affinitygroup.CreateAffinityGroupCmd; +import org.apache.cloudstack.api.command.user.affinitygroup.DeleteAffinityGroupCmd; +import org.apache.cloudstack.api.command.user.affinitygroup.ListAffinityGroupTypesCmd; +import org.apache.cloudstack.api.command.user.affinitygroup.ListAffinityGroupsCmd; +import org.apache.cloudstack.api.command.user.affinitygroup.UpdateVMAffinityGroupCmd; import com.cloud.agent.AgentManager; import com.cloud.agent.api.GetVncPortAnswer; import com.cloud.agent.api.GetVncPortCommand; @@ -140,7 +119,6 @@ import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; -import com.cloud.event.ActionEventUtils; import com.cloud.event.EventTypes; import com.cloud.event.EventVO; import com.cloud.event.dao.EventDao; @@ -175,7 +153,6 @@ import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.*; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Upload.Mode; -import com.cloud.storage.dao.*; import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.snapshot.SnapshotManager; @@ -193,11 +170,7 @@ import com.cloud.utils.EnumUtils; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.PasswordGenerator; -import com.cloud.utils.ReflectUtil; import com.cloud.utils.Ternary; -import com.cloud.utils.component.Adapter; -import com.cloud.utils.component.AdapterBase; -import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ComponentLifecycle; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; @@ -214,10 +187,6 @@ import com.cloud.vm.dao.*; import edu.emory.mathcs.backport.java.util.Arrays; import edu.emory.mathcs.backport.java.util.Collections; import org.apache.cloudstack.acl.ControlledEntity; -import org.apache.cloudstack.acl.SecurityChecker.AccessType; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd; -import org.apache.cloudstack.api.command.admin.account.*; import org.apache.cloudstack.api.command.admin.autoscale.CreateCounterCmd; import org.apache.cloudstack.api.command.admin.autoscale.DeleteCounterCmd; import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd; @@ -228,12 +197,8 @@ import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd; import org.apache.cloudstack.api.command.admin.config.ListHypervisorCapabilitiesCmd; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; import org.apache.cloudstack.api.command.admin.config.UpdateHypervisorCapabilitiesCmd; -import org.apache.cloudstack.api.command.admin.domain.*; -import org.apache.cloudstack.api.command.admin.host.*; import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd; import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd; -import org.apache.cloudstack.api.command.admin.network.*; -import org.apache.cloudstack.api.command.admin.offering.*; 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; @@ -241,22 +206,15 @@ import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd; import org.apache.cloudstack.api.command.admin.region.AddRegionCmd; import org.apache.cloudstack.api.command.admin.region.RemoveRegionCmd; import org.apache.cloudstack.api.command.admin.region.UpdateRegionCmd; -import org.apache.cloudstack.api.command.admin.resource.*; -import org.apache.cloudstack.api.command.admin.router.*; -import org.apache.cloudstack.api.command.admin.storage.*; import org.apache.cloudstack.api.command.admin.swift.AddSwiftCmd; import org.apache.cloudstack.api.command.admin.swift.ListSwiftsCmd; -import org.apache.cloudstack.api.command.admin.systemvm.*; import org.apache.cloudstack.api.command.admin.template.PrepareTemplateCmd; -import org.apache.cloudstack.api.command.admin.usage.*; -import org.apache.cloudstack.api.command.admin.user.*; import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd; import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd; import org.apache.cloudstack.api.command.admin.vlan.ListVlanIpRangesCmd; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.admin.vpc.*; import org.apache.cloudstack.api.command.admin.zone.CreateZoneCmd; import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd; import org.apache.cloudstack.api.command.admin.zone.MarkDefaultZoneForAccountCmd; @@ -268,29 +226,19 @@ import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd; import org.apache.cloudstack.api.command.user.address.AssociateIPAddrCmd; import org.apache.cloudstack.api.command.user.address.DisassociateIPAddrCmd; import org.apache.cloudstack.api.command.user.address.ListPublicIpAddressesCmd; -import org.apache.cloudstack.api.command.user.autoscale.*; import org.apache.cloudstack.api.command.user.config.ListCapabilitiesCmd; import org.apache.cloudstack.api.command.user.event.ArchiveEventsCmd; import org.apache.cloudstack.api.command.user.event.DeleteEventsCmd; import org.apache.cloudstack.api.command.user.event.ListEventTypesCmd; import org.apache.cloudstack.api.command.user.event.ListEventsCmd; -import org.apache.cloudstack.api.command.user.firewall.*; import org.apache.cloudstack.api.command.user.guest.ListGuestOsCategoriesCmd; import org.apache.cloudstack.api.command.user.guest.ListGuestOsCmd; -import org.apache.cloudstack.api.command.user.iso.*; import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd; import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; -import org.apache.cloudstack.api.command.user.loadbalancer.*; -import org.apache.cloudstack.api.command.user.nat.*; -import org.apache.cloudstack.api.command.user.network.*; import org.apache.cloudstack.api.command.user.offering.ListDiskOfferingsCmd; import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd; -import org.apache.cloudstack.api.command.user.project.*; import org.apache.cloudstack.api.command.user.region.ListRegionsCmd; import org.apache.cloudstack.api.command.user.region.ha.gslb.*; -import org.apache.cloudstack.api.command.user.resource.*; -import org.apache.cloudstack.api.command.user.securitygroup.*; -import org.apache.cloudstack.api.command.user.snapshot.*; import org.apache.cloudstack.api.command.user.ssh.CreateSSHKeyPairCmd; import org.apache.cloudstack.api.command.user.ssh.DeleteSSHKeyPairCmd; import org.apache.cloudstack.api.command.user.ssh.ListSSHKeyPairsCmd; @@ -298,8 +246,6 @@ import org.apache.cloudstack.api.command.user.ssh.RegisterSSHKeyPairCmd; import org.apache.cloudstack.api.command.user.tag.CreateTagsCmd; import org.apache.cloudstack.api.command.user.tag.DeleteTagsCmd; import org.apache.cloudstack.api.command.user.tag.ListTagsCmd; -import org.apache.cloudstack.api.command.user.template.*; -import org.apache.cloudstack.api.command.user.vm.*; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd; @@ -308,27 +254,10 @@ import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd; import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd; import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd; import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToSnapshotCmd; -import org.apache.cloudstack.api.command.user.volume.*; -import org.apache.cloudstack.api.command.user.vpc.*; -import org.apache.cloudstack.api.command.user.vpn.*; import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd; -import org.apache.cloudstack.api.response.ExtractResponse; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.inject.Inject; -import javax.naming.ConfigurationException; -import java.lang.reflect.Field; -import java.net.*; -import java.util.*; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; public class ManagementServerImpl extends ManagerBase implements ManagementServer { public static final Logger s_logger = Logger.getLogger(ManagementServerImpl.class.getName()); @@ -466,6 +395,12 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Inject ClusterManager _clusterMgr; private String _hashKey = null; + @Inject + protected AffinityGroupVMMapDao _affinityGroupVMMapDao; + + @Inject + protected List _affinityProcessors; + public ManagementServerImpl() { setRunLevel(ComponentLifecycle.RUN_LEVEL_APPLICATION_MAINLOOP); } @@ -824,6 +759,15 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe ExcludeList excludes = new ExcludeList(); excludes.addHost(srcHostId); + // call affinitygroup chain + long vmGroupCount = _affinityGroupVMMapDao.countAffinityGroupsForVm(vm.getId()); + + if (vmGroupCount > 0) { + for (AffinityGroupProcessor processor : _affinityProcessors) { + processor.process(vmProfile, plan, excludes); + } + } + for (HostAllocator allocator : _hostAllocators) { suitableHosts = allocator.allocateTo(vmProfile, plan, Host.Type.Routing, excludes, HostAllocator.RETURN_UPTO_ALL, false); if (suitableHosts != null && !suitableHosts.isEmpty()) { @@ -2308,6 +2252,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(DeleteAffinityGroupCmd.class); cmdList.add(ListAffinityGroupsCmd.class); cmdList.add(UpdateVMAffinityGroupCmd.class); + cmdList.add(ListAffinityGroupTypesCmd.class); + return cmdList; } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index ca158f1995d..8b6ad3b8829 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2284,10 +2284,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } // check that the affinity groups exist - for (Long affinityGroupId : affinityGroupIdList) { - AffinityGroupVO ag = _affinityGroupDao.findById(affinityGroupId); - if (ag == null) { - throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId); + if (affinityGroupIdList != null) { + for (Long affinityGroupId : affinityGroupIdList) { + AffinityGroupVO ag = _affinityGroupDao.findById(affinityGroupId); + if (ag == null) { + throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId); + } } } @@ -2582,7 +2584,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _securityGroupMgr.addInstanceToGroups(vm.getId(), securityGroupIdList); - _affinityGroupVMMapDao.updateMap(vm.getId(), affinityGroupIdList); + if (affinityGroupIdList != null && !affinityGroupIdList.isEmpty()) { + _affinityGroupVMMapDao.updateMap(vm.getId(), affinityGroupIdList); + } return vm; } diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 08c6e7c1208..40725314f46 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -703,8 +703,10 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac try { dest = _dpMgr.planDeployment(vmProfile, plan, avoids); } catch (AffinityConflictException e2) { - // TODO Auto-generated catch block - e2.printStackTrace(); + s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2); + throw new CloudRuntimeException( + "Unable to create deployment, affinity rules associted to the VM conflict"); + } if (dest == null) { @@ -718,6 +720,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile, DataCenter.class, plan.getDataCenterId()); } + if (dest != null) { + avoids.addHost(dest.getHost().getId()); + journal.record("Deployment found ", vmProfile, dest); + } + long destHostId = dest.getHost().getId(); vm.setPodId(dest.getPod().getId()); Long cluster_id = dest.getCluster().getId(); @@ -1486,25 +1493,23 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac DeployDestination dest = null; while (true) { - for (DeploymentPlanner planner : _planners) { - if (planner.canHandle(profile, plan, excludes)) { - dest = planner.plan(profile, plan, excludes); - } else { - continue; - } - if (dest != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Planner " + planner + " found " + dest + " for migrating to."); - } - break; - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("Planner " + planner + " was unable to find anything."); - } + try { + dest = _dpMgr.planDeployment(profile, plan, excludes); + } catch (AffinityConflictException e2) { + s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2); + throw new CloudRuntimeException( + "Unable to create deployment, affinity rules associted to the VM conflict"); } - if (dest == null) { + if (dest != null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Found destination " + dest + " for migrating to."); + } + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Unable to find destination for migrating the vm " + profile); + } throw new InsufficientServerCapacityException("Unable to find a server to migrate to.", host.getClusterId()); } diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java index 853602231d1..b22ed837533 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java @@ -16,6 +16,7 @@ import org.apache.log4j.Logger; import org.springframework.context.annotation.Primary; +import com.cloud.deploy.DeploymentPlanner; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; @@ -77,28 +78,22 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro //validate the affinityGroupType - String internalAffinityType = null; Map typeProcessorMap = getAffinityTypeToProcessorMap(); if (typeProcessorMap != null && !typeProcessorMap.isEmpty()) { if (!typeProcessorMap.containsKey(affinityGroupType)) { throw new InvalidParameterValueException("Unable to create affinity group, invalid affinity group type" + affinityGroupType); - } else { - AffinityGroupProcessor processor = typeProcessorMap.get(affinityGroupType); - internalAffinityType = processor.getType(); } } else { throw new InvalidParameterValueException( "Unable to create affinity group, no Affinity Group Types configured"); } - if (internalAffinityType == null) { - throw new InvalidParameterValueException( - "Unable to create affinity group, Affinity Group Processor for type " + affinityGroupType - + "is wrongly configured"); + if (domainId == null) { + domainId = owner.getDomainId(); } - AffinityGroupVO group = new AffinityGroupVO(affinityGroupName, internalAffinityType, description, domainId, + AffinityGroupVO group = new AffinityGroupVO(affinityGroupName, affinityGroupType, description, domainId, owner.getId()); _affinityGroupDao.persist(group); @@ -174,8 +169,6 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro vmInstanceSearch.and("instanceId", vmInstanceSearch.entity().getInstanceId(), SearchCriteria.Op.EQ); SearchBuilder groupSearch = _affinityGroupDao.createSearchBuilder(); - groupSearch.join("vmInstanceSearch", vmInstanceSearch, groupSearch.entity().getId(), vmInstanceSearch.entity() - .getAffinityGroupId(), JoinBuilder.JoinType.INNER); SearchCriteria sc = groupSearch.create(); @@ -207,6 +200,8 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro } _accountMgr.checkAccess(caller, null, true, userVM); // add join to affinity_groups_vm_map + groupSearch.join("vmInstanceSearch", vmInstanceSearch, groupSearch.entity().getId(), vmInstanceSearch + .entity().getAffinityGroupId(), JoinBuilder.JoinType.INNER); sc.setJoinParameters("vmInstanceSearch", "instanceId", vmId); } @@ -222,11 +217,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro if (componentMap.size() > 0) { for (Entry entry : componentMap.entrySet()) { - Map params = entry.getValue().getConfigParams(); - if (params.containsKey("type")) { - types.add((String) params.get("type")); - } - + types.add(entry.getValue().getType()); } } @@ -235,17 +226,13 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro protected Map getAffinityTypeToProcessorMap() { Map typeProcessorMap = new HashMap(); - Map componentMap = ComponentContext.getComponentsOfType(AffinityGroupProcessor.class); + Map componentMap = ComponentContext + .getComponentsOfType(AffinityGroupProcessor.class); if (componentMap.size() > 0) { for (Entry entry : componentMap.entrySet()) { - Map params = entry.getValue().getConfigParams(); - if (params.containsKey("type")) { - typeProcessorMap.put((String) params.get("type"), entry.getValue()); - } - + typeProcessorMap.put(entry.getValue().getType(), entry.getValue()); } - } return typeProcessorMap; } diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java index 5401b4aef70..f84e4c351aa 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java @@ -30,7 +30,6 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity @Table(name = ("affinity_group_vm_map")) -@SecondaryTables({ @SecondaryTable(name = "affinity_group", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "affinity_group_id", referencedColumnName = "id") }) }) public class AffinityGroupVMMapVO implements InternalIdentity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -43,9 +42,6 @@ public class AffinityGroupVMMapVO implements InternalIdentity { @Column(name = "instance_id") private long instanceId; - @Column(name = "name", table = "affinity_group", insertable = false, updatable = false) - private String groupName; - public AffinityGroupVMMapVO() { } @@ -67,8 +63,4 @@ public class AffinityGroupVMMapVO implements InternalIdentity { return instanceId; } - - public String getGroupName() { - return groupName; - } } diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java index ea315ac595c..b17d0b38383 100644 --- a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java +++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java @@ -76,12 +76,12 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase groupSearch = _affinityGroupDao.createSearchBuilder(); groupSearch.and("type", groupSearch.entity().getType(), SearchCriteria.Op.EQ); - ListByVmIdType.join("groupSearch", groupSearch, ListByVmIdType.entity().getAffinityGroupId(), groupSearch - .entity().getId(), JoinType.INNER); + + ListByVmIdType = createSearchBuilder(); + ListByVmIdType.and("instanceId", ListByVmIdType.entity().getInstanceId(), SearchCriteria.Op.EQ); + ListByVmIdType.join("groupSearch", groupSearch, ListByVmIdType.entity().getAffinityGroupId(), groupSearch.entity().getId(), JoinType.INNER); ListByVmIdType.done(); CountSGForVm = createSearchBuilder(Long.class); @@ -145,7 +145,7 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase sc = ListByVmIdType.create(); sc.setParameters("instanceId", instanceId); sc.setJoinParameters("groupSearch", "type", type); - return customSearch(sc, null).get(0); + return findOneBy(sc); } @Override From e312158f1c32de9c2f713c42c9175041b68920bf Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Fri, 29 Mar 2013 00:20:31 -0700 Subject: [PATCH 24/45] Adding the missing header! --- .../affinity/AffinityProcessorBase.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java b/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java index 74fdde166eb..70ecd08350f 100644 --- a/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java +++ b/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.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 org.apache.cloudstack.affinity; import com.cloud.deploy.DeploymentPlan; From ee45437036afa743390c5d39e965cd6c85eafb87 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Fri, 29 Mar 2013 13:10:29 -0700 Subject: [PATCH 25/45] Build failure fixes after rebase. --- api/src/org/apache/cloudstack/api/BaseCmd.java | 1 + api/src/org/apache/cloudstack/api/ResponseGenerator.java | 4 +++- server/src/com/cloud/api/ApiResponseHelper.java | 3 --- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index c94f3fb3089..42c0680ce0f 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -61,6 +61,7 @@ import com.cloud.projects.ProjectService; import com.cloud.resource.ResourceService; import com.cloud.server.ManagementService; import com.cloud.server.TaggedResourceService; +import com.cloud.storage.DataStoreProviderApiService; import com.cloud.storage.StorageService; import com.cloud.storage.VolumeApiService; import com.cloud.storage.snapshot.SnapshotService; diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java index 977713005f2..c0dd57e15bd 100644 --- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java @@ -22,6 +22,8 @@ import java.util.List; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupResponse; +import org.apache.cloudstack.api.ApiConstants.HostDetails; +import org.apache.cloudstack.api.ApiConstants.VMDetails; import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.AsyncJobResponse; @@ -138,6 +140,7 @@ import com.cloud.org.Cluster; import com.cloud.projects.Project; import com.cloud.projects.ProjectAccount; import com.cloud.projects.ProjectInvitation; +import com.cloud.region.ha.GlobalLoadBalancerRule; import com.cloud.server.ResourceTag; import com.cloud.storage.*; import com.cloud.storage.snapshot.SnapshotPolicy; @@ -149,7 +152,6 @@ import com.cloud.user.UserAccount; import com.cloud.uservm.UserVm; import com.cloud.vm.InstanceGroup; import com.cloud.vm.Nic; -import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.api.response.*; diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index d651f1f1c6a..651a8bed110 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -270,10 +270,8 @@ import com.cloud.vm.NicVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; -<<<<<<< HEAD import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.snapshot.VMSnapshot; -======= import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.affinity.AffinityGroup; @@ -304,7 +302,6 @@ import javax.inject.Inject; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; ->>>>>>> More API changes @Component public class ApiResponseHelper implements ResponseGenerator { From b633dde744057d8fbeb8bfa2b05b04ca8159793a Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Mon, 1 Apr 2013 11:08:16 -0700 Subject: [PATCH 26/45] Adding a unit test for the new affinity groups API --- .../affinity/AffinityGroupServiceImpl.java | 5 +- .../AffinityApiTestConfiguration.java | 318 ++++++++++++++++++ .../affinity/AffinityApiUnitTest.java | 164 +++++++++ server/test/resources/affinityContext.xml | 44 +++ 4 files changed, 529 insertions(+), 2 deletions(-) create mode 100644 server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java create mode 100644 server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java create mode 100644 server/test/resources/affinityContext.xml diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java index b22ed837533..e143db414e3 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java @@ -308,8 +308,9 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId); } } - _affinityGroupVMMapDao.updateMap(vmId, affinityGroupIds); - + if (affinityGroupIds != null && !affinityGroupIds.isEmpty()) { + _affinityGroupVMMapDao.updateMap(vmId, affinityGroupIds); + } // APIResponseHelper will pull out the updated affinitygroups. return vmInstance; diff --git a/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java b/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java new file mode 100644 index 00000000000..d778ed44ef3 --- /dev/null +++ b/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java @@ -0,0 +1,318 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT 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.affinity; + +import java.io.IOException; + +import org.apache.cloudstack.acl.SecurityChecker; +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; +import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; +import com.cloud.utils.component.ComponentContext; +import com.cloud.agent.AgentManager; +import com.cloud.alert.AlertManager; +import com.cloud.api.query.dao.UserAccountJoinDaoImpl; +import com.cloud.capacity.dao.CapacityDaoImpl; +import com.cloud.cluster.agentlb.dao.HostTransferMapDaoImpl; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.dc.dao.AccountVlanMapDaoImpl; +import com.cloud.dc.dao.ClusterDaoImpl; +import com.cloud.dc.dao.DataCenterDaoImpl; +import com.cloud.dc.dao.DataCenterIpAddressDaoImpl; +import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDaoImpl; +import com.cloud.dc.dao.DataCenterVnetDaoImpl; +import com.cloud.dc.dao.DcDetailsDaoImpl; +import com.cloud.dc.dao.HostPodDaoImpl; +import com.cloud.dc.dao.PodVlanDaoImpl; +import com.cloud.dc.dao.PodVlanMapDaoImpl; +import com.cloud.dc.dao.VlanDaoImpl; +import com.cloud.domain.dao.DomainDaoImpl; +import com.cloud.event.dao.UsageEventDaoImpl; +import com.cloud.host.dao.HostDaoImpl; +import com.cloud.host.dao.HostDetailsDaoImpl; +import com.cloud.host.dao.HostTagsDaoImpl; +import com.cloud.network.Ipv6AddressManager; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.NetworkService; +import com.cloud.network.StorageNetworkManager; +import com.cloud.network.dao.FirewallRulesCidrsDaoImpl; +import com.cloud.network.dao.FirewallRulesDaoImpl; +import com.cloud.network.dao.IPAddressDaoImpl; +import com.cloud.network.dao.LoadBalancerDaoImpl; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkDomainDaoImpl; +import com.cloud.network.dao.NetworkServiceMapDaoImpl; +import com.cloud.network.dao.PhysicalNetworkDaoImpl; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDaoImpl; +import com.cloud.network.dao.PhysicalNetworkTrafficTypeDaoImpl; +import com.cloud.network.dao.UserIpv6AddressDaoImpl; +import com.cloud.network.element.DhcpServiceProvider; +import com.cloud.network.element.IpDeployer; +import com.cloud.network.element.NetworkElement; +import com.cloud.network.guru.NetworkGuru; +import com.cloud.network.lb.LoadBalancingRulesManager; +import com.cloud.network.rules.FirewallManager; +import com.cloud.network.rules.RulesManager; +import com.cloud.network.rules.dao.PortForwardingRulesDaoImpl; +import com.cloud.network.vpc.NetworkACLManager; +import com.cloud.network.vpc.VpcManager; +import com.cloud.network.vpc.dao.PrivateIpDaoImpl; +import com.cloud.network.vpn.RemoteAccessVpnService; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.projects.ProjectManager; +import com.cloud.service.dao.ServiceOfferingDaoImpl; +import com.cloud.storage.dao.DiskOfferingDaoImpl; +import com.cloud.storage.dao.S3DaoImpl; +import com.cloud.storage.dao.SnapshotDaoImpl; +import com.cloud.storage.dao.StoragePoolDetailsDaoImpl; +import com.cloud.storage.dao.SwiftDaoImpl; +import com.cloud.storage.dao.VolumeDaoImpl; +import com.cloud.storage.s3.S3Manager; +import com.cloud.storage.secondary.SecondaryStorageVmManager; +import com.cloud.storage.swift.SwiftManager; +import com.cloud.tags.dao.ResourceTagsDaoImpl; +import com.cloud.user.AccountManager; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.UserContext; +import com.cloud.user.UserContextInitializer; +import com.cloud.user.dao.AccountDaoImpl; +import com.cloud.user.dao.UserDaoImpl; +import com.cloud.utils.component.SpringComponentScanUtils; +import com.cloud.utils.db.GenericDao; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.dao.InstanceGroupDaoImpl; +import com.cloud.vm.dao.NicDaoImpl; +import com.cloud.vm.dao.NicSecondaryIpDaoImpl; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDaoImpl; + +@Configuration +@ComponentScan(basePackageClasses = { AccountVlanMapDaoImpl.class, VolumeDaoImpl.class, HostPodDaoImpl.class, + DomainDaoImpl.class, SwiftDaoImpl.class, ServiceOfferingDaoImpl.class, VlanDaoImpl.class, + IPAddressDaoImpl.class, ResourceTagsDaoImpl.class, AccountDaoImpl.class, InstanceGroupDaoImpl.class, + UserAccountJoinDaoImpl.class, CapacityDaoImpl.class, SnapshotDaoImpl.class, HostDaoImpl.class, + VMInstanceDaoImpl.class, HostTransferMapDaoImpl.class, PortForwardingRulesDaoImpl.class, + PrivateIpDaoImpl.class, UsageEventDaoImpl.class, PodVlanMapDaoImpl.class, DiskOfferingDaoImpl.class, + DataCenterDaoImpl.class, DataCenterIpAddressDaoImpl.class, DataCenterLinkLocalIpAddressDaoImpl.class, + DataCenterVnetDaoImpl.class, PodVlanDaoImpl.class, DcDetailsDaoImpl.class, NicSecondaryIpDaoImpl.class, + UserIpv6AddressDaoImpl.class, S3DaoImpl.class, UserDaoImpl.class, NicDaoImpl.class, NetworkDomainDaoImpl.class, + HostDetailsDaoImpl.class, HostTagsDaoImpl.class, ClusterDaoImpl.class, FirewallRulesDaoImpl.class, + FirewallRulesCidrsDaoImpl.class, PhysicalNetworkDaoImpl.class, PhysicalNetworkTrafficTypeDaoImpl.class, + PhysicalNetworkServiceProviderDaoImpl.class, LoadBalancerDaoImpl.class, NetworkServiceMapDaoImpl.class, + PrimaryDataStoreDaoImpl.class, StoragePoolDetailsDaoImpl.class, AffinityGroupServiceImpl.class, + ComponentContext.class, AffinityGroupProcessor.class, UserVmVO.class }, includeFilters = { @Filter(value = AffinityApiTestConfiguration.Library.class, type = FilterType.CUSTOM) }, useDefaultFilters = false) +public class AffinityApiTestConfiguration { + + @Bean + public AffinityGroupProcessor affinityGroupProcessor() { + return Mockito.mock(AffinityGroupProcessor.class); + } + + @Bean + public ComponentContext componentContext() { + return Mockito.mock(ComponentContext.class); + } + + + @Bean + public UserContextInitializer userContextInitializer() { + return Mockito.mock(UserContextInitializer.class); + } + + @Bean + public UserVmVO userVmVO() { + return Mockito.mock(UserVmVO.class); + } + + @Bean + public AffinityGroupDao affinityGroupDao() { + return Mockito.mock(AffinityGroupDao.class); + } + + @Bean + public AffinityGroupVMMapDao affinityGroupVMMapDao() { + return Mockito.mock(AffinityGroupVMMapDao.class); + } + + @Bean + public AccountManager acctMgr() { + return Mockito.mock(AccountManager.class); + } + + @Bean + public NetworkService ntwkSvc() { + return Mockito.mock(NetworkService.class); + } + + @Bean + public NetworkModel ntwkMdl() { + return Mockito.mock(NetworkModel.class); + } + + @Bean + public AlertManager alertMgr() { + return Mockito.mock(AlertManager.class); + } + + @Bean + public SecurityChecker securityChkr() { + return Mockito.mock(SecurityChecker.class); + } + + @Bean + public ResourceLimitService resourceSvc() { + return Mockito.mock(ResourceLimitService.class); + } + + @Bean + public ProjectManager projectMgr() { + return Mockito.mock(ProjectManager.class); + } + + @Bean + public SecondaryStorageVmManager ssvmMgr() { + return Mockito.mock(SecondaryStorageVmManager.class); + } + + @Bean + public SwiftManager swiftMgr() { + return Mockito.mock(SwiftManager.class); + } + + @Bean + public S3Manager s3Mgr() { + return Mockito.mock(S3Manager.class); + } + + @Bean + public VpcManager vpcMgr() { + return Mockito.mock(VpcManager.class); + } + + @Bean + public UserVmDao userVMDao() { + return Mockito.mock(UserVmDao.class); + } + + @Bean + public RulesManager rulesMgr() { + return Mockito.mock(RulesManager.class); + } + + @Bean + public LoadBalancingRulesManager lbRulesMgr() { + return Mockito.mock(LoadBalancingRulesManager.class); + } + + @Bean + public RemoteAccessVpnService vpnMgr() { + return Mockito.mock(RemoteAccessVpnService.class); + } + + @Bean + public NetworkGuru ntwkGuru() { + return Mockito.mock(NetworkGuru.class); + } + + @Bean + public NetworkElement ntwkElement() { + return Mockito.mock(NetworkElement.class); + } + + @Bean + public IpDeployer ipDeployer() { + return Mockito.mock(IpDeployer.class); + } + + @Bean + public DhcpServiceProvider dhcpProvider() { + return Mockito.mock(DhcpServiceProvider.class); + } + + @Bean + public FirewallManager firewallMgr() { + return Mockito.mock(FirewallManager.class); + } + + @Bean + public AgentManager agentMgr() { + return Mockito.mock(AgentManager.class); + } + + @Bean + public StorageNetworkManager storageNtwkMgr() { + return Mockito.mock(StorageNetworkManager.class); + } + + @Bean + public NetworkACLManager ntwkAclMgr() { + return Mockito.mock(NetworkACLManager.class); + } + + @Bean + public Ipv6AddressManager ipv6Mgr() { + return Mockito.mock(Ipv6AddressManager.class); + } + + @Bean + public ConfigurationDao configDao() { + return Mockito.mock(ConfigurationDao.class); + } + + @Bean + public NetworkManager networkManager() { + return Mockito.mock(NetworkManager.class); + } + + @Bean + public NetworkOfferingDao networkOfferingDao() { + return Mockito.mock(NetworkOfferingDao.class); + } + + @Bean + public NetworkDao networkDao() { + return Mockito.mock(NetworkDao.class); + } + + @Bean + public NetworkOfferingServiceMapDao networkOfferingServiceMapDao() { + return Mockito.mock(NetworkOfferingServiceMapDao.class); + } + + public static class Library implements TypeFilter { + + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + mdr.getClassMetadata().getClassName(); + ComponentScan cs = AffinityApiTestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + + } +} diff --git a/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java new file mode 100644 index 00000000000..17f165dd4dd --- /dev/null +++ b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.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.affinity; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; +import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceInUseException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountManagerImpl; +import com.cloud.user.AccountVO; +import com.cloud.user.UserContext; +import com.cloud.user.UserContextInitializer; +import com.cloud.utils.component.ComponentContext; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.dao.UserVmDao; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = "classpath:/affinityContext.xml") +public class AffinityApiUnitTest { + + @Inject + AffinityGroupServiceImpl _affinityService; + + @Inject + AccountManager _acctMgr; + + @Inject + AffinityGroupProcessor _processor; + + @Inject + AffinityGroupDao _groupDao; + + @Inject + UserVmDao _vmDao; + + @Inject + AffinityGroupVMMapDao _affinityGroupVMMapDao; + + private static long domainId = 5L; + + + @BeforeClass + public static void setUp() throws ConfigurationException { + + } + + @Before + public void testSetUp() { + AccountVO acct = new AccountVO(200L); + acct.setType(Account.ACCOUNT_TYPE_NORMAL); + acct.setAccountName("user"); + acct.setDomainId(domainId); + + UserContext.registerContext(1, acct, null, true); + + when(_acctMgr.finalizeOwner((Account) anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct); + when(_processor.getType()).thenReturn("mock"); + } + + @Test + public void createAffinityGroupTest() { + AffinityGroup group = _affinityService.createAffinityGroup("user", domainId, "group1", "mock", + "affinity group one"); + assertNotNull("Affinity group 'group1' of type 'mock' failed to create ", group); + + } + + @Test(expected = InvalidParameterValueException.class) + public void invalidAffinityTypeTest() { + AffinityGroup group = _affinityService.createAffinityGroup("user", domainId, "group1", "invalid", + "affinity group one"); + + } + + @Test(expected = InvalidParameterValueException.class) + public void uniqueAffinityNameTest() { + when(_groupDao.isNameInUse(anyLong(), anyLong(), eq("group1"))).thenReturn(true); + AffinityGroup group2 = _affinityService.createAffinityGroup("user", domainId, "group1", "mock", + "affinity group two"); + } + + @Test(expected = InvalidParameterValueException.class) + public void deleteAffinityGroupInvalidIdTest() throws ResourceInUseException { + when(_groupDao.findById(20L)).thenReturn(null); + _affinityService.deleteAffinityGroup(20L, "user", domainId, "group1"); + } + + @Test(expected = InvalidParameterValueException.class) + public void deleteAffinityGroupInvalidIdName() throws ResourceInUseException { + when(_groupDao.findByAccountAndName(200L, "group1")).thenReturn(null); + _affinityService.deleteAffinityGroup(null, "user", domainId, "group1"); + } + + @Test(expected = InvalidParameterValueException.class) + public void deleteAffinityGroupNullIdName() throws ResourceInUseException { + _affinityService.deleteAffinityGroup(null, "user", domainId, null); + } + + @Test(expected = ResourceInUseException.class) + public void deleteAffinityGroupInUse() throws ResourceInUseException { + List affinityGroupVmMap = new ArrayList(); + AffinityGroupVMMapVO mapVO = new AffinityGroupVMMapVO(20L, 10L); + affinityGroupVmMap.add(mapVO); + when(_affinityGroupVMMapDao.listByAffinityGroup(20L)).thenReturn(affinityGroupVmMap); + + AffinityGroupVO groupVO = new AffinityGroupVO(); + when(_groupDao.findById(20L)).thenReturn(groupVO); + when(_groupDao.lockRow(20L, true)).thenReturn(groupVO); + + _affinityService.deleteAffinityGroup(20L, "user", domainId, null); + } + + @Test(expected = InvalidParameterValueException.class) + public void updateAffinityGroupVMRunning() throws ResourceInUseException { + + UserVmVO vm = new UserVmVO(10L, "test", "test", 101L, HypervisorType.Any, 21L, false, false, domainId, 200L, + 5L, "", "test", 1L); + vm.setState(VirtualMachine.State.Running); + when(_vmDao.findById(10L)).thenReturn(vm); + + List affinityGroupIds = new ArrayList(); + affinityGroupIds.add(20L); + + _affinityService.updateVMAffinityGroups(10L, affinityGroupIds); + } + +} diff --git a/server/test/resources/affinityContext.xml b/server/test/resources/affinityContext.xml new file mode 100644 index 00000000000..652905c108e --- /dev/null +++ b/server/test/resources/affinityContext.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From fd23b36c119db1c77ee8b31a24f889630dd863c2 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Wed, 3 Apr 2013 16:22:58 -0700 Subject: [PATCH 27/45] Integration testcase and the config file needed, that runs with marvin. --- tools/apidoc/gen_toc.py | 3 +- .../live/testDeployVMWithAffinityGroup.py | 157 ++++++++++++++++++ .../sandbox/demo/live/testaffinitygroup.cfg | 45 +++++ 3 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 tools/marvin/marvin/sandbox/demo/live/testDeployVMWithAffinityGroup.py create mode 100644 tools/marvin/marvin/sandbox/demo/live/testaffinitygroup.cfg diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index ab2456dd3eb..2d5292b8426 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/cygdrive/c/Python27 # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -137,6 +137,7 @@ known_categories = { 'addIpToNic': 'Nic', 'removeIpFromNic': 'Nic', 'listNics':'Nic', + 'AffinityGroup': 'Affinity Group', } diff --git a/tools/marvin/marvin/sandbox/demo/live/testDeployVMWithAffinityGroup.py b/tools/marvin/marvin/sandbox/demo/live/testDeployVMWithAffinityGroup.py new file mode 100644 index 00000000000..93c6571bd12 --- /dev/null +++ b/tools/marvin/marvin/sandbox/demo/live/testDeployVMWithAffinityGroup.py @@ -0,0 +1,157 @@ +#!/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 marvin +from marvin.cloudstackTestCase import * +from marvin.remoteSSHClient import remoteSSHClient +import hashlib +import random + +class TestDeployVmWithAffinityGroup(cloudstackTestCase): + """ + This test deploys a virtual machine into a user account + using the small service offering and builtin template + """ + def setUp(self): + """ + CloudStack internally saves its passwords in md5 form and that is how we + specify it in the API. Python's hashlib library helps us to quickly hash + strings as follows + """ + mdf = hashlib.md5() + mdf.update('password') + mdf_pass = mdf.hexdigest() + + self.apiClient = self.testClient.getApiClient() #Get ourselves an API client + + self.acct = createAccount.createAccountCmd() #The createAccount command + self.acct.accounttype = 0 #We need a regular user. admins have accounttype=1 + self.acct.firstname = 'test' + self.acct.lastname = 'user' #What's up doc? + self.acct.password = mdf_pass #The md5 hashed password string + self.acct.username = 'testuser' + self.acct.email = 'testuser@xyz.com' + self.acct.account = 'testacct' + self.acct.domainid = 1 #The default ROOT domain + self.acctResponse = self.apiClient.createAccount(self.acct) + # And upon successful creation we'll log a helpful message in our logs + # using the default debug logger of the test framework + self.debug("successfully created account: %s, user: %s, id: \ + %s"%(self.acctResponse.account.account, \ + self.acctResponse.account.username, \ + self.acctResponse.account.id)) + + + self.zone = listZones.listZonesCmd() + self.zone.uuid = self.apiClient.listZones(self.zone)[0].id + + self.service_offering = listServiceOfferings.listServiceOfferingsCmd() + self.service_offering.uuid = self.apiClient.listServiceOfferings(self.service_offering)[0].id + + self.template = listTemplates.listTemplatesCmd() + self.template.templatefilter = 'featured' + self.template.name = 'CentOS' + self.template.uuid = self.apiClient.listTemplates(self.template)[0].id + + def test_DeployVm(self): + """ + Let's start by defining the attributes of our VM that we will be + deploying on CloudStack. We will be assuming a single zone is available + and is configured and all templates are Ready + + The hardcoded values are used only for brevity. + + First create the host anti-affinity group for this account + """ + createAGCmd = createAffinityGroup.createAffinityGroupCmd() + createAGCmd.name = 'webvms1' + createAGCmd.type = 'host anti-affinity' + createAGCmd.account = self.acct.account + createAGCmd.domainid = self.acct.domainid + + createAGResponse = self.apiClient.createAffinityGroup(createAGCmd) + self.debug("AffinityGroup %s was created in the job %s"%(createAGResponse.id, createAGResponse.jobid)) + + + deployVmCmd = deployVirtualMachine.deployVirtualMachineCmd() + deployVmCmd.zoneid = self.zone.uuid + deployVmCmd.templateid = self.template.uuid #CentOS 5.6 builtin + deployVmCmd.serviceofferingid = self.service_offering.uuid + deployVmCmd.account = self.acct.account + deployVmCmd.domainid = self.acct.domainid + deployVmCmd.affinitygroupnames=[] + deployVmCmd.affinitygroupnames.append(str(createAGResponse.name)) + deployVmResponse = self.apiClient.deployVirtualMachine(deployVmCmd) + self.debug("VM %s was deployed in the job %s"%(deployVmResponse.id, deployVmResponse.jobid)) + + # At this point our VM is expected to be Running. Let's find out what + # listVirtualMachines tells us about VMs in this account + + listVmCmd = listVirtualMachines.listVirtualMachinesCmd() + listVmCmd.id = deployVmResponse.id + listVmResponse = self.apiClient.listVirtualMachines(listVmCmd) + + self.assertNotEqual(len(listVmResponse), 0, "Check if the list API \ + returns a non-empty response") + + vm = listVmResponse[0] + self.assertEqual(vm.state, "Running", "Check if VM has reached Running state in CS") + + VM1hostid = vm.hostid + + #Deploy another VM in same affinity group + deployVm2Cmd = deployVirtualMachine.deployVirtualMachineCmd() + deployVm2Cmd.zoneid = self.zone.uuid + deployVm2Cmd.templateid = self.template.uuid #CentOS 5.6 builtin + deployVm2Cmd.serviceofferingid = self.service_offering.uuid + deployVm2Cmd.account = self.acct.account + deployVm2Cmd.domainid = self.acct.domainid + deployVm2Cmd.affinitygroupnames=[] + deployVm2Cmd.affinitygroupnames.append(str(createAGResponse.name)) + + deployVm2Response = self.apiClient.deployVirtualMachine(deployVm2Cmd) + self.debug("VM2 %s was deployed in the job %s"%(deployVm2Response.id, deployVm2Response.jobid)) + + # At this point our VM is expected to be Running. Let's find out what + # listVirtualMachines tells us about VMs in this account + + listVm2Cmd = listVirtualMachines.listVirtualMachinesCmd() + listVm2Cmd.id = deployVm2Response.id + listVm2Response = self.apiClient.listVirtualMachines(listVm2Cmd) + + self.assertNotEqual(len(listVm2Response), 0, "Check if the list API \ + returns a non-empty response") + + vm2 = listVm2Response[0] + self.assertEqual(vm2.state, "Running", "Check if VM has reached Running state in CS") + + VM2hostid = vm2.hostid + + self.assertNotEqual(VM1hostid, VM2hostid, "The hosts of the 2 VM's in the host anti-affinity group are not different, test failed") + + def tearDown(self): + """ + And finally let us cleanup the resources we created by deleting the + account. All good unittests are atomic and rerunnable this way + """ + deleteAcct = deleteAccount.deleteAccountCmd() + deleteAcct.id = self.acctResponse.account.id + self.apiClient.deleteAccount(deleteAcct) + self.testClient.close() diff --git a/tools/marvin/marvin/sandbox/demo/live/testaffinitygroup.cfg b/tools/marvin/marvin/sandbox/demo/live/testaffinitygroup.cfg new file mode 100644 index 00000000000..a814016cad0 --- /dev/null +++ b/tools/marvin/marvin/sandbox/demo/live/testaffinitygroup.cfg @@ -0,0 +1,45 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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 config is designed to run as an advanced network, with management server in devcloud +# It also requires an 'apt-get install dnsmasq' to run a resolver in devcloud for internal dns + +{ + "dbSvr": { + "dbSvr": "127.0.0.1", + "passwd": "cloud", + "db": "cloud", + "port": 3306, + "user": "cloud" + }, + "logger": [ + { + "name": "TestClient", + "file": "C:\\var\\log\\testclient.log" + }, + { + "name": "TestCase", + "file": "C:\\var\\log\\testcase.log" + } + ], + "mgtSvr": [ + { + "mgtSvrIp": "127.0.0.1", + "port": 8096 + } + ] +} From ec3f844ef1004ae6ecaf8b7150842fcb50759b84 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Wed, 3 Apr 2013 16:23:57 -0700 Subject: [PATCH 28/45] Correcting the rebase merge issues. --- .../api/command/user/vm/DeployVMCmd.java | 8 +-- setup/db/db/schema-410to420.sql | 71 +------------------ 2 files changed, 5 insertions(+), 74 deletions(-) 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 22fe1ba3a08..77ba9fed59e 100755 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -174,15 +174,13 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { private Boolean startVm; @ACL - @Parameter(name = ApiConstants.AFFINITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups id that are 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 securitygroupnames parameter") + @Parameter(name = ApiConstants.AFFINITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups id that are going to be applied to the virtual machine." + + " Mutually exclusive with affinitygroupnames parameter") private List affinityGroupIdList; @ACL @Parameter(name = ApiConstants.AFFINITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups names that are 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") + + "Mutually exclusive with affinitygroupids parameter") private List affinityGroupNameList; diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 0f6b41eb25d..b4c693a9ba9 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -166,77 +166,8 @@ CREATE TABLE `cloud`.`affinity_group_vm_map` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE nic_secondary_ips ( - `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, - `uuid` varchar(40), - `vmId` bigint unsigned COMMENT 'vm instance id', - `nicId` bigint unsigned NOT NULL, - `ip4_address` char(40) COMMENT 'ip4 address', - `ip6_address` char(40) COMMENT 'ip6 address', - `network_id` bigint unsigned NOT NULL COMMENT 'network configuration id', - `created` datetime NOT NULL COMMENT 'date created', - `account_id` bigint unsigned NOT NULL COMMENT 'owner. foreign key to account table', - `domain_id` bigint unsigned NOT NULL COMMENT 'the domain that the owner belongs to', - PRIMARY KEY (`id`), - CONSTRAINT `fk_nic_secondary_ip__vmId` FOREIGN KEY `fk_nic_secondary_ip__vmId`(`vmId`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE, - CONSTRAINT `fk_nic_secondary_ip__networks_id` FOREIGN KEY `fk_nic_secondary_ip__networks_id`(`network_id`) REFERENCES `networks`(`id`), - CONSTRAINT `uc_nic_secondary_ip__uuid` UNIQUE (`uuid`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -ALTER TABLE `cloud`.`nics` ADD COLUMN secondary_ip SMALLINT DEFAULT '0' COMMENT 'secondary ips configured for the nic'; -ALTER TABLE `cloud`.`user_ip_address` ADD COLUMN dnat_vmip VARCHAR(40); - -ALTER TABLE `cloud`.`alert` ADD COLUMN `archived` tinyint(1) unsigned NOT NULL DEFAULT 0; -ALTER TABLE `cloud`.`event` ADD COLUMN `archived` tinyint(1) unsigned NOT NULL DEFAULT 0; -INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'alert.purge.interval', '86400', 'The interval (in seconds) to wait before running the alert purge thread'); -INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'alert.purge.delay', '0', 'Alerts older than specified number days will be purged. Set this value to 0 to never delete alerts'); - -DROP VIEW IF EXISTS `cloud`.`event_view`; -CREATE VIEW `cloud`.`event_view` AS - select - event.id, - event.uuid, - event.type, - event.state, - event.description, - event.created, - event.level, - event.parameters, - event.start_id, - eve.uuid start_uuid, - event.user_id, - event.archived, - user.username user_name, - account.id account_id, - account.uuid account_uuid, - account.account_name account_name, - account.type account_type, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path, - projects.id project_id, - projects.uuid project_uuid, - projects.name project_name - from - `cloud`.`event` - inner join - `cloud`.`account` ON event.account_id = account.id - inner join - `cloud`.`domain` ON event.domain_id = domain.id - inner join - `cloud`.`user` ON event.user_id = user.id - left join - `cloud`.`projects` ON projects.project_account_id = event.account_id - left join - `cloud`.`event` eve ON event.start_id = eve.id; - ALTER TABLE `cloud`.`service_offering` ADD COLUMN `deployment_planner` varchar(255) NOT NULL DEFAULT 'FirstFitPlanner' COMMENT 'Planner heuristics used to deploy a VM of this offering'; --- Re-enable foreign key checking, at the end of the upgrade path -SET foreign_key_checks = 1; - - CREATE TABLE nic_secondary_ips ( `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, `uuid` varchar(40), @@ -539,3 +470,5 @@ CREATE TABLE `cloud`.`vm_snapshots` ( ALTER TABLE `cloud`.`hypervisor_capabilities` ADD COLUMN `vm_snapshot_enabled` tinyint(1) DEFAULT 0 NOT NULL COMMENT 'Whether VM snapshot is supported by hypervisor'; UPDATE `cloud`.`hypervisor_capabilities` SET `vm_snapshot_enabled`=1 WHERE `hypervisor_type` in ('VMware', 'XenServer'); +-- Re-enable foreign key checking, at the end of the upgrade path +SET foreign_key_checks = 1; From 0b3850c14f9f3420d92bf6eb3477959b8f28e4ad Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Wed, 3 Apr 2013 16:53:57 -0700 Subject: [PATCH 29/45] Added cleanup of affinitygroups when a VM is expunging and when the account is deleted. --- server/src/com/cloud/user/AccountManagerImpl.java | 9 ++++++++- .../cloudstack/affinity/AffinityGroupServiceImpl.java | 5 ++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index bc93df8e756..fe714c530b9 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -42,6 +42,7 @@ import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; import org.apache.cloudstack.api.command.admin.user.RegisterCmd; @@ -220,6 +221,8 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @Inject private AutoScaleManager _autoscaleMgr; @Inject VolumeManager volumeMgr; + @Inject + private AffinityGroupDao _affinityGroupDao; private List _userAuthenticators; List _userPasswordEncoders; @@ -238,7 +241,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M public List getUserAuthenticators() { return _userAuthenticators; } - + public void setUserAuthenticators(List authenticators) { _userAuthenticators = authenticators; } @@ -623,6 +626,10 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M int numRemoved = _securityGroupDao.removeByAccountId(accountId); s_logger.info("deleteAccount: Deleted " + numRemoved + " network groups for account " + accountId); + // Cleanup affinity groups + int numAGRemoved = _affinityGroupDao.removeByAccountId(accountId); + s_logger.info("deleteAccount: Deleted " + numAGRemoved + " affinity groups for account " + accountId); + // Delete all the networks boolean networksDeleted = true; s_logger.debug("Deleting networks for account " + account.getId()); diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java index e143db414e3..17f740118f1 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java @@ -240,6 +240,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro @Override public boolean configure(final String name, final Map params) throws ConfigurationException { _name = name; + VirtualMachine.State.getStateMachine().registerListener(this); return true; } @@ -308,9 +309,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId); } } - if (affinityGroupIds != null && !affinityGroupIds.isEmpty()) { - _affinityGroupVMMapDao.updateMap(vmId, affinityGroupIds); - } + _affinityGroupVMMapDao.updateMap(vmId, affinityGroupIds); // APIResponseHelper will pull out the updated affinitygroups. return vmInstance; From 09a6eb735d2d14c27be4f1911798e581ff60b678 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 4 Apr 2013 14:40:05 -0700 Subject: [PATCH 30/45] Changes to return affinity groups information during listVMsCmd --- .../apache/cloudstack/api/ApiConstants.java | 2 +- .../api/response/UserVmResponse.java | 14 ++ .../cloud/api/query/ViewResponseHelper.java | 2 +- .../api/query/dao/UserVmJoinDaoImpl.java | 27 +++ .../com/cloud/api/query/vo/UserVmJoinVO.java | 37 ++++ setup/db/db/schema-410to420.sql | 179 ++++++++++++++++++ 6 files changed, 259 insertions(+), 2 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index dd8bfcdc67a..b08e992abd2 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -482,7 +482,7 @@ public class ApiConstants { } public enum VMDetails { - all, group, nics, stats, secgrp, tmpl, servoff, iso, volume, min; + all, group, nics, stats, secgrp, tmpl, servoff, iso, volume, min, affgrp; } public enum LDAPParams { diff --git a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java index 71d1b823c6a..212601ce20c 100644 --- a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java +++ b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java @@ -21,6 +21,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; +import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; @@ -169,10 +170,15 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp @SerializedName(ApiConstants.SSH_KEYPAIR) @Param(description="ssh key-pair") private String keyPairName; + @SerializedName("affinitygroup") + @Param(description = "list of affinity groups associated with the virtual machine", responseObject = AffinityGroupResponse.class) + private Set affinityGroupList; + public UserVmResponse(){ securityGroupList = new LinkedHashSet(); nics = new LinkedHashSet(); tags = new LinkedHashSet(); + affinityGroupList = new LinkedHashSet(); } public void setHypervisor(String hypervisor) { @@ -381,4 +387,12 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp this.keyPairName = keyPairName; } + public void setAffinityGroupList(Set affinityGroups) { + this.affinityGroupList = affinityGroups; + } + + public void addAffinityGroup(AffinityGroupResponse affinityGroup) { + this.affinityGroupList.add(affinityGroup); + } + } diff --git a/server/src/com/cloud/api/query/ViewResponseHelper.java b/server/src/com/cloud/api/query/ViewResponseHelper.java index 9e612b07d1b..931327aa86c 100644 --- a/server/src/com/cloud/api/query/ViewResponseHelper.java +++ b/server/src/com/cloud/api/query/ViewResponseHelper.java @@ -123,7 +123,7 @@ public class ViewResponseHelper { // first time encountering this vm userVmData = ApiDBUtils.newUserVmResponse(objectName, userVm, details, caller); } else{ - // update nics, securitygroups, tags for 1 to many mapping fields + // update nics, securitygroups, tags, affinitygroups for 1 to many mapping fields userVmData = ApiDBUtils.fillVmDetails(userVmData, userVm); } vmDataList.put(userVm.getId(), userVmData); diff --git a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java index 8b6abf8a3e4..4ed62262966 100644 --- a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java @@ -26,6 +26,7 @@ import java.util.Set; import javax.ejb.Local; import javax.inject.Inject; +import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.ApiConstants.VMDetails; import org.apache.cloudstack.api.response.NicResponse; import org.apache.cloudstack.api.response.SecurityGroupResponse; @@ -216,6 +217,20 @@ public class UserVmJoinDaoImpl extends GenericDaoBase implem userVmResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); } } + + if (details.contains(VMDetails.all) || details.contains(VMDetails.affgrp)) { + Long affinityGroupId = userVm.getAffinityGroupId(); + if (affinityGroupId != null && affinityGroupId.longValue() != 0) { + AffinityGroupResponse resp = new AffinityGroupResponse(); + resp.setId(userVm.getAffinityGroupUuid()); + resp.setName(userVm.getAffinityGroupName()); + resp.setDescription(userVm.getAffinityGroupDescription()); + resp.setObjectName("affinitygroup"); + resp.setAccountName(userVm.getAccountName()); + userVmResponse.addAffinityGroup(resp); + } + } + userVmResponse.setObjectName(objectName); return userVmResponse; @@ -276,6 +291,18 @@ public class UserVmJoinDaoImpl extends GenericDaoBase implem userVmData.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); } } + + Long affinityGroupId = uvo.getAffinityGroupId(); + if (affinityGroupId != null && affinityGroupId.longValue() != 0) { + AffinityGroupResponse resp = new AffinityGroupResponse(); + resp.setId(uvo.getAffinityGroupUuid()); + resp.setName(uvo.getAffinityGroupName()); + resp.setDescription(uvo.getAffinityGroupDescription()); + resp.setObjectName("affinitygroup"); + resp.setAccountName(uvo.getAccountName()); + userVmData.addAffinityGroup(resp); + } + return userVmData; } diff --git a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java index 33c49cdeae9..8d1314eafae 100644 --- a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java @@ -368,6 +368,18 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { @Column(name="tag_customer") private String tagCustomer; + @Column(name = "affinity_group_id") + private long affinityGroupId; + + @Column(name = "affinity_group_uuid") + private String affinityGroupUuid; + + @Column(name = "affinity_group_name") + private String affinityGroupName; + + @Column(name = "affinity_group_description") + private String affinityGroupDescription; + transient String password; @Transient @@ -1671,4 +1683,29 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { public void setIp6Cidr(String ip6Cidr) { this.ip6Cidr = ip6Cidr; } + + + public long getAffinityGroupId() { + return affinityGroupId; + } + + + + public String getAffinityGroupUuid() { + return affinityGroupUuid; + } + + + + public String getAffinityGroupName() { + return affinityGroupName; + } + + + + public String getAffinityGroupDescription() { + return affinityGroupDescription; + } + + } diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index b4c693a9ba9..6464c08b29b 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -470,5 +470,184 @@ CREATE TABLE `cloud`.`vm_snapshots` ( ALTER TABLE `cloud`.`hypervisor_capabilities` ADD COLUMN `vm_snapshot_enabled` tinyint(1) DEFAULT 0 NOT NULL COMMENT 'Whether VM snapshot is supported by hypervisor'; UPDATE `cloud`.`hypervisor_capabilities` SET `vm_snapshot_enabled`=1 WHERE `hypervisor_type` in ('VMware', 'XenServer'); + +DROP VIEW IF EXISTS `cloud`.`user_vm_view`; +CREATE VIEW `cloud`.`user_vm_view` AS + select + vm_instance.id id, + vm_instance.name name, + user_vm.display_name display_name, + user_vm.user_data user_data, + account.id account_id, + account.uuid account_uuid, + account.account_name account_name, + account.type account_type, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path, + projects.id project_id, + projects.uuid project_uuid, + projects.name project_name, + instance_group.id instance_group_id, + instance_group.uuid instance_group_uuid, + instance_group.name instance_group_name, + vm_instance.uuid uuid, + vm_instance.last_host_id last_host_id, + vm_instance.vm_type type, + vm_instance.vnc_password vnc_password, + vm_instance.limit_cpu_use limit_cpu_use, + vm_instance.created created, + vm_instance.state state, + vm_instance.removed removed, + vm_instance.ha_enabled ha_enabled, + vm_instance.hypervisor_type hypervisor_type, + vm_instance.instance_name instance_name, + vm_instance.guest_os_id guest_os_id, + guest_os.uuid guest_os_uuid, + vm_instance.pod_id pod_id, + host_pod_ref.uuid pod_uuid, + vm_instance.private_ip_address private_ip_address, + vm_instance.private_mac_address private_mac_address, + vm_instance.vm_type vm_type, + data_center.id data_center_id, + data_center.uuid data_center_uuid, + data_center.name data_center_name, + data_center.is_security_group_enabled security_group_enabled, + host.id host_id, + host.uuid host_uuid, + host.name host_name, + vm_template.id template_id, + vm_template.uuid template_uuid, + vm_template.name template_name, + vm_template.display_text template_display_text, + vm_template.enable_password password_enabled, + iso.id iso_id, + iso.uuid iso_uuid, + iso.name iso_name, + iso.display_text iso_display_text, + service_offering.id service_offering_id, + disk_offering.uuid service_offering_uuid, + service_offering.cpu cpu, + service_offering.speed speed, + service_offering.ram_size ram_size, + disk_offering.name service_offering_name, + storage_pool.id pool_id, + storage_pool.uuid pool_uuid, + storage_pool.pool_type pool_type, + volumes.id volume_id, + volumes.uuid volume_uuid, + volumes.device_id volume_device_id, + volumes.volume_type volume_type, + security_group.id security_group_id, + security_group.uuid security_group_uuid, + security_group.name security_group_name, + security_group.description security_group_description, + nics.id nic_id, + nics.uuid nic_uuid, + nics.network_id network_id, + nics.ip4_address ip_address, + nics.ip6_address ip6_address, + nics.ip6_gateway ip6_gateway, + nics.ip6_cidr ip6_cidr, + nics.default_nic is_default_nic, + nics.gateway gateway, + nics.netmask netmask, + nics.mac_address mac_address, + nics.broadcast_uri broadcast_uri, + nics.isolation_uri isolation_uri, + vpc.id vpc_id, + vpc.uuid vpc_uuid, + networks.uuid network_uuid, + networks.name network_name, + networks.traffic_type traffic_type, + networks.guest_type guest_type, + user_ip_address.id public_ip_id, + user_ip_address.uuid public_ip_uuid, + user_ip_address.public_ip_address public_ip_address, + ssh_keypairs.keypair_name keypair_name, + resource_tags.id tag_id, + resource_tags.uuid tag_uuid, + resource_tags.key tag_key, + resource_tags.value tag_value, + resource_tags.domain_id tag_domain_id, + resource_tags.account_id tag_account_id, + resource_tags.resource_id tag_resource_id, + resource_tags.resource_uuid tag_resource_uuid, + resource_tags.resource_type tag_resource_type, + resource_tags.customer tag_customer, + async_job.id job_id, + async_job.uuid job_uuid, + async_job.job_status job_status, + async_job.account_id job_account_id, + affinity_group.id affinity_group_id, + affinity_group.uuid affinity_group_uuid, + affinity_group.name affinity_group_name, + affinity_group.description affinity_group_description + from + `cloud`.`user_vm` + inner join + `cloud`.`vm_instance` ON vm_instance.id = user_vm.id + and vm_instance.removed is NULL + inner join + `cloud`.`account` ON vm_instance.account_id = account.id + inner join + `cloud`.`domain` ON vm_instance.domain_id = domain.id + left join + `cloud`.`guest_os` ON vm_instance.guest_os_id = guest_os.id + left join + `cloud`.`host_pod_ref` ON vm_instance.pod_id = host_pod_ref.id + left join + `cloud`.`projects` ON projects.project_account_id = account.id + left join + `cloud`.`instance_group_vm_map` ON vm_instance.id = instance_group_vm_map.instance_id + left join + `cloud`.`instance_group` ON instance_group_vm_map.group_id = instance_group.id + left join + `cloud`.`data_center` ON vm_instance.data_center_id = data_center.id + left join + `cloud`.`host` ON vm_instance.host_id = host.id + left join + `cloud`.`vm_template` ON vm_instance.vm_template_id = vm_template.id + left join + `cloud`.`vm_template` iso ON iso.id = user_vm.iso_id + left join + `cloud`.`service_offering` ON vm_instance.service_offering_id = service_offering.id + left join + `cloud`.`disk_offering` ON vm_instance.service_offering_id = disk_offering.id + left join + `cloud`.`volumes` ON vm_instance.id = volumes.instance_id + left join + `cloud`.`storage_pool` ON volumes.pool_id = storage_pool.id + left join + `cloud`.`security_group_vm_map` ON vm_instance.id = security_group_vm_map.instance_id + left join + `cloud`.`security_group` ON security_group_vm_map.security_group_id = security_group.id + left join + `cloud`.`nics` ON vm_instance.id = nics.instance_id + left join + `cloud`.`networks` ON nics.network_id = networks.id + left join + `cloud`.`vpc` ON networks.vpc_id = vpc.id + left join + `cloud`.`user_ip_address` ON user_ip_address.vm_id = vm_instance.id + left join + `cloud`.`user_vm_details` ON user_vm_details.vm_id = vm_instance.id + and user_vm_details.name = 'SSH.PublicKey' + left join + `cloud`.`ssh_keypairs` ON ssh_keypairs.public_key = user_vm_details.value + left join + `cloud`.`resource_tags` ON resource_tags.resource_id = vm_instance.id + and resource_tags.resource_type = 'UserVm' + left join + `cloud`.`async_job` ON async_job.instance_id = vm_instance.id + and async_job.instance_type = 'VirtualMachine' + and async_job.job_status = 0 + left join + `cloud`.`affinity_group_vm_map` ON vm_instance.id = affinity_group_vm_map.instance_id + left join + `cloud`.`affinity_group` ON affinity_group_vm_map.affinity_group_id = affinity_group.id; + + -- Re-enable foreign key checking, at the end of the upgrade path SET foreign_key_checks = 1; From 3403b547735fe14e22b879f2627776548394951e Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 4 Apr 2013 22:46:11 -0700 Subject: [PATCH 31/45] Added AffinityGroup View in order to include VM details while listing AffinityGroups. --- .../affinity/AffinityGroupResponse.java | 16 +- .../affinitygroup/ListAffinityGroupsCmd.java | 26 +- .../UpdateVMAffinityGroupCmd.java | 8 +- .../apache/cloudstack/query/QueryService.java | 4 + client/tomcatconf/applicationContext.xml.in | 10 + client/tomcatconf/componentContext.xml.in | 1 + .../affinity/HostAntiAffinityProcessor.java | 9 +- server/src/com/cloud/api/ApiDBUtils.java | 14 + .../com/cloud/api/query/QueryManagerImpl.java | 108 ++++++++ .../cloud/api/query/ViewResponseHelper.java | 18 ++ .../api/query/dao/AffinityGroupJoinDao.java | 37 +++ .../query/dao/AffinityGroupJoinDaoImpl.java | 155 +++++++++++ .../api/query/vo/AffinityGroupJoinVO.java | 248 ++++++++++++++++++ .../affinity/dao/AffinityGroupDaoImpl.java | 1 - .../dao/AffinityGroupVMMapDaoImpl.java | 1 - setup/db/db/schema-410to420.sql | 34 ++- 16 files changed, 661 insertions(+), 29 deletions(-) create mode 100644 server/src/com/cloud/api/query/dao/AffinityGroupJoinDao.java create mode 100644 server/src/com/cloud/api/query/dao/AffinityGroupJoinDaoImpl.java create mode 100644 server/src/com/cloud/api/query/vo/AffinityGroupJoinVO.java diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupResponse.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupResponse.java index 073a82c4363..1ae7c59a0ef 100644 --- a/api/src/org/apache/cloudstack/affinity/AffinityGroupResponse.java +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupResponse.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.affinity; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; import org.apache.cloudstack.api.ApiConstants; @@ -24,6 +25,7 @@ import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; import org.apache.cloudstack.api.response.ControlledEntityResponse; import org.apache.cloudstack.api.response.ControlledViewEntityResponse; +import org.apache.cloudstack.api.response.UserVmResponse; import com.cloud.network.security.SecurityGroup; import com.cloud.serializer.Param; @@ -31,7 +33,7 @@ import com.google.gson.annotations.SerializedName; @SuppressWarnings("unused") @EntityReference(value = AffinityGroup.class) -public class AffinityGroupResponse extends BaseResponse implements ControlledEntityResponse { +public class AffinityGroupResponse extends BaseResponse implements ControlledViewEntityResponse { @SerializedName(ApiConstants.ID) @Param(description="the ID of the affinity group") private String id; @@ -55,8 +57,12 @@ public class AffinityGroupResponse extends BaseResponse implements ControlledEnt @Param(description = "the type of the affinity group") private String type; + @SerializedName("virtualmachine") + @Param(description = "virtual machines associated with this affinity group ", responseObject = UserVmResponse.class) + private Set vmList; public AffinityGroupResponse() { + this.vmList = new LinkedHashSet(); } @Override @@ -136,4 +142,12 @@ public class AffinityGroupResponse extends BaseResponse implements ControlledEnt } + public void setVMList(Set vmList) { + this.vmList = vmList; + } + + public void addVM(UserVmResponse vm) { + this.vmList.add(vm); + } + } diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java index effbd869b95..9310fb91016 100644 --- a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java @@ -16,23 +16,16 @@ // under the License. package org.apache.cloudstack.api.command.user.affinitygroup; -import java.util.ArrayList; -import java.util.List; - -import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.log4j.Logger; import com.cloud.async.AsyncJob; -import com.cloud.utils.Pair; @APICommand(name = "listAffinityGroups", description = "Lists affinity groups", responseObject = AffinityGroupResponse.class) public class ListAffinityGroupsCmd extends BaseListCmd { @@ -83,22 +76,11 @@ public class ListAffinityGroupsCmd extends BaseListCmd { @Override public void execute(){ - Pair, Integer> result = _affinityGroupService.listAffinityGroups(id, - affinityGroupName, + ListResponse response = _queryService.listAffinityGroups(id, affinityGroupName, affinityGroupType, virtualMachineId, this.getStartIndex(), this.getPageSizeVal()); - if (result != null) { - ListResponse response = new ListResponse(); - List groupResponses = new ArrayList(); - for (AffinityGroup group : result.first()) { - AffinityGroupResponse groupResponse = _responseGenerator.createAffinityGroupResponse(group); - groupResponses.add(groupResponse); - } - response.setResponses(groupResponses, result.second()); - response.setResponseName(getCommandName()); - this.setResponseObject(response); - } else { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to search for affinity groups"); - } + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } @Override diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.java index 94f8446fa26..44d017b7d8b 100644 --- a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.api.command.user.affinitygroup; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; import org.apache.cloudstack.affinity.AffinityGroupResponse; @@ -27,6 +28,7 @@ import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiConstants.VMDetails; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.log4j.Logger; @@ -131,8 +133,12 @@ public class UpdateVMAffinityGroupCmd extends BaseAsyncCmd { InsufficientCapacityException, ServerApiException { UserContext.current().setEventDetails("Vm Id: "+getId()); UserVm result = _affinityGroupService.updateVMAffinityGroups(getId(), getAffinityGroupIdList()); + ArrayList dc = new ArrayList(); + dc.add(VMDetails.valueOf("affgrp")); + EnumSet details = EnumSet.copyOf(dc); + if (result != null){ - UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", result).get(0); + UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", details, result).get(0); response.setResponseName(getCommandName()); this.setResponseObject(response); } else { diff --git a/api/src/org/apache/cloudstack/query/QueryService.java b/api/src/org/apache/cloudstack/query/QueryService.java index c3f86aabb7f..443c5df65b5 100644 --- a/api/src/org/apache/cloudstack/query/QueryService.java +++ b/api/src/org/apache/cloudstack/query/QueryService.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.query; +import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd; @@ -97,4 +98,7 @@ public interface QueryService { public ListResponse searchForServiceOfferings(ListServiceOfferingsCmd cmd); public ListResponse listDataCenters(ListZonesByCmd cmd); + + public ListResponse listAffinityGroups(Long affinityGroupId, String affinityGroupName, + String affinityGroupType, Long vmId, Long startIndex, Long pageSize); } diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 67b1286eaed..0d13877b49b 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -836,5 +836,15 @@ --> + + + + + + + + + + diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 7f3e02d879d..92838fd85d3 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -31,6 +31,7 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + - - + + @@ -122,9 +121,9 @@ - - - + + + + + + + + diff --git a/test/integration/smoke/test_affinity_groups.py b/test/integration/smoke/test_affinity_groups.py index 432751c77c6..83fccf5c127 100644 --- a/test/integration/smoke/test_affinity_groups.py +++ b/test/integration/smoke/test_affinity_groups.py @@ -16,142 +16,181 @@ # specific language governing permissions and limitations # under the License. - - -import marvin from marvin.cloudstackTestCase import * -from marvin.remoteSSHClient import remoteSSHClient -import hashlib -import random +from marvin.cloudstackAPI import * +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from marvin import remoteSSHClient +from nose.plugins.attrib import attr + +class Services: + """Test Account Services + """ + + def __init__(self): + self.services = { + "domain": { + "name": "Domain", + }, + "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": 64, + # In MBs + }, + "ostype": 'CentOS 5.3 (64-bit)', + "mode": 'advanced', + "affinity": { + "name": "webvms", + "type": "host anti-affinity", + } + } + class TestDeployVmWithAffinityGroup(cloudstackTestCase): """ This test deploys a virtual machine into a user account using the small service offering and builtin template """ - def setUp(self): - """ - CloudStack internally saves its passwords in md5 form and that is how we - specify it in the API. Python's hashlib library helps us to quickly hash - strings as follows - """ - mdf = hashlib.md5() - mdf.update('password') - mdf_pass = mdf.hexdigest() - self.apiClient = self.testClient.getApiClient() #Get ourselves an API client + @classmethod + def setUpClass(cls): + cls.api_client = super(TestDeployVmWithAffinityGroup, cls).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + cls.disk_offering = DiskOffering.create( + cls.api_client, + cls.services["disk_offering"] + ) + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.services["volume"]["zoneid"] = cls.zone.id - self.acct = createAccount.createAccountCmd() #The createAccount command - self.acct.accounttype = 0 #We need a regular user. admins have accounttype=1 - self.acct.firstname = 'test' - self.acct.lastname = 'user' #What's up doc? - self.acct.password = mdf_pass #The md5 hashed password string - self.acct.username = 'testuser' - self.acct.email = 'testuser@xyz.com' - self.acct.account = 'testacct' - self.acct.domainid = 1 #The default ROOT domain - self.acctResponse = self.apiClient.createAccount(self.acct) - # And upon successful creation we'll log a helpful message in our logs - # using the default debug logger of the test framework - self.debug("successfully created account: %s, user: %s, id: \ - %s"%(self.acctResponse.account.account, \ - self.acctResponse.account.username, \ - self.acctResponse.account.id)) + cls.services["template"] = cls.template.id + cls.services["zoneid"] = cls.zone.id + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) - self.zone = listZones.listZonesCmd() - self.zone.uuid = self.apiClient.listZones(self.zone)[0].id + cls.services["account"] = cls.account.account.name - self.service_offering = listServiceOfferings.listServiceOfferingsCmd() - self.service_offering.uuid = self.apiClient.listServiceOfferings(self.service_offering)[0].id + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) - self.template = listTemplates.listTemplatesCmd() - self.template.templatefilter = 'featured' - self.template.name = 'CentOS' - self.template.uuid = self.apiClient.listTemplates(self.template)[0].id + cls.ag = AffinityGroup.create(cls.api_client, cls.services["affinity"], domainid=cls.domain.id) - def test_DeployVm(self): + cls._cleanup = [ + cls.service_offering, + cls.disk_offering, + cls.account, + ] + return + + @attr(tags=["simulator", "basic", "advanced"]) + def test_DeployVmAntiAffinityGroup(self): """ - Let's start by defining the attributes of our VM that we will be - deploying on CloudStack. We will be assuming a single zone is available - and is configured and all templates are Ready - - The hardcoded values are used only for brevity. - - First create the host anti-affinity group for this account + Deploys a couple of VMs in the same affinity group and verifies they are not on the same host """ - createAGCmd = createAffinityGroup.createAffinityGroupCmd() - createAGCmd.name = 'webvms1' - createAGCmd.type = 'host anti-affinity' - createAGCmd.account = self.acct.account - createAGCmd.domainid = self.acct.domainid + #deploy VM1 in affinity group created in setUp + vm1 = VirtualMachine.create( + self.api_client, + self.services["virtual_machine"], + templateid=self.template.id, + accountid=self.account.account.name, + domainid=self.account.account.domainid, + serviceofferingid=self.service_offering.id, + affinitygroupnames=self.ag.name, + mode=self.services["mode"] + ) - createAGResponse = self.apiClient.createAffinityGroup(createAGCmd) - self.debug("AffinityGroup %s was created in the job %s"%(createAGResponse.id, createAGResponse.jobid)) + list_vm1 = list_virtual_machines( + self.api_client, + id=vm1.id + ) + self.assertEqual( + isinstance(list_vm1, list), + True, + "Check list response returns a valid list" + ) + self.assertNotEqual( + len(list_vm1), + 0, + "Check VM available in List Virtual Machines" + ) + vm1_response = list_vm1[0] + self.assertEqual( + vm1_response.state, + 'Running', + msg="VM is not in Running state" + ) + host_of_vm1 = vm1_response.hostid + + #deploy VM2 in affinity group created in setUp + vm2 = VirtualMachine.create( + self.api_client, + self.services["virtual_machine"], + templateid=self.template.id, + accountid=self.account.account.name, + domainid=self.account.account.domainid, + serviceofferingid=self.service_offering.id, + affinitygroupnames=self.ag.name, + mode=self.services["mode"] + ) + list_vm2 = list_virtual_machines( + self.api_client, + id=self.vm1.id + ) + self.assertEqual( + isinstance(list_vm2, list), + True, + "Check list response returns a valid list" + ) + self.assertNotEqual( + len(list_vm2), + 0, + "Check VM available in List Virtual Machines" + ) + vm2_response = list_vm2[0] + self.assertEqual( + vm2_response.state, + 'Running', + msg="VM is not in Running state" + ) + host_of_vm2 = vm2_response.hostid + + self.assertNotEqual(host_of_vm1, host_of_vm2, + msg="Both VMs of affinity group %s are on the same host" % self.ag.name) - deployVmCmd = deployVirtualMachine.deployVirtualMachineCmd() - deployVmCmd.zoneid = self.zone.uuid - deployVmCmd.templateid = self.template.uuid #CentOS 5.6 builtin - deployVmCmd.serviceofferingid = self.service_offering.uuid - deployVmCmd.account = self.acct.account - deployVmCmd.domainid = self.acct.domainid - deployVmCmd.affinitygroupnames=[] - deployVmCmd.affinitygroupnames.append(str(createAGResponse.name)) - deployVmResponse = self.apiClient.deployVirtualMachine(deployVmCmd) - self.debug("VM %s was deployed in the job %s"%(deployVmResponse.id, deployVmResponse.jobid)) - - # At this point our VM is expected to be Running. Let's find out what - # listVirtualMachines tells us about VMs in this account - - listVmCmd = listVirtualMachines.listVirtualMachinesCmd() - listVmCmd.id = deployVmResponse.id - listVmResponse = self.apiClient.listVirtualMachines(listVmCmd) - - self.assertNotEqual(len(listVmResponse), 0, "Check if the list API \ - returns a non-empty response") - - vm = listVmResponse[0] - self.assertEqual(vm.state, "Running", "Check if VM has reached Running state in CS") - - VM1hostid = vm.hostid - - #Deploy another VM in same affinity group - deployVm2Cmd = deployVirtualMachine.deployVirtualMachineCmd() - deployVm2Cmd.zoneid = self.zone.uuid - deployVm2Cmd.templateid = self.template.uuid #CentOS 5.6 builtin - deployVm2Cmd.serviceofferingid = self.service_offering.uuid - deployVm2Cmd.account = self.acct.account - deployVm2Cmd.domainid = self.acct.domainid - deployVm2Cmd.affinitygroupnames=[] - deployVm2Cmd.affinitygroupnames.append(str(createAGResponse.name)) - - deployVm2Response = self.apiClient.deployVirtualMachine(deployVm2Cmd) - self.debug("VM2 %s was deployed in the job %s"%(deployVm2Response.id, deployVm2Response.jobid)) - - # At this point our VM is expected to be Running. Let's find out what - # listVirtualMachines tells us about VMs in this account - - listVm2Cmd = listVirtualMachines.listVirtualMachinesCmd() - listVm2Cmd.id = deployVm2Response.id - listVm2Response = self.apiClient.listVirtualMachines(listVm2Cmd) - - self.assertNotEqual(len(listVm2Response), 0, "Check if the list API \ - returns a non-empty response") - - vm2 = listVm2Response[0] - self.assertEqual(vm2.state, "Running", "Check if VM has reached Running state in CS") - - VM2hostid = vm2.hostid - - self.assertNotEqual(VM1hostid, VM2hostid, "The hosts of the 2 VM's in the host anti-affinity group are not different, test failed") - - def tearDown(self): - """ - And finally let us cleanup the resources we created by deleting the - account. All good unittests are atomic and rerunnable this way - """ - deleteAcct = deleteAccount.deleteAccountCmd() - deleteAcct.id = self.acctResponse.account.id - self.apiClient.deleteAccount(deleteAcct) - self.testClient.close() + @classmethod + def tearDown(cls): + try: + cls.api_client = super(TestDeployVmWithAffinityGroup, cls).getClsTestClient().getApiClient() + #Clean up, terminate the created templates + cleanup_resources(cls.api_client, cls.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index f3370eb3190..8c7470e65e1 100644 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -223,7 +223,7 @@ class VirtualMachine: def create(cls, apiclient, services, templateid=None, accountid=None, domainid=None, zoneid=None, networkids=None, serviceofferingid=None, securitygroupids=None, projectid=None, startvm=None, - diskofferingid=None, hostid=None, mode='basic'): + diskofferingid=None, affinitygroupname=None, hostid=None, mode='basic'): """Create the instance""" cmd = deployVirtualMachine.deployVirtualMachineCmd() @@ -268,6 +268,9 @@ class VirtualMachine: if "userdata" in services: cmd.userdata = base64.b64encode(services["userdata"]) + if "affinitygroupnames" in services: + cmd.affinitygroupnames = services["affinitygroupnames"] + if projectid: cmd.projectid = projectid @@ -2424,3 +2427,27 @@ class VPC: cmd = listVPCs.listVPCsCmd() [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listVPCs(cmd)) + + +class AffinityGroup: + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, account=None, domainid=None): + agCmd = createAffinityGroup.createAffinityGroupCmd() + agCmd.name = services['name'] + agCmd.displayText = services['displaytext'] if 'displaytext' in services else services['name'] + agCmd.type = services['type'] + agCmd.account = services['account'] if 'account' in services else account + agCmd.domainid = services['domainid'] if 'domainid' in services else domainid + + def update(self): + pass + + def delete(self): + pass + + @classmethod + def list(cls): + pass \ No newline at end of file From 943aef76f1c7339cd31613b7780fb0e93c6a7a90 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Mon, 8 Apr 2013 23:25:06 +0530 Subject: [PATCH 36/45] marvin bvt: getting rid of unused keys in the test Signed-off-by: Prasanna Santhanam --- test/integration/smoke/test_affinity_groups.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/test/integration/smoke/test_affinity_groups.py b/test/integration/smoke/test_affinity_groups.py index 83fccf5c127..0d06e6480b7 100644 --- a/test/integration/smoke/test_affinity_groups.py +++ b/test/integration/smoke/test_affinity_groups.py @@ -53,9 +53,11 @@ class Services: }, "ostype": 'CentOS 5.3 (64-bit)', "mode": 'advanced', - "affinity": { - "name": "webvms", - "type": "host anti-affinity", + "virtual_machine" : { + "affinity": { + "name": "webvms", + "type": "host anti-affinity", + } } } @@ -73,17 +75,12 @@ class TestDeployVmWithAffinityGroup(cloudstackTestCase): # Get Zone, Domain and templates cls.domain = get_domain(cls.api_client, cls.services) cls.zone = get_zone(cls.api_client, cls.services) - cls.disk_offering = DiskOffering.create( - cls.api_client, - cls.services["disk_offering"] - ) cls.template = get_template( cls.api_client, cls.zone.id, cls.services["ostype"] ) cls.services["virtual_machine"]["zoneid"] = cls.zone.id - cls.services["volume"]["zoneid"] = cls.zone.id cls.services["template"] = cls.template.id cls.services["zoneid"] = cls.zone.id @@ -101,7 +98,7 @@ class TestDeployVmWithAffinityGroup(cloudstackTestCase): cls.services["service_offering"] ) - cls.ag = AffinityGroup.create(cls.api_client, cls.services["affinity"], domainid=cls.domain.id) + cls.ag = AffinityGroup.create(cls.api_client, cls.services["virtual_machine"]["affinity"], domainid=cls.domain.id) cls._cleanup = [ cls.service_offering, From 7201eb9ee492e3faad5c70db81906fa32e1861bb Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Mon, 8 Apr 2013 11:04:01 -0700 Subject: [PATCH 37/45] CLOUDSTACK-1968: affinity_groups: Column 'deployment planner' cannot be null when creating a service offering Added default value to all constructors.. --- server/src/com/cloud/service/ServiceOfferingVO.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/server/src/com/cloud/service/ServiceOfferingVO.java b/server/src/com/cloud/service/ServiceOfferingVO.java index 40f817d076b..a3da904688c 100755 --- a/server/src/com/cloud/service/ServiceOfferingVO.java +++ b/server/src/com/cloud/service/ServiceOfferingVO.java @@ -87,6 +87,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering this.volatileVm = false; this.default_use = defaultUse; this.vm_type = vm_type == null ? null : vm_type.toString().toLowerCase(); + this.deploymentPlanner = "FirstFitPlanner"; } public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse, boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId) { @@ -100,11 +101,13 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering this.limitCpuUse = limitCpuUse; this.volatileVm = volatileVm; this.vm_type = vm_type == null ? null : vm_type.toString().toLowerCase(); + this.deploymentPlanner = "FirstFitPlanner"; } public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId, String hostTag) { this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, displayText, useLocalStorage, recreatable, tags, systemUse, vm_type, domainId); this.hostTag = hostTag; + this.deploymentPlanner = "FirstFitPlanner"; } public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, @@ -113,7 +116,11 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering String hostTag, String deploymentPlanner) { this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, displayText, useLocalStorage, recreatable, tags, systemUse, vm_type, domainId, hostTag); - this.deploymentPlanner = deploymentPlanner; + if (deploymentPlanner != null) { + this.deploymentPlanner = deploymentPlanner; + } else { + this.deploymentPlanner = "FirstFitPlanner"; + } } @Override From 9de7a68e922951d9a92c6f6ac3ae1f06199a943c Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Tue, 9 Apr 2013 16:31:18 +0530 Subject: [PATCH 38/45] affinitygroup bvt: changes to the bvt for affinity groups Added tags for the test, base.py extensions for list, craete, delete and fixes to the test Signed-off-by: Prasanna Santhanam --- .../integration/smoke/test_affinity_groups.py | 23 +++++++++-------- tools/marvin/marvin/integration/lib/base.py | 25 +++++++++++-------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/test/integration/smoke/test_affinity_groups.py b/test/integration/smoke/test_affinity_groups.py index 0d06e6480b7..832c4a4e1fa 100644 --- a/test/integration/smoke/test_affinity_groups.py +++ b/test/integration/smoke/test_affinity_groups.py @@ -52,12 +52,12 @@ class Services: # In MBs }, "ostype": 'CentOS 5.3 (64-bit)', - "mode": 'advanced', "virtual_machine" : { "affinity": { "name": "webvms", "type": "host anti-affinity", - } + }, + "hypervisor" : "XenServer", } } @@ -98,19 +98,22 @@ class TestDeployVmWithAffinityGroup(cloudstackTestCase): cls.services["service_offering"] ) - cls.ag = AffinityGroup.create(cls.api_client, cls.services["virtual_machine"]["affinity"], domainid=cls.domain.id) + cls.ag = AffinityGroup.create(cls.api_client, cls.services["virtual_machine"]["affinity"], + account=cls.services["account"], domainid=cls.domain.id) cls._cleanup = [ cls.service_offering, - cls.disk_offering, cls.account, ] return - @attr(tags=["simulator", "basic", "advanced"]) + @attr(tags=["simulator", "basic", "advanced", "multihost"]) def test_DeployVmAntiAffinityGroup(self): """ - Deploys a couple of VMs in the same affinity group and verifies they are not on the same host + test DeployVM in anti-affinity groups + + deploy VM1 and VM2 in the same host-anti-affinity groups + Verify that the vms are deployed on separate hosts """ #deploy VM1 in affinity group created in setUp vm1 = VirtualMachine.create( @@ -120,8 +123,7 @@ class TestDeployVmWithAffinityGroup(cloudstackTestCase): accountid=self.account.account.name, domainid=self.account.account.domainid, serviceofferingid=self.service_offering.id, - affinitygroupnames=self.ag.name, - mode=self.services["mode"] + affinitygroupnames=[self.ag.name] ) list_vm1 = list_virtual_machines( @@ -154,12 +156,11 @@ class TestDeployVmWithAffinityGroup(cloudstackTestCase): accountid=self.account.account.name, domainid=self.account.account.domainid, serviceofferingid=self.service_offering.id, - affinitygroupnames=self.ag.name, - mode=self.services["mode"] + affinitygroupnames=[self.ag.name] ) list_vm2 = list_virtual_machines( self.api_client, - id=self.vm1.id + id=vm2.id ) self.assertEqual( isinstance(list_vm2, list), diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index 8c7470e65e1..d27ab3b2903 100644 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -90,10 +90,7 @@ class Account: cmd.firstname = services["firstname"] cmd.lastname = services["lastname"] - # Password Encoding - mdf = hashlib.md5() - mdf.update(services["password"]) - cmd.password = mdf.hexdigest() + cmd.password = services["password"] cmd.username = "-".join([services["username"], random_gen()]) if domainid: @@ -223,7 +220,7 @@ class VirtualMachine: def create(cls, apiclient, services, templateid=None, accountid=None, domainid=None, zoneid=None, networkids=None, serviceofferingid=None, securitygroupids=None, projectid=None, startvm=None, - diskofferingid=None, affinitygroupname=None, hostid=None, mode='basic'): + diskofferingid=None, affinitygroupnames=None, hostid=None, mode='basic'): """Create the instance""" cmd = deployVirtualMachine.deployVirtualMachineCmd() @@ -270,6 +267,8 @@ class VirtualMachine: if "affinitygroupnames" in services: cmd.affinitygroupnames = services["affinitygroupnames"] + elif affinitygroupnames: + cmd.affinitygroupnames = affinitygroupnames if projectid: cmd.projectid = projectid @@ -2441,13 +2440,19 @@ class AffinityGroup: agCmd.type = services['type'] agCmd.account = services['account'] if 'account' in services else account agCmd.domainid = services['domainid'] if 'domainid' in services else domainid + return AffinityGroup(apiclient.createAffinityGroup(agCmd).__dict__) - def update(self): + def update(self, apiclient): pass - def delete(self): - pass + def delete(self, apiclient): + cmd = deleteAffinityGroup.deleteAffinityGroupCmd() + cmd.id = self.id + return apiclient.deleteVPC(cmd) + @classmethod - def list(cls): - pass \ No newline at end of file + def list(cls, apiclient, **kwargs): + cmd = listAffinityGroups.listAffinityGroupsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVPCs(cmd)) From fc248cb99c2febfa165e215dc2d2c38fddf980b5 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Mon, 8 Apr 2013 13:27:18 -0700 Subject: [PATCH 39/45] ACl on affinity group --- server/src/com/cloud/vm/UserVmManagerImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 8b6ad3b8829..d281e5b4dc8 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2289,6 +2289,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use AffinityGroupVO ag = _affinityGroupDao.findById(affinityGroupId); if (ag == null) { throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId); + } else { + // verify permissions + _accountMgr.checkAccess(caller, null, true, owner, ag); } } } From bbf7900732d46e60a4708901b4767e3ef73dbb10 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Wed, 10 Apr 2013 14:18:36 -0700 Subject: [PATCH 40/45] Adding pretty toString() to AffinityGroup --- .../org/apache/cloudstack/affinity/AffinityGroupVO.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupVO.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupVO.java index fab3835feda..b6c4a027484 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupVO.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupVO.java @@ -104,4 +104,11 @@ public class AffinityGroupVO implements AffinityGroup { return type; } + @Override + public String toString() { + StringBuilder buf = new StringBuilder("AffinityGroup["); + buf.append(id).append("|").append(name).append("|").append(type).append("]"); + return buf.toString(); + } + } From eea0ed5c4e9b55b4ded12dc268c93f1cf3bb20a0 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 11 Apr 2013 12:17:31 -0700 Subject: [PATCH 41/45] Fixes for issues found while testing after the merge --- .../user/affinitygroup/DeleteAffinityGroupCmd.java | 2 +- .../cloudstack/affinity/HostAntiAffinityProcessor.java | 1 + .../cloudstack/affinity/AffinityGroupServiceImpl.java | 10 +++++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/DeleteAffinityGroupCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/DeleteAffinityGroupCmd.java index 4ceba29e63e..ea4a010ab93 100644 --- a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/DeleteAffinityGroupCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/DeleteAffinityGroupCmd.java @@ -52,7 +52,7 @@ public class DeleteAffinityGroupCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, description = "The ID of the affinity group. Mutually exclusive with name parameter", entityType = AffinityGroupResponse.class) private Long id; - @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "The ID of the affinity group. Mutually exclusive with id parameter") + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "The name of the affinity group. Mutually exclusive with id parameter") private String name; diff --git a/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java b/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java index 4011c028546..430cf92659d 100644 --- a/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java +++ b/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java @@ -62,6 +62,7 @@ public class HostAntiAffinityProcessor extends AffinityProcessorBase implements } List groupVMIds = _affinityGroupVMMapDao.listVmIdsByAffinityGroup(group.getId()); + groupVMIds.remove(vm.getId()); for (Long groupVMId : groupVMIds) { VMInstanceVO groupVM = _vmInstanceDao.findById(groupVMId); diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java index 5c7edc567d5..613c095ae9f 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java @@ -130,7 +130,9 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro throw new InvalidParameterValueException( "Either the affinity group Id or group name must be specified to delete the group"); } - + if (affinityGroupId == null) { + affinityGroupId = group.getId(); + } // check permissions _accountMgr.checkAccess(caller, null, true, group); @@ -302,11 +304,17 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro + "; make sure the virtual machine is stopped and not in an error state before updating."); } + Account caller = UserContext.current().getCaller(); + Account owner = _accountMgr.getAccount(vmInstance.getAccountId()); + // check that the affinity groups exist for (Long affinityGroupId : affinityGroupIds) { AffinityGroupVO ag = _affinityGroupDao.findById(affinityGroupId); if (ag == null) { throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId); + } else { + // verify permissions + _accountMgr.checkAccess(caller, null, true, owner, ag); } } _affinityGroupVMMapDao.updateMap(vmId, affinityGroupIds); From 6137d327a8969e403c4fe0ae05c2bd1d7a12033e Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 11 Apr 2013 13:09:49 -0700 Subject: [PATCH 42/45] Fixes to unit-test dues to changes in master --- .../affinity/AffinityGroupServiceImpl.java | 3 ++- .../AffinityApiTestConfiguration.java | 18 ++++++++++++++-- .../affinity/AffinityApiUnitTest.java | 10 +++++++++ server/test/resources/affinityContext.xml | 21 +++++++++++-------- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java index 613c095ae9f..2ea887cc6cf 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java @@ -64,6 +64,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro private UserVmDao _userVmDao; @Override + @ActionEvent(eventType = EventTypes.EVENT_AFFINITY_GROUP_CREATE, eventDescription = "Creating Affinity Group", create = true) public AffinityGroup createAffinityGroup(String account, Long domainId, String affinityGroupName, String affinityGroupType, String description) { @@ -106,7 +107,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro @DB @Override - @ActionEvent(eventType = EventTypes.EVENT_SECURITY_GROUP_DELETE, eventDescription = "deleting affinity group") + @ActionEvent(eventType = EventTypes.EVENT_AFFINITY_GROUP_DELETE, eventDescription = "Deleting affinity group") public boolean deleteAffinityGroup(Long affinityGroupId, String account, Long domainId, String affinityGroupName) throws ResourceInUseException { diff --git a/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java b/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java index d778ed44ef3..c6a0755744c 100644 --- a/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java +++ b/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java @@ -50,6 +50,8 @@ import com.cloud.dc.dao.PodVlanDaoImpl; import com.cloud.dc.dao.PodVlanMapDaoImpl; import com.cloud.dc.dao.VlanDaoImpl; import com.cloud.domain.dao.DomainDaoImpl; +import com.cloud.event.EventUtils; +import com.cloud.event.dao.EventDaoImpl; import com.cloud.event.dao.UsageEventDaoImpl; import com.cloud.host.dao.HostDaoImpl; import com.cloud.host.dao.HostDetailsDaoImpl; @@ -100,6 +102,7 @@ import com.cloud.user.AccountManager; import com.cloud.user.ResourceLimitService; import com.cloud.user.UserContext; import com.cloud.user.UserContextInitializer; +import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.AccountDaoImpl; import com.cloud.user.dao.UserDaoImpl; import com.cloud.utils.component.SpringComponentScanUtils; @@ -115,7 +118,7 @@ import com.cloud.vm.dao.VMInstanceDaoImpl; @Configuration @ComponentScan(basePackageClasses = { AccountVlanMapDaoImpl.class, VolumeDaoImpl.class, HostPodDaoImpl.class, DomainDaoImpl.class, SwiftDaoImpl.class, ServiceOfferingDaoImpl.class, VlanDaoImpl.class, - IPAddressDaoImpl.class, ResourceTagsDaoImpl.class, AccountDaoImpl.class, InstanceGroupDaoImpl.class, + IPAddressDaoImpl.class, ResourceTagsDaoImpl.class, InstanceGroupDaoImpl.class, UserAccountJoinDaoImpl.class, CapacityDaoImpl.class, SnapshotDaoImpl.class, HostDaoImpl.class, VMInstanceDaoImpl.class, HostTransferMapDaoImpl.class, PortForwardingRulesDaoImpl.class, PrivateIpDaoImpl.class, UsageEventDaoImpl.class, PodVlanMapDaoImpl.class, DiskOfferingDaoImpl.class, @@ -126,9 +129,20 @@ import com.cloud.vm.dao.VMInstanceDaoImpl; FirewallRulesCidrsDaoImpl.class, PhysicalNetworkDaoImpl.class, PhysicalNetworkTrafficTypeDaoImpl.class, PhysicalNetworkServiceProviderDaoImpl.class, LoadBalancerDaoImpl.class, NetworkServiceMapDaoImpl.class, PrimaryDataStoreDaoImpl.class, StoragePoolDetailsDaoImpl.class, AffinityGroupServiceImpl.class, - ComponentContext.class, AffinityGroupProcessor.class, UserVmVO.class }, includeFilters = { @Filter(value = AffinityApiTestConfiguration.Library.class, type = FilterType.CUSTOM) }, useDefaultFilters = false) + ComponentContext.class, AffinityGroupProcessor.class, UserVmVO.class, EventUtils.class, UserVmVO.class, + EventDaoImpl.class }, includeFilters = { @Filter(value = AffinityApiTestConfiguration.Library.class, type = FilterType.CUSTOM) }, useDefaultFilters = false) public class AffinityApiTestConfiguration { + @Bean + public AccountDao accountDao() { + return Mockito.mock(AccountDao.class); + } + + @Bean + public EventUtils eventUtils() { + return Mockito.mock(EventUtils.class); + } + @Bean public AffinityGroupProcessor affinityGroupProcessor() { return Mockito.mock(AffinityGroupProcessor.class); diff --git a/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java index 17f165dd4dd..86cf0174579 100644 --- a/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java +++ b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java @@ -34,6 +34,7 @@ import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import com.cloud.event.EventUtils; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceInUseException; import com.cloud.hypervisor.Hypervisor.HypervisorType; @@ -43,6 +44,7 @@ import com.cloud.user.AccountManagerImpl; import com.cloud.user.AccountVO; import com.cloud.user.UserContext; import com.cloud.user.UserContextInitializer; +import com.cloud.user.dao.AccountDao; import com.cloud.utils.component.ComponentContext; import com.cloud.vm.UserVmVO; import com.cloud.vm.VirtualMachine; @@ -73,6 +75,12 @@ public class AffinityApiUnitTest { @Inject AffinityGroupVMMapDao _affinityGroupVMMapDao; + @Inject + EventUtils _eventUtils; + + @Inject + AccountDao _accountDao; + private static long domainId = 5L; @@ -83,6 +91,7 @@ public class AffinityApiUnitTest { @Before public void testSetUp() { + ComponentContext.initComponentsLifeCycle(); AccountVO acct = new AccountVO(200L); acct.setType(Account.ACCOUNT_TYPE_NORMAL); acct.setAccountName("user"); @@ -92,6 +101,7 @@ public class AffinityApiUnitTest { when(_acctMgr.finalizeOwner((Account) anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct); when(_processor.getType()).thenReturn("mock"); + when(_accountDao.findByIdIncludingRemoved(0L)).thenReturn(acct); } @Test diff --git a/server/test/resources/affinityContext.xml b/server/test/resources/affinityContext.xml index 652905c108e..15476c1a1b3 100644 --- a/server/test/resources/affinityContext.xml +++ b/server/test/resources/affinityContext.xml @@ -23,13 +23,18 @@ - - - - - - - + + + + + + + + + + + + @@ -38,7 +43,5 @@ - - \ No newline at end of file From bfed74c4119d23dd88ccd2c3e7b15d9a9ac66ea3 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 11 Apr 2013 13:37:03 -0700 Subject: [PATCH 43/45] Fixing rat. Merge with master missed the header change --- .../exception/AffinityConflictException.java | 16 ++++++++++++++++ .../cloudstack/affinity/AffinityGroup.java | 16 ++++++++++++++++ .../affinity/AffinityGroupProcessor.java | 16 ++++++++++++++++ .../affinity/AffinityGroupService.java | 16 ++++++++++++++++ .../cloud/deploy/DeploymentPlanningManager.java | 16 ++++++++++++++++ .../deploy/DeploymentPlanningManagerImpl.java | 16 ++++++++++++++++ .../affinity/AffinityGroupServiceImpl.java | 16 ++++++++++++++++ 7 files changed, 112 insertions(+) diff --git a/api/src/com/cloud/exception/AffinityConflictException.java b/api/src/com/cloud/exception/AffinityConflictException.java index da7148f1e2d..8b187783f24 100644 --- a/api/src/com/cloud/exception/AffinityConflictException.java +++ b/api/src/com/cloud/exception/AffinityConflictException.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.exception; import com.cloud.utils.SerialVersionUID; diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroup.java b/api/src/org/apache/cloudstack/affinity/AffinityGroup.java index b8215a279a8..ac2eb613370 100644 --- a/api/src/org/apache/cloudstack/affinity/AffinityGroup.java +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroup.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 org.apache.cloudstack.affinity; import org.apache.cloudstack.acl.ControlledEntity; diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java index 9bdd0515f47..60b8e4c554f 100644 --- a/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.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 org.apache.cloudstack.affinity; import com.cloud.deploy.DeploymentPlan; diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java index b6bf2ab1d78..26c32c89c1f 100644 --- a/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupService.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 org.apache.cloudstack.affinity; import java.util.List; diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManager.java b/server/src/com/cloud/deploy/DeploymentPlanningManager.java index 4ac71e3ac81..13f1c67d613 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManager.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManager.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.deploy; import com.cloud.deploy.DeploymentPlanner.ExcludeList; diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index 11e5b82d176..92aac3775a1 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.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.deploy; import java.util.List; diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java index 2ea887cc6cf..2b490efe6e5 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.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 org.apache.cloudstack.affinity; import java.util.ArrayList; From b1f67a08816f683ed44456fd7c4124ba2a82f495 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 11 Apr 2013 13:37:30 -0700 Subject: [PATCH 44/45] CLOUDSTACK-1065: cloudstack UI - AWS Style Regions - set autocomplete off. --- ui/index.jsp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/index.jsp b/ui/index.jsp index 3b8f37886ef..46f49f00984 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -56,7 +56,7 @@ under the License.
- +
From 5f8a2781967971e28bc2751d0903d9c99ea4e28e Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 11 Apr 2013 13:38:25 -0700 Subject: [PATCH 45/45] CLOUDSTACK-1065: cloudstack UI - AWS Style Regions - make loginCmdText local. --- ui/scripts/cloudStack.js | 4 ++-- ui/scripts/ui-custom/regions.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/scripts/cloudStack.js b/ui/scripts/cloudStack.js index 0cf80b02066..a8bca91769c 100644 --- a/ui/scripts/cloudStack.js +++ b/ui/scripts/cloudStack.js @@ -255,11 +255,11 @@ array1.push("&domain=" + encodeURIComponent("/")); } - g_loginCmdText = array1.join(""); + var loginCmdText = array1.join(""); $.ajax({ type: "POST", - data: "command=login" + g_loginCmdText + "&response=json", + data: "command=login" + loginCmdText + "&response=json", dataType: "json", async: false, success: function(json) { diff --git a/ui/scripts/ui-custom/regions.js b/ui/scripts/ui-custom/regions.js index 2f61dfddeaf..0469638f8f2 100644 --- a/ui/scripts/ui-custom/regions.js +++ b/ui/scripts/ui-custom/regions.js @@ -89,7 +89,7 @@ closeRegionSelector({ complete: function() { $('#container').prepend($('
').addClass('loading-overlay')); - window.name = g_loginCmdText; + //window.name = g_loginCmdText; document.location.href = url; } });